mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
feat(hw): add XNOR-popcount CAM design with cocotb verification
Implement a multi-lane Content Addressable Memory (CAM) that scores rows by XNOR popcount against a query hash and returns the top-1 match. RTL modules: - popcount: parallel group-based population count - argmax_update: iterative best-match tracking with tie-break - cam_core: parameterized scanning engine (NUM_ROWS/HASH_BITS/LANES) with optional SIM_NOISE and SIM_DEBUG ifdef guards - cam_top: thin wrapper exposing cam_core ports Verification: - Python reference model (ref_model.py) for score-level golden comparison - cocotb testbench (test_cam_basic.py) covering write/query/reset and external noise mask scenarios with score debug verification - Noise sweep script (sweep_noise.py) measuring top-1 stability under configurable bit-flip rates - Verilator-oriented Makefile with parameterizable compile options
This commit is contained in:
57
hw/sim/sweep_noise.py
Normal file
57
hw/sim/sweep_noise.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
import numpy as np
|
||||
from model.ref_model import match_top1, random_hashes, random_noise_masks
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--rows", type=int, default=512)
|
||||
parser.add_argument("--queries", type=int, default=128)
|
||||
parser.add_argument("--width", type=int, default=512)
|
||||
parser.add_argument("--seed", type=int, default=1234)
|
||||
parser.add_argument(
|
||||
"--rates",
|
||||
type=float,
|
||||
nargs="+",
|
||||
default=[0.0, 0.001, 0.005, 0.01, 0.02, 0.05],
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
rng = np.random.default_rng(args.seed)
|
||||
rows = random_hashes(rng, args.rows, width=args.width)
|
||||
|
||||
# Construct simple positive queries by selecting existing rows.
|
||||
query_indices = rng.integers(0, args.rows, size=args.queries)
|
||||
queries = [rows[int(i)] for i in query_indices]
|
||||
|
||||
clean_results = [match_top1(q, rows, width=args.width) for q in queries]
|
||||
|
||||
print("rate,top1_stability,avg_clean_margin")
|
||||
for rate in args.rates:
|
||||
stable = 0
|
||||
margins = []
|
||||
|
||||
for q, clean in zip(queries, clean_results):
|
||||
noise_masks = random_noise_masks(
|
||||
rng,
|
||||
args.rows,
|
||||
width=args.width,
|
||||
bit_flip_rate=rate,
|
||||
)
|
||||
noisy = match_top1(q, rows, width=args.width, noise_masks=noise_masks)
|
||||
|
||||
if noisy.top1_index == clean.top1_index:
|
||||
stable += 1
|
||||
|
||||
sorted_scores = np.sort(clean.scores)
|
||||
margin = int(sorted_scores[-1] - sorted_scores[-2])
|
||||
margins.append(margin)
|
||||
|
||||
print(f"{rate},{stable / args.queries:.6f},{np.mean(margins):.3f}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user