chore(tb): remove Verilator TBs + framework; parallelize XSIM runs
Verilator is no longer used (all verification is via Vivado XSIM). Remove: - 10 per-module tb_*.cpp Verilator testbenches - the entire test_framework/ Verilator harness (lib/, run_all.py, config.json, per-module test_plan.json/gen_vectors.py, golden vectors, reports) - stale specs: verilator-conventions.md, test_framework/structure.md (index.md updated to drop the Verilator entry) Parallelize run_tb.sh K x case execution (modules stay serial): - new run_xsim_jobs helper: compile+elaborate once (serial, populates the shared xsim.dir), then run each (K,case) xsim in its own private workdir with a COPY of xsim.dir (~1MB) so concurrent same-snapshot runs don't clobber each other's runtime logs. Each workdir symlinks the repo sync_rtl tree so the TB's repo-relative $readmemh vector paths resolve. - top/enc/dec runners refactored to build a (snapshot:K:case) spec list and hand it to run_xsim_jobs; ordered PASS/FAIL summary + per-job /tmp logs preserved. Bare './run_tb.sh top' now also takes the parallel path. Speedup (20 cores): top full sweep 2:11 -> 0:51 (~2.6x), ~320% CPU. Verified: top (11) / enc (9) / dec (9) all PASS; missing-vector runs still fail (file-not-found guard -> exit 1).
This commit is contained in:
@@ -1,125 +0,0 @@
|
||||
// tb_comp_decomp.cpp - Verilator C++ testbench for comp_decomp_sync
|
||||
//
|
||||
// Reads test vectors from a hex file specified by +VECTOR_FILE= plusarg.
|
||||
// Each line: "MODE D COEFF" (e.g. "C A 3FF" for compress d=10 coeff=0x3FF).
|
||||
// MODE: 'C' for compress, 'D' for decompress.
|
||||
// Drives the DUT, waits for valid_o, writes "RESULT: COEFF" to stdout.
|
||||
//
|
||||
// Clock: 10 ns period. Reset: 2 cycles low. Timeout: 100,000 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include "Vcomp_decomp_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 100000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13; // skip "+VECTOR_FILE="
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vcomp_decomp_sync* dut = new Vcomp_decomp_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->coeff_in = 0;
|
||||
dut->d = 0;
|
||||
dut->mode = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 cycles low
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
dut->rst_n = 1;
|
||||
|
||||
// Always ready to receive results
|
||||
dut->ready_i = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
// Skip empty lines and comments
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse: MODE D COEFF
|
||||
std::istringstream iss(line);
|
||||
char mode_char;
|
||||
unsigned int d_val, coeff_val;
|
||||
if (!(iss >> mode_char >> std::hex >> d_val >> coeff_val)) continue;
|
||||
|
||||
if (mode_char == 'C')
|
||||
dut->mode = 0;
|
||||
else if (mode_char == 'D')
|
||||
dut->mode = 1;
|
||||
else
|
||||
continue;
|
||||
|
||||
dut->d = d_val & 0x1F;
|
||||
dut->coeff_in = coeff_val & 0xFFF;
|
||||
dut->valid_i = 1;
|
||||
|
||||
// posedge: DUT samples valid_i, pipeline_reg captures data
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
cycle++;
|
||||
dut->valid_i = 0;
|
||||
|
||||
// posedge: pipeline_reg sends result out (valid_o=1)
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
cycle++;
|
||||
|
||||
printf("RESULT: %03X\n", dut->coeff_out & 0xFFF);
|
||||
}
|
||||
|
||||
infile.close();
|
||||
delete dut;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
// tb_mod_add.cpp - Verilator C++ testbench for mod_add_sync
|
||||
//
|
||||
// Reads test vectors from a hex file specified by +VECTOR_FILE= plusarg.
|
||||
// Each line: "AAA BBB" (two 12-bit hex operands).
|
||||
// Drives the DUT, waits for valid_o, writes "RESULT: CCC" to stdout.
|
||||
//
|
||||
// Clock: CLK_PERIOD ns period (from defines.vh).
|
||||
// Reset: 2 cycles low, then high.
|
||||
// Timeout: 100,000 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include "Vmod_add_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 100000
|
||||
#define Q 3329
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13; // skip "+VECTOR_FILE="
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vmod_add_sync* dut = new Vmod_add_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->a = 0;
|
||||
dut->b = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 cycles low
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
dut->rst_n = 1;
|
||||
|
||||
// Always ready to receive results
|
||||
dut->ready_i = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
bool waiting_result = false;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
// Skip empty lines and comments
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse hex operands
|
||||
std::istringstream iss(line);
|
||||
unsigned int a_val, b_val;
|
||||
if (!(iss >> std::hex >> a_val >> b_val)) continue;
|
||||
|
||||
dut->a = a_val & 0xFFF;
|
||||
dut->b = b_val & 0xFFF;
|
||||
dut->valid_i = 1;
|
||||
|
||||
// posedge: DUT samples valid_i, pipeline_reg captures data, valid_o→1
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
cycle++;
|
||||
dut->valid_i = 0;
|
||||
|
||||
// posedge: pipeline_reg clears valid_o (ready_i=1), but result is
|
||||
// available on sum port right now (combinational from data_r)
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
cycle++;
|
||||
|
||||
printf("RESULT: %03X\n", dut->sum & 0xFFF);
|
||||
}
|
||||
|
||||
infile.close();
|
||||
delete dut;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
// tb_ntt.cpp - Verilator C++ testbench for ntt_sync
|
||||
//
|
||||
// Reads test vectors from +VECTOR_FILE= plusarg.
|
||||
// Format: "MODE COEFF0 COEFF1 ... COEFF255"
|
||||
// MODE: "F" = forward NTT, "I" = inverse NTT
|
||||
// COEFFx: 3-digit hex (12-bit, 000..CFF)
|
||||
//
|
||||
// Drives DUT with coefficients one per cycle, waits for output,
|
||||
// prints "RESULT: COEFF0 COEFF1 ... COEFF255\n" to stdout.
|
||||
//
|
||||
// Clock: 10ns period. Reset: 2 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include "Vntt_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 500000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
// Toggle clock: both edges + eval (one full cycle)
|
||||
static void posedge(Vntt_sync* dut) {
|
||||
dut->clk = 1;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = 0;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
static int hex_char_to_nibble(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse 3-char hex token to 12-bit value.
|
||||
static uint16_t hex3_to_val(const std::string& tok) {
|
||||
uint16_t val = 0;
|
||||
for (size_t i = 0; i < tok.length() && i < 3; i++) {
|
||||
val = (val << 4) | hex_char_to_nibble(tok[i]);
|
||||
}
|
||||
return val & 0xFFF;
|
||||
}
|
||||
|
||||
// Format 12-bit value as 3-char hex (lowercase for consistency).
|
||||
static std::string val_to_hex3(uint16_t val) {
|
||||
char buf[4];
|
||||
snprintf(buf, sizeof(buf), "%03X", val & 0xFFF);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vntt_sync* dut = new Vntt_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->mode = 0;
|
||||
dut->coeff_in = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 full cycles
|
||||
for (int i = 0; i < 2; i++) posedge(dut);
|
||||
dut->rst_n = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
int vec_count = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse: MODE COEFF0 COEFF1 ... COEFF255
|
||||
std::istringstream iss(line);
|
||||
std::string mode_str;
|
||||
if (!(iss >> mode_str)) continue;
|
||||
|
||||
int mode_val = 0;
|
||||
if (mode_str == "I") mode_val = 1;
|
||||
|
||||
// Parse 256 coefficients into vector
|
||||
std::vector<uint16_t> input_coeffs(256);
|
||||
std::string tok;
|
||||
int coeff_idx = 0;
|
||||
while (iss >> tok && coeff_idx < 256) {
|
||||
input_coeffs[coeff_idx] = hex3_to_val(tok);
|
||||
coeff_idx++;
|
||||
}
|
||||
if (coeff_idx != 256) {
|
||||
std::cerr << "ERROR: Expected 256 coefficients, got " << coeff_idx
|
||||
<< " (vec " << vec_count << ")" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set mode
|
||||
dut->mode = mode_val;
|
||||
|
||||
// ---- Load 256 coefficients ----
|
||||
while (!dut->ready_o) {
|
||||
posedge(dut); cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
for (int i = 0; i < 256; i++) {
|
||||
dut->coeff_in = input_coeffs[i];
|
||||
dut->valid_i = 1;
|
||||
posedge(dut); cycle++;
|
||||
dut->valid_i = 0;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
|
||||
// At this point, the DUT has captured all 256 coeffs and
|
||||
// transitioned to S_COMPUTE_RD (ready_o went low).
|
||||
|
||||
// ---- Wait for valid_o (DUT computing) ----
|
||||
dut->ready_i = 1;
|
||||
while (!dut->valid_o) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
|
||||
// ---- Read 256 output coefficients ----
|
||||
printf("RESULT: ");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
// Wait for valid_o to be asserted (data is valid NOW)
|
||||
while (!dut->valid_o) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
|
||||
// Capture coefficient BEFORE consuming posedge
|
||||
uint16_t coeff_val = (uint16_t)(dut->coeff_out & 0xFFF);
|
||||
printf("%s%s", val_to_hex3(coeff_val).c_str(),
|
||||
(i < 255) ? " " : "");
|
||||
|
||||
// Consume this coefficient: posedge with ready_i=1
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
vec_count++;
|
||||
}
|
||||
|
||||
std::cout << "Processed " << vec_count << " vectors" << std::endl;
|
||||
infile.close();
|
||||
delete dut;
|
||||
return (vec_count > 0) ? 0 : 1;
|
||||
|
||||
timeout_err:
|
||||
std::cerr << "ERROR: Timeout at cycle " << cycle
|
||||
<< " (vec " << vec_count << ")" << std::endl;
|
||||
infile.close();
|
||||
delete dut;
|
||||
return 1;
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
// tb_poly_arith.cpp - Verilator C++ testbench for poly_arith_sync
|
||||
//
|
||||
// Reads test vectors from a hex file specified by +VECTOR_FILE= plusarg.
|
||||
// Each line: "MODE A0 A1 ... A255 B0 B1 ... B255"
|
||||
// MODE: 'A' for add, 'S' for sub
|
||||
// A0..A255: 256 hex coefficients (12-bit, 3 hex digits each)
|
||||
// B0..B255: 256 hex coefficients
|
||||
//
|
||||
// Feeds 256 (A, B) pairs through the DUT, collects 256 output coeffs,
|
||||
// prints one "RESULT: C0 C1 ... C255" line per vector.
|
||||
//
|
||||
// Clock: 10 ns period (100 MHz).
|
||||
// Reset: 2 cycles low, then high.
|
||||
// Timeout: 100,000 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include "Vpoly_arith_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 100000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
// Helper: toggle clock (full cycle: low->high->low) with eval
|
||||
static void posedge(Vpoly_arith_sync* dut) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vpoly_arith_sync* dut = new Vpoly_arith_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->coeff_a_in = 0;
|
||||
dut->coeff_b_in = 0;
|
||||
dut->mode = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 cycles low
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
dut->rst_n = 1;
|
||||
|
||||
// Always ready to receive results
|
||||
dut->ready_i = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
// Skip empty lines and comments
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse: MODE A0..A255 B0..B255 (513 values on one line)
|
||||
std::istringstream iss(line);
|
||||
std::string mode_str;
|
||||
if (!(iss >> mode_str)) continue;
|
||||
|
||||
// Determine mode
|
||||
bool mode_val;
|
||||
if (mode_str == "A" || mode_str == "a") {
|
||||
mode_val = false;
|
||||
} else if (mode_str == "S" || mode_str == "s") {
|
||||
mode_val = true;
|
||||
} else {
|
||||
std::cerr << "ERROR: Unknown mode: " << mode_str << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
dut->mode = mode_val ? 1 : 0;
|
||||
|
||||
// Read 256 A coeffs
|
||||
unsigned int coeff;
|
||||
std::vector<unsigned int> a_coeffs, b_coeffs;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (!(iss >> std::hex >> coeff)) {
|
||||
std::cerr << "ERROR: Missing A coeff at index " << i << std::endl;
|
||||
return 1;
|
||||
}
|
||||
a_coeffs.push_back(coeff & 0xFFF);
|
||||
}
|
||||
|
||||
// Read 256 B coeffs
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (!(iss >> std::hex >> coeff)) {
|
||||
std::cerr << "ERROR: Missing B coeff at index " << i << std::endl;
|
||||
return 1;
|
||||
}
|
||||
b_coeffs.push_back(coeff & 0xFFF);
|
||||
}
|
||||
|
||||
// Feed 256 coefficient pairs and collect results
|
||||
std::vector<unsigned int> results;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
// Drive inputs
|
||||
dut->coeff_a_in = a_coeffs[i];
|
||||
dut->coeff_b_in = b_coeffs[i];
|
||||
dut->valid_i = 1;
|
||||
|
||||
// Posedge: DUT samples input, pipeline_reg captures data, valid_o→1
|
||||
posedge(dut);
|
||||
dut->valid_i = 0;
|
||||
|
||||
// Read result now (valid_o is high, coeff_out is valid)
|
||||
// Posedge: pipeline_reg clears valid_o (ready_i=1), but result
|
||||
// is available on coeff_out port (combinational from data_r)
|
||||
posedge(dut);
|
||||
|
||||
results.push_back(dut->coeff_out & 0xFFF);
|
||||
|
||||
cycle += 2;
|
||||
if (cycle > TIMEOUT_CYCLES) {
|
||||
std::cerr << "ERROR: Timeout after " << cycle << " cycles" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Print result as one space-separated hex line
|
||||
printf("RESULT:");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
printf(" %03X", results[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
infile.close();
|
||||
delete dut;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
// tb_poly_mul.cpp - Verilator C++ testbench for poly_mul_sync
|
||||
//
|
||||
// Reads test vectors from +VECTOR_FILE= plusarg.
|
||||
// Format: one line with 512 space-separated hex values:
|
||||
// A[0] A[1] ... A[255] B[0] B[1] ... B[255]
|
||||
// Each value is a 3-digit hex (12-bit).
|
||||
//
|
||||
// Drives DUT with 256 paired (A,B) coefficients, waits for valid_o,
|
||||
// then reads 256 output coefficients via valid/ready handshake.
|
||||
// Prints "RESULT: COEFF0 COEFF1 ... COEFF255\n" to stdout.
|
||||
//
|
||||
// Clock: 10ns period. Reset: 2 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include "Vpoly_mul_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 500000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
// Toggle clock: both edges + eval (one full cycle)
|
||||
static void posedge(Vpoly_mul_sync* dut) {
|
||||
dut->clk = 1;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = 0;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
static int hex_char_to_nibble(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse 3-char hex token to 12-bit value.
|
||||
static uint16_t hex3_to_val(const std::string& tok) {
|
||||
uint16_t val = 0;
|
||||
for (size_t i = 0; i < tok.length() && i < 3; i++) {
|
||||
val = (val << 4) | hex_char_to_nibble(tok[i]);
|
||||
}
|
||||
return val & 0xFFF;
|
||||
}
|
||||
|
||||
// Format 12-bit value as 3-char hex.
|
||||
static std::string val_to_hex3(uint16_t val) {
|
||||
char buf[4];
|
||||
snprintf(buf, sizeof(buf), "%03X", val & 0xFFF);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vpoly_mul_sync* dut = new Vpoly_mul_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->coeff_a_in = 0;
|
||||
dut->coeff_b_in = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 full cycles
|
||||
for (int i = 0; i < 2; i++) posedge(dut);
|
||||
dut->rst_n = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
int vec_count = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse: A[0] A[1] ... A[255] B[0] B[1] ... B[255]
|
||||
// Total: 512 hex values, one line
|
||||
std::istringstream iss(line);
|
||||
std::string tok;
|
||||
|
||||
std::vector<uint16_t> input_coeffs(512);
|
||||
int coeff_idx = 0;
|
||||
while (iss >> tok && coeff_idx < 512) {
|
||||
input_coeffs[coeff_idx] = hex3_to_val(tok);
|
||||
coeff_idx++;
|
||||
}
|
||||
if (coeff_idx != 512) {
|
||||
std::cerr << "ERROR: Expected 512 coefficients, got " << coeff_idx
|
||||
<< " (vec " << vec_count << ")" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- Load 256 A+B pairs ----
|
||||
while (!dut->ready_o) {
|
||||
posedge(dut); cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
for (int i = 0; i < 256; i++) {
|
||||
dut->coeff_a_in = input_coeffs[i];
|
||||
dut->coeff_b_in = input_coeffs[256 + i];
|
||||
dut->valid_i = 1;
|
||||
posedge(dut); cycle++;
|
||||
dut->valid_i = 0;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
|
||||
// ---- Wait for valid_o (DUT computing) ----
|
||||
dut->ready_i = 1;
|
||||
while (!dut->valid_o) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
|
||||
// ---- Read 256 output coefficients ----
|
||||
printf("RESULT: ");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
// Wait for valid_o to be asserted (data is valid NOW)
|
||||
while (!dut->valid_o) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) goto timeout_err;
|
||||
}
|
||||
|
||||
// Capture coefficient BEFORE consuming posedge
|
||||
uint16_t coeff_val = (uint16_t)(dut->coeff_out & 0xFFF);
|
||||
printf("%s%s", val_to_hex3(coeff_val).c_str(),
|
||||
(i < 255) ? " " : "");
|
||||
|
||||
// Consume this coefficient: posedge with ready_i=1
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
vec_count++;
|
||||
}
|
||||
|
||||
std::cout << "Processed " << vec_count << " vectors" << std::endl;
|
||||
infile.close();
|
||||
delete dut;
|
||||
return (vec_count > 0) ? 0 : 1;
|
||||
|
||||
timeout_err:
|
||||
std::cerr << "ERROR: Timeout at cycle " << cycle
|
||||
<< " (vec " << vec_count << ")" << std::endl;
|
||||
infile.close();
|
||||
delete dut;
|
||||
return 1;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// tb_rng.cpp - Verilator C++ testbench for rng_sync
|
||||
//
|
||||
// Drives valid_i pulses and prints 256-bit LFSR output values.
|
||||
// Reads a hex input file to determine how many vectors to generate
|
||||
// (one line per vector, content ignored).
|
||||
// Prints "RESULT: <64-char hex>" for each output.
|
||||
//
|
||||
// Clock: 10ns period. Reset: 2 cycles low.
|
||||
// Timeout: 100,000 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include "Vrng_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Count non-empty, non-comment lines to determine vector count
|
||||
int num_vectors = 0;
|
||||
std::string line;
|
||||
while (std::getline(infile, line)) {
|
||||
if (!line.empty() && line[0] != '#')
|
||||
num_vectors++;
|
||||
}
|
||||
infile.close();
|
||||
|
||||
// Instantiate DUT
|
||||
Vrng_sync* dut = new Vrng_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 cycles low
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dut->clk = 1; main_time += 5; dut->eval();
|
||||
dut->clk = 0; main_time += 5; dut->eval();
|
||||
}
|
||||
dut->rst_n = 1;
|
||||
dut->ready_i = 1;
|
||||
|
||||
// Generate vectors
|
||||
for (int n = 0; n < num_vectors; n++) {
|
||||
// Drive valid_i and posedge → LFSR advances, valid_o→1
|
||||
dut->valid_i = 1;
|
||||
dut->clk = 1; main_time += 5; dut->eval();
|
||||
dut->clk = 0; main_time += 5; dut->eval();
|
||||
dut->valid_i = 0;
|
||||
|
||||
// Posedge to consume → valid_o→0
|
||||
dut->clk = 1; main_time += 5; dut->eval();
|
||||
// Print 256-bit result (8 × 32-bit words, MSB first)
|
||||
printf("RESULT: %08X%08X%08X%08X%08X%08X%08X%08X\n",
|
||||
dut->data_o[7], dut->data_o[6], dut->data_o[5], dut->data_o[4],
|
||||
dut->data_o[3], dut->data_o[2], dut->data_o[1], dut->data_o[0]);
|
||||
dut->clk = 0; main_time += 5; dut->eval();
|
||||
}
|
||||
|
||||
delete dut;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
// tb_sample_cbd.cpp - Verilator C++ testbench for sample_cbd_sync
|
||||
//
|
||||
// Reads test vectors from +VECTOR_FILE= plusarg.
|
||||
// Format: "SEED_HEX NONCE_HEX ETA"
|
||||
// SEED_HEX: 64 hex chars (256-bit seed, MSB-first)
|
||||
// NONCE_HEX: 2 hex chars (8-bit nonce)
|
||||
// ETA: "2" or "3" (decimal)
|
||||
//
|
||||
// Drives DUT with seed, nonce, eta. Waits for valid_o, collects 256
|
||||
// coefficients. Prints "RESULT: COEFF_HEX\n" for each coefficient.
|
||||
//
|
||||
// Clock: 10ns period. Reset: 2 cycles.
|
||||
// Timeout: 500000 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include "Vsample_cbd_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 500000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
// Toggle clock: both edges + eval (one full cycle)
|
||||
static void posedge(Vsample_cbd_sync* dut) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
static int hex_char_to_nibble(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse hex string (MSB-first) into 8 x 32-bit words for 256-bit seed.
|
||||
// Word 0 = bits[31:0], word 7 = bits[255:224].
|
||||
// Hex string: leftmost char = most significant nibble (bits 255:252).
|
||||
static void hex_to_256(const std::string& hex, uint32_t data_words[8]) {
|
||||
for (int w = 0; w < 8; w++) data_words[w] = 0;
|
||||
|
||||
int len = (int)hex.length();
|
||||
int nibble_idx = 0;
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
char c = hex[i];
|
||||
if (c == ' ' || c == '\t') continue;
|
||||
int nib = hex_char_to_nibble(c);
|
||||
int word_idx = nibble_idx / 8;
|
||||
int shift = (nibble_idx % 8) * 4;
|
||||
if (word_idx < 8) {
|
||||
data_words[word_idx] |= ((uint32_t)nib << shift);
|
||||
}
|
||||
nibble_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse 2-char hex string into an 8-bit value.
|
||||
// "FF" → 0xFF, "0A" → 0x0A.
|
||||
static uint8_t hex_to_8(const std::string& hex) {
|
||||
int val = 0;
|
||||
for (size_t i = 0; i < hex.length(); i++) {
|
||||
val = (val << 4) | hex_char_to_nibble(hex[i]);
|
||||
}
|
||||
return (uint8_t)(val & 0xFF);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vsample_cbd_sync* dut = new Vsample_cbd_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
for (int w = 0; w < 8; w++) dut->seed_i[w] = 0;
|
||||
dut->nonce_i = 0;
|
||||
dut->eta_i = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 full cycles
|
||||
for (int i = 0; i < 2; i++) posedge(dut);
|
||||
dut->rst_n = 1;
|
||||
|
||||
// Consumer always ready
|
||||
dut->ready_i = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
int vec_count = 0;
|
||||
int total_coeff_count = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse: SEED_HEX NONCE_HEX ETA
|
||||
std::istringstream iss(line);
|
||||
std::string seed_hex, nonce_hex;
|
||||
int eta_val;
|
||||
if (!(iss >> seed_hex >> nonce_hex >> eta_val)) continue;
|
||||
if (seed_hex.length() < 64) continue;
|
||||
|
||||
// Set seed_i (256 bits)
|
||||
uint32_t seed_words[8];
|
||||
hex_to_256(seed_hex, seed_words);
|
||||
for (int w = 0; w < 8; w++) dut->seed_i[w] = seed_words[w];
|
||||
|
||||
// Set nonce_i (8 bits)
|
||||
dut->nonce_i = hex_to_8(nonce_hex);
|
||||
|
||||
// Set eta_i (2'd2 or 2'd3)
|
||||
dut->eta_i = (eta_val == 3) ? 3 : 2;
|
||||
|
||||
// Assert valid_i for one cycle
|
||||
dut->valid_i = 1;
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
dut->valid_i = 0;
|
||||
|
||||
// Wait for 256 coefficients
|
||||
int coeffs_collected = 0;
|
||||
bool timed_out = false;
|
||||
|
||||
while (coeffs_collected < 256) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
|
||||
if (cycle > TIMEOUT_CYCLES) {
|
||||
std::cerr << "ERROR: Timeout waiting for coeffs (vec "
|
||||
<< vec_count << ", got " << coeffs_collected
|
||||
<< "/256)" << std::endl;
|
||||
timed_out = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dut->valid_o && dut->ready_i) {
|
||||
// Read 12-bit coefficient and print
|
||||
uint32_t coeff = dut->coeff_o & 0xFFF;
|
||||
printf("RESULT: %03X\n", coeff);
|
||||
coeffs_collected++;
|
||||
total_coeff_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (timed_out) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Wait for DUT to return to IDLE before next vector
|
||||
int wait_cycles = 0;
|
||||
while (!dut->ready_o && wait_cycles < 100) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
wait_cycles++;
|
||||
}
|
||||
|
||||
vec_count++;
|
||||
}
|
||||
|
||||
done:
|
||||
infile.close();
|
||||
delete dut;
|
||||
|
||||
if (vec_count == 0) {
|
||||
std::cerr << "ERROR: No vectors processed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
// tb_sample_ntt.cpp - Verilator C++ testbench for sample_ntt_sync
|
||||
//
|
||||
// Reads test vectors from +VECTOR_FILE= plusarg.
|
||||
// Each line: "RHO_HEX K_HEX I_HEX J_HEX"
|
||||
// RHO_HEX: 64 hex chars (32 bytes, MSB-first per byte pair)
|
||||
// K_HEX, I_HEX, J_HEX: single hex digits
|
||||
//
|
||||
// Drives DUT, waits for 256 coefficients via valid_o handshake,
|
||||
// prints "RESULT: CCC" for each (12-bit hex).
|
||||
//
|
||||
// Clock: 10ns period. Reset: 2 cycles. Timeout: 2,000,000 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "Vsample_ntt_sync.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 2000000
|
||||
#define Q 3329
|
||||
#define N_COEFFS 256
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
static void posedge(Vsample_ntt_sync* dut) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
static int hex_char_to_nibble(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_rho(const std::string& hex, Vsample_ntt_sync* dut) {
|
||||
for (int w = 0; w < 8; w++) dut->rho_i[w] = 0;
|
||||
|
||||
int byte_count = 0;
|
||||
for (size_t i = 0; i < hex.length() && byte_count < 32; i += 2) {
|
||||
while (i < hex.length() && (hex[i] == ' ' || hex[i] == '\t')) i++;
|
||||
if (i + 1 >= hex.length()) break;
|
||||
|
||||
char high_c = hex[i];
|
||||
char low_c = hex[i + 1];
|
||||
uint8_t byte_val = (hex_char_to_nibble(high_c) << 4) |
|
||||
hex_char_to_nibble(low_c);
|
||||
|
||||
int word_idx = byte_count / 4;
|
||||
int byte_off = byte_count % 4;
|
||||
if (word_idx < 8) {
|
||||
dut->rho_i[word_idx] |= ((uint32_t)byte_val << (byte_off * 8));
|
||||
}
|
||||
byte_count++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vsample_ntt_sync* dut = new Vsample_ntt_sync;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
for (int i = 0; i < 8; i++) dut->rho_i[i] = 0;
|
||||
dut->k_i = 0;
|
||||
dut->i_idx = 0;
|
||||
dut->j_idx = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
|
||||
// Reset: 2 full cycles
|
||||
for (int i = 0; i < 2; i++) posedge(dut);
|
||||
dut->rst_n = 1;
|
||||
|
||||
dut->ready_i = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
int vec_count = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
std::string rho_hex, k_str, i_str, j_str;
|
||||
std::istringstream iss(line);
|
||||
if (!(iss >> rho_hex >> k_str >> i_str >> j_str)) {
|
||||
std::cerr << "ERROR: Malformed input line: " << line << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rho_hex.length() < 64) {
|
||||
std::cerr << "ERROR: RHO_HEX too short" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
int k_val = 0, i_val = 0, j_val = 0;
|
||||
if (!k_str.empty()) k_val = hex_char_to_nibble(k_str[0]);
|
||||
if (!i_str.empty()) i_val = hex_char_to_nibble(i_str[0]);
|
||||
if (!j_str.empty()) j_val = hex_char_to_nibble(j_str[0]);
|
||||
|
||||
// Set inputs
|
||||
parse_rho(rho_hex, dut);
|
||||
dut->k_i = k_val & 0x7;
|
||||
dut->i_idx = i_val & 0x3;
|
||||
dut->j_idx = j_val & 0x3;
|
||||
dut->valid_i = 1;
|
||||
|
||||
// Wait for ready_o (DUT must be IDLE)
|
||||
while (!dut->ready_o && cycle < TIMEOUT_CYCLES) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
}
|
||||
if (cycle >= TIMEOUT_CYCLES) {
|
||||
std::cerr << "ERROR: Timeout waiting for ready_o (vec "
|
||||
<< vec_count << ")" << std::endl;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Capture edge
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
dut->valid_i = 0;
|
||||
|
||||
// Wait for and print 256 coefficients
|
||||
int coeff_count = 0;
|
||||
while (coeff_count < N_COEFFS && cycle < TIMEOUT_CYCLES) {
|
||||
while (!dut->valid_o && cycle < TIMEOUT_CYCLES) {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
}
|
||||
if (cycle >= TIMEOUT_CYCLES) {
|
||||
std::cerr << "ERROR: Timeout waiting for coeff "
|
||||
<< coeff_count << " (vec " << vec_count << ")"
|
||||
<< std::endl;
|
||||
goto done;
|
||||
}
|
||||
|
||||
uint32_t coeff_val = (uint32_t)(dut->coeff_o) & 0xFFF;
|
||||
printf("RESULT: %03X\n", coeff_val);
|
||||
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
coeff_count++;
|
||||
}
|
||||
|
||||
vec_count++;
|
||||
}
|
||||
|
||||
done:
|
||||
infile.close();
|
||||
delete dut;
|
||||
|
||||
if (vec_count == 0) {
|
||||
std::cerr << "ERROR: No vectors processed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
// tb_sha3.cpp - Verilator C++ testbench for sha3_top
|
||||
//
|
||||
// Reads test vectors from +VECTOR_FILE=plusarg.
|
||||
// Format: "MM DDDD..." (mode hex, then 512-bit message hex)
|
||||
// MM: "00"=G, "01"=H, "10"=J
|
||||
// DDDD...: 128 hex chars representing 512-bit data_i
|
||||
//
|
||||
// Drives DUT with mode and input, waits for ready_o/valid_o,
|
||||
// prints "RESULT: OUTPUT_HEX\n" to stdout.
|
||||
//
|
||||
// Clock: 10ns period. Reset: 2 cycles.
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include "Vsha3_top.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_PERIOD_NS 10.0
|
||||
#define TIMEOUT_CYCLES 500000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
|
||||
// Toggle clock: both edges + eval (one full cycle)
|
||||
static void posedge(Vsha3_top* dut) {
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
dut->clk = !dut->clk;
|
||||
main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0);
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
static int hex_char_to_nibble(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse a hex string into Verilator WData words (16 x 32-bit = 512 bits).
|
||||
// Hex string is MSB-first (leftmost hex char = bits 511:508).
|
||||
// data[0] = bits[31:0], data[15] = bits[511:480].
|
||||
static void hex_to_512(const std::string& hex, uint32_t data_words[16]) {
|
||||
for (int w = 0; w < 16; w++) data_words[w] = 0;
|
||||
|
||||
int len = (int)hex.length();
|
||||
// nibble_idx increments for each hex char from RIGHT to LEFT
|
||||
int nibble_idx = 0;
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
char c = hex[i];
|
||||
if (c == ' ' || c == '\t') continue;
|
||||
int nib = hex_char_to_nibble(c);
|
||||
int word_idx = nibble_idx / 8; // 8 nibbles per 32-bit word
|
||||
int shift = (nibble_idx % 8) * 4; // shift within the word
|
||||
if (word_idx < 16) {
|
||||
data_words[word_idx] |= ((uint32_t)nib << shift);
|
||||
}
|
||||
nibble_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// Print hash_o as hex (MSB-first).
|
||||
// data[0] = bits[31:0], data[15] = bits[511:480].
|
||||
static void print_hex(uint32_t data_words[16], int bits) {
|
||||
int full_words = bits / 32;
|
||||
// Build hex from MSB nibble to LSB nibble
|
||||
for (int w = full_words - 1; w >= 0; w--) {
|
||||
uint32_t val = data_words[w];
|
||||
for (int j = 28; j >= 0; j -= 4) {
|
||||
int nib = (int)((val >> j) & 0xF);
|
||||
printf("%01X", nib);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Parse +VECTOR_FILE= plusarg
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Instantiate DUT
|
||||
Vsha3_top* dut = new Vsha3_top;
|
||||
|
||||
// Initialize
|
||||
dut->clk = 0;
|
||||
dut->rst_n = 0;
|
||||
dut->mode = 0;
|
||||
for (int w = 0; w < 16; w++) dut->data_i[w] = 0;
|
||||
dut->valid_i = 0;
|
||||
dut->ready_i = 0;
|
||||
// multi-block absorb path disabled for single-block G/H/J tests
|
||||
dut->mb_en = 0;
|
||||
dut->mb_valid_i = 0;
|
||||
dut->mb_last_i = 0;
|
||||
|
||||
// Reset: 2 full cycles
|
||||
for (int i = 0; i < 2; i++) posedge(dut);
|
||||
dut->rst_n = 1;
|
||||
|
||||
// Consumer always ready
|
||||
dut->ready_i = 1;
|
||||
|
||||
std::string line;
|
||||
vluint64_t cycle = 0;
|
||||
int vec_count = 0;
|
||||
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
|
||||
// Parse: MODE_HEX MESSAGE_HEX
|
||||
std::istringstream iss(line);
|
||||
std::string mode_str, data_hex;
|
||||
if (!(iss >> mode_str >> data_hex)) continue;
|
||||
if (mode_str.length() < 2) continue;
|
||||
|
||||
int mode_val = hex_char_to_nibble(mode_str[1]);
|
||||
|
||||
// Set mode
|
||||
dut->mode = mode_val & 0x3;
|
||||
|
||||
// Set data_i from hex string
|
||||
uint32_t data_words[16];
|
||||
hex_to_512(data_hex, data_words);
|
||||
for (int w = 0; w < 16; w++) dut->data_i[w] = data_words[w];
|
||||
|
||||
// Assert valid_i for one cycle
|
||||
dut->valid_i = 1;
|
||||
|
||||
// posedge: DUT samples valid_i, starts keccak_core
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
dut->valid_i = 0;
|
||||
|
||||
// Wait for valid_o (keccak_core takes ~25 cycles)
|
||||
do {
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
if (cycle > TIMEOUT_CYCLES) {
|
||||
std::cerr << "ERROR: Timeout waiting for valid_o (vec " << vec_count << ")" << std::endl;
|
||||
goto done;
|
||||
}
|
||||
} while (!dut->valid_o);
|
||||
|
||||
// Read hash_o and print
|
||||
uint32_t hash_words[16];
|
||||
for (int w = 0; w < 16; w++) hash_words[w] = dut->hash_o[w];
|
||||
|
||||
int out_bits = (mode_val == 0) ? 512 : 256;
|
||||
printf("RESULT: ");
|
||||
print_hex(hash_words, out_bits);
|
||||
|
||||
// One more cycle for valid_o handshake
|
||||
posedge(dut);
|
||||
cycle++;
|
||||
vec_count++;
|
||||
}
|
||||
|
||||
done:
|
||||
infile.close();
|
||||
delete dut;
|
||||
|
||||
if (vec_count == 0) {
|
||||
std::cerr << "ERROR: No vectors processed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
// tb_storage.cpp - Verilator C++ testbench for storage (sd_bram top)
|
||||
//
|
||||
// Reads test vectors from +VECTOR_FILE= hex file.
|
||||
// Format: "ADDR DATA" per line (addr in 2-char hex, data in 12-char hex).
|
||||
// Writes values via sd_bram, reads back, prints "RESULT: VAL_HEX".
|
||||
// s_bram is compiled as rtl_dep.
|
||||
//
|
||||
// Clock: 10ns period. W=48, D=64, A=6 (default sd_bram parameters).
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include "Vsd_bram.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#define CLK_HALF_PS 5000
|
||||
|
||||
static vluint64_t main_time = 0;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return (double)main_time / 1000.0;
|
||||
}
|
||||
|
||||
static void tick(Vsd_bram* dut) {
|
||||
dut->clk = 1;
|
||||
main_time += CLK_HALF_PS;
|
||||
dut->eval();
|
||||
dut->clk = 0;
|
||||
main_time += CLK_HALF_PS;
|
||||
dut->eval();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
const char* vector_file = NULL;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
std::string arg(argv[i]);
|
||||
if (arg.rfind("+VECTOR_FILE=", 0) == 0) {
|
||||
vector_file = argv[i] + 13;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vector_file) {
|
||||
std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ifstream infile(vector_file);
|
||||
if (!infile.is_open()) {
|
||||
std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct Vec { int addr; uint64_t data; };
|
||||
std::vector<Vec> vectors;
|
||||
|
||||
std::string line;
|
||||
while (std::getline(infile, line)) {
|
||||
if (line.empty() || line[0] == '#') continue;
|
||||
std::istringstream iss(line);
|
||||
int a;
|
||||
uint64_t d;
|
||||
if (!(iss >> std::hex >> a >> d)) continue;
|
||||
if (a < 0 || a > 63) continue;
|
||||
vectors.push_back({a, d & 0xFFFFFFFFFFFFULL});
|
||||
}
|
||||
infile.close();
|
||||
|
||||
if (vectors.empty()) {
|
||||
std::cerr << "ERROR: No valid vectors in file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vsd_bram* dut = new Vsd_bram;
|
||||
|
||||
dut->clk = 0;
|
||||
dut->rd_addr = 0;
|
||||
dut->wr_en = 0;
|
||||
dut->wr_addr = 0;
|
||||
dut->wr_data = 0;
|
||||
dut->eval();
|
||||
main_time += CLK_HALF_PS;
|
||||
dut->eval();
|
||||
|
||||
// --- WRITE PHASE ---
|
||||
for (size_t i = 0; i < vectors.size(); i++) {
|
||||
dut->wr_en = 1;
|
||||
dut->wr_addr = vectors[i].addr & 0x3F;
|
||||
dut->wr_data = vectors[i].data & 0xFFFFFFFFFFFFULL;
|
||||
tick(dut);
|
||||
}
|
||||
dut->wr_en = 0;
|
||||
dut->wr_addr = 0;
|
||||
dut->wr_data = 0;
|
||||
tick(dut);
|
||||
|
||||
// --- READ PHASE ---
|
||||
for (size_t i = 0; i < vectors.size(); i++) {
|
||||
dut->rd_addr = vectors[i].addr & 0x3F;
|
||||
tick(dut);
|
||||
printf("RESULT: %012lX\n", (unsigned long)(dut->rd_data & 0xFFFFFFFFFFFFULL));
|
||||
}
|
||||
|
||||
delete dut;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user