verilator is, well, I will just paste the wiki one-liner here

Verilator is a free and open-source software tool which converts Verilog to a cycle-accurate behavioral model in C++ or SystemC.

Similar to iverilog, It compiles verilog to a different language but verilator generates C++ not the iverilog-specific commands.

Installation Link to heading

git clone https://github.com/verilator/verilator
autoconf
./configure --prefix=`pwd`/build
make install

Or we can use the pre-built packages. Whatever easier!

Hello World Link to heading

I am using an example shipped with verilator. This is the command to build the top.v and sim_main.cpp and run the compiled executable.

verilator -cc --exe top.v sim_main.cpp
cd obj_dir
make -f Vtop.mk
./Vtop

And the world famous hello world!

Hello World!
- top.v:11: Verilog $finish

For top.v, it doesn’t need much explanation here

module top;
   initial begin
      $display("Hello World!");
      $finish;
   end
endmodule

The verilator runner uses the generated C++ for top module and calls eval() until end of simulation.

#include <verilated.h>
#include "Vtop.h"

int main(int argc, char** argv, char** env) {

    Vtop* top = new Vtop;

    while (!Verilated::gotFinish()) {
        top->eval();
    }

    top->final();
    delete top;

    return 0;
}

Beyond Hello world Link to heading

Now that we got hello world out of the way, Let’s dig deeper into Vtop.cpp and Vtop.h.

  VL_MODULE(Vtop) {
    public:

      Vtop(const char* name="TOP");
      ~Vtop();

      void eval();

VL_MODULE make Vtop inherits VerilatedModule Which probably have common methods called in the Vtop model, I assume.

#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule

Starting with eval (I removed commants and debug messages to keep it short), I will go through _eval_initial_loop because it is short and sweet and good enough to show how initial is evaluated.

 void Vtop::eval() {
     VL_DEBUG_IF(VL_DBG_MSGF("+++++TOP Evaluate Vtop::eval\n"); );
     Vtop__Syms* __restrict vlSymsp = this->__VlSymsp;  // Setup global symbol table
     Vtop* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;

     // Initialize
     if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);

...
...

Vtop::_eval_initial calls Vtop::_initial__TOP__1 and Vtop::_initial__TOP__1 calls methods generated to print `Hello World!'.

void Vtop::_initial__TOP__1(Vtop__Syms* __restrict vlSymsp) {
    VL_DEBUG_IF(VL_DBG_MSGF("+    Vtop::_initial__TOP__1\n"); );
    Vtop* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
    // Body
    // INITIAL at top.v:9
    VL_WRITEF("Hello World!\n");
    VL_FINISH_MT("top.v",11,"");
}

...
...

void Vtop::_eval_initial(Vtop__Syms* __restrict vlSymsp) {
    VL_DEBUG_IF(VL_DBG_MSGF("+    Vtop::_eval_initial\n"); );
    Vtop* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;
    // Body
    vlTOPp->_initial__TOP__1(vlSymsp);
}