mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
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
58 lines
1.7 KiB
Python
58 lines
1.7 KiB
Python
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()
|