Verilator testbench for unit tests

This commit is contained in:
Blaise Tine 2021-03-24 09:53:10 -04:00
parent 4de75fad31
commit eee74a25cd
7 changed files with 178 additions and 259 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -0,0 +1,58 @@
#include <cstdlib>
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <chrono>
#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<Device> 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<double, std::milli>(latency).count()
<< " ms" << std::endl;
std::cout << "Simulation run time: " << std::dec << ticks/2 << " cycles" << std::endl;
return 0;
}

View file

@ -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

View file

@ -0,0 +1,81 @@
#pragma once
#include <array>
#include <cstdint>
#include "verilated.h"
#ifdef VM_TRACE
#include <verilated_vcd_c.h> // Trace file format header
#endif
template <typename T>
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 <typename... Args>
void vl_setw(uint32_t* sig, Args&&... args) {
std::array<uint32_t, sizeof... (Args)> arr{static_cast<uint32_t>(std::forward<Args>(args))...};
for (size_t i = 0; i < sizeof... (Args); ++i) {
sig[i] = arr[i];
}
}
template <typename... Args>
int vl_cmpw(const uint32_t* sig, Args&&... args) {
std::array<uint32_t, sizeof... (Args)> arr{static_cast<uint32_t>(std::forward<Args>(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;
}