feat(tb): add Vivado XSIM Verilog testbenches for all 10 sync modules
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
This commit is contained in:
241
sync_rtl/ntt/TB/gen_vectors.py
Normal file
241
sync_rtl/ntt/TB/gen_vectors.py
Normal file
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env python3
|
||||
"""gen_vectors.py - Generate NTT test vectors for Vivado XSIM testbench.
|
||||
|
||||
Generates input vectors for ntt_core module in hex format compatible
|
||||
with $readmemh. Each line encodes {1-bit mode, 256x12-bit coefficients}
|
||||
packed as a single 3073-bit hex number (769 hex chars).
|
||||
|
||||
Q = 3329, N = 256, primitive root zeta = 17.
|
||||
NTT uses Cooley-Tukey DIT with bit-reversed zeta ROM.
|
||||
INTT uses Gentleman-Sande DIF with zeta ROM in reverse.
|
||||
|
||||
Usage:
|
||||
python3 gen_vectors.py
|
||||
Output:
|
||||
vectors/ntt_core_input.hex
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import random
|
||||
|
||||
# ============================================================
|
||||
# Constants
|
||||
# ============================================================
|
||||
Q = 3329 # ML-KEM modulus
|
||||
N = 256 # NTT size
|
||||
LAYERS = 7 # log2(N) - 1 for Cooley-Tukey
|
||||
|
||||
# zeta_rom values: bit-reversed powers of the primitive root zeta=17
|
||||
# These match sync_rtl/ntt/zeta_rom.v exactly
|
||||
ZETA_ROM = [
|
||||
1, 1729, 2580, 3289, 2642, 630, 1897, 848,
|
||||
1062, 1919, 193, 797, 2786, 3260, 569, 1746,
|
||||
296, 2447, 1339, 1476, 3046, 56, 2240, 1333,
|
||||
1426, 2094, 535, 2882, 2393, 2879, 1974, 821,
|
||||
289, 331, 3253, 1756, 1197, 2304, 2277, 2055,
|
||||
650, 1977, 2513, 632, 2865, 33, 1320, 1915,
|
||||
2319, 1435, 807, 452, 1438, 2868, 1534, 2402,
|
||||
2647, 2617, 1481, 648, 2474, 3110, 1227, 910,
|
||||
17, 2761, 583, 2649, 1637, 723, 2288, 1100,
|
||||
1409, 2662, 3281, 233, 756, 2156, 3015, 3050,
|
||||
1703, 1651, 2789, 1789, 1847, 952, 1461, 2687,
|
||||
939, 2308, 2437, 2388, 733, 2337, 268, 641,
|
||||
1584, 2298, 2037, 3220, 375, 2549, 2090, 1645,
|
||||
1063, 319, 2773, 757, 2099, 561, 2466, 2594,
|
||||
2804, 1092, 403, 1026, 1143, 2150, 2775, 886,
|
||||
1722, 1212, 1874, 1029, 2110, 2935, 885, 2154,
|
||||
]
|
||||
|
||||
|
||||
def barrett_mul(a: int, b: int) -> int:
|
||||
"""Barrett modular multiplication: (a * b) mod Q."""
|
||||
return (a * b) % Q
|
||||
|
||||
|
||||
def ntt_forward(coeffs: list) -> list:
|
||||
"""Forward NTT: Cooley-Tukey DIT, matches ntt_core RTL exactly.
|
||||
|
||||
Processes 7 layers. At each layer:
|
||||
- Pairs are (j, j+layer_len)
|
||||
- Zeta for each block comes from zeta_rom (index increments per block)
|
||||
- Butterfly: t = zeta*b; a_out = a+t; b_out = a-t (all mod Q)
|
||||
|
||||
Input: normal-order coefficients (index 0..255)
|
||||
Output: bit-reversed NTT result
|
||||
"""
|
||||
a = list(coeffs)
|
||||
layer_len = 128
|
||||
zeta_idx = 1 # Forward NTT starts at zeta_rom[1]
|
||||
|
||||
for layer in range(LAYERS):
|
||||
for start in range(0, N, 2 * layer_len):
|
||||
zeta = ZETA_ROM[zeta_idx]
|
||||
for j in range(start, start + layer_len):
|
||||
t = barrett_mul(zeta, a[j + layer_len])
|
||||
a_j_plus_len = (a[j] - t) % Q
|
||||
a[j] = (a[j] + t) % Q
|
||||
a[j + layer_len] = a_j_plus_len
|
||||
zeta_idx += 1
|
||||
layer_len >>= 1
|
||||
|
||||
return a
|
||||
|
||||
|
||||
def intt_inverse(coeffs: list) -> list:
|
||||
"""Inverse NTT: Gentleman-Sande DIF, matches ntt_core RTL exactly.
|
||||
|
||||
Processes 7 layers in reverse order (len=2,4,8,...,128).
|
||||
- Zeta for each block comes from zeta_rom (index decrements per block)
|
||||
- Butterfly: a_out = a+b; diff = b-a; b_out = zeta*diff (all mod Q)
|
||||
|
||||
After all layers, output is scaled by N (no 1/2 factors in GS butterfly).
|
||||
The RTL then scales output by 3303 in the OUTPUT state for mode=1.
|
||||
"""
|
||||
a = list(coeffs)
|
||||
layer_len = 2
|
||||
zeta_idx = 127 # Inverse NTT starts at zeta_rom[127]
|
||||
|
||||
for layer in range(LAYERS):
|
||||
for start in range(0, N, 2 * layer_len):
|
||||
zeta = ZETA_ROM[zeta_idx]
|
||||
for j in range(start, start + layer_len):
|
||||
a_sum = (a[j] + a[j + layer_len]) % Q
|
||||
diff = (a[j + layer_len] - a[j]) % Q
|
||||
a[j] = a_sum
|
||||
a[j + layer_len] = barrett_mul(zeta, diff)
|
||||
zeta_idx -= 1
|
||||
layer_len <<= 1
|
||||
|
||||
# Apply output scaling (multiply by 3303) as the RTL does in mode=1
|
||||
for i in range(N):
|
||||
a[i] = barrett_mul(a[i], 3303)
|
||||
|
||||
return a
|
||||
|
||||
|
||||
def coeffs_to_hex(coeffs: list) -> str:
|
||||
"""Convert 256 12-bit coefficients to a 768-char hex string.
|
||||
|
||||
coeffs[0] is the MSB of the hex output, coeffs[255] is the LSB.
|
||||
Each coefficient is 3 hex chars (12 bits).
|
||||
"""
|
||||
result = 0
|
||||
for c in coeffs:
|
||||
result = (result << 12) | (c & 0xFFF)
|
||||
return f"{result:0768X}"
|
||||
|
||||
|
||||
def write_vector(f, mode: int, coeffs: list, label: str):
|
||||
"""Write a single test vector to the hex file.
|
||||
|
||||
Format: {mode_hex_digit}{768 hex chars for 256 coeffs}
|
||||
Total: 769 hex chars per line.
|
||||
mode=0 -> hex digit '0', mode=1 -> hex digit '1'.
|
||||
"""
|
||||
mode_hex = "0" if mode == 0 else "1"
|
||||
coeffs_hex = coeffs_to_hex(coeffs)
|
||||
line = mode_hex + coeffs_hex
|
||||
f.write(f"// {label}\n")
|
||||
f.write(line + "\n")
|
||||
|
||||
|
||||
def hex_char_to_int(c: str) -> int:
|
||||
"""Convert single hex char to integer."""
|
||||
return int(c, 16)
|
||||
|
||||
|
||||
def generate_vectors():
|
||||
"""Generate test vectors for ntt_core."""
|
||||
os.makedirs("vectors", exist_ok=True)
|
||||
hex_path = os.path.join("vectors", "ntt_core_input.hex")
|
||||
|
||||
# All tests are listed here with labels
|
||||
tests = []
|
||||
|
||||
# --- Test 0: Forward NTT on all zeros ---
|
||||
zeros = [0] * N
|
||||
expected = ntt_forward(zeros)
|
||||
tests.append((0, zeros, expected, "FWD: all zeros"))
|
||||
|
||||
# --- Test 1: Forward NTT on impulse at index 0 ---
|
||||
imp0 = [0] * N
|
||||
imp0[0] = 1
|
||||
expected = ntt_forward(imp0)
|
||||
tests.append((0, imp0, expected, "FWD: impulse at [0]"))
|
||||
|
||||
# --- Test 2: Forward NTT on impulse at index 1 ---
|
||||
imp1 = [0] * N
|
||||
imp1[1] = 1
|
||||
expected = ntt_forward(imp1)
|
||||
tests.append((0, imp1, expected, "FWD: impulse at [1]"))
|
||||
|
||||
# --- Test 3: Forward NTT on ramp [0,1,2,...,255] ---
|
||||
ramp = [i % Q for i in range(N)]
|
||||
expected = ntt_forward(ramp)
|
||||
tests.append((0, ramp, expected, "FWD: ramp 0..255"))
|
||||
|
||||
# --- Test 4: Forward NTT on all ones ---
|
||||
ones = [1] * N
|
||||
expected = ntt_forward(ones)
|
||||
tests.append((0, ones, expected, "FWD: all ones"))
|
||||
|
||||
# --- Test 5: Inverse NTT on all zeros ---
|
||||
expected = intt_inverse(zeros)
|
||||
tests.append((1, zeros, expected, "INV: all zeros"))
|
||||
|
||||
# --- Test 6: Inverse NTT on impulse at index 0 ---
|
||||
expected = intt_inverse(imp0)
|
||||
tests.append((1, imp0, expected, "INV: impulse at [0]"))
|
||||
|
||||
# --- Test 7: Inverse NTT on NTT(impulse) → should recover impulse*256 ---
|
||||
ntt_imp0 = ntt_forward(imp0)
|
||||
expected = intt_inverse(ntt_imp0)
|
||||
tests.append((1, ntt_imp0, expected, "INV(NTT(imp[0])) → imp[0]*256"))
|
||||
|
||||
# --- Test 8: Inverse NTT on NTT(ramp) → should recover ramp*256 ---
|
||||
ntt_ramp = ntt_forward(ramp)
|
||||
expected = intt_inverse(ntt_ramp)
|
||||
tests.append((1, ntt_ramp, expected, "INV(NTT(ramp)) → ramp*256"))
|
||||
|
||||
# --- Tests 9-12: Forward NTT on random vectors ---
|
||||
random.seed(0x5EED)
|
||||
for i in range(4):
|
||||
rand_vec = [random.randrange(0, Q) for _ in range(N)]
|
||||
expected = ntt_forward(rand_vec)
|
||||
tests.append((0, rand_vec, expected, f"FWD: random {i}"))
|
||||
|
||||
# --- Tests 13-16: Inverse NTT on random vectors ---
|
||||
for i in range(4):
|
||||
rand_vec = [random.randrange(0, Q) for _ in range(N)]
|
||||
expected = intt_inverse(rand_vec)
|
||||
tests.append((1, rand_vec, expected, f"INV: random {i}"))
|
||||
|
||||
# --- Tests 17-18: Inverse NTT on NTT(random) → roundtrip ---
|
||||
for i in range(2):
|
||||
rand_vec = [random.randrange(0, Q) for _ in range(N)]
|
||||
ntt_vec = ntt_forward(rand_vec)
|
||||
recovered = intt_inverse(ntt_vec)
|
||||
tests.append((1, ntt_vec, recovered, f"INV(NTT(random {i})) → random*256"))
|
||||
|
||||
# Write input hex file
|
||||
with open(hex_path, "w") as f:
|
||||
f.write("// ntt_core test vectors\n")
|
||||
f.write("// Format: {1 hex digit mode}{768 hex chars coeffs}\n")
|
||||
f.write("// mode: 0=forward NTT, 1=inverse NTT\n")
|
||||
f.write("// coeffs: 256 x 12-bit values, coeff[0] at MSB position\n")
|
||||
f.write("\n")
|
||||
for mode, coeffs, expected, label in tests:
|
||||
write_vector(f, mode, coeffs, label)
|
||||
|
||||
print(f"Generated {len(tests)} test vectors → {hex_path}")
|
||||
|
||||
# Print expected results for reference (for manual verification)
|
||||
print("\nExpected output summary (first 4 coeffs of each test):")
|
||||
for mode, coeffs, expected, label in tests:
|
||||
first4 = expected[:4]
|
||||
print(f" {label:45s} → [{first4[0]:4d}, {first4[1]:4d}, {first4[2]:4d}, {first4[3]:4d}, ...]")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_vectors()
|
||||
317
sync_rtl/ntt/TB/tb_ntt_core_xsim.v
Normal file
317
sync_rtl/ntt/TB/tb_ntt_core_xsim.v
Normal file
@@ -0,0 +1,317 @@
|
||||
// tb_ntt_core_xsim.v - Standard Verilog testbench for ntt_core targeting Vivado xsim
|
||||
//
|
||||
// Reads test vectors from a hex file using $readmemh.
|
||||
// Each line is a single hex number encoding both mode and 256 input coefficients:
|
||||
// - bit [3075]: mode (0 = forward NTT, 1 = inverse NTT)
|
||||
// - bits [3074:3]: 256 x 12-bit input coefficients
|
||||
// - bits [2:0]: unused (padding)
|
||||
// - Total: 769 hex chars per line, NO spaces
|
||||
//
|
||||
// Drives ntt_core, streams in 256 coefficients via valid/ready handshake,
|
||||
// waits for valid_o, streams out 256 transformed coefficients,
|
||||
// and writes "RESULT: MODE INDEX COEFF_HEX" to the output file.
|
||||
//
|
||||
// ntt_core FSM: IDLE → LOAD → CMP_A/B/C (7 stages) → OUTPUT → DONE → IDLE
|
||||
// valid_o is asserted during OUTPUT state (before done_o).
|
||||
// done_o pulses for 1 cycle AFTER all outputs have been read.
|
||||
//
|
||||
// Parameters:
|
||||
// VECTOR_FILE - path to input hex file (default: "vectors/ntt_core_input.hex")
|
||||
// RESULT_FILE - path to output file (default: "vectors/ntt_core_result.hex")
|
||||
//
|
||||
// Usage:
|
||||
// xvlog -sv ntt_core.v butterfly_unit.v barrett_mul.v zeta_rom.v tb_ntt_core_xsim.v
|
||||
// xelab tb_ntt_core_xsim -s tb_ntt_core_xsim
|
||||
// xsim tb_ntt_core_xsim -R
|
||||
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module tb_ntt_core_xsim;
|
||||
|
||||
// ================================================================
|
||||
// Parameters
|
||||
// ================================================================
|
||||
parameter VECTOR_FILE = "sync_rtl/ntt/TB/vectors/ntt_core_input.hex";
|
||||
parameter RESULT_FILE = "sync_rtl/ntt/TB/vectors/ntt_core_result.hex";
|
||||
parameter MAX_VECTORS = 64;
|
||||
parameter N_COEFFS = 256;
|
||||
parameter TIMEOUT_CYCLES= 100000;
|
||||
|
||||
// ================================================================
|
||||
// DUT signals
|
||||
// ================================================================
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
reg [11:0] coeff_in;
|
||||
reg valid_i;
|
||||
wire ready_o;
|
||||
reg mode;
|
||||
wire [11:0] coeff_out;
|
||||
wire valid_o;
|
||||
reg ready_i;
|
||||
wire done_o;
|
||||
|
||||
// ================================================================
|
||||
// DUT instantiation
|
||||
// ================================================================
|
||||
ntt_core u_dut (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.coeff_in (coeff_in),
|
||||
.valid_i (valid_i),
|
||||
.ready_o (ready_o),
|
||||
.mode (mode),
|
||||
.coeff_out (coeff_out),
|
||||
.valid_o (valid_o),
|
||||
.ready_i (ready_i),
|
||||
.done_o (done_o)
|
||||
);
|
||||
|
||||
// ================================================================
|
||||
// Clock generation: 100 MHz (10 ns period)
|
||||
// ================================================================
|
||||
initial clk = 1'b0;
|
||||
always #5 clk = ~clk;
|
||||
|
||||
// ================================================================
|
||||
// Vector memory (loaded by $readmemh)
|
||||
// 3076 bits per word:
|
||||
// bit [3075]: mode (0=FWD NTT, 1=INV NTT)
|
||||
// bits [3074:3]: 256 x 12-bit coefficients (coeff[0] at MSB)
|
||||
// bits [2:0]: unused padding
|
||||
// ================================================================
|
||||
reg [3075:0] vector_mem [0:MAX_VECTORS-1];
|
||||
integer vec_count;
|
||||
integer idx;
|
||||
integer ci;
|
||||
integer cycle_count;
|
||||
integer result_fd;
|
||||
|
||||
// Test result tracking
|
||||
integer pass_count;
|
||||
integer fail_count;
|
||||
|
||||
// Temporary storage for coefficients
|
||||
reg [11:0] input_coeffs [0:N_COEFFS-1];
|
||||
reg [11:0] output_coeffs [0:N_COEFFS-1];
|
||||
|
||||
// ================================================================
|
||||
// Hex-to-ASCII conversion helper
|
||||
// ================================================================
|
||||
function [7:0] nibble_to_ascii;
|
||||
input [3:0] nibble;
|
||||
begin
|
||||
if (nibble < 4'd10)
|
||||
nibble_to_ascii = 8'h30 + {4'd0, nibble}; // '0'-'9'
|
||||
else
|
||||
nibble_to_ascii = 8'h41 + ({4'd0, nibble} - 4'd10); // 'A'-'F'
|
||||
end
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// Main test sequence
|
||||
// ================================================================
|
||||
initial begin
|
||||
// Count loaded vectors
|
||||
vec_count = 0;
|
||||
|
||||
// Load vectors from hex file
|
||||
$readmemh(VECTOR_FILE, vector_mem);
|
||||
|
||||
// Count entries (XSim leaves unloaded entries as 3076'hX)
|
||||
begin
|
||||
integer found_end;
|
||||
found_end = 0;
|
||||
for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin
|
||||
if (!found_end && (vector_mem[idx] === 3076'hx ||
|
||||
vector_mem[idx] === 3076'hz))
|
||||
found_end = 1;
|
||||
else if (!found_end)
|
||||
vec_count = vec_count + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (vec_count == 0) begin
|
||||
$display("ERROR: No vectors loaded from %s", VECTOR_FILE);
|
||||
$display(" Check that the file exists and format is correct.");
|
||||
$display(" Each line: 769 hex chars = {1 hex digit mode, 768 hex chars coeffs}");
|
||||
$finish;
|
||||
end
|
||||
|
||||
$display("INFO: Loaded %0d test vectors from %s", vec_count, VECTOR_FILE);
|
||||
|
||||
// Open result file
|
||||
result_fd = $fopen(RESULT_FILE, "w");
|
||||
if (result_fd == 0) begin
|
||||
$display("ERROR: Cannot open result file: %s", RESULT_FILE);
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Initialize DUT inputs
|
||||
mode <= 1'b0;
|
||||
coeff_in <= 12'd0;
|
||||
valid_i <= 1'b0;
|
||||
ready_i <= 1'b1; // always ready to accept output
|
||||
|
||||
// Reset sequence: rst_n low for 3 cycles, then high
|
||||
rst_n <= 1'b0;
|
||||
repeat (3) @(posedge clk);
|
||||
rst_n <= 1'b1;
|
||||
@(posedge clk);
|
||||
|
||||
pass_count = 0;
|
||||
fail_count = 0;
|
||||
|
||||
// ============================================================
|
||||
// Process each vector
|
||||
// ============================================================
|
||||
for (idx = 0; idx < vec_count; idx = idx + 1) begin
|
||||
begin
|
||||
reg vec_mode;
|
||||
integer out_idx;
|
||||
integer got_done;
|
||||
|
||||
// Extract mode and coefficients from vector memory
|
||||
vec_mode = vector_mem[idx][3075];
|
||||
|
||||
// Extract 256 input coefficients
|
||||
// coeff[0] at bits [3074:3063], coeff[255] at bits [11:0]
|
||||
// NOTE: bits[2:0] are unused padding below coeff[255]
|
||||
for (ci = 0; ci < N_COEFFS; ci = ci + 1) begin
|
||||
input_coeffs[ci] = vector_mem[idx][(N_COEFFS-1-ci)*12 + 11
|
||||
: (N_COEFFS-1-ci)*12];
|
||||
end
|
||||
|
||||
$display("INFO: Vector %0d - mode=%0d (0=FWD, 1=INV)", idx, vec_mode);
|
||||
|
||||
// Set mode
|
||||
mode <= vec_mode;
|
||||
|
||||
// ----------------------------------------------------
|
||||
// LOAD phase: stream in 256 coefficients via valid/ready
|
||||
// ----------------------------------------------------
|
||||
for (ci = 0; ci < N_COEFFS; ci = ci + 1) begin
|
||||
// Wait for ready_o before driving next input
|
||||
cycle_count = 0;
|
||||
while (!ready_o && cycle_count < TIMEOUT_CYCLES) begin
|
||||
@(posedge clk);
|
||||
cycle_count = cycle_count + 1;
|
||||
end
|
||||
if (cycle_count >= TIMEOUT_CYCLES) begin
|
||||
$display("ERROR: Timeout waiting for ready_o (input ci=%0d) on vector %0d",
|
||||
ci, idx);
|
||||
fail_count = fail_count + 1;
|
||||
ci = N_COEFFS; // break out of input loop
|
||||
end else begin
|
||||
coeff_in <= input_coeffs[ci];
|
||||
valid_i <= 1'b1;
|
||||
@(posedge clk);
|
||||
valid_i <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------
|
||||
// OUTPUT phase: wait for valid_o, then stream out results
|
||||
// ntt_core asserts valid_o during S_OUTPUT state.
|
||||
// After all 256 outputs are consumed, done_o pulses.
|
||||
// ----------------------------------------------------
|
||||
got_done = 0;
|
||||
out_idx = 0;
|
||||
|
||||
while (out_idx < N_COEFFS) begin
|
||||
// Wait for valid_o or done_o
|
||||
cycle_count = 0;
|
||||
while (!valid_o && !done_o && cycle_count < TIMEOUT_CYCLES) begin
|
||||
@(posedge clk);
|
||||
cycle_count = cycle_count + 1;
|
||||
end
|
||||
|
||||
if (cycle_count >= TIMEOUT_CYCLES) begin
|
||||
$display("ERROR: Timeout waiting for output (out_idx=%0d) on vector %0d",
|
||||
out_idx, idx);
|
||||
fail_count = fail_count + 1;
|
||||
out_idx = N_COEFFS; // break out
|
||||
end else if (done_o) begin
|
||||
// done_o before all outputs? This shouldn't happen
|
||||
// unless outputs were consumed in previous test somehow.
|
||||
// Treat as error.
|
||||
$display("WARN: done_o asserted before output %0d on vector %0d",
|
||||
out_idx, idx);
|
||||
got_done = 1;
|
||||
@(posedge clk); // consume done_o cycle
|
||||
end else begin
|
||||
// valid_o is high: capture output
|
||||
output_coeffs[out_idx] = coeff_out;
|
||||
out_idx = out_idx + 1;
|
||||
@(posedge clk); // ready_i=1, consume this output
|
||||
end
|
||||
end
|
||||
|
||||
// After all 256 outputs captured, check if done_o was seen
|
||||
// or wait briefly for it
|
||||
if (!got_done) begin
|
||||
cycle_count = 0;
|
||||
while (!done_o && cycle_count < 100) begin
|
||||
@(posedge clk);
|
||||
cycle_count = cycle_count + 1;
|
||||
end
|
||||
if (cycle_count >= 100) begin
|
||||
$display("WARN: done_o not seen after all outputs on vector %0d", idx);
|
||||
end else begin
|
||||
@(posedge clk); // consume done_o
|
||||
end
|
||||
end
|
||||
|
||||
pass_count = pass_count + 1;
|
||||
|
||||
// Write result to output file
|
||||
// Format: "RESULT: MODE INDEX COEFF_HEX"
|
||||
$fwrite(result_fd, "RESULT: %0d %0d ", vec_mode, idx);
|
||||
// Write all 256 output coeffs as hex (3 hex chars each = 768 total)
|
||||
begin
|
||||
integer oi;
|
||||
reg [3:0] nib;
|
||||
for (oi = 0; oi < N_COEFFS; oi = oi + 1) begin
|
||||
// Write 3 hex chars per coefficient (12 bits)
|
||||
nib = output_coeffs[oi][11:8];
|
||||
$fwrite(result_fd, "%c", nibble_to_ascii(nib));
|
||||
nib = output_coeffs[oi][7:4];
|
||||
$fwrite(result_fd, "%c", nibble_to_ascii(nib));
|
||||
nib = output_coeffs[oi][3:0];
|
||||
$fwrite(result_fd, "%c", nibble_to_ascii(nib));
|
||||
end
|
||||
end
|
||||
$fwrite(result_fd, "\n");
|
||||
|
||||
// Extra cycle before next vector
|
||||
@(posedge clk);
|
||||
end // inner begin block
|
||||
end
|
||||
|
||||
// ============================================================
|
||||
// Summary
|
||||
// ============================================================
|
||||
$fclose(result_fd);
|
||||
|
||||
$display("========================================");
|
||||
$display("TEST COMPLETE");
|
||||
$display(" Total vectors: %0d", vec_count);
|
||||
$display(" Passed: %0d", pass_count);
|
||||
$display(" Failed: %0d", fail_count);
|
||||
$display(" Results written to: %s", RESULT_FILE);
|
||||
$display("========================================");
|
||||
|
||||
$finish;
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Timeout watchdog
|
||||
// ================================================================
|
||||
initial begin
|
||||
// TIMEOUT_CYCLES * 10ns per cycle * 10x margin
|
||||
#(TIMEOUT_CYCLES * 10 * 10);
|
||||
$display("FATAL: Global simulation timeout reached");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
43
sync_rtl/ntt/TB/vectors/ntt_core_input.hex
Normal file
43
sync_rtl/ntt/TB/vectors/ntt_core_input.hex
Normal file
@@ -0,0 +1,43 @@
|
||||
// ntt_core test vectors
|
||||
// Format: {1 hex digit mode}{768 hex chars coeffs}
|
||||
// mode: 0=forward NTT, 1=inverse NTT
|
||||
// coeffs: 256 x 12-bit values, coeff[0] at MSB position
|
||||
|
||||
// FWD: all zeros
|
||||
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
// FWD: impulse at [0]
|
||||
0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
// FWD: impulse at [1]
|
||||
0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
// FWD: ramp 0..255
|
||||
000000100200300400500600700800900A00B00C00D00E00F01001101201301401501601701801901A01B01C01D01E01F02002102202302402502602702802902A02B02C02D02E02F03003103203303403503603703803903A03B03C03D03E03F04004104204304404504604704804904A04B04C04D04E04F05005105205305405505605705805905A05B05C05D05E05F06006106206306406506606706806906A06B06C06D06E06F07007107207307407507607707807907A07B07C07D07E07F08008108208308408508608708808908A08B08C08D08E08F09009109209309409509609709809909A09B09C09D09E09F0A00A10A20A30A40A50A60A70A80A90AA0AB0AC0AD0AE0AF0B00B10B20B30B40B50B60B70B80B90BA0BB0BC0BD0BE0BF0C00C10C20C30C40C50C60C70C80C90CA0CB0CC0CD0CE0CF0D00D10D20D30D40D50D60D70D80D90DA0DB0DC0DD0DE0DF0E00E10E20E30E40E50E60E70E80E90EA0EB0EC0ED0EE0EF0F00F10F20F30F40F50F60F70F80F90FA0FB0FC0FD0FE0FF
|
||||
// FWD: all ones
|
||||
0001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001001
|
||||
// INV: all zeros
|
||||
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
// INV: impulse at [0]
|
||||
1001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
// INV(NTT(imp[0])) → imp[0]*256
|
||||
1001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000001000
|
||||
// INV(NTT(ramp)) → ramp*256
|
||||
197DB1D1A931B74954C27001F9B3895AA5A6CA932055D08927B332339A0E790F26543325E132C47564A9E483213332632B3A09B1305A2A3B6B087986F5C7A4AB307DE68FC8006678364322E2A913C2053A36C47CF7E84468E486F88B7B5A4D86E9450C6BAA0F75CA1C148550A4218AC4643FB19089E4C98B9560B40A682667A87B6B76A77B2C8A9B51CA27710249028610DB245BB8562958B1369544341E86621FC789D6CAE8E523A0EF9DA3467C607EA4D07E332CA04333AC2E6A3927628AAD8A2E1E28A036479D865BFA768BB490203F37399F52179FBB706170EB0E8386EB995172A2D3675BB97A7C193B2923F728F1F52984E1C3006AC1C4FA77F7628637A979D6CA1CDAD44F6C1782941BA1065C6C7C7B7F228F20CC7B3857D758B09D91E928B0927A3529DBA522A06440D8CD052538948D5FCBF33090F26D88042153EE74292049F6786847F5B82888418068B0936D06F5537C57CB29300C1FA60F7E6C8C63766591A659AEB3060463EAC7A3A03DBA9DBBDB43095A22C219C6856A9D8FF
|
||||
// FWD: random 0
|
||||
02449D06853239596B8A407B14F79D6C8BC35CEC584389BB7682947A21A3099F65B6567429EF5533930E6580992CB8BF9423C114752479D7CC2A583E00CE5F9402A0BBE99A0C76AA30D531D1C86355195A0CCD475C3EAD93CCABC64C1B4C5C0AC6F73BEB2238E21B81C3507200220C54309307503554831A491056FCD33FB6571BBC379493F850058147BA8E2195AA73F0FE339BD24FB7AFAA1348326A91B80842648A9B06FA9B29792AA5A8667031B8A38345A8F18D3CB5FE326CB41A73592564485705E1CB689BB1622506621A34C8435E64AB4B11859E03FF42DC0783F21B03E52F8228FD4B5928464CD881B86B90856B93A54479BCCA89D675755A88A3B6F645238DB39C6EC9F8603549A042838840E29EC5FB12A36597B0161AC316155830DCB60A00835075919A0150A0934012C1B76B271D1B4ACF1C001CF1D13D14F40B8A2A274804C92B548C494A8989138B6311CF04159E91F530C61E612CCA56A2635E887A7465246FC64C5122CE17B636718867193BB56A13A49B47803919FF9CC
|
||||
// FWD: random 1
|
||||
055262448E6FE8456E2B00774C1D389CC768DB89CCF3D0897CA102BC891CA3B90C13CCB36271241AAC4FFAD42084DBBBA09D6F8A1567731CB8606FB46529B7271844B4C810177F20439B4ADAFEADACF98E4507C10A09B63876C7AB10BE37124E5340A11C16C05BC3012AD723345799436A49E4FC1AA3A65BDC2B86ABADB846AE98C010A4D4AA0A63709A6BBAA9CCB222B4EA2A1A724C6B73CDD89D87B70D7B96C6C3F1FDAE2235C106470323C27B642A0521A26F53072B75FB71EB3B6E274DA4E2312E482E97799D0C810F2B71549711740F28DD47E51C712B741274B4C9A02100251C4ECCEA10537416284D6A81B3A0177A96C7965D00D2A78BC83FA4D60D006448262D5A9BEEA893FB594CC0C50728784C615CE361C4608DBAB85FB72AD54D500270C9C253D71C7E92A44A800F5FCAE41684D12335DB25B8A21819D54689283BC4D14B799E52442076B3F4B6954E007511C3FCB2C31BA823A2B002160627D29AC07A08C39B059B31D40608BD37390D648B9D808B2D3F34AC9BE7D339F62B5E2
|
||||
// FWD: random 2
|
||||
0C57799091368B1F5F375F815CF0BAC04878468E5A73D49D16CE96E27371610D69A2D46BB7DD943C577D61EAB4216BC4B29030E4EAA4276E7CA9CECF37E63A5B2FBE03B039D528BB0C5974367CB447E763FCEAA08BCA26A119CC88B800F00ECC640D8236A0ABC76886161116B15A05E126B7E87BBA4BFDADDC1BA7C91E91C95A9D875D3AABE38AD6A603B00A6B6868C47015AE3CCB0A1A4A1388724ED42E6281558F99866E08AE509ACBC51526BCD241609B7DA214CB0708B4C124209305AB633097378576C7584109411380D9634DCC5B3B8A20C82C1DB300712030B43A661468C6427147F75968E06CC78F6F2CF2CB737515B0649EC7CA48274B8281D71F04E838060E60C358B386936A1869CFCA6B36637A1E77A9CD349F519CAA090BFECBE46AADA2D480ACEC99194290C18388B7D061947D241BE4BE0B3A25B7539CA40D57DA42CA41132AEAF555E5289A990389C5530AC9484526988F8501B3FA03A9AB430E15A364ACC05A4A522553137215F8C42B947622623F826173207A6BCCBF859
|
||||
// FWD: random 3
|
||||
08852790477785DA6462B48C30AF563317B045018BD9762C222778F86C7C94E7B3D9BAC9E1BF8A91718DDC6C07D3348CC6B00B635B62207936C51B64AA6048A70A79D21D9CC8D48C51155847149B82896A6C1E1BAA3D94C48B3485F34B71ACB63995CBD6864B59B38861C5148CF1372734523410BDCC9F4B8CB3BCD2AA206A333B727D264B07BAE0715061793CF29DAFA9884D56BD929C030E62915884D258E2FB08481CB9ECFDC5825FCED5D1B5E2C1BDD90DA522388CA66FB0BA2F01CC049155FBCB40D038DA24C810131CA1E83E15BB5414D21AA2FA8D644D87057B30F283A5DCA9A5E515A327B1836546BCE20C24929F22F369251754596B9F15C4BD44D7BE2BB5CA892CB3609BE783496E0EC04744668917AB4164E481375A1B11706029278F741C567BA30500507995E9FF31096D67FB666391CF903484AB7ABFB8FAFD76D7001926C435B1E647475EB7530F4FD844B69AC0CBD3A5CDA4A637842BA3C4BCA7714F5881AEC3DCFE2C224002646C2107605E57203B519EAB74277A0761653
|
||||
// INV: random 0
|
||||
197D71D2709E24F36F95315B99B05CD73CA655DC77E5084A95AD55B1DEA520B1B70546B3FA6B093904793BEE8319E0C888A767395C56379D3D058288AA62BB55E53BD4C43892613717BD8286F7601C90C06BB8A3FB88C94A16A15B12953A83AC3B653D0B702F38218EF8738D659EBDF4ACAD340D984BA9A91AA89E4C3B2157350C5C5608F5EE1B1220CE0C13B72000C7FBBF8435AF0DD98FA0583397ACF35C581A5852421CCB139E34A2401A431F0B870F1725CA9B391939959E593284A6A70F13540CA233700788BD56D4442BB0B14753B0C2634B3B8E0777BE0378A62E119A20D33BB74CE2B7359BBD16003EC91E95E2BCC2B4712E168F70C98EC588207D09C5BB27DAC7D35A51D4E5C461C95B3BCF3FD314900B3B97719D75302982A9008813B4440807B713ED1B58F9748BD9244AFF187271BFD66C725141AF15F7AB6B0C56E3B47A5962A480D07C944C3D92D6949B2E07D4BFAE2171304C818506A867F14E1E67CF8BFA7F6DC4CD1D0C0034B7591920337D38F267869ECD2BD380F93B678
|
||||
// INV: random 1
|
||||
1BCEA253B22891A56FA38A9B6643C3BC2DC3B64A5CBBAC8FA0B92172BD9C6056CA2A772BA4187D2AB2130923B287D02CA3BD1AA1E65E22E747AAA05B3BF31E172F88B6E1008C896DE11118720F9C258773ABCA8C5A72A32B0683E8380B40A82D95345849D416620106E01D1523F28DA2617AF56736BA0F7AC1591538CC9120DA3FC75A3C3A688A2459964AC071D1B90B610B6BB598135481B552B2BD4C0C4513C236759D7C341E4EC3D31B99E9C108DF97A93A13C5D45D3787C4A2EC4FBB579F281FC8151872A9215E8851A339F7488C0681E4FD3A370E7E30220212C3B2934895F0473CA7B96C01945178B951B0002E10C053D917818548CDD2683125DE20EC6754725B1EE64B2FB9A744C28C0056C098C37B426A340EAA319C452619588300330B4BD19AA4263E90F9A61F85071D71CF5DA9742C10C44BAB03CF277170C5068ABC884DB0571160CB7D6BCB29E27C4DD90718837F19973B856C9E72984228C89084CACA7A560761A20083F901CE40CC6D690A93D26613B7DD1B4C5B4333FA9C0
|
||||
// INV: random 2
|
||||
1068B8B1480E300B40F2AA02A99CCA5B9D757302B989EC9B22083D3CD41DC9D940B75A7E77408B53C75DFB3736822417A614A1E33EB2BC2549039973057009E9339E310BAF6A93077A43685BC34944182893A2CD617E08F70A35C67D07A0F0B669A5364B9836D15F3E4C410AC1F938B5F1A9990A30A4094CB1DC1F68C88B15D74AB3CC8296980101CC84A9E05B4AC9463CC80E647E1C8BFDBC245876537C6CA6E4AE9425981821978310A2FB69A1A22F6FE8929F2789A8FB30C3256EC3306EA4224F2FA75C42406A59C7E216599108F555CBC431230427B318AF51D52EAC45EBCE2A9FB2C8192F3787A3F75A93D4B3BF47F56CA583B944EA6279855B3C1C77893630952D190C663D68CD4D89501A7783849B203FF0F37D1783510AE222C4695B604C4A1641CC497A696C5F6A6A7523A7E555579A892070A25101C4A6E50D6184B4D008C55840A2E7EB46E31CC2FA56A8990B33BA03569179C9C028A57CF527E33847324730469D7FB3131401AA8FECFA1C31A5C7F78F16850F6D6B3B8FC36707B
|
||||
// INV: random 3
|
||||
1A258A84A254FAAF64C4731BA6348D78061818974EFB0682C17A2E062AC5E2F27C584B5F52FC7D4A0D3C19C89D4BD0AFE3C05F927FB9A0EF64C438BCF58D2E686A7E31E65A248653A97B88B2779A5AF420965E1F42E633284F96B1C801EC9C83F6471E845659F7C93DD8E297D86F537C6D8DE8CE6726E24809DA2A00770217BD8036A37FAA72C9972C6BD8EB461B68A54B399F92E4AB088A84C09AAF22D07B528D145AEBA4605F5E9B12BF919C7AD043B86B9D6B23676DCA6043D2A111B09D5A79E595C9191A19C8AAE156C1DB23BA3C8918B382C3DA73075A2825A8366076585D45CD9823320EF5261FA7F51556946D953746003ECE463E4554E6AE8A128B911F31A1374C4068A0F3CFC8C1C315387165F068187B4283D9B3433A9D8DBBAAB63A8E0395CA7D5334B792529DF57484D7208BB778532B02BF67F6099000B2AAD746F9C7117AE7593C4A345B5B5CC9C8B8190129D147A0B5ED99CBCF4A818775955B9682400A04916021961BF5369005332C675E45F9B182FBFC49B5037618DA0BE
|
||||
// INV(NTT(random 0)) → random*256
|
||||
1C893A501FB1FC01ABBAFABBFB711F40A42A71A277C0FD13D05806C4A8948853C37CB72E47CF89B74A747BB6C8808830075394FC0CB67CA30D593E7AD013C0EB3EC959189BD22303D97B1827BF6611384F6212A8E35EB822ED182575852147A7D0A37DE0EE0AF9EA60956490AA875B833CA067F73DFAF874FC99869102644426498A51964CC6006344CC9A21ACFB0A0F6491153B7B8AD5EB8687E10959E2AC8C062F08895AF934C12133CAC73784541AAA7179AABADAC67861707AA5C1CBA254E0C2B357335DF9E35FDBDA3A81552FABA269836906D14A7887FB45AAEB17163144927EBB62BF321111A2549FA3E6B49FE81746D98B646639A2A9FFC6E5A8019C8EB22BC01416361BDB2F4D89AF7FD684C8F78657374F96084F60E6BA1604A8B435FDAF875215BCD533A6CA413396AAC7163C9915243B9889FBE4A9E89FC0B4F3A5207855A2A6536898856C8336CBEC87241F0D77506CB0200C3B291540D5A2E55C76D9EE0CA56205D169A604466310FFA355858B96D1B9A83E99B26079255C68C
|
||||
// INV(NTT(random 1)) → random*256
|
||||
190423B37EA2101DAD3CCC02177663395CBF024A2598CF74E55712BAC08C07BD49D7D952326D497370BA82685C429D699639540A0859B0CDC19CB1B0E57146F06E42A65CC0A49C2DCA2BBB1500092C086A401F28E5C9A271F94773544A815A9EC01F3EE0379BBC5681C2581B32FB3B4CDE46B40ACCF456CA9C3E0BB8CA89E5B309208841BCA23AE2C94AE7F22B018019D4328911D27F973D1E31E10940EF56B928C05AA218D45117E69820F5591BF4AD2179A064E60690C6499A645C818748BFF7D44D84BA45A37C4D4C5F0817AFB86B3A30C41C261282565A14C7B9071DF5113355C7B3779C7B583F06FBF1479941AA700D5EDAAD45F75C4FFC78290BF56F0B975F081A523B283F7ABBA054D86249F5C500A39050065DF13C1561CD72ABFD72EBF6451589BAB21730E1A1A4B7AC2D79133D62714411047FA9BF95572BAAC33528409B0D982CA409E55E0583A5E8A6183B2A3DD4457108A4C0E5EA4B699E95F287B7B9DF6DFCDB5B14A41BE46D95C1870867473953D02A349349A6670A639D9E2
|
||||
62
sync_rtl/ntt/TB/xsim_run.tcl
Normal file
62
sync_rtl/ntt/TB/xsim_run.tcl
Normal file
@@ -0,0 +1,62 @@
|
||||
# xsim_run.tcl - Vivado xsim compilation and simulation script for NTT
|
||||
#
|
||||
# Compiles all NTT RTL sources plus testbench and runs simulation.
|
||||
# Run from the project root: ~/Dev/mlkem/
|
||||
#
|
||||
# Prerequisites:
|
||||
# source /opt/Xilinx/Vivado/2019.2/settings64.sh
|
||||
#
|
||||
# Usage examples:
|
||||
# # Run ntt_core testbench
|
||||
# xsim ntt_core_sim -R
|
||||
#
|
||||
# # Step-by-step:
|
||||
# vivado -mode batch -source xsim_run.tcl
|
||||
|
||||
# ================================================================
|
||||
# Configuration
|
||||
# ================================================================
|
||||
set SRC_DIR sync_rtl/ntt
|
||||
set TB_DIR sync_rtl/ntt/TB
|
||||
|
||||
# ================================================================
|
||||
# Step 1: Compile all source files (xvlog)
|
||||
# ================================================================
|
||||
puts "=== Compiling RTL sources ==="
|
||||
|
||||
# Barrett modular multiplier (combinational)
|
||||
xvlog -sv ${SRC_DIR}/barrett_mul.v
|
||||
|
||||
# Zeta ROM (combinational)
|
||||
xvlog -sv ${SRC_DIR}/zeta_rom.v
|
||||
|
||||
# Butterfly unit (combinational, instantiates barrett_mul)
|
||||
xvlog -sv ${SRC_DIR}/butterfly_unit.v
|
||||
|
||||
# NTT core (FSM-based, instantiates butterfly_unit + zeta_rom + barrett_mul)
|
||||
xvlog -sv ${SRC_DIR}/ntt_core.v
|
||||
|
||||
# ================================================================
|
||||
# Step 2: Compile testbench
|
||||
# ================================================================
|
||||
puts "=== Compiling testbench ==="
|
||||
|
||||
# File-based vector testbench for ntt_core
|
||||
xvlog -sv ${TB_DIR}/tb_ntt_core_xsim.v
|
||||
|
||||
# ================================================================
|
||||
# Step 3: Elaborate (xelab)
|
||||
# ================================================================
|
||||
puts "=== Elaborating snapshot ==="
|
||||
|
||||
xelab tb_ntt_core_xsim -s ntt_core_sim
|
||||
|
||||
# ================================================================
|
||||
# Step 4: Run simulation
|
||||
# ================================================================
|
||||
puts ""
|
||||
puts "=== Running ntt_core test ==="
|
||||
xsim ntt_core_sim -R
|
||||
|
||||
puts ""
|
||||
puts "=== Simulation complete ==="
|
||||
Reference in New Issue
Block a user