mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
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:
0
hw/sim/tests/modules/__init__.py
Normal file
0
hw/sim/tests/modules/__init__.py
Normal file
9
hw/sim/tests/modules/cam_core_banked/Makefile
Normal file
9
hw/sim/tests/modules/cam_core_banked/Makefile
Normal 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
|
||||
0
hw/sim/tests/modules/cam_core_banked/__init__.py
Normal file
0
hw/sim/tests/modules/cam_core_banked/__init__.py
Normal file
49
hw/sim/tests/modules/cam_core_banked/test_cam_core_banked.py
Normal file
49
hw/sim/tests/modules/cam_core_banked/test_cam_core_banked.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
|
||||
|
||||
async def reset_core(dut):
|
||||
dut.rst_n.value = 0
|
||||
dut.wr_valid.value = 0
|
||||
dut.wr_row.value = 0
|
||||
dut.wr_hash.value = 0
|
||||
dut.rd_valid_i.value = 0
|
||||
dut.rd_base_row_i.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 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 = 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
|
||||
dut.wr_row.value = row
|
||||
dut.wr_hash.value = row + 0x100
|
||||
await RisingEdge(dut.clk)
|
||||
dut.wr_valid.value = 0
|
||||
|
||||
dut.rd_base_row_i.value = 0
|
||||
dut.rd_valid_i.value = 1
|
||||
await RisingEdge(dut.clk)
|
||||
dut.rd_valid_i.value = 0
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
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 * HASH_BITS)) & ((1 << HASH_BITS) - 1)
|
||||
assert got_row == lane
|
||||
assert got_hash == lane + 0x100
|
||||
15
hw/sim/tests/modules/cam_read_noise/Makefile
Normal file
15
hw/sim/tests/modules/cam_read_noise/Makefile
Normal 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
|
||||
0
hw/sim/tests/modules/cam_read_noise/__init__.py
Normal file
0
hw/sim/tests/modules/cam_read_noise/__init__.py
Normal file
49
hw/sim/tests/modules/cam_read_noise/test_cam_read_noise.py
Normal file
49
hw/sim/tests/modules/cam_read_noise/test_cam_read_noise.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
|
||||
|
||||
async def reset_read_noise(dut):
|
||||
dut.rst_n.value = 0
|
||||
dut.valid_i.value = 0
|
||||
dut.row_ids_i.value = 0
|
||||
dut.hashes_i.value = 0
|
||||
dut.lane_valid_i.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 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 = 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 RisingEdge(dut.clk)
|
||||
dut.valid_i.value = 0
|
||||
await RisingEdge(dut.clk)
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
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
|
||||
15
hw/sim/tests/modules/cam_write_noise/Makefile
Normal file
15
hw/sim/tests/modules/cam_write_noise/Makefile
Normal 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
|
||||
0
hw/sim/tests/modules/cam_write_noise/__init__.py
Normal file
0
hw/sim/tests/modules/cam_write_noise/__init__.py
Normal file
41
hw/sim/tests/modules/cam_write_noise/test_cam_write_noise.py
Normal file
41
hw/sim/tests/modules/cam_write_noise/test_cam_write_noise.py
Normal file
@@ -0,0 +1,41 @@
|
||||
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
|
||||
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)
|
||||
9
hw/sim/tests/modules/match_engine_pipeline/Makefile
Normal file
9
hw/sim/tests/modules/match_engine_pipeline/Makefile
Normal 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
|
||||
@@ -0,0 +1,66 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
|
||||
|
||||
async def reset_match(dut):
|
||||
dut.rst_n.value = 0
|
||||
dut.query_valid.value = 0
|
||||
dut.query_hash.value = 0
|
||||
dut.result_ready.value = 1
|
||||
dut.rd_valid_i.value = 0
|
||||
dut.rd_row_ids_i.value = 0
|
||||
dut.rd_hashes_i.value = 0
|
||||
dut.rd_lane_valid_i.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 match_engine_returns_top1_after_pipeline_drain(dut):
|
||||
cocotb.start_soon(Clock(dut.clk, 10, unit="ns").start())
|
||||
await reset_match(dut)
|
||||
|
||||
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)
|
||||
TARGET_ROW = 9
|
||||
|
||||
query = (1 << HASH_BITS) - 1
|
||||
dut.query_hash.value = query
|
||||
dut.query_valid.value = 1
|
||||
await RisingEdge(dut.clk)
|
||||
dut.query_valid.value = 0
|
||||
|
||||
for base in range(0, NUM_ROWS, LANES):
|
||||
while int(dut.rd_valid_o.value) == 0:
|
||||
await RisingEdge(dut.clk)
|
||||
assert int(dut.rd_base_row_o.value) == base
|
||||
rows = 0
|
||||
hashes = 0
|
||||
for lane in range(LANES):
|
||||
row_id = base + lane
|
||||
rows |= row_id << (lane * ROW_BITS)
|
||||
row_hash = query if row_id == TARGET_ROW else 0
|
||||
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 = (1 << LANES) - 1
|
||||
dut.rd_valid_i.value = 1
|
||||
await RisingEdge(dut.clk)
|
||||
dut.rd_valid_i.value = 0
|
||||
|
||||
for _ in range(20):
|
||||
if int(dut.result_valid.value):
|
||||
break
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
assert int(dut.result_valid.value) == 1
|
||||
assert int(dut.result_row.value) == TARGET_ROW
|
||||
assert int(dut.result_score.value) == HASH_BITS
|
||||
Reference in New Issue
Block a user