How to use Verilator to simulate Verilog code

  1. Prepare Source Code

cnt_ceil.v:

`timescale 1ns / 1ns
module counter (
    input wire clk,
    input wire rst,
    output reg [3:0] cnt
);
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            cnt <= 4'b0;
        end else begin
            cnt <= cnt + 1;
        end
    end
endmodule

cnt_ceil_tb.v

`timescale 1ns / 1ns
module counter_tb;
    // input signals
    reg        clk;
    reg        rst;
    //output signals
    wire [3:0] cnt;
    //instance
    counter x0 (
        .clk(clk),
        .rst(rst),
        .cnt(cnt)
    );

    //inputs
    initial begin  //clk
        forever #1 clk = ~clk;
    end

    initial begin
        #0 clk = 1'b0;
        rst = 1'b1;
        #10 rst = 1'b0;
        #110 $finish;
    end
endmodule
  1. Prepare Verilator Wrapper

sim_main.cpp

#include <verilated.h>
#include <verilated_vcd_c.h>
#include "Vcounter_tb.h" // <-- design changes here

int main(int argc, char** argv){
//构造环境对象,设计对象,波形对象
  VerilatedContext* m_contextp = new VerilatedContext;//环境
  VerilatedVcdC*    m_tracep   = new VerilatedVcdC;//波形
  Vcounter_tb*     m_duvp     = new Vcounter_tb;// <-- design changes here
//波形配置
  m_contextp->traceEverOn(true);//环境里打开波形开关
  m_duvp->trace(m_tracep,3);//深度为3
  m_tracep->open("wave.vcd");//打开要存数据的vcd文件
//写入数据到波形文件里
  while (!m_contextp->gotFinish()){
  //刷新电路状态
    m_duvp->eval();
  //dump数据
    m_tracep->dump(m_contextp->time());
  //增加仿真时间
    m_contextp->timeInc(1);
  }
//记得关闭trace对象以保存文件里的数据
  m_tracep->close();
//释放内存
  delete m_duvp;
  return 0;
}
  1. To Run Simulation

run.sh

verilator -cc -trace --timing counter_tb.v -exe sim_main.cpp # <-- design changes here
cd ./obj_dir
make -f Vcounter_tb.mk # <-- design changes here
./Vcounter_tb
# gtkwave wave.vcd  # use gtkwave to open resultent waveform