이전에 정리한 글에서 tesebench에 해당하는 부분을 정리합니다.
verilator를 거쳐서 빌드한 소스코드에는 다음과 같은 파일들이 생성됩니다.
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
위의 코드에서 중요한 것은 헤더 파일인 Vdff_sync_reset.h 파일입니다.
내용을 보면
#ifndef _Vdff_sync_reset_H_
#define _Vdff_sync_reset_H_
#include "verilated.h"
class Vdff_sync_reset__Syms;
//----------
VL_MODULE(Vdff_sync_reset) {
public:
// CELLS
// Public to allow access to /*verilator_public*/ items;
// otherwise the application code can consider these internals.
// PORTS
// The application code writes and reads these signals to
// propagate new values into/out from the Verilated model.
VL_IN8(clk,0,0);
VL_IN8(data,0,0);
VL_IN8(reset,0,0);
VL_OUT8(q,0,0);
// LOCAL SIGNALS
// Internals; generally not touched by application code
// LOCAL VARIABLES
// Internals; generally not touched by application code
VL_SIG8(__Vclklast__TOP__clk,0,0);
//char __VpadToAlign13[3];
....
코드의 중간에 입출력 신호로 clk,daa,reset,q가 선언되어 있는 것을 볼 수 있습니다.
대략 통밥으로 굴리면 매크로만 보아도 8비트 char 타입으로 선언된것을 알 수 있습니다. ㅋㅋ
전체적으로는 클래스를 선언하고 입출력 포트는 해당 타입에 맞는 변수로 선언하는 것을 알 수 있습니다.
- 원래 C++로 하면 이렇게 밖에 할 수 없죠..
입출력 변수들은 public 에 위치시키고 있습니다.
그러면 이렇게 선언된 입출력 변수들을 main에서 access하기위해서는
class의 public 변수 참조 방식을 그대로 사용합니다.
#include "Vdff_sync_reset.h"
...
Vdff_sync_reset *dff_sync_reset;
...
dff_sync_reset = new Vdff_sync_reset;
....
if (( main_time % 10) == 1) {
dff_sync_reset->clk = 1; // Toggle clock
}
if (( main_time % 10) == 6) {
dff_sync_reset->clk = 0;
}
...
위와 같이 합니다. 일단 header파일을 인쿨루드 한 후에
module의 포인터를 선언하고
new로 해당 모듈을 생성합니다.
나머진 모듈(클래스)의 public값 쓰듯이 작업하면 됩니다.
testbench 격인 C++코드는 아래와 같은 구조로 되어 있습니다.
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
......
cout << "Start Simulation" << endl;
while (!Verilated::gotFinish()) {
........
main_time++; // Time passes...
}
dff_sync_reset->final(); // Done simulating
// // (Though this example doesn't get here)
cout << "End Simulation" << endl;
}
main_time 변수는 verilog에서 $time을 호출할 때 반환되는 변수입니다.
verilog에서 $time을 호출하면 sc_time_stamp를 호출하게 되고 이때 main_time을 반환합니다.
main함수는
초기화 블럭과
무한 루프 블럭으로 나누어집니다.
초기화 블럭은 시스템의 입출력 값을 초기화 시키는 것을 먼저 하고
무한 루프 블럭에서 이리저리 한 작업을 계속 하게 됩니다.
지정된 조건에 부합되면 무한 루프를 빠져나오면 되고요,
만약 Verilog 에서 $finish를 호출하게 되면
Verilated::gotFinish()
에서 true를 돌려주게 되어 루프를 빠져나가게 됩니다.
이후 작업은 finsh작업에 해당합니다.
'ASIC SoC' 카테고리의 다른 글
Verilator로 SoC 플랫폼 시뮬레이션 하기 - High Performance SoC Modeling with Verilator (1) | 2010.12.02 |
---|---|
맥에서 Verilog Simulation 하기 (3) (0) | 2010.11.13 |
맥에서 Verilog Simulation 하기 (0) | 2010.11.13 |
EMACS에 Verilog Mode 설치하고 활용하기 (2) | 2010.10.30 |
사상 최강의 보드 (2) | 2010.04.18 |