In Part 2, we went from using Icarus in Part 1 to using Verilator to run our test bench. In itself, in can be useful but the major benefit is that that test bench can be easily used by other C++ code and can utilize other libraries fairly easily. In this example we'll throw together a simple test framework that will visualize input and outputs to the ALU.

Starting with the test bench from the previous section, 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;
}

my_alu_test_sdl.cpp:

//include the SDL and font headers
#ifdef WIN32
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#else
#include <SDL.h>
#include <SDL_ttf.h>
#endif

#include <memory>
#include <vector>
#include "Vmy_alu.h" //the ALU Verilog to C++ header
using namespace std;

Vmy_alu top; //ALU implementation

//SDL renderer and single font (leaving global for simplicity)
SDL_Renderer *renderer;
TTF_Font *font;

//parent class Vis will be inherited by our 16 bit and 1 bit values,
//it sets up common items click the text rendering and interface for
//draw and click
class Vis {
public:
    Vis(int x, int y)
    {
        //set starting position of rect, the size is unknown at this time
        m_rect = { x, y, 0, 0};
    }
    virtual void draw()
    {
        //if there's a texture set, draw it
        if(textTexture) {
            SDL_Rect dest = m_rect;
            //get the text size
            SDL_QueryTexture(textTexture, NULL, NULL, &dest.w, &dest.h);
            //offset of -5, -10 from the Vis item itself
            dest.x -= dest.w + 5;
            dest.y -= 10;
            //draw the text to the renderer surface
            SDL_RenderCopy(renderer, textTexture, nullptr, &dest);
        }
    }
    //interface for mouse
    virtual bool click(int x, int y) = 0;
    void setText(const char *str)
    {
        //if there's already a texture, remove it
        if(textTexture) {
            SDL_DestroyTexture(textTexture);
            textTexture = nullptr;
        }
        //white font
        SDL_Color color = {255, 255, 255, 255};
        //create the surface of the font in host space
        SDL_Surface *textSurface = TTF_RenderText_Solid(font, str, color);
        //create the texture of the font in video space
        textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
        //should probably free the textSurface?
        //SDL_FreeSurface(textSurface);
    }
protected:
    //stores our Vis elements location and size (not including message)
    SDL_Rect m_rect;
    SDL_Texture *textTexture = nullptr;
    //some defaults
    static int box_size, box_space, group_space;
};

int Vis::box_size = 20; //size of each bit
int Vis::box_space = 5; //space between each bit
int Vis::group_space = 10; //space between each 4-bit group (simple for hex)

//Vis16 is the 16bit visualization element
class Vis16 : public Vis {
public:
    Vis16(int x, int y, SData &value) : Vis(x, y), m_value(value) { }
    void draw()
    {
        Vis::draw(); //handles text rendering

        //iterate through each group of 4-bits
        int ipos = 0;
        int c = 0;
        for (int g = 0; g < 4; g++) {
            //iterate through each bit in the group
            for (int i = 0; i < 4; i++) {
                SDL_Rect rect = { ipos + m_rect.x, m_rect.y, box_size, box_size };

                //each bit value in the value itself (reverses bit order visually)
                //and sets color to white or black accordingly
                if (m_value & 1 << (15 - c))
                    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                else
                    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

                //display bit
                SDL_RenderFillRect(renderer, &rect);
                ipos += box_size + box_space;
                c++;
            }
            //increase position by group spacing
            ipos += group_space;
        }
    }
    bool click(int x, int y)
    {
        //mouse click position
        SDL_Point p = { x, y };

        int ipos = 0;
        int c = 0;
        //iterate each group
        for (int g = 0; g < 4; g++) {
            //iterate each bit
            for (int i = 0; i < 4; i++) {
                SDL_Rect rect = { ipos + m_rect.x, m_rect.y, box_size, box_size };

                //checks for mouse point in bit's rectangle...
Read more »