refactor(core/cam_core_banked): extract per-bank modules for improved timing isolation

- Extract cam_bank as a parameterized submodule with independent read/write ports
- Replace flat 2D memory array with generate loop of bank instances
- Derive bank selection from address bit slicing instead of modulo arithmetic
- Align rd_base_row_i check with new bank addressing scheme
- Add test verifying bank address isolation across multiple banks
This commit is contained in:
2026-05-19 13:59:25 +08:00
parent 5d09f13a08
commit 8bcad1f23f
2 changed files with 119 additions and 11 deletions

View File

@@ -19,6 +19,26 @@ async def reset_core(dut):
await RisingEdge(dut.clk)
def lane_word(value: int, lane: int, width: int) -> int:
return (value >> (lane * width)) & ((1 << width) - 1)
async def write_row(dut, row: int, hash_value: int):
dut.wr_valid.value = 1
dut.wr_row.value = row
dut.wr_hash.value = hash_value
await RisingEdge(dut.clk)
dut.wr_valid.value = 0
async def request_batch(dut, base_row: int):
dut.rd_base_row_i.value = base_row
dut.rd_valid_i.value = 1
await RisingEdge(dut.clk)
dut.rd_valid_i.value = 0
await RisingEdge(dut.clk)
@cocotb.test()
async def banked_core_reads_aligned_eight_row_batch_after_one_cycle(dut):
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
@@ -47,3 +67,35 @@ async def banked_core_reads_aligned_eight_row_batch_after_one_cycle(dut):
got_hash = (int(dut.rd_hashes_o.value) >> (lane * HASH_BITS)) & ((1 << HASH_BITS) - 1)
assert got_row == lane
assert got_hash == lane + 0x100
@cocotb.test()
async def banked_core_keeps_internal_bank_addresses_isolated(dut):
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
await reset_core(dut)
LANES = len(dut.rd_lane_valid_o)
ROW_BITS = len(dut.rd_row_ids_o) // LANES
HASH_BITS = len(dut.rd_hashes_o) // LANES
expected_by_row = {}
for bank_addr in range(3):
base_row = bank_addr * LANES
for lane in range(LANES):
row = base_row + lane
hash_value = 0xABC000 + (bank_addr << 8) + lane
expected_by_row[row] = hash_value
await write_row(dut, row, hash_value)
for bank_addr in range(3):
base_row = bank_addr * LANES
await request_batch(dut, base_row)
assert int(dut.rd_valid_o.value) == 1
assert int(dut.rd_lane_valid_o.value) == (1 << LANES) - 1
for lane in range(LANES):
row = base_row + lane
got_row = lane_word(int(dut.rd_row_ids_o.value), lane, ROW_BITS)
got_hash = lane_word(int(dut.rd_hashes_o.value), lane, HASH_BITS)
assert got_row == row
assert got_hash == expected_by_row[row]