refactor(cam): remove read noise from noise architecture (Phase 2)

- Make cam_read_noise a pass-through module, removing all noise injection logic
- Switch write noise to use noise_mask_bernoulli instead of noise_mask_grouped
- Add state machine to cam_write_noise for mask generation timing
- Remove noise_mask_grouped.sv (no longer needed)
- Remove read noise parameters from cam_noisy and cam_top
- Update simulation and benchmark code to reflect read noise removal
- Sync documentation to reflect Phase 2 architecture
This commit is contained in:
2026-05-26 23:02:22 +08:00
parent e5d13917b2
commit 8b4d4c1b57
29 changed files with 277 additions and 863 deletions

View File

@@ -7,9 +7,5 @@ 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

@@ -2,7 +2,7 @@ from __future__ import annotations
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.triggers import RisingEdge, Timer
async def reset_read_noise(dut):
@@ -38,11 +38,45 @@ async def read_noise_disabled_forwards_hashes_after_one_stage(dut):
dut.row_ids_i.value = rows
dut.lane_valid_i.value = all_lanes_valid
dut.valid_i.value = 1
await RisingEdge(dut.clk)
await Timer(1, unit="step")
await RisingEdge(dut.clk) # valid_o ← valid_i=1 internally
await Timer(1, unit="step")
dut.valid_i.value = 0
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
# One-stage pass-through: valid_o holds the latched value for this cycle
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) == all_lanes_valid
@cocotb.test()
async def read_noise_enabled_still_forwards_hashes_unmodified(dut):
"""With READ_NOISE_EN=1, the pass-through still forwards hashes unmodified."""
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
await reset_read_noise(dut)
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
for lane in range(LANES):
hashes |= (lane + 0x55) << (lane * HASH_BITS_PER_LANE)
rows |= lane << (lane * ROW_BITS)
dut.hashes_i.value = hashes
dut.row_ids_i.value = rows
dut.lane_valid_i.value = all_lanes_valid
dut.valid_i.value = 1
await Timer(1, unit="step")
await RisingEdge(dut.clk) # valid_o ← valid_i=1 internally
await Timer(1, unit="step")
dut.valid_i.value = 0
# One-stage pass-through: valid_o holds latched value from previous cycle
assert int(dut.valid_o.value) == 1
assert int(dut.hashes_noisy_o.value) == hashes
assert int(dut.row_ids_o.value) == rows