Add file-based vector testbenches ( + ) for: - mod_add_sync, rng_sync, poly_arith_sync, comp_decomp_sync - s_bram/sd_bram, sha3_chain_top - ntt_core, poly_mul_sync - sample_cbd_sync, sample_ntt_sync Each module includes: - tb_<module>_xsim.v: Vivado XSIM testbench - gen_vectors.py: Python vector generator (stdlib only) - vectors/<module>_input.hex: test input vectors - xsim_run.tcl: compile + elaborate + simulate script
113 lines
3.4 KiB
Python
113 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate test vectors for mod_add_sync module.
|
|
|
|
Produces mod_add_input.hex: one 24-bit hex word per line.
|
|
Each word encodes {a[11:0], b[11:0]} as a single hex value
|
|
suitable for $readmemh.
|
|
|
|
Also prints expected results to stdout for reference.
|
|
"""
|
|
|
|
import os
|
|
|
|
Q = 3329
|
|
|
|
def mod_add(a, b):
|
|
"""Compute (a + b) mod Q."""
|
|
s = a + b
|
|
if s >= Q:
|
|
s -= Q
|
|
return s
|
|
|
|
# Test cases: (a, b, description)
|
|
test_cases = [
|
|
# Normal operations
|
|
(0, 0, "zero + zero"),
|
|
(100, 200, "small + small (no overflow)"),
|
|
(500, 1000, "medium + medium (no overflow)"),
|
|
(2000, 1000, "medium pair (no overflow)"),
|
|
(1500, 1500, "medium pair (no overflow)"),
|
|
(3328, 0, "max + zero"),
|
|
(0, 3328, "zero + max"),
|
|
|
|
# Near-Q values (still < Q each)
|
|
(3000, 300, "near max + small (no overflow)"),
|
|
(300, 3000, "small + near max (no overflow)"),
|
|
(2000, 1500, "medium pair (overflow by small)"),
|
|
(2000, 2000, "medium pair (overflow)"),
|
|
(2500, 2500, "large pair (overflow)"),
|
|
(3000, 1000, "large + medium (overflow)"),
|
|
|
|
# Exact Q boundary
|
|
(3328, 1, "max + 1 (exact overflow to zero)"),
|
|
(1, 3328, "1 + max (exact overflow to zero)"),
|
|
|
|
# Max values (both Q-1)
|
|
(3328, 3328, "max + max (double overflow)"),
|
|
|
|
# Various overflow amounts
|
|
(2000, 3328, "medium + max (overflow)"),
|
|
(3328, 2000, "max + medium (overflow)"),
|
|
(2500, 1000, "large + medium (overflow)"),
|
|
(1000, 2500, "medium + large (overflow)"),
|
|
(1234, 2100, "random pair (overflow)"),
|
|
(456, 2900, "small + near max (overflow)"),
|
|
|
|
# No overflow but close
|
|
(1500, 1828, "pair sums exactly to Q-1"),
|
|
(1829, 1500, "pair sums exactly to Q (overflow -> 0)"),
|
|
|
|
# Back-to-back stress (all different values)
|
|
(1111, 2222, "stress pair"),
|
|
(333, 444, "stress pair"),
|
|
(777, 1888, "stress pair"),
|
|
(2999, 333, "stress pair near overflow"),
|
|
(500, 2800, "stress pair near max"),
|
|
]
|
|
|
|
# Restore previously removed concise test cases
|
|
additional = [
|
|
(42, 42),
|
|
(777, 1337),
|
|
(1664, 1664), # exactly Q//2 + Q//2 = Q-1? 1664+1664=3328 = Q-1
|
|
(200, 3100), # overflow
|
|
(0, 1),
|
|
(1, 0),
|
|
(3327, 2), # exact overflow: 3329 → 0
|
|
(1000, 2329), # overflow: 3329 → 0
|
|
(50, 3279), # overflow: 3329 → 0
|
|
(1600, 1729), # overflow by 0: 3329 → 0
|
|
]
|
|
test_cases.extend([(a, b) for a, b in additional])
|
|
|
|
def format_hex(val, bits):
|
|
"""Format integer as zero-padded hex string."""
|
|
nibbles = (bits + 3) // 4
|
|
return f"{val:0{nibbles}x}"
|
|
|
|
vectors_dir = os.path.join(os.path.dirname(__file__), "vectors")
|
|
os.makedirs(vectors_dir, exist_ok=True)
|
|
|
|
output_path = os.path.join(vectors_dir, "mod_add_input.hex")
|
|
|
|
with open(output_path, "w") as f:
|
|
for idx, item in enumerate(test_cases):
|
|
if len(item) == 3:
|
|
a, b, desc = item
|
|
else:
|
|
a, b = item
|
|
desc = ""
|
|
# Ensure inputs are in valid range
|
|
assert 0 <= a < Q, f"a={a} out of range"
|
|
assert 0 <= b < Q, f"b={b} out of range"
|
|
# Pack: upper 12 bits = a, lower 12 bits = b
|
|
word = (a << 12) | b
|
|
expected = mod_add(a, b)
|
|
f.write(format_hex(word, 24) + "\n")
|
|
if desc:
|
|
print(f"[{idx:3d}] a={a:4d} b={b:4d} -> expected={expected:4d} ({desc})")
|
|
else:
|
|
print(f"[{idx:3d}] a={a:4d} b={b:4d} -> expected={expected:4d}")
|
|
|
|
print(f"\nWrote {len(test_cases)} vectors to {output_path}")
|