mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
refactor(hw/sim): reorganize CAM top-level tests into per-noise-config suites
Split the monolithic test_cam_basic.py into separate test suites organized by noise configuration (no_noise, write_noise, read_noise), with shared utilities extracted to tests/top/utils.py. - Remove test_cam_basic.py; add no_noise/, write_noise/, read_noise/ test suites with Makefiles that set noise parameters statically - Extract helpers (reset_dut, write_rows, query_once, collect_topk, etc.) into tests/top/utils.py - Update hw/sim/Makefile with per-config test targets and a test-top-all meta-target - Update scripts/run_cam_correctness.py to build per-directory instead of centrally, removing inline parameter overrides - Add __init__.py for result_serializer and topk_tracker module tests - Expand docstrings in test_ref_model_noise.py with architectural context and test rationale
This commit is contained in:
@@ -64,7 +64,7 @@ default_scenarios: list[Scenario] = [
|
||||
Scenario(
|
||||
name="cam_top_basic",
|
||||
kind="cocotb",
|
||||
module="tests.test_cam_basic",
|
||||
module="tests.top.no_noise.test_no_noise",
|
||||
testcase=None,
|
||||
params={},
|
||||
noise_mode="none",
|
||||
@@ -73,28 +73,18 @@ default_scenarios: list[Scenario] = [
|
||||
Scenario(
|
||||
name="cam_top_write_noise",
|
||||
kind="cocotb",
|
||||
module="tests.test_cam_basic",
|
||||
module="tests.top.write_noise.test_write_noise",
|
||||
testcase=None,
|
||||
params={
|
||||
"WRITE_NOISE_EN": "1",
|
||||
"WRITE_NOISE_RATE_NUM": "1",
|
||||
"WRITE_NOISE_RATE_DEN": "100",
|
||||
"READ_NOISE_EN": "0",
|
||||
},
|
||||
params={},
|
||||
noise_mode="write_noise",
|
||||
expected="bit_flip_injected",
|
||||
),
|
||||
Scenario(
|
||||
name="cam_top_read_noise",
|
||||
kind="cocotb",
|
||||
module="tests.test_cam_basic",
|
||||
module="tests.top.read_noise.test_read_noise",
|
||||
testcase=None,
|
||||
params={
|
||||
"WRITE_NOISE_EN": "0",
|
||||
"READ_NOISE_EN": "1",
|
||||
"READ_NOISE_RATE_NUM": "1",
|
||||
"READ_NOISE_RATE_DEN": "100",
|
||||
},
|
||||
params={},
|
||||
noise_mode="read_noise",
|
||||
expected="read_perturbed",
|
||||
),
|
||||
@@ -150,19 +140,28 @@ default_scenarios: list[Scenario] = [
|
||||
# Command builders
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Internal: map unit scenario names to their Verilog TOPLEVEL module.
|
||||
# cam_top_* scenarios use the Makefile default (cam_top) and are omitted.
|
||||
_UNIT_TOPLEVEL: dict[str, str] = {
|
||||
"cam_core_banked": "cam_core_banked",
|
||||
"match_engine_pipeline": "match_engine_pipeline",
|
||||
"cam_write_noise": "cam_write_noise",
|
||||
"cam_read_noise": "cam_read_noise",
|
||||
# Map scenario names to their Makefile directory under hw/sim/tests/.
|
||||
# Top-level cam_top tests are now split by noise configuration.
|
||||
_MAKE_DIR: dict[str, str] = {
|
||||
"cam_top_basic": "top/no_noise",
|
||||
"cam_top_write_noise": "top/write_noise",
|
||||
"cam_top_read_noise": "top/read_noise",
|
||||
"cam_core_banked": "modules/cam_core_banked",
|
||||
"match_engine_pipeline": "modules/match_engine_pipeline",
|
||||
"cam_write_noise": "modules/cam_write_noise",
|
||||
"cam_read_noise": "modules/cam_read_noise",
|
||||
}
|
||||
|
||||
|
||||
def _infer_toplevel(scenario: Scenario) -> str | None:
|
||||
"""Return the Verilog TOPLEVEL for *scenario* or None to use Makefile default."""
|
||||
return _UNIT_TOPLEVEL.get(scenario.name)
|
||||
def _make_dir_for(scenario: Scenario) -> str:
|
||||
"""Return the relative Makefile directory under hw/sim/tests/ for *scenario*."""
|
||||
if scenario.name in _MAKE_DIR:
|
||||
return _MAKE_DIR[scenario.name]
|
||||
# Fallback: guess from module path (e.g. tests.top.foo → top/foo)
|
||||
parts = scenario.module.split(".") if scenario.module else []
|
||||
if len(parts) >= 4 and parts[0] == "tests":
|
||||
return "/".join(parts[1:-1]) # tests.top.no_noise → top/no_noise
|
||||
return "."
|
||||
|
||||
|
||||
def build_scenario_command(
|
||||
@@ -178,15 +177,16 @@ def build_scenario_command(
|
||||
"uv",
|
||||
"run",
|
||||
"pytest",
|
||||
"hw/sim/tests/test_ref_model_noise.py",
|
||||
"hw/sim/tests/model/test_ref_model_noise.py",
|
||||
"-q",
|
||||
]
|
||||
|
||||
# cocotb
|
||||
# cocotb — run make in the specific test subdirectory
|
||||
make_dir = f"hw/sim/tests/{_make_dir_for(scenario)}"
|
||||
cmd = [
|
||||
"make",
|
||||
"-C",
|
||||
"hw/sim",
|
||||
make_dir,
|
||||
f"NUM_ROWS={num_rows}",
|
||||
f"HASH_BITS={hash_bits}",
|
||||
f"LANES={lanes}",
|
||||
@@ -196,9 +196,6 @@ def build_scenario_command(
|
||||
cmd.append(f"COCOTB_TESTCASE={scenario.testcase}")
|
||||
for key, value in scenario.params.items():
|
||||
cmd.append(f"{key}={value}")
|
||||
toplevel = _infer_toplevel(scenario)
|
||||
if toplevel is not None:
|
||||
cmd.append(f"TOPLEVEL={toplevel}")
|
||||
return cmd
|
||||
|
||||
|
||||
@@ -206,7 +203,8 @@ def build_clean_command(scenario: Scenario) -> list[str] | None:
|
||||
"""Build a clean command or None if cleanup is not needed."""
|
||||
if scenario.kind == "pytest":
|
||||
return None
|
||||
return ["make", "-C", "hw/sim", "clean"]
|
||||
make_dir = f"hw/sim/tests/{_make_dir_for(scenario)}"
|
||||
return ["make", "-C", make_dir, "clean"]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user