// 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 #include #include #include #include #include #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 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 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; }