ASIC SoC2010. 11. 13. 10:11
맥을 가진자의 숙명으로 그런 저런 불편함을 감수하면서 살아가고 있는 중에
몇일전에 날라온 메일을 보다가 발견한것이 Verilog 시뮬레이터인 Verilator입니다.
VCS라던가 다른 넘들처럼 Cycle Based Simulation 을 진행하여
엄청 빠른것을 자랑하고 있습니다. 흠...
여타 RTL 시뮬레이터 보다 2~30배 빠르다는 둥 하여튼 열심히 이야기하고 있길래 한번 사용해보고 사용법을 정리하였습니다.

Verilator는 엄밀하게는 시뮬레이터가 아니고 Verilog, SystemVerliog 등을 SystemC나 C++등으로 변환시켜주는 툴입니다. 실행파일로 만들어주니까 빠르게 된다는 것을 장점으로 삼고 있습니다.


(1) 설치하기
   
     설치하려면 gmake등이 필요합니다.
     일단 gmake는
 
     su port install gmake

    하고 루트 암호를 넣어주면 잘 설치가 됩니다.
 
    verilator는 아래 사이트에서 다운 받습니다.

   http://www.veripool.org/

   압축을 풀고 다음과 같이 진행합니다.

   ./configure
   gmake
   make test
   sudo make install

   차례로 치면 컴파일과 설정이 됩니다.

   체크는  
   
   verilator --help

   하면 쭈욱 화면에 프린트가 됩니다.

(2) 빠른 부분에 대한 설명

   홈페이지에 보면 아래와 같이 되어 있습니다. VCS대비 1.5배 NC-Verilog 대비 3배 빠르다고 나옵니다.

  • Verilator is 90x faster than Icarus Verilog.
  • Verilator is 10-40x faster than Modelsim SE.
  • Verilator is 3x faster than NC-Verilog.
  • Verilator is 1.5x faster than VCS.
  • VTOC is 4x faster than Verilator.
  • VTOC is 50x faster than NC-Verilog.
  • VCS is 3x faster than Verilator.
  • VCS is 3x faster than NC-Verilog.
  • VCS is 10x faster than NC-Verilog.
  • VCS is the same speed as NC-Verilog.
  • CVer is the same speed as Icarus Verilog.
 
   이렇게 빠른것은 Verilog Simulator가 아니라 Verilog Compiler입니다.
   verilog 코드를 받아 들여서

   C++이나 SystemC, SystemPerl ( 이건 왜나오는건지.. ) 등으로 바꾸는 역활을 합니다.

(3) 사용법에 대해서는....
    
    두단계로 나누어서 작업합니다.
   
    일단 Verilog Code가 완성 된 뒤에
    testbench에 해당하는 main.cpp를 만들어 둡니다.

    (1) C++ 코드로 만들기
         verilator는 시뮬레이터가 아니라 verilog를 c++등으로 바꾸어주는 translator에 가깝습니다.
        
         verilator를 이용해서 C++을 만들어 가는 것이 첫번째 작업입니다.

    (2) C++ 코드 빌드하기
        만들어진 코드는 obj_dir 이라는 폴더에 생깁니다.
        이 폴더에 보면 make파일이 생성되는데 이 make파일을 이용해서 실행 화일을 빌드하는 것이
       두번째 작업입니다.
        
    
  사용될 verilog code는 아래와 같습니다.
  간단한 DFF의 예제입니다.

//-----------------------------------------------------
// Design Name : dff_sync_reset
// File Name   : dff_sync_reset.v
// Function    : D flip-flop sync reset
// Coder       : Deepak Kumar Tala
//-----------------------------------------------------
module dff_sync_reset (
data   , // Data Input
clk    , // Clock Input
reset  , // Reset input
q        // Q output
);
//-----------Input Ports---------------
input data, clk, reset ;

//-----------Output Ports---------------
output q;

//------------Internal Variables--------
reg q;

//-------------Code Starts Here---------
always @ ( posedge clk)
if (~reset) begin
  q <= 1'b0;
end  else begin
  q <= data;
end

endmodule //End Of Module dff_sync_reset

 인터넷에서 구할 수 있는 간단한 dff의 예제입니다.
 
 자세한 설명은 나중에 하고 testbench에 대한 코드는 아래와 같습니다.

#include <verilated.h>          // Defines common routines
#include "Vdff_sync_reset.h"               // From Verilating "top.v"

Vdff_sync_reset *dff_sync_reset;                      // Instantiation of module
unsigned int  main_time = 0;     // Current simulation time

double sc_time_stamp () {       // Called by $time in Verilog
        return main_time;
}
        
int main(int argc, char** argv) {
            Verilated::commandArgs(argc, argv);   // Remember args
            dff_sync_reset = new Vdff_sync_reset;             // Create instance
            
            dff_sync_reset->reset = 0;           // Set some inputs

            cout << "Start Simulation" << endl;  

            while (!Verilated::gotFinish()) {
                if (main_time > 10) {
                    dff_sync_reset->reset = 1;   // Deassert reset
                }
                if (( main_time % 10) == 1) {
                    dff_sync_reset->clk = 1;       // Toggle clock
                }
                if (( main_time % 10) == 6) {
                    dff_sync_reset->clk = 0;
                }
                dff_sync_reset->eval();            // Evaluate model
                //cout << "Output : " << hex << dff_sync_reset->q << endl;       // Read a output
                printf("SIM %010d : (reset) %d, (clk) %d, (data) %d , (q) %d\n", main_time ,                                                    dff_sync_reset->reset ,  
                                                  dff_sync_reset->clk,
                                                  dff_sync_reset->data,
                                                  dff_sync_reset->q );
                main_time++;            // Time passes...
 
                if( main_time == 20) dff_sync_reset->data = 1 ;
                if( main_time == 80) dff_sync_reset->data = 0 ;
                if( main_time > 100) break;

            }
            dff_sync_reset->final();               // Done simulating
            //    // (Though this example doesn't get here)
            cout << "End Simulation" << endl;
}

 verilog code의 파일명은 dff_sync_reset.v 이고
c++ 테스트 벤치 코드는 dff_sync_reset_main.cpp 으로 지정해 둡니다.

그리고 make파일을 만드는 명령은 아래와 같습니다.

verilator --cc  -exe dff_sync_reset_main.cpp  dff_sync_reset.v

--cc 옵션은 c++ 형태로 코드를 만들어 돌라는 의미입니다.
-exe 옵션은 실행 파일로 만들어 돌라는 옵션입니다.
       이 옵션이 없으면 .a 파일인 라이브러리 파일로 만들어집니다.
       이 옵션을 주게 되면 main() 함수를 찾게 되는데 이 것으 없으면 나중에 컴파일 시에 오류가 발생합니다.
       따라서 main()함수가 포함된 .cpp파일을  --exe 옵션 뒤에 명시합니다.

그러면 obj_dir 폴더가 만들어집니다.

GUNDAM-NT:test kevinim$ cd obj_dir/
GUNDAM-NT:obj_dir kevinim$ ls
Vdff_sync_reset.cpp           Vdff_sync_reset.mk            Vdff_sync_reset__Syms.h       Vdff_sync_reset__verFiles.dat
Vdff_sync_reset.h             Vdff_sync_reset__Syms.cpp     Vdff_sync_reset__ver.d        Vdff_sync_reset_classes.mk

해당 되는 폴더에 들어가면 위와 같은 파일들이 있습니다.

나머지 파일은 넘어가고 .mk 파일이 make 파일입니다.

빌드는 아래와 같이 수행합니다.


GUNDAM-NT:obj_dir kevinim$ make -f Vdff_sync_reset.mk
g++  -I. -MMD -I/usr/local/share/verilator/include -I/usr/local/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0        -c -o dff_sync_reset_main.o ../dff_sync_reset_main.cpp
g++  -I. -MMD -I/usr/local/share/verilator/include -I/usr/local/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0        -c -o verilated.o /usr/local/share/verilator/include/verilated.cpp
/opt/local/bin/perl /usr/local/share/verilator/bin/verilator_includer Vdff_sync_reset.cpp > Vdff_sync_reset__ALLcls.cpp
g++  -I. -MMD -I/usr/local/share/verilator/include -I/usr/local/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0        -c -o Vdff_sync_reset__ALLcls.o Vdff_sync_reset__ALLcls.cpp
/opt/local/bin/perl /usr/local/share/verilator/bin/verilator_includer Vdff_sync_reset__Syms.cpp > Vdff_sync_reset__ALLsup.cpp
g++  -I. -MMD -I/usr/local/share/verilator/include -I/usr/local/share/verilator/include/vltstd -DVL_PRINTF=printf -DVM_TRACE=0 -DVM_COVERAGE=0        -c -o Vdff_sync_reset__ALLsup.o Vdff_sync_reset__ALLsup.cpp
      Archiving Vdff_sync_reset__ALL.a ...
ar r Vdff_sync_reset__ALL.a Vdff_sync_reset__ALLcls.o Vdff_sync_reset__ALLsup.o
ar: creating archive Vdff_sync_reset__ALL.a
ranlib Vdff_sync_reset__ALL.a
g++    dff_sync_reset_main.o verilated.o Vdff_sync_reset__ALL.a    -o Vdff_sync_reset -lm -lstdc++  2>&1 | c++filt

  이상 없이 빌드 되었으면 실행하면 됩니다.

GUNDAM-NT:obj_dir kevinim$ ./Vdff_sync_reset
Start Simulation
SIM 0000000000 : (reset) 0, (clk) 0, (data) 0 , (q) 0
SIM 0000000001 : (reset) 0, (clk) 1, (data) 0 , (q) 0
SIM 0000000002 : (reset) 0, (clk) 1, (data) 0 , (q) 0
SIM 0000000003 : (reset) 0, (clk) 1, (data) 0 , (q) 0
SIM 0000000004 : (reset) 0, (clk) 1, (data) 0 , (q) 0
SIM 0000000005 : (reset) 0, (clk) 1, (data) 0 , (q) 0
SIM 0000000006 : (reset) 0, (clk) 0, (data) 0 , (q) 0
....

대충 움직이는 것을 확인해 볼 수 있습니다.

다음번에는 wave로 덤프하는 것을 추가해보도록 하겠습니다.


        

    

Posted by GUNDAM_IM