refactor(hw/sim): extract common cocotb make infrastructure into shared mk/ directory

- Split monolithic hw/sim/Makefile into modular include files (mk/cocotb-common.mk, mk/rtl-sources.mk)
- Add per-module test Makefiles (cam_core_banked, cam_read_noise, cam_write_noise, match_engine_pipeline, perf, top)
- Add missing simulation tools (yosys, graphviz, xdot) to devenv.nix
- Fix path handling in sweep_noise.py and test modules to be HASH_BITS-aware
This commit is contained in:
2026-05-16 19:23:49 +08:00
parent 2e0e36eea5
commit ca167e79c6
27 changed files with 241 additions and 97 deletions

0
hw/sim/tests/__init__.py Normal file
View File

View File

View File

View File

@@ -0,0 +1,9 @@
SIM_ROOT := $(abspath ../../..)
RTL_ROOT := $(abspath $(SIM_ROOT)/../rtl)
include $(SIM_ROOT)/mk/rtl-sources.mk
TOPLEVEL := cam_core_banked
COCOTB_TEST_MODULES := tests.modules.cam_core_banked.test_cam_core_banked
VERILOG_SOURCES := $(RTL_CAM_CORE_BANKED)
include $(SIM_ROOT)/mk/cocotb-common.mk

View File

@@ -24,8 +24,9 @@ async def banked_core_reads_aligned_eight_row_batch_after_one_cycle(dut):
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
await reset_core(dut)
LANES = 8
LANES = len(dut.rd_lane_valid_o)
ROW_BITS = len(dut.rd_row_ids_o) // LANES
HASH_BITS = len(dut.rd_hashes_o) // LANES
for row in range(LANES):
dut.wr_valid.value = 1
@@ -43,6 +44,6 @@ async def banked_core_reads_aligned_eight_row_batch_after_one_cycle(dut):
assert int(dut.rd_valid_o.value) == 1
for lane in range(LANES):
got_row = (int(dut.rd_row_ids_o.value) >> (lane * ROW_BITS)) & ((1 << ROW_BITS) - 1)
got_hash = (int(dut.rd_hashes_o.value) >> (lane * 512)) & ((1 << 512) - 1)
got_hash = (int(dut.rd_hashes_o.value) >> (lane * HASH_BITS)) & ((1 << HASH_BITS) - 1)
assert got_row == lane
assert got_hash == lane + 0x100

View File

@@ -0,0 +1,15 @@
SIM_ROOT := $(abspath ../../..)
RTL_ROOT := $(abspath $(SIM_ROOT)/../rtl)
include $(SIM_ROOT)/mk/rtl-sources.mk
TOPLEVEL := cam_read_noise
COCOTB_TEST_MODULES := tests.modules.cam_read_noise.test_cam_read_noise
VERILOG_SOURCES := $(RTL_READ_NOISE)
HASH_BITS ?= 512
READ_NOISE_EN ?= 0
READ_NOISE_RATE_NUM ?= 0
READ_NOISE_RATE_DEN ?= 100
READ_NOISE_BITS ?= $(shell echo $$(( $(HASH_BITS) / 64 )))
include $(SIM_ROOT)/mk/cocotb-common.mk

View File

@@ -23,9 +23,10 @@ async def read_noise_disabled_forwards_hashes_after_one_stage(dut):
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
await reset_read_noise(dut)
LANES = 8
LANES = len(dut.lane_valid_i)
ROW_BITS = len(dut.row_ids_i) // LANES
HASH_BITS_PER_LANE = len(dut.hashes_i) // LANES
all_lanes_valid = (1 << LANES) - 1
hashes = 0
rows = 0
@@ -35,7 +36,7 @@ async def read_noise_disabled_forwards_hashes_after_one_stage(dut):
dut.hashes_i.value = hashes
dut.row_ids_i.value = rows
dut.lane_valid_i.value = 0xFF
dut.lane_valid_i.value = all_lanes_valid
dut.valid_i.value = 1
await RisingEdge(dut.clk)
dut.valid_i.value = 0
@@ -45,4 +46,4 @@ async def read_noise_disabled_forwards_hashes_after_one_stage(dut):
assert int(dut.valid_o.value) == 1
assert int(dut.hashes_noisy_o.value) == hashes
assert int(dut.row_ids_o.value) == rows
assert int(dut.lane_valid_o.value) == 0xFF
assert int(dut.lane_valid_o.value) == all_lanes_valid

View File

@@ -0,0 +1,15 @@
SIM_ROOT := $(abspath ../../..)
RTL_ROOT := $(abspath $(SIM_ROOT)/../rtl)
include $(SIM_ROOT)/mk/rtl-sources.mk
TOPLEVEL := cam_write_noise
COCOTB_TEST_MODULES := tests.modules.cam_write_noise.test_cam_write_noise
VERILOG_SOURCES := $(RTL_WRITE_NOISE)
HASH_BITS ?= 512
WRITE_NOISE_EN ?= 1
WRITE_NOISE_RATE_NUM ?= 1
WRITE_NOISE_RATE_DEN ?= 100
WRITE_NOISE_BITS ?= $(shell echo $$(( $(HASH_BITS) / 64 )))
include $(SIM_ROOT)/mk/cocotb-common.mk

View File

@@ -34,6 +34,8 @@ async def write_noise_outputs_grouped_noisy_hash(dut):
await RisingEdge(dut.clk)
seed = 0xB504_F32D_B504_F32D
flip, _ = generate_write_flip_mask((seed << 64) | seed, 512, 8, 1, 100)
hash_bits = len(dut.wr_hash)
noise_bits = hash_bits // 64
flip, _ = generate_write_flip_mask((seed << 64) | seed, hash_bits, noise_bits, 1, 100)
assert int(dut.core_wr_row.value) == 3
assert int(dut.core_wr_hash.value) == (value ^ flip)

View File

@@ -0,0 +1,9 @@
SIM_ROOT := $(abspath ../../..)
RTL_ROOT := $(abspath $(SIM_ROOT)/../rtl)
include $(SIM_ROOT)/mk/rtl-sources.mk
TOPLEVEL := match_engine_pipeline
COCOTB_TEST_MODULES := tests.modules.match_engine_pipeline.test_match_engine_pipeline
VERILOG_SOURCES := $(RTL_MATCH_ENGINE)
include $(SIM_ROOT)/mk/cocotb-common.mk

View File

@@ -26,7 +26,7 @@ async def match_engine_returns_top1_after_pipeline_drain(dut):
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
await reset_match(dut)
LANES = 8
LANES = len(dut.rd_lane_valid_i)
ROW_BITS = len(dut.rd_row_ids_i) // LANES
HASH_BITS = len(dut.rd_hashes_i) // LANES
NUM_ROWS = 1 << len(dut.rd_base_row_o)
@@ -51,7 +51,7 @@ async def match_engine_returns_top1_after_pipeline_drain(dut):
hashes |= row_hash << (lane * HASH_BITS)
dut.rd_row_ids_i.value = rows
dut.rd_hashes_i.value = hashes
dut.rd_lane_valid_i.value = 0xFF
dut.rd_lane_valid_i.value = (1 << LANES) - 1
dut.rd_valid_i.value = 1
await RisingEdge(dut.clk)
dut.rd_valid_i.value = 0

View File

@@ -0,0 +1,15 @@
SIM_ROOT := $(abspath ../..)
RTL_ROOT := $(abspath $(SIM_ROOT)/../rtl)
include $(SIM_ROOT)/mk/rtl-sources.mk
TOPLEVEL := cam_top
COCOTB_TEST_MODULES := tests.perf.test_cam_perf
VERILOG_SOURCES := $(RTL_CAM_TOP)
HASH_BITS ?= 512
WRITE_NOISE_EN := 0
READ_NOISE_EN := 0
WRITE_NOISE_BITS := $(shell echo $$(( $(HASH_BITS) / 64 )))
READ_NOISE_BITS := $(shell echo $$(( $(HASH_BITS) / 64 )))
include $(SIM_ROOT)/mk/cocotb-common.mk

View File

View File

@@ -0,0 +1,9 @@
SIM_ROOT := $(abspath ../..)
RTL_ROOT := $(abspath $(SIM_ROOT)/../rtl)
include $(SIM_ROOT)/mk/rtl-sources.mk
TOPLEVEL := cam_top
COCOTB_TEST_MODULES := tests.top.test_cam_basic
VERILOG_SOURCES := $(RTL_CAM_TOP)
include $(SIM_ROOT)/mk/cocotb-common.mk

View File