From cdbb6a9720e2f777069656ca385b7fa980d2e995 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Sun, 24 May 2026 20:30:34 -0700 Subject: [PATCH] Get it to ACTUALLY compile :) --- .../application_wrapper_cache_l1_test.py | 493 ------------------ .../application_wrapper_cache_top_test.py | 34 ++ sim/application_wrapper/cache/cache.yaml | 8 + ...application_wrapper_cache_bus_interface.sv | 8 +- .../cache/application_wrapper_cache_lru.sv | 8 +- .../cache/application_wrapper_cache_top.sv | 23 +- 6 files changed, 76 insertions(+), 498 deletions(-) delete mode 100644 sim/application_wrapper/cache/application_wrapper_cache_l1_test.py create mode 100644 sim/application_wrapper/cache/application_wrapper_cache_top_test.py diff --git a/sim/application_wrapper/cache/application_wrapper_cache_l1_test.py b/sim/application_wrapper/cache/application_wrapper_cache_l1_test.py deleted file mode 100644 index 9911be6..0000000 --- a/sim/application_wrapper/cache/application_wrapper_cache_l1_test.py +++ /dev/null @@ -1,493 +0,0 @@ -import cocotb -from cocotb.handle import Immediate, LogicArray - -from cocotb.simulator import get_sim_time - -from cocotb.clock import Clock -from cocotb.triggers import Timer, RisingEdge, FallingEdge, with_timeout - -from enum import IntEnum - -from collections import defaultdict -from collections.abc import Mapping - -import logging - -import random - - -logger = logging.getLogger() - -logger.setLevel(logging.INFO) - -CLK_PERIOD = 5 - -reference_cache_data = defaultdict(bytearray) - -higher_cache_data = defaultdict(bytearray) - -async def cpu_sequencer(dut, sequence: Mapping[int, int, bool, bool]): - - - addr, do, we, sync = sequence[0] - - dut.i_addr.value = addr - dut.i_data.value = do - dut.i_we.value = we - dut.i_sync.value = sync - - await FallingEdge(dut.i_rst) - - index = 1 - - while index < len(sequence): - await RisingEdge(dut.i_clk) - if not dut.o_rdy.value: - continue - - addr, do, we, sync = sequence[index] - - dut.i_addr.value = addr - dut.i_data.value = do - dut.i_we.value = we - dut.i_sync.value = sync - - index += 1 - - await Timer(150, "ns") - -async def cpu_data_monitor(dut): - previous_address = 0 - address = 0 - - we = 0 - previous_we = 0 - - i_data = 0 - previous_i_data = 0 - - await FallingEdge(dut.i_rst) - - while True: - await RisingEdge(dut.i_clk) - if not dut.o_rdy.value: - continue - - previous_address = address - previous_we = we - address = int(dut.i_addr.value) - we = int(dut.i_we.value) - - previous_i_data = i_data - i_data = int(dut.i_data.value) - - data = int(dut.o_data.value) - - if previous_address == 0: - continue - - # don't care if it was a write - if previous_we: - - index = (previous_address // 64) % 64 - offset = previous_address % 64 - - cacheline = reference_cache_data[index] - - cacheline[offset] = previous_i_data - logger.debug(f"We saw a write here {index=} {offset=} previous_data={previous_i_data:x}") - else: - index = (previous_address // 64) % 64 - offset = previous_address % 64 - - cacheline = reference_cache_data[index] - - expected_data = cacheline[offset] - - if (data != expected_data): - logger.error(f"{get_sim_time()} {address=:x} {previous_address=:x} {data=:x} {expected_data=:x}") - - - -async def mmu_sequencer(dut): - while True: - await RisingEdge(dut.i_clk) - dut.i_phys_address.value = dut.i_addr.value - -async def handle_higher_level_cache(dut): - dut.i_cache_rdy.value = 0 - - class CacheCmd(IntEnum): - CACHE_NONE = 0 - CACHE_READ = 1 - CACHE_WRITE = 2 - - while True: - await RisingEdge(dut.i_clk) - dut.i_cache_rdy.value = 0 - - if not dut.o_cache_valid.value: - continue - - cmd = CacheCmd(dut.o_cache_cmd.value) - addr = int(dut.o_cache_addr.value) - - logger.debug(f"{cmd=} {addr=}") - - - if cmd == CacheCmd.CACHE_READ: - - if addr not in higher_cache_data: - data = bytearray(random.randbytes(64)) - higher_cache_data[addr] = data - - dut.i_cache_data.value = LogicArray.from_bytes(higher_cache_data[addr] , byteorder="little") - - dut.i_cache_rdy.value = 1 - - reference_cache_data[int(dut.read_index.value)] = higher_cache_data[addr] - - await RisingEdge(dut.i_clk) - - dut.i_cache_rdy.value = 0 - - elif cmd == CacheCmd.CACHE_WRITE: - - dut.i_cache_rdy.value = 1 - - data = dut.o_cache_data.value.to_bytes(byteorder="little") - - higher_cache_data[addr] = bytearray(data) - - await RisingEdge(dut.i_clk) - - dut.i_cache_rdy.value = 0 - -@cocotb.test -async def sanity_test(dut): - expected_cache_misses = 0 - expected_evictions = 0 - - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - cpu_sequence = [ - (0x100, 0xaa, True, False), - (0x101, 0xbb, True, False), - (0x100, 0x00, False, False), - (0x101, 0x00, False, False), - (0x200, 0xcc, True, False), - (0x201, 0xdd, True, False), - (0x100, 0x00, False, False), - (0x101, 0x00, False, False), - (0x200, 0x00, False, False), - (0x201, 0x00, False, False), - (0x100, 0x11, True, False), - (0x101, 0x22, True, False), - (0x100, 0x00, False, False), - (0x200, 0x33, True, False), - (0x101, 0x00, False, False), - (0x201, 0x44, True, False), - (0x100, 0x00, False, False), - (0x200, 0x00, False, False), - (0x101, 0x00, False, False), - (0x201, 0x00, False, False), - ] - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - - expected_cache_misses = 2 - expected_evictions = 0 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - - -@cocotb.test -async def clean_evict_test(dut): - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - # Read from one cacheline, then read from an aliased cacheline without writing. - # cacheline should be overwritten without evicting - cpu_sequence = [ - (0x100, 0x00, False, False), - (0x1100, 0x00, False, False), - ] - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - expected_cache_misses = 2 - expected_evictions = 0 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - -@cocotb.test -async def dirty_evict_test(dut): - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - # Read from one cacheline, then read from an aliased cacheline without writing. - # cacheline should be overwritten without evicting - cpu_sequence = [ - (0x100, 0x41, True, False), - (0x101, 0x42, True, False), - (0x1100, 0x00, False, False), - (0x1100, 0xaa, True, False), - (0x100, 0x00, False, False) - ] - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - expected_cache_misses = 3 - expected_evictions = 2 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - - -@cocotb.test -async def long_write_thrash_test(dut): - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - num_lines_read = 2**20//64 - - cpu_sequence = [ - (i*64, i % 256, True, False) - for i in range(num_lines_read)] - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - # The last 64 lines aren't evicted - expected_cache_misses = num_lines_read - expected_evictions = num_lines_read - 64 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - - -@cocotb.test -async def long_write_read_thrash_test(dut): - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - num_lines_read = 2**20//64 - - - cpu_sequence = [ - (i*64, i % 256, True, False) - for i in range(num_lines_read)] - - cpu_sequence.extend([ - (i*64, 0, False, False) - for i in range(num_lines_read)]) - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - expected_cache_misses = num_lines_read * 2 - expected_evictions = num_lines_read - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - - -@cocotb.test -async def long_write_linear_test(dut): - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - num_bytes_read = 2**16 - - cpu_sequence = [ - (i, i % 256, True, False) - for i in range(num_bytes_read)] - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - expected_cache_misses = num_bytes_read // 64 - expected_evictions = num_bytes_read//64 - 64 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - - -@cocotb.test -async def long_write_read_linear_test(dut): - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - num_bytes_read = 2**16 - - - cpu_sequence = [ - (i, i % 256, True, False) - for i in range(num_bytes_read)] - - cpu_sequence.extend([ - (i, 0, False, False) - for i in range(num_bytes_read)]) - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - expected_cache_misses = (num_bytes_read // 64) * 2 - expected_evictions = num_bytes_read // 64 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - -@cocotb.test -async def short_write_read_linear_test(dut): - # What makes this test "short" is that we read 64 cachelines, - # so we shouldn't have to make any evictions - # TODO add number of evictions and cachlines loaded as performance counteres - - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - num_bytes_read = 64*64 - - cpu_sequence = [ - (i, i % 256, True, False) - for i in range(num_bytes_read)] # 64 bytes times 64 cachelines - - cpu_sequence.extend([ - (i, i % 256, False, False) - for i in range(num_bytes_read)]) # 64 bytes times 64 cachelines - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) - - expected_cache_misses = num_bytes_read//64 - expected_evictions = num_bytes_read//64 - 64 - - dut_evictions = int(dut.eviction_count.value) - dut_misses = int(dut.cache_miss_count.value) - - if dut_evictions != expected_evictions: - logger.error(f"Eviction count mismatch! Expected {expected_evictions}, saw {dut_evictions}") - - if dut_misses != expected_cache_misses: - logger.error(f"Miss count mismatch! Expected {expected_cache_misses}, saw {dut_misses}") - -@cocotb.test -async def random_access_test(dut): - # Just fully random accesses - # This is also kind of a thrash test since this is not realistic - - cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) - cocotb.start_soon(mmu_sequencer(dut)) - cocotb.start_soon(handle_higher_level_cache(dut)) - cocotb.start_soon(cpu_data_monitor(dut)) - - num_bytes_read = 2**18 - - cpu_sequence = [ - (random.randint(0, 2**32), random.randint(0, 255), random.randint(0,1), random.randint(0,1)) - for _ in range(num_bytes_read)] # 64 bytes times 64 cachelines - - dut.i_rst.value = Immediate(1) - for _ in range(10): - await RisingEdge(dut.i_clk) - dut.i_rst.value = 0 - - await cpu_sequencer(dut, cpu_sequence) \ No newline at end of file diff --git a/sim/application_wrapper/cache/application_wrapper_cache_top_test.py b/sim/application_wrapper/cache/application_wrapper_cache_top_test.py new file mode 100644 index 0000000..121cfce --- /dev/null +++ b/sim/application_wrapper/cache/application_wrapper_cache_top_test.py @@ -0,0 +1,34 @@ +import cocotb +from cocotb.handle import Immediate + + +from cocotb.clock import Clock +from cocotb.triggers import Timer, RisingEdge + + +import logging + +import random + + +logger = logging.getLogger() + +logger.setLevel(logging.INFO) + +CLK_PERIOD = 5 + +@cocotb.test +async def test_sanity(dut): + # Request a read from the cache, then request a write to the cache + cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start()) + + dut.i_cpu_we.value = 0 + + dut.i_rst.value = Immediate(1) + for _ in range(10): + await RisingEdge(dut.i_clk) + dut.i_rst.value = 0 + + await RisingEdge(dut.o_cpu_rdy) + + await Timer(10, "us") \ No newline at end of file diff --git a/sim/application_wrapper/cache/cache.yaml b/sim/application_wrapper/cache/cache.yaml index 8304cbd..417e9c7 100644 --- a/sim/application_wrapper/cache/cache.yaml +++ b/sim/application_wrapper/cache/cache.yaml @@ -5,9 +5,17 @@ tests: - "application_wrapper_cache_arrays_test" sources: "sources.list" waves: True + - name: "application_wrapper_cache_miss_handler_test" toplevel: "application_wrapper_cache_miss_handler" modules: - "application_wrapper_cache_miss_handler_test" sources: "sources.list" + waves: True + + - name: "application_wrapper_cache_top_test" + toplevel: "application_wrapper_cache_top" + modules: + - "application_wrapper_cache_top_test" + sources: "sources.list" waves: True \ No newline at end of file diff --git a/src/application_wrapper/cache/application_wrapper_cache_bus_interface.sv b/src/application_wrapper/cache/application_wrapper_cache_bus_interface.sv index d307c12..c3d0631 100644 --- a/src/application_wrapper/cache/application_wrapper_cache_bus_interface.sv +++ b/src/application_wrapper/cache/application_wrapper_cache_bus_interface.sv @@ -1,7 +1,13 @@ import application_wrapper_cache_pkg::*; module application_wrapper_cache_bus_interface #( - parameter DATA_W = 64*8 + parameter DATA_W = 64*8, + + // these are all wip + localparam REQ_W = 32, + localparam RSP_W = 32, + localparam DAT_W = 512+64, + localparam SNP_W = 32 ) ( input logic i_clk, input logic i_rst, diff --git a/src/application_wrapper/cache/application_wrapper_cache_lru.sv b/src/application_wrapper/cache/application_wrapper_cache_lru.sv index f61bcd6..0db01f2 100644 --- a/src/application_wrapper/cache/application_wrapper_cache_lru.sv +++ b/src/application_wrapper/cache/application_wrapper_cache_lru.sv @@ -1,11 +1,15 @@ module application_wrapper_cache_lru #( // This should be NUM_WAYS - 1 parameter LRU_W = 3, - parameter NUM_SETS = 64 + parameter NUM_SETS = 64, + + localparam INDEX_W = $clog2(NUM_SETS) ) ( + input logic i_clk, + input logic [INDEX_W-1:0] i_read_index, input logic i_read_valid, - output logic [LRU_W-1:0] o_read_data, + output logic [LRU_W-1:0] o_read_data, input logic [INDEX_W-1:0] i_write_index, input logic i_write_valid, diff --git a/src/application_wrapper/cache/application_wrapper_cache_top.sv b/src/application_wrapper/cache/application_wrapper_cache_top.sv index 2bde648..0db9b8c 100644 --- a/src/application_wrapper/cache/application_wrapper_cache_top.sv +++ b/src/application_wrapper/cache/application_wrapper_cache_top.sv @@ -10,14 +10,19 @@ module application_wrapper_cache_top #( localparam TAG_W = 32 - INDEX_W - OFFSET_W, localparam LRU_W = NUM_WAYS-1, - localparam META_W = TAG_W + 2 + localparam META_W = TAG_W + 2, + + localparam REQ_W = 32, + localparam RSP_W = 32, + localparam DAT_W = 512+64, + localparam SNP_W = 32 ) ( input logic i_clk, input logic i_rst, // CPU Interface input logic [31:0] i_cpu_addr, - input logic i_we, + input logic i_cpu_we, input logic i_cpu_sync, input logic [7:0] i_cpu_data, output logic [7:0] o_cpu_data, @@ -140,6 +145,11 @@ logic [31:0] snoop_writeback_addr; logic snoop_writeback_valid; logic snoop_writeback_done; +logic [DATA_W-1:0] bus_writeback_data; +logic [31:0] bus_writeback_addr; +logic bus_writeback_valid; +logic bus_writeback_done; + logic [31:0] cpu_memory_addr; logic cpu_memory_valid; cache_cmd_e cpu_memory_cmd; @@ -148,6 +158,11 @@ logic [DATA_W-1:0] cpu_memory_data; logic cpu_memory_done; cache_resp_e cpu_memory_resp; + +logic [31:0] snoop_addr; +snoop_cmd_e snoop_cmd; +logic snoop_valid; + logic [31:0] snoop_memory_addr; logic snoop_memory_valid; cache_cmd_e snoop_memory_cmd; @@ -164,6 +179,8 @@ assign cpu_tag = mmu_phys_address[31:INDEX_W+OFFSET_W]; assign cpu_index = i_cpu_addr[INDEX_W+OFFSET_W-1:OFFSET_W]; assign cpu_offset = i_cpu_addr[OFFSET_W-1:0]; +assign o_cpu_rdy = miss_handler_rdy; + application_wrapper_cache_miss_handler #( .NUM_WAYS (NUM_WAYS), .NUM_SETS (NUM_SETS) @@ -250,6 +267,8 @@ application_wrapper_cache_lru #( .LRU_W (LRU_W), .NUM_SETS (NUM_SETS) ) u_lru ( + .i_clk (i_clk), + .i_read_index (cpu_lru_read_index), .i_read_valid (cpu_lru_read_valid), .o_read_data (cpu_lru_read_data),