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 »