This page describes a cpp bench, which is used to verify a parallel fifo, using
verilator.
-
In order to practice cpp (c++) verification benches, with system verilog DPI, using a
verilog DUT, I decided to download verilator
and do some self study exercises.
-
This cpp bench is based on an hierarchical Design Under Test and a time management cpp bench.
Both cases are used as simple exercises to gain some experience with
verilator.
In addition to time management and VCD wave trace, this example also generates stimuli
to the Design Under Test.
This page describes the coding of a data stimuli generator, using
verilator.
More, complex benches, will come later.
-
The Design Under Test is a FIFO. The data path of the FIFO is N (4 in this example) 8 bits
flip-flops connected in parallel (direct connect between Qn-1 to Dn) to achieve the fastest FIFO on an FPGA.
The control is also based on N 1 bit flip flops connected as shift register. The full and empty
flags as well as other control is taken from this shift register. All outputs
are registered to farther facilitate timing in an FPGA.
-
The cpp bench is shown below. The changes, stimuli drive and generation, from previous
example are marked. The DUT signals are accessed using
verilator's
pointer signal access
(entry.fe=pipe_fifo->fe).
- #include "Vpipe_fifo.h"
- #include "verilated.h"
- //vcd traces
- #include "verilated_vcd_c.h"
- //cout
- #include <iostream>
- Vpipe_fifo *pipe_fifo; // Instantiation of module
- unsigned int main_time = 0; // Current simulation time
- double sc_time_stamp () { // Called by $time in Verilog
- return main_time;
- }
- typedef struct _Entry{
- unsigned int ti;
- unsigned char rd;
- unsigned char wr;
- unsigned char fe;
- unsigned char ff;
- } Entry;
- void gen(Entry& entry) {
- entry.rd=0;
- entry.wr=0;
- if(entry.ti == 42) {
- entry.rd=0;
- entry.wr=1;
- }
- }
- int main(int argc, char** argv) {
- Verilated::commandArgs(argc, argv);
- pipe_fifo = new Vpipe_fifo;
- //vcd traces
- Verilated::traceEverOn(true);
- VerilatedVcdC* tfp = new VerilatedVcdC;
- pipe_fifo->trace (tfp, 99);
- tfp->open ("obj_dir/simx.vcd");
- pipe_fifo->rst = 1;
- pipe_fifo->rd = 0;
- pipe_fifo->wr = 0;
- pipe_fifo->DI = 16;
- Entry entry;
- while (!Verilated::gotFinish()) {
- if (main_time > 10) {
- pipe_fifo->rst = 0; // Deassert reset
- }
- if ((main_time % 10) == 1) {
- pipe_fifo->clk = 1; // Toggle clock
- }
- if ((main_time % 10) == 6) {
- pipe_fifo->clk = 0;
- }
- if (((main_time-1) % 10) == 1) {
- //cout << "sim gen :time is " << main_time << endl; // Read a output
- entry.ti=main_time;
- entry.fe=pipe_fifo->fe;
- entry.ff=pipe_fifo->ff;
- gen(entry);
- pipe_fifo->rd = entry.rd;
- pipe_fifo->wr = entry.wr;
- }
- pipe_fifo->eval(); // Evaluate model
- if(main_time > 200) break;
- main_time++; // Time passes...
- tfp->dump (main_time);
- } //while
- cout << "sim end :time is " << main_time << endl; // Read a output
- tfp->close();
- delete pipe_fifo;
- exit(0);
- }
-
The design is compiled and run by the following script:
- #!/bin/bash
- if [ -e obj_dir/Vpipe_fifo ] ; then
- rm obj_dir/Vpipe_fifo
- fi
- clear;/usr/bin/verilator --trace --trace-depth 1 --cc pipe_fifo.v --exe sim_main.cpp
- #sed -i "s/VERILATOR_ROOT = \/usr\/bin/VERILATOR_ROOT = \/usr\/share\/verilator/" obj_dir/Vpipe_fifo.mk
- cd obj_dir
- make -j -f Vpipe_fifo.mk Vpipe_fifo && echo "make ended ok"
Regression is run by the following script. An error is detected if ERROR is found
or sim end okay is not found.
- #!/bin/bash
- for i in {1..50000} ; do
- if [ -e run_reg.log ] ; then
- rm -f run_reg.log
- fi
- seed=$RANDOM
- cmd="./obj_dir/Vpipe_fifo_tool "$seed" > run_reg.log"
- eval $cmd
- grep ERROR run_reg.log >& /dev/null
- if [ $? -eq 0 ] ; then
- cmd="cp run_reg.log run_reg_"$seed".log"
- eval $cmd
- else
- grep "sim end.*okay" run_reg.log >& /dev/null
- if [ $? -eq 1 ] ; then
- cmd="cp run_reg.log run_reg_"$seed".log"
- eval $cmd
- fi
- fi
- done
|