Nand to Tetris in Verilog Part 2 - Verilator

This project includes info I've used to use to simulate Nand2Tetris (Compiling Verilog to C++ and using a test bench in C++)

Following up to the last project, we'll take a small bit of a turn from the previous test bench in Verilog. The reason for this, is that it ends up being a bit easier to implement with another simulator called Verilator that will take our Verilog and compile it to C++. Icarus Verilog still does a great job and gives us a good idea of how Verilog test benches are created (this method is quite popular), but we'll be using some of the features that C++ allows us to get our simulation to be a little bit more interactive. We could have used GTKWave from Icarus output but I'm going to go ahead and skip on that for now.

Once I had the tests passing, I wanted to see and interact with my model in a more visual way, at first I just wanted to find a VGA simulator that I could attach to my code that generates a VGA signal. I'll get into that later, but it ends up being a little difficult to do with the more traditional tools. Just a little bit ago, I came across Taking a New Look at Verilator - https://zipcpu.com/blog/2017/06/21/looking-at-verilator.html where it's mentioned that Verilator actually maps pretty well to this task.

Before I get into the details of a visual simulation, I'd like to demonstrate how Verilator can be used to redo the test from Part 1 using a simple test bench created in C++ that simply includes our design that gets converted to C++ by verilator.

We'll take the my_not.v created in Part 1, then add the C++ test bench,
my_not_test.cpp:

#include <fstream>
#include "Vmy_not.h"
using namespace std;

ofstream dump("my_not_test.out");
Vmy_not top;

void evalDump()
{
	top.eval();
	dump << "|   " << (int)top.in << "   |   " << (int)top.out << "   |" << endl;
}

int main()
{
	dump << "|  in   |  out  |" << endl;
	top.in = 0;
	evalDump();
	top.in = 1;
	evalDump();
	return 0;
}

This will basically create a output file, my_not_test.out. It will print out a test header, set the design (imported from Vmy_not.h and instantiated as top) in port to zero, update the model with eval, then print out the values of the in and out ports. It then sets the in port to one and repeats. Then exits.

We'll set up another Bash script to compile, run, and compare the output like before. This time using Verilator.

not.tst.sh:

set -e
verilator -Wall --cc my_not.v --exe my_not_test.cpp
make -s -j -C obj_dir -f Vmy_not.mk Vmy_not
obj_dir/Vmy_not
diff --strip-trailing-cr Not.cmp my_not_test.out
echo "successful"

 If everything went well, we'll have a message about Archiving, creating, then successful. If there's a problem in the compile Verilator will give us some error (maybe signal not used or driven) and if there's an implementation error, we'll just get the diff output < for the file that we're comparing against, > for the file we're generating from the simulation.

(In Part 3, I'll demonstrate how we can test our ALU visually using a similar setup.)