feat(hw): add banked CAM pipeline with grouped read/write noise

- Add cam_core_banked.sv with 8-lane banked CAM core
- Add cam_write_noise.sv and cam_read_noise.sv for grouped noise injection
- Add noise_mask_grouped.sv generating grouped flip masks from 128-bit PRNG
- Add match_engine_pipeline.sv with multi-stage pipelined top-1 selection
- Add popcount_pipeline.sv for pipelined popcount operations
- Refactor test_cam_basic.py with parametrized DUT introspection helpers
- Add Python ref_model match_top1_with_read_noise() for read noise verification
- Update Makefile with separate WRITE_NOISE_* and READ_NOISE_* parameter groups
- Add new testbenches: test_cam_core_banked, test_cam_read_noise,
  test_cam_write_noise, test_match_engine_pipeline, test_ref_model_noise
  
breaking change hint: NUM_ROWS default changed from 512→4096, LANES from 16→8
This commit is contained in:
2026-05-13 16:21:27 +08:00
parent c41e64d1c6
commit 8f59a287c4
17 changed files with 1331 additions and 384 deletions

View File

@@ -0,0 +1,39 @@
from __future__ import annotations
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from model.ref_model import generate_write_flip_mask
async def reset_write_noise(dut):
dut.rst_n.value = 0
dut.wr_valid.value = 0
dut.wr_row.value = 0
dut.wr_hash.value = 0
for _ in range(3):
await RisingEdge(dut.clk)
dut.rst_n.value = 1
for _ in range(2):
await RisingEdge(dut.clk)
@cocotb.test()
async def write_noise_outputs_grouped_noisy_hash(dut):
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
await reset_write_noise(dut)
value = 0x123456789ABCDEF
dut.wr_row.value = 3
dut.wr_hash.value = value
dut.wr_valid.value = 1
await RisingEdge(dut.clk)
dut.wr_valid.value = 0
while int(dut.core_wr_valid.value) == 0:
await RisingEdge(dut.clk)
seed = 0xB504_F32D_B504_F32D
flip, _ = generate_write_flip_mask((seed << 64) | seed, 512, 8, 1, 100)
assert int(dut.core_wr_row.value) == 3
assert int(dut.core_wr_hash.value) == (value ^ flip)