본문으로 바로가기

Verilator 를 이용한 function simulation

category SoC 2020. 5. 1. 16:16
반응형

지난 포스터에서 언급한 Icarus Verilog 와 함께 open simulator 중 하나의 Verilator 를 이용하여 시뮬레이션을 진행해 보도록 하겠습니다. 이전에 사용한 코드를 기반으로 Verilator 에 사용할 C++ testbench 를 작성하였으며, 해당 코드는 글 마지막에 다운로드 받을 수 있습니다. 

 

Verilator 는 Verilog 혹은 SytemVerilog 를  C++ 나 SystemC 로 변환하여 실행파일을 만들고 시뮬레이션을  돌리기 때문에 빠르다는 장점이 있습니다. 그 동안 회사의 업무에서 전혀 사용하지 않아 개인적으로는 접할 기회가 많이 없었는데 RISC-V 2018 SoftCPU Contest 에 기본 simulator로 선정되기도 하고, Tesla Hot Chips 2019 에 사용 된 것을 보면 꽤 보편화가 된것 같습니다.

 

1. Verilator 설치 하기 

Verilator 역시 소스를 다운 받고 직접 컴파일을 하여 설치 할수 있지만 Package를 이용하여 손쉽게 설치 할 수 있습니다. 자세한 설치 방법은  Verilator Installation 를 참조 하시기 바랍니다.

 

myskan@TP-P72:~$ sudo apt-get install verilator  
myskan@TP-P72:~$ verilator --V
Verilator 4.028 2020-02-06 rev v4.026-92-g890cecc1

Copyright 2003-2020 by Wilson Snyder.  Verilator is free software; you can
redistribute it and/or modify the Verilator internals under the terms of
either the GNU Lesser General Public License Version 3 or the Perl Artistic
License Version 2.0.

See https://verilator.org for documentation

Summary of configuration:
  Compiled in defaults if not in environment:
    SYSTEMC            =
    SYSTEMC_ARCH       =
    SYSTEMC_INCLUDE    = /usr/include
    SYSTEMC_LIBDIR     = /usr/lib/x86_64-linux-gnu
    VERILATOR_ROOT     = /usr/share/verilator

Environment:
    PERL               =
    SYSTEMC            =
    SYSTEMC_ARCH       =
    SYSTEMC_INCLUDE    =
    SYSTEMC_LIBDIR     =
    VERILATOR_ROOT     =
    VERILATOR_BIN      =
myskan@TP-P72:~$

 

2. Testbench 작성

Verilator 의 testbench는 C++ 혹은 SystemC로 작성이 되어야 하는데 여기서는 C++로 작성하였습니다. 기존의 testbench 이었던 acgen_tb.v 에서 생성하였던 신호들을 acgen_tb.cpp 에서 생성하도록 변경 하였습니다. 라인 49는 해당 신호들의 초기화 부분이며, 라인 57의 while 구문에서 시뮬레이션이 반복적으로 수행하면서 기본 testbench 와 동일하게 입력 신호들이 변경되도록 구성 하였습니다.  

 

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
#include <verilated.h>          // Defines common routines
#include "Vacgen_tb.h"

#include "verilated_vcd_c.h"

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>

Vacgen_tb *uut;               // Instantiation of module
vluint64_t main_time = 0;     // Current simulation time

double sc_time_stamp () {     // Called by $time in Verilog
  return main_time;           // converts to double, to match
}

int main(int argc, char** argv)
{
  int tclk = 0;
  int fin_sim = 0;

  // turn on trace or not?
  bool vcdTrace = true;
  VerilatedVcdC* tfp = NULL;
  
  Verilated::commandArgs(argc, argv); // Remember args
  uut = new Vacgen_tb;                // Create instance
  
  uut->eval();
  
  if (vcdTrace)
  {
    Verilated::traceEverOn(true);
    
    tfp = new VerilatedVcdC;
    uut->trace(tfp, 99);
    
    std::string vcdname = argv[0];
    vcdname += ".vcd";
    std::cout << vcdname << std::endl;
    tfp->open(vcdname.c_str());
  }

  std::cout << "==============================" << std::endl;
  std::cout << "=== Start Sim === " << std::endl;
  std::cout << "==============================" << std::endl;
 
  // Initalziation 
  uut->clk   = 0;
  uut->rstb  = 0;
  uut->sg_en = 0;
  uut->vav   = 0;

  uut->eval();
  
  while ((!Verilated::gotFinish()) && !fin_sim)
  {
    uut->clk = uut->clk ? 0 : 1;  // Toggle clock
    if (uut->clk) { tclk++; }

    if (tclk == 10)             { uut->rstb   = 1; }
    if (tclk == 20)             { uut->vav    = 1; }
    if (tclk == 30)             { uut->sg_en  = 1; }
    if (main_time == 28800000)  { uut->vav    = 0; }
    if (main_time == 28810000)  { uut->vav    = 1; }
    if (main_time == 38810000)  { uut->vav    = 0; }
    if (main_time == 58810000)  { fin_sim     = 1; }

    uut->eval();            // Evaluate model
    
    if (tfp != NULL)
    {
        tfp->dump (main_time);
    }
    
    main_time = main_time + 10; // Time passes...

  }
  
  uut->final();               // Done simulating
  
  std::cout << "==============================" << std::endl;
  std::cout << "=== End Sim === " << std::endl;
  std::cout << "==============================" << std::endl;
  
  if (tfp != NULL)
  {
    tfp->close();
    delete tfp;
  }
  
  delete uut;
  
  return 0;
}

 

3. 컴파일 및 Simulation 하기 

Make 화일을 이용하여 컴파일을 하게 되면 acgen_tb 폴더가 생성이 되고 Vacgen_tb 실행 화일이 생성이 됩니다. 해당 화일을 실행 시켜보면 지난 포스터에서 언급한 Icarus Verilog 와 비교하여 시뮬레이션이 정말 빠른 것을 체감 할 수 있습니다.  

 

myskan@TP-P72:~/Work/verilator/awb/fsim$ make
verilator -Wno-fatal -I. -I../rtl -I./sim_model  --cc acgen_tb.v --trace --exe ../acgen_tb.cpp  -Mdir acgen_tb -CFLAGS "-g -O3"
make -C acgen_tb -f Vacgen_tb.mk
make[1]: Entering directory '/home/myskan/awb/fsim/acgen_tb'
g++  -I.  -MMD -I/usr/share/verilator/include -I/usr/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=1 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow     -g -O3   -c -o acgen_tb.o ../acgen_tb.cpp
g++  -I.  -MMD -I/usr/share/verilator/include -I/usr/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=1 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow     -g -O3   -c -o verilated.o /usr/share/verilator/include/verilated.cpp
g++  -I.  -MMD -I/usr/share/verilator/include -I/usr/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=1 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow     -g -O3   -c -o verilated_vcd_c.o /usr/share/verilator/include/verilated_vcd_c.cpp
/usr/bin/perl /usr/share/verilator/bin/verilator_includer -DVL_INCLUDE_OPT=include Vacgen_tb.cpp > Vacgen_tb__ALLcls.cpp
g++  -I.  -MMD -I/usr/share/verilator/include -I/usr/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=1 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow     -g -O3   -c -o Vacgen_tb__ALLcls.o Vacgen_tb__ALLcls.cpp
/usr/bin/perl /usr/share/verilator/bin/verilator_includer -DVL_INCLUDE_OPT=include Vacgen_tb__Trace.cpp Vacgen_tb__Syms.cpp Vacgen_tb__Trace__Slow.cpp > Vacgen_tb__ALLsup.cpp
g++  -I.  -MMD -I/usr/share/verilator/include -I/usr/share/verilator/include/vltstd -DVM_COVERAGE=0 -DVM_SC=0 -DVM_TRACE=1 -faligned-new -fcf-protection=none -Wno-bool-operation -Wno-sign-compare -Wno-uninitialized -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable -Wno-shadow     -g -O3   -c -o Vacgen_tb__ALLsup.o Vacgen_tb__ALLsup.cpp
ar -cr Vacgen_tb__ALL.a Vacgen_tb__ALLcls.o Vacgen_tb__ALLsup.o
ranlib Vacgen_tb__ALL.a
g++    acgen_tb.o verilated.o verilated_vcd_c.o Vacgen_tb__ALL.a    -o Vacgen_tb -lm -lstdc++
make[1]: Leaving directory '/home/myskan/awb/fsim/acgen_tb'
myskan@TP-P72:~/awb/fsim$ ./acgen_tb/Vacgen_tb
./acgen_tb/Vacgen_tb.vcd
==============================
=== Start Sim ===
==============================
==============================
=== End Sim ===
==============================
myskan@TP-P72:~/awb/fsim$

 

 

4. Waveform 확인

gatewave 를 이용하여 waveform을 분석 할 수 있습니다. 

 

myskan@TP-P72:~/Work/verilator/awb/fsim/acgen_tb$ gtkwave Vacgen_tb.vcd & 

 

 

 

5. 작성된 코드 및 Makefile

awb_verilator.zip
1.61MB

 

 

반응형