ASIC SoC2010. 11. 13. 10:26
이전에 정리한 글에서 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작업에 해당합니다.








Posted by GUNDAM_IM