맥을 가진자의 숙명으로 그런 저런 불편함을 감수하면서 살아가고 있는 중에
몇일전에 날라온 메일을 보다가 발견한것이 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로 덤프하는 것을 추가해보도록 하겠습니다.