ASIC SoC2010. 12. 23. 10:42
Module hierarchy and file organization

Distribution code organization

RTL 코드의 계층 구조는 아래와 같습니다.
사용자 삽입 이미지
기본 계층 구조는 ORPSOC에서 시작합니다. 테스트를 위한 패스는 ORPSOC_FPGA_TOP을 기준으로 시작합니다.
각각의 IP를 연결하는 BUS Connection은 tcop_top이고 나머지는 이름을 기준으로 유추하여 볼 수 있습니다.

testbench의 코드를 보면 탑레벨 module의 이름은  orpsoc 입니다.
그리고 앞서 설명한 l.nop명령어들의 동작을 반영하는 것이 or1200_monitor 모듈입니다.

Verilator model에서는 이러한 기능은 SystemC 모델로 제공됩니다.

이 강의에서 사용되는 모든 파일은 tar  파일로 제공됩니다만,
필요하면 opencore.org 에서 새로 받아서 사용할 수 있습니다. 이 경우에는 필요한 몇개 파일을 수정해야
합니다.

tar 파일은 아래 링크에서 다운 받을 수 있습니다.

http://www.embecosm.com/download/esp5.html

Distribution code organization


tar 파일을 풀면 몇개의 폴더가 보이게 됩니다.
그 구조는 아래와 같습니다.

Top level directory
    - Makefile
        main 프로젝트 파일입니다. verilator를 이용해서 프로젝트를 빌드 할 수 있도록 해 줍니다.
    - Testbench file
        orpsocmain.cpp , orpsocmain.h
        verilator를 위한 테스트 벤치 파일입니다.
        자세한 설명은 다음에 하기로 하고
        여기서는 그냥 이런 파일들이 Top Folder에 있다는 것만 알고 있으면됩니다.

orp_soc
     현재 ORPSoC 버전이 들어가 있습니다.
     이것은 www.opencores.org에서 구할 수 있는것과 같습니다.

local
     orp_soc의 shadow 폴더입니다. local로 수정할 파일을 이곳에 두게 됩니다.
     그리고 PATH변수에 의해서 Search 순서를 지정하여 두었기 때문에 이곳에서 바꾸게 됩니다.

sim
    icarus 시뮬레이터용 스크립트가 들어 있는 폴더입니다.
    *.scr  파일이 이 폴더 입니다.

sysc_modules
    systemc로 작성된 모듈들이 있으며, 이 모듈들은 테스트 벤치를 구성하는 일부 입니다.
    or1200monitorSC와  ResetSC가 들어 있습니다.

verilator-model
    이 폴더에는  verilator에서 사용하는 커맨드 파일과
    verilator model 내부의 시그널을 볼 수 있는 OrpsocAccess  가 있습니다.
    

Original ORPSoC Source code organization


  원래의 orpsoc의 소스 트리 구조는 orp_soc 폴더에서 찾아 볼 수 있습니다.
 
bench
   테스트 벤치 코드입니다.
   서브 디렉토리로 verilog를 가지고 있고 (사실 이것밖에 없습니다.) 이 폴더 내에 ORPSoC를 위한
    Verilog Code를 가지고 있습니다.  
    일단 두개의 헤더 파일을 찾아 볼 수 있습니다.
    bench_defines.v
      `define 들이 들어 있습니다.
    timescale.v
      `timescale에 대한 정의가 있습니다.

doc
   당연히 문서가 모여 있습니다.

rtl
   ORPSoC의 verilog code가 있습니다.

sw
   타겟 소프트웨어 입니다.
   이 코드들은 컴파일 되어서 내부의 Flash memory에 올려져서 운용됩니다.
   utils  폴더에 있는 파일들을 먼저 빌드해야 합니다.
   이 후에 support 파일을 빌드합니다.
   나머진 필요할 때 순서에 상관 없이 빌드하면 됩니다.


Modifications to the ORPSoC source code


local 폴더에는 앞서 설명하대로
원래의 코드를 수정하지 않고 이쪽에서 수정할 수 있도록 해주는 파일을 모아두었습니다.
그리고 PATH 순서를 바꾸어서 이쪽 파일들이 먼저  선택되도록 하였습니다.

(1) bench/verilog/bench_defines.v.
        half clock을 50nS로 정의해서 전체 동작을 10MHz로 되도록 만들어 두었습니다.

원래는 아래와 같이 되어 있지만 local  폴더에서 수정되어 있습니다.
........
//
// OR1200 clock mode
//
`ifdef OR1200_CLMODE_1TO2
`define CLK2_HALFPERIOD 25
`else
`ifdef OR1200_CLMODE_1TO4
Unsuppported
`else                  
`define CLK2_HALFPERIOD 50
`endif
`endif
..........

local 폴더의 bench_defines.v 파일은 아래와 같습니다.

.....
//
// Clock half period for simulation (10MHz)
//
`define BENCH_CLK_HALFPERIOD 50
....



(2) bench/verilog/or1200_monitor.v
   여러차례 설명한 l.nop xxxx 명령어로 내부 정보를 얻어내는 기능을 넣어둔 파일입니다.
   내부에 코드를 보면 쉽게 알 수 있습니다.

(3) bench/verilog/orpsoc_bench.v
    원래의 코드는 bench/verilog/xess_top.v 입니다.
   이 파일은 xilinx용 top 파일입니다.
   이 코드를 wrapping 하여서 ORPSOC용으로 테스트 벤치를 구성한 것이 이 파일 입니다.

(4) rtl/verilog/orpsoc_fpga_top.v
    Top 레벨의 FPGA 모델입니다.
    ORPSoC의 FPGA Top 파일이됩니다.

(5) rtl/verilog/orpsoc_fpga_defines.v
     rtl/verilog/xsv_fpga_defines.v를 다시 정의한 것입니다.
      주요한 내용은 주로
      `define TARGET_VIRTEX
    을 제거하여서 자이링스용 라이브러리를 사용하지 않도록 막아둔 것입니다.

(6) rtl/verilog/or1200_defines.v
    현재 사용하는 형태로 적합하도록 프로세서의 내용을 다시 설정하였습니다.
    주로 캐쉬나 MMU의 사용 여부를 설정하는데 사용합니다.
    그리고 나눗셈기등의 사용 여부를 결정합니다.

(7) rtl/verilog/ssvga/ssvga_fifo.v
         rtl/verilog/ssvga/ssvga_top.v
         rtl/verilog/ssvga/ssvga_dpram_4x8x16.v
         rtl/verilog/ssvga/ssvga_dpram_4x16x16.v
 
     ORPSoC 내에서 사용되는 메모리 블럭등에 대한 정의를 합니다.

Posted by GUNDAM_IM
ASIC SoC2010. 11. 13. 11:22
이번에는 verilator로 실행하여서 vcd파일을 덤프하는 것을 만들어 보겠습니다.

일단 verilator로 c++ 소스 코드를 빌드할 때 이전과 차이점은  --trace 옵션이 붙습니다.

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

위와 같이 실행하여서 Makefile과 c++ 코드를 만들어 냅니다.

testbench격인  dff_sync_reset_main.cpp 역시 수정해야 합니다.

#include <stdlib.h>
#include<iostream>

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

......

int main(int argc, char** argv) {
            Verilated::commandArgs(argc, argv);   // Remember args

            Verilated::traceEverOn(true);
            VerilatedVcdC* tfp = new VerilatedVcdC;


            dff_sync_reset = new Vdff_sync_reset;             // Create instance

            dff_sync_reset->trace (tfp, 99);
            tfp->open ("./simx.vcd");

            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
           .........
                main_time++;            // Time passes...

                tfp->dump (main_time);

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

추가되는 코드는 위와 같습니다.

먼저 헤더 파일로
#include "verilated_vcd_c.h"
을 읽어들이도록 합니다. 이것은 vcd 덤프를 위한 정보가 들어있습니다.

그리고 trace를 on하고
dump파일을 생성합니다.

            Verilated::traceEverOn(true);
            VerilatedVcdC* tfp = new VerilatedVcdC;
...
            dff_sync_reset->trace (tfp, 99);
            tfp->open ("./simx.vcd");

위에서 traceEverOn은 Trace를 항상 한다는 의미이고
dff_sync_reset->trace(tfp,99)는  최상위 모듈에서 밑으로 99개 depth까지 추적한다는 의미입니다.
거의 무한대겠군요

이후에

tfp->open(...)

을 호출하여 파일을 생성합니다.

            while (!Verilated::gotFinish()) {
                if (main_time > 10) {
                    dff_sync_reset->reset = 1;   // Deassert reset
           .........
                main_time++;            // Time passes...

                tfp->dump (main_time);

            }

무한 루프를 돌면서 한 턴이 끝나면 모두 save할 수 있도록 dump함수를 호출합니다.

이후에 시뮬레이션이 끝나면
            tfp->close();
으로 화일을 닫습니다.

이렇게 해서
simx.vcd
라는 파일을 얻어냅니다.
이것을 vcd 파일 볼 수 있는 프로그램인 gtkwave라던가 scansion에서 불러들이면 됩니다.

개인적으로는 맥스러운 GUI라면 Scansion인데 이 scansion에서 약간의 버그가 있습니다.
vcd파일에서 각 행의 시작열에 공백이 있으면 버그로 인식하게 됩니다.
이 프로그램은 잘 안팔려서 그런지 업데이트가 아주 느립니다.

요부분은 수작업으로 바꾸거나
스크립트로 바꾸면 됩니다.


=== Before ===
$version Generated by VerilatedVcd $end
$date Sat Nov 13 11:15:57 2010
 $end
$timescale 1ns $end

 $scope module TOP $end
  $var wire  1 $ clk $end
  $var wire  1 # data $end
  $var wire  1 & q $end
  $var wire  1 % reset $end
  $scope module v $end
   $var wire  1 $ clk $end
   $var wire  1 # data $end
   $var wire  1 & q $end
   $var wire  1 % reset $end
  $upscope $end
 $upscope $end
$enddefinitions $end


=== After ===
$version
   Generated by VerilatedVcd
$end
$date
    Sat Nov 13 10:51:15 2010
$end
$timescale
    1ns
$end

$scope module TOP $end
$var wire  1 $ clk $end
$var wire  1 # data $end
$var wire  1 & q $end
$var wire  1 % reset $end
$scope module v $end
$var wire  1 $ clk $end
$var wire  1 # data $end
$var wire  1 & q $end
$var wire  1 % reset $end
$upscope $end
$upscope $end
$enddefinitions $end
...

위와 같이 첫번째 열들부터 나타나는 공백을 모두 지우고 불러들이면 됩니다.

사용자 삽입 이미지

그리고 일일이 스크립트를 돌리기  귀찮으면verilator 소스 코드를 직접 수정하면 됩니다.
ident에 관한 일이므로 verilator 스타일로 보건데 한군데서 다 처리할 것 같아 뒤져보았습니다.

일단,
verilator source code가 있는 폴더에서 다음 파일을 찾아서 정리합니다.
.
...../verilator-3.804/include/verilated_vcd_c.cpp

이 파일에서 void VerilatedVcd::dumpHeader ()  함수가 헤더를 덤프해주는 함수입니다.
이 함수 내에 있는 printIdent(xxx) 함수 호출에서 xxx 부분을 몽땅 0으로 바꾸어 주면 됩니다.

=== before ===
354 행 :  printIndent(1);
=== after  ===
              printIndent(0);


382행
=== before ===
 printIndent(-1);
=== after ==
 printIndent(0);

392행
=== before ===
 printIndent(1);
=== after ==
 printIndent(0);


407행
=== before ==
printIndent(-1);
=== after ===
printIndent(0);

411행
=== before ====
printIndent(-1);
=== after ===
printIndent(0);

으로 변경합니다.
결론적으로 해당 함수의 printIdent는 모두 0으로 만들어버리면 ident가 VCD 파일에 들어가지 않습니다.
이제 새롭게 컴파일해서 설치하면 앞서의 scansion에서 파일 오픈할 때 일일이 헤더 부분을 수정할 수고를 덜어줍니다. 어차피 VCD파일 내부를 누가 보겠습니까 ?  IDENT가 없다고 상관없겠죠

이제 일일이 스크립트 돌릴 필요 없이 그냥 출력 파일을  scansion 에서 읽어들일 수 있습니다.







Posted by GUNDAM_IM