From eee74a25cd6e1c5049e1a7ce82d850417992bea1 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 24 Mar 2021 09:53:10 -0400 Subject: [PATCH] Verilator testbench for unit tests --- hw/unit_tests/VX_divide_tb.v | 159 --------------------- hw/unit_tests/cache/Makefile | 32 ++--- hw/unit_tests/cache/cachesim.cpp | 10 +- hw/unit_tests/generic_queue/Makefile | 33 ++++- hw/unit_tests/generic_queue/main.cpp | 58 ++++++++ hw/unit_tests/generic_queue/testbench.v | 64 --------- hw/unit_tests/generic_queue/vl_simulator.h | 81 +++++++++++ 7 files changed, 178 insertions(+), 259 deletions(-) delete mode 100644 hw/unit_tests/VX_divide_tb.v create mode 100644 hw/unit_tests/generic_queue/main.cpp delete mode 100644 hw/unit_tests/generic_queue/testbench.v create mode 100644 hw/unit_tests/generic_queue/vl_simulator.h diff --git a/hw/unit_tests/VX_divide_tb.v b/hw/unit_tests/VX_divide_tb.v deleted file mode 100644 index a4ba539e..00000000 --- a/hw/unit_tests/VX_divide_tb.v +++ /dev/null @@ -1,159 +0,0 @@ -`timescale 1ns/1ps - -module VX_tb_divide(); - -`ifdef TRACE - initial - begin - $dumpfile("trace.vcd"); - $dumpvars(0,test); - end -`endif - - reg clk; - reg rst; - - reg [31:0] numer, denom; - - wire [31:0] o_div[0:7], o_rem[0:7]; - - for (genvar i = 0; i < 8; i++) begin - VX_divide#( - .WIDTHN(32), - .WIDTHD(32), - .WIDTHQ(32), - .WIDTHR(32), - .PIPELINE(i) - ) div( - .clock(clk), - .aclr(rst), - .clken(1'b1), - .numer(numer), - .denom(denom), - .quotient(o_div[i]), - .remainder(o_rem[i]) - ); - end - - initial begin - clk = 0; rst = 0; - - numer = 56; - denom = 11; - - $display("56 / 11 #0"); - if (o_div[0] != 5 || o_rem[0] != 1) begin - $display("PIPE0: div=", o_div[0], " rem=", o_rem[0]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[1] != 1'bx || o_rem[1] != 1'bx) begin - $display("PIPE1: div=", o_div[1], " rem=", o_rem[1]); - $display("expected x,x EXITING"); - $finish(); - end - - if (o_div[2] != 1'bx || o_rem[2] != 1'bx) begin - $display("PIPE2: div=", o_div[2], " rem=", o_rem[2]); - $display("expected x,x EXITING"); - $finish(); - end - - if (o_div[3] != 1'bx || o_rem[3] != 1'bx) begin - $display("PIPE3: div=", o_div[3], " rem=", o_rem[3]); - $display("expected x,x EXITING"); - $finish(); - end - - #2; - - $display("56 / 11 #2"); - if (o_div[0] != 5 || o_rem[0] != 1) begin - $display("PIPE0: div=", o_div[0], " rem=", o_rem[0]); - $display("expected 5,1, EXITING"); - $finish(); - end - - if (o_div[1] != 5 || o_rem[1] != 1) begin - $display("PIPE1: div=", o_div[1], " rem=", o_rem[1]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[2] != 1'bx || o_rem[2] != 1'bx) begin - $display("PIPE2: div=", o_div[2], " rem=", o_rem[2]); - $display("expected x,x EXITING"); - $finish(); - end - - if (o_div[3] != 1'bx || o_rem[3] != 1'bx) begin - $display("PIPE3: div=", o_div[3], " rem=", o_rem[3]); - $display("expected x,x EXITING"); - $finish(); - end - - #2; - - $display("56 / 11 #4"); - if (o_div[0] != 5 || o_rem[0] != 1) begin - $display("PIPE0: div=", o_div[0], " rem=", o_rem[0]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[1] != 5 || o_rem[1] != 1) begin - $display("PIPE1: div=", o_div[1], " rem=", o_rem[1]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[2] != 5 || o_rem[2] != 1) begin - $display("PIPE2: div=", o_div[2], " rem=", o_rem[2]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[3] != 1'bx || o_rem[3] != 1'bx) begin - $display("PIPE3: div=", o_div[3], " rem=", o_rem[3]); - $display("expected x,x EXITING"); - $finish(); - end - - #2; - - $display("56 / 11 #6"); - - if (o_div[0] != 5 || o_rem[0] != 1) begin - $display("PIPE0: div=", o_div[0], " rem=", o_rem[0]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[1] != 5 || o_rem[1] != 1) begin - $display("PIPE1: div=", o_div[1], " rem=", o_rem[1]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[2] != 5 || o_rem[2] != 1) begin - $display("PIPE2: div=", o_div[2], " rem=", o_rem[2]); - $display("expected 5,1 EXITING"); - $finish(); - end - - if (o_div[3] != 5 || o_rem[3] != 1) begin - $display("PIPE3: div=", o_div[3], " rem=", o_rem[3]); - $display("expected 5,1 EXITING"); - $finish(); - end - - $display("PASS"); - - $finish(); - end - - always #1 - clk = !clk; - -endmodule \ No newline at end of file diff --git a/hw/unit_tests/cache/Makefile b/hw/unit_tests/cache/Makefile index bf22bcbc..508efc76 100644 --- a/hw/unit_tests/cache/Makefile +++ b/hw/unit_tests/cache/Makefile @@ -1,46 +1,30 @@ -PARAM += -DCACHE_SIZE=4096 -DWORD_SIZE=4 -DCACHE_LINE_SIZE=16 -DNUM_BANKS=4 -DCREQ_SIZE=4 -DMRVQ_SIZE=16 -DDFPQ_SIZE=16 -DSNRQ_SIZE=16 -DCWBQ_SIZE=4 -DDWBQ_SIZE=4 -DFQQ_SIZE=4 - +TOP = VX_cache +PARAMS += -DCACHE_SIZE=4096 -DWORD_SIZE=4 -DCACHE_LINE_SIZE=16 -DNUM_BANKS=4 -DCREQ_SIZE=4 -DMRVQ_SIZE=16 -DDFPQ_SIZE=16 -DSNRQ_SIZE=16 -DCWBQ_SIZE=4 -DDWBQ_SIZE=4 -DFQQ_SIZE=4 -# control RTL debug print states -DBG_PRINT_FLAGS = -DDBG_PRINT_CORE_ICACHE \ - -DDBG_PRINT_CORE_DCACHE \ - -DDBG_PRINT_CACHE_BANK \ - -DDBG_PRINT_CACHE_SNP \ - -DDBG_PRINT_CACHE_MSHR \ - -DDBG_PRINT_CACHE_TAG \ - -DDBG_PRINT_CACHE_DATA \ - -DDBG_PRINT_DRAM \ - -DDBG_PRINT_OPAE \ - -DDBG_PRINT_AVS - -#DBG_PRINT=$(DBG_PRINT_FLAGS) - -INCLUDE = -I../../rtl/ -I../../rtl/cache -I../../rtl/libs - +INCLUDE = -I../../rtl/ -I../../rtl/libs -I../../rtl/cache SRCS = cachesim.cpp testbench.cpp all: build CF += -std=c++11 -fms-extensions -I../.. +CF += $(PARAMS) VF += --language 1800-2009 --assert -Wall --trace #-Wpedantic VF += -Wno-DECLFILENAME VF += --x-initial unique VF += -exe $(SRCS) $(INCLUDE) - -DBG += -DVCD_OUTPUT $(DBG_PRINT) - +VF += $(PARAMS) gen: - verilator $(VF) -DNDEBUG -cc VX_cache.v $(PARAM) -CFLAGS '$(CF) -DNDEBUG $(PARAM)' --exe $(SRCS) + verilator $(VF) -cc $(TOP).v -CFLAGS '$(CF)' --exe $(SRCS) build: gen - (cd obj_dir && make -j -f VVX_cache.mk) + (cd obj_dir && make -j -f V$(TOP).mk) run: build - (cd obj_dir && ./VVX_cache) + (cd obj_dir && ./V$(TOP)) clean: rm -rf obj_dir diff --git a/hw/unit_tests/cache/cachesim.cpp b/hw/unit_tests/cache/cachesim.cpp index 93bef54b..15bd1e45 100644 --- a/hw/unit_tests/cache/cachesim.cpp +++ b/hw/unit_tests/cache/cachesim.cpp @@ -173,10 +173,10 @@ void CacheSim::stall_dram(){ } void CacheSim::send_snoop_req(){ - cache_->snp_req_valid = 1; + /*cache_->snp_req_valid = 1; cache_->snp_req_addr = 0x12222222; cache_->snp_req_invalidate = 1; - cache_->snp_req_tag = 0xff; + cache_->snp_req_tag = 0xff; */ } void CacheSim::eval_dram_bus() { @@ -274,9 +274,9 @@ bool CacheSim::assert_equal(unsigned int* data, unsigned int tag){ //DEBUG void CacheSim::display_miss(){ - int i = (unsigned int)cache_->miss_vec; - std::bitset<8> x(i); - if (i) std::cout << "Miss Vec " << x << std::endl; + //int i = (unsigned int)cache_->miss_vec; + //std::bitset<8> x(i); + //if (i) std::cout << "Miss Vec " << x << std::endl; //std::cout << "Miss Vec 0" << cache_->miss_vec[0] << std::endl; } diff --git a/hw/unit_tests/generic_queue/Makefile b/hw/unit_tests/generic_queue/Makefile index 76d53af2..f13d14a1 100644 --- a/hw/unit_tests/generic_queue/Makefile +++ b/hw/unit_tests/generic_queue/Makefile @@ -1,11 +1,30 @@ -all: testbench.iv +TOP = VX_fifo_queue -testbench.iv: testbench.v - iverilog testbench.v -o testbench.iv -I ../../rtl/ +PARAMS ?= -run: testbench.iv - ! vvp testbench.iv | grep 'ERROR' || false +INCLUDE = -I../../rtl/ -I../../rtl/libs + +SRCS = main.cpp + +all: build + +CF += -std=c++11 -fms-extensions -I../.. +VF += $(PARAMS) + +VF += --language 1800-2009 --assert -Wall --trace +VF += -Wno-DECLFILENAME +VF += --x-initial unique +VF += -exe $(SRCS) $(INCLUDE) +VF += $(PARAMS) + +gen: + verilator $(VF) -cc $(TOP).v -CFLAGS '$(CF)' --exe $(SRCS) + +build: gen + (cd obj_dir && make -j -f V$(TOP).mk) + +run: build + (cd obj_dir && ./V$(TOP)) clean: - rm testbench.iv - + rm -rf obj_dir diff --git a/hw/unit_tests/generic_queue/main.cpp b/hw/unit_tests/generic_queue/main.cpp new file mode 100644 index 00000000..c3dd026d --- /dev/null +++ b/hw/unit_tests/generic_queue/main.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include "vl_simulator.h" +#include "VVX_fifo_queue.h" +#include "VVX_fifo_queue__Syms.h" + +static const uint32_t MAX_TICKS = 10000000; +static const uint32_t NUM_ITERATIONS = 20000; + +using Device = VVX_fifo_queue; + +int main(int argc, char **argv) { + // Initialize Verilators variables + Verilated::commandArgs(argc, argv); + + vl_simulator sim; + + auto start_time = std::chrono::system_clock::now(); + + // run simulation + unit64_t ticks = sim.reset(0); + + for (;;) { + //sim->io_in_valid = (in_sample < num_iterations * FFT_SIZE); + //sim->io_out_ready = (out_sample < num_iterations * FFT_SIZE); + + // enqueue data + //if (sim->io_in_valid && sim->io_in_ready) { + //std::cout << "t" << std::dec << ticks << std::hex << " input: re=" << re << ", im=" << im << std::endl; + //sim->io_in_data = sample; + //} + + // dequeue data + //if (sim->io_out_valid && sim->io_out_ready) { + //std::cout << "t" << std::dec << ticks << std::hex << " output: re=" << re << ", im=" << im << std::endl; + //test_outputs[out_sample++] = sample; + //} + + // check for completion + + + // advance clock + ticks = sim.step(ticks, 2); + } + + auto end_time = std::chrono::system_clock::now(); + auto latency = end_time - start_time; + std::cout << "Average elapsed time = " + << std::chrono::duration(latency).count() + << " ms" << std::endl; + + std::cout << "Simulation run time: " << std::dec << ticks/2 << " cycles" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/hw/unit_tests/generic_queue/testbench.v b/hw/unit_tests/generic_queue/testbench.v deleted file mode 100644 index 66cafbaf..00000000 --- a/hw/unit_tests/generic_queue/testbench.v +++ /dev/null @@ -1,64 +0,0 @@ -`timescale 1ns/1ns -`include "VX_fifo_queue.v" - -`define check(x, y) if ((x == y) !== 1) if ((x == y) === 0) $error("x=%h, expected=%h", x, y); else $warning("x=%h, expected=%h", x, y) - -module testbench(); - - reg clk; - reg reset; - reg[3:0] data_in; - reg push; - reg pop; - wire[3:0] data_out; - wire full; - wire empty; - - VX_fifo_queue #( - .DATAW(4), - .SIZE(4) - ) dut ( - .clk(clk), - .reset(reset), - .data_in(data_in), - .push(push), - .pop(pop), - .data_out(data_out), - .empty(empty), - .full(full), - `UNUSED_PIN (alm_empty), - `UNUSED_PIN (alm_full), - `UNUSED_VAR (size) - ); - - always begin - #1 clk = !clk; - end - - initial begin - $monitor ("%d: clk=%b rst=%b push=%b, pop=%b, din=%h, empty=%b, full=%b, dout=%h", - $time, clk, reset, push, pop, data_in, empty, full, data_out); - #0 clk=0; reset=1; pop=0; push=0; - #2 reset=0; data_in=4'ha; pop=0; push=1; - #2 `check(full, 0); `check(data_out, 4'ha); `check(empty, 0); - #0 data_in=4'hb; - #2 `check(full, 0); `check(data_out, 4'ha); `check(empty, 0); - #0 data_in=4'hc; - #2 `check(full, 0); `check(data_out, 4'ha); `check(empty, 0); - #0 data_in=4'hd; - #2 `check(full, 1); `check(data_out, 4'ha); `check(empty, 0); - #0 push=0; pop=1; - #2 `check(full, 0); `check(data_out, 4'hb); `check(empty, 0); - #2 `check(full, 0); `check(data_out, 4'hc); `check(empty, 0); - #2 `check(full, 0); `check(data_out, 4'hd); `check(empty, 0); - #2 `check(full, 0); `check(data_out, 4'ha); `check(empty, 1); - #0 data_in=4'he; push=1; pop=0; - #2 `check(full, 0); `check(data_out, 4'he); `check(empty, 0); - #0 data_in=4'hf; pop=1; - #2 `check(full, 0); `check(data_out, 4'hf); `check(empty, 0); - #0 push=0; - #2 `check(full, 0); `check(data_out, 4'hc); `check(empty, 1); - #1 $finish; - end - -endmodule diff --git a/hw/unit_tests/generic_queue/vl_simulator.h b/hw/unit_tests/generic_queue/vl_simulator.h new file mode 100644 index 00000000..a00886c3 --- /dev/null +++ b/hw/unit_tests/generic_queue/vl_simulator.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include "verilated.h" + +#ifdef VM_TRACE +#include // Trace file format header +#endif + +template +class vl_simulator { +private: + + T top_; +#ifdef VM_TRACE + VerilatedVcdC tfp_; +#endif + +public: + + vl_simulator() { + top_.clk = 0; + top_.reset = 0; + #ifdef VM_TRACE + Verilated::traceEverOn(true); + top_.trace(&tfp_, 99); + tfp_.open("trace.vcd"); + #endif + } + + ~vl_simulator() { + #ifdef VM_TRACE + tfp_.close(); + #endif + top_.final(); + } + + uint64_t reset(uint64_t ticks) { + top_.reset = 1; + ticks = this->step(ticks, 2); + top_.reset = 0; + return ticks; + } + + uint64_t step(uint64_t ticks, uint32_t count = 1) { + while (count--) { + top_.eval(); + #ifdef VM_TRACE + tfp_.dump(ticks); + #endif + top_.clk = !top_.clk; + ++ticks; + } + return ticks; + } + + auto operator->() { + return &top_; + } +}; + +template +void vl_setw(uint32_t* sig, Args&&... args) { + std::array arr{static_cast(std::forward(args))...}; + for (size_t i = 0; i < sizeof... (Args); ++i) { + sig[i] = arr[i]; + } +} + +template +int vl_cmpw(const uint32_t* sig, Args&&... args) { + std::array arr{static_cast(std::forward(args))...}; + for (size_t i = 0; i < sizeof... (Args); ++i) { + if (sig[i] < arr[i]) + return -1; + if (sig[i] > arr[i]) + return 1; + } + return 0; +} \ No newline at end of file