[베릴로그 RTL 예제] 탁구 게임기 -7편: 에뮬레이션 검증-
목차:
1. RTL 베릴로그로 "탁구대" 그리기
2. 그래픽 LCD 구동 칩의 시뮬레이션 모델
3. "탁구대"의 그래픽 테스트 벤치
4. 움직이는 탁구공
5. GLCD의 버스 기능 모델
6. 탁구대, 움직이는 공 그리고 탁구채
7. 코-에뮬레이션(Co-Emulation) 검증
7-1. 테스트벤치 재사용 코-에뮬레이션
7-2. "내 칩" 에뮬레이션 검증 키트
7-3. 에뮬레이터 작동 모드
a. 싸이클 상세(CA, Cycle Accurate) 모드
b. 전송수준(TL, Transaction Level) 모드
c. 시스템 응용(SA, System Application) 모드
7-4. 실습 및 과제
a. 싸이클 상세(CA) 모드
b. 전송수준(TL) 모드
c. 시스템 응용(SA) 모드
d. 과제
----------------------------------------------------------------------------------------------------------------
오픈-소스 반도체 설계 도구가 설치된 "내 칩 디자인 킷"의 WSL 가상 디스크 이미지 [링크]
----------------------------------------------------------------------------------------------------------------
7-1. 테스트벤치 재사용 코-에뮬레이션
베릴로그는 하드웨어를 묘사하려는 목적을 가진 컴퓨팅 언어다. 컴퓨팅 언어로 디지털 회로가 하게될 행위를 인간이 읽고 쓰기에 용이한 문장으로 하드웨어를 문서화 한다. 인간의 사고체계에 근접한 표현 일 수록 "추상화 수준(abstraction level)이 높다". 디지털 요소(각종 게이트를 표현한 그림, 심볼)을 동원한 전통적인 회로도를 보려면 디지털 회로의 상당한 전문지식을 필요로 한다. 이에 비해 생활 단어들과 단순 대수식을 사용하는 컴퓨팅 언어의 문장들은 친근하면서 매우 복합적인 표현이 가능하다. 회로도에 비하면 컴퓨팅 언어는 매우 추상성이 높다. 그림 혹은 사진에서 받는 인상을 대하소설에 담긴 서사와 비교할 수 없는 것과 같다.
간결하며 문법 적용이 매우 엄격한 컴퓨팅 언어로 작성된 문장은 소프트웨어 도구를 통하여 디지털 반도체 회로로 변환할 수 있다. 인간이 작성한 문서를 제조(또는 실행) 가능한 형식으로 변환해 주는 소프트웨어를 컴파일러(compiler)라고 한다. 컴퓨팅 언어로 작성된 문서를 디지털 하드웨어로 변환해 주는 자동화 도구가 합성기(synthesizer)다. 컴퓨팅 언어로서 베릴로그는 매우 다양한 기능을 가지고 넓은 추상화 수준을 수용하지만 하드웨어로 변환 가능한 수준은 그중 일부분이다. 이 수준을 합성 가능한 수준 또는 RTL(Register Transfer Level)이라 한다.
하드웨어를 기술한 문서로부터 변환된 회로가 원하는 대로 작동하는지 확인할 방법은 만들어 보는 것이다. 설계의 과정은 "묘사"와 "확인(검증)" 그리고 "고침"의 수없는 반복이다. 그때 마다 매번 하드웨어를 제작하려면 비용도 문제지만 제작에 시간소요가 엄청나다. 이를 극복하기 위한 방안으로 실물 없이 가상으로 하드웨어를 모사하는 '시뮬레이션'을 수행한다. 소프트웨어로서 시뮬레이터는 내부 오류로부터 자유롭지 않으며 실제 하드웨어에서 일어나는 물리적인 현상(특히 병렬로 발생하는)을 정확히 재현하지 못한다. 더구나 예정된 절차를 기술한 테스트벤치로는 실제 환경에서 벌어지는 예외적인 사건들을 검증하기 쉽지 않다. 앞서 대화형 테스트벤치를 작성 했었지만 하드웨어의 물리적 반응을 검증하기에 충분치 않다.
에뮬레이션은 하드웨어 설계를 직접 물리적인 하드웨어에서 검증한다. 재 프로그램 가능한 반도체를 쓰면 합성을 통해 얻은 디지털 회로를 하드웨어로 제작하는 수고를 덜 수 있다. 이 반도체를 FPGA (Field-Programmable Gate Array)라 한다. FPGA에는 디지털 회로의 기본 기능 요소(게이트와 플립플롭)들을 미리 깔아두었다. 배선만 재구성하여 특정 디지털 회로를 완성할 수 있다. FPGA에 구현한 디지털 회로를 시험하기 위해 주변회로를 꾸미는 대신 시뮬레이션에 사용했던 대화형 테스트 벤치를 그대로 재사용(Testbench Re-Use)한다. 코-에뮬레이션(Co-Emulation)은 시뮬레이션 소프트웨어에서 작동하는 테스트벤치를 FPGA에 구현된 하드웨어에 물려 시험하는 검증기법이다.
7-2. "내 칩" 에뮬레이션 검증 키트
아래 그림은 "내 칩" 에뮬레이션 검증 키트[링크]의 구성을 보여준다. "내 칩"을 설계하고 검증하며 테스트까지 수행할 수 있는 반도체 설계실을 내 책상위에 차릴 수 있다(MyChip-on-MyDesk).

"내 칩" 에뮬레이션 검증 키트[링크]
에뮬레이터가 작동하는 원리는 기본적으로 컴퓨팅 시스템에 장착되는 주변장치와 같다. 주변장치(하드웨어)를 무작정 연결할 수 없다. 미리 마련된 장치 연결 규칙에 따라야 한다. 이 규칙은 하드웨어와 소프트웨어로 구성되었다. 하드웨어 규칙은 버스 인터페이스(Bus Interface Protocol), 소프트웨어 규격은 운영체제의 구동 프로그램(Device Driver)이다. 응용 프로그램은 구동 프로그램을 경유하여 버스에 장착된 하드웨어와 통신 할 수 있다.
"내 칩 에뮬레이션 검증 키트"를 컴퓨팅 시스템의 관점에서 보면 USB 버스에 연결된 주변장치다. "내 칩"이 주변 장치이며 "테스트벤치"가 이 장치의 응용 프로그램이다. 이 둘을 연결할 버스 규격은 USB 다.
USB는 매우 광범위한 기능의 주변장치를 수용할 수 있는데 직렬 통신 장치 규격(CDC, Communication Device Class)도 그중 하나다. USB 규격의 하드웨어와 구동 소프트웨어를 직접 만들려면 엄청난 비용이 든다. 검증된 상용 칩들을 활용하여 통신을 맏기도록 한다. 라즈베리 파이 피코(Raspberry Pi PICO) 보드가 테스트벤치와 USB를 통해 통신하면서 "내 칩(My Chip)" 사이를 중계하는 역활을 한다.
"내 칩"의 입출력은 고정되어 있지 않고 설계한 내용에 따라 다르다. 칩을 설계 하는 중에 수시로 변경된다. 따라서 "내 칩"과 인터페이스는 유연해야 한다. 피코의 펌웨어(FW, Firm-Ware)로 유연성을 갖도록 했다. 피코의 USB 포트와 펌웨어를 모델링 인터페이스(MI, Modeling-Interface)라 한다.
"내 칩"의 하드웨어 입출력에 대한 유연성은 FPGA를 통해 확보한다. "내 칩"에 인터페이스 포장기(Wrapper)를 씌워 피코의 입출력 포트와 연결한다. 이 포장기와 통신 프로토콜을 트랜잭터(TRANS, Transactor)라 한다. 내 칩 에뮬레이션 키트는 입력과 출력 각각 64핀의 설계를 수용할 수 있다.
설계마다 다르고 개발중에 수시로 변경되는 "내 칩"의 입출력에 대응하여 모델링 인터페이스와 트랜잭터를 수정해 주어야 하는 번거로움이 있다. 검증에서 발견된 오류가 설계 결함인지 도구의 결함인지 판단하는 것 역시 중대한 관리요소다. 수많은 사용자를 가진 소프트웨어 도구에 비하면 "인-하우스(In-House)" 검증 도구의 신뢰도를 확보하기 어렵다. 번거로움은 설계자의 나태함을 낳고 결함을 지나칠 염려가 커진다. 따라서 에뮬레이션에 적용되는 각 부분별 요소마다 표준화가 이뤄져야 한다. SCE-MI[링크] 는 이에 대한 기본 개념을 설명한다. "내 칩 에뮬레이션 검증 키트"는 하드웨어와 함께 표준화된 인터페이스를 제공한다.
7-3. 에뮬레이터 작동 모드
입출력과 클럭을 다루는 주체에 따라 세가지 모드로 작동한다.
a. 싸이클 상세(Cycle Accurate) 모드
- 클럭 소스: 테스트벤치(소프트웨어 모델)
- 장점: 테스트벤치 재사용, 기능 시뮬레이션과 동일한 테스트벤치에서 입력 및 출력 신호 처리
- 단점: 느린 속도
- 용도: RTL 검증, 칩 테스트
"MyChip Co-Emulator" "Work Station"
+-------+ +------+ +----------------+
| TRANS | | MI | | Testbench |
+--------+ | | | +-----+ +--------+
| DUT |Wrap | |I/F FW| |Proxy| |GLCD |
| <-> <=> <==USB===> <-----> (SDL2) |
| | | | PSCE | (UART) | | +--------+
| | | | API | | | |
| clk_dut<-------....------------------sc_clock |
+--------+ | +------+ +-----+ |
| | | |
+-------+ +----------------+
|<----FPGA---->|<-PICO->| |<--SystemC/C++-->|
(Hardware) (Software)
Hardware
- DUT: pong_SbS.v
- TRANS: pons_SbS_wrapper.v, pong_SbS_wrapper.tcl
- MI: Epong_SbS.ino, PSCE_API.h
Software
- Proxy: Epong_SbS.h
- Testbench: sc_pong_SbS_TB.h
USB-CDC
- UART: 115200bps
CA 모드에서 DUT의 외형과 동작은 베릴로그 pong_SbS.v 에서 변환된 크래스 Vpong_SbS와 완전히 동일하다. 따라서 테스트벤치는 재사용된다. 테스트벤치 소프트웨어에서 에뮬레이션 하드웨어의 싸개(wrapper) 또는 대행자(proxy) 크래스 Epong_SbS를 사례화 한다.
//
// Filename: simulation/sc_pong_SbS_TB.h
//
#ifndef _SC_PONG_SBS_TB_H_
#define _SC_PONG_SBS_TB_H_
#include <systemc.h>
...
#ifdef EMULATED_CO_SIM
#include "Epong_SbS.h" // Wrapper/Proxy Class
#else
#include "Vpong_SbS.h" // Verilated Class
#endif
#include "sc_glcd128x64_TLM.h"
SC_MODULE(sc_pong_SbS_TB)
{
sc_clock clk;
sc_signal<bool> reset;
sc_signal<bool> pixel;
sc_signal<sc_uint<7> > x_pos;
sc_signal<sc_uint<6> > y_pos;
sc_signal<bool> p_tick;
sc_signal<bool> busy;
sc_signal<bool> up;
sc_signal<bool> down;
#ifdef EMULATED_CO_SIM
Epong_SbS* u_pong_SbS;
#else
Vpong_SbS* u_pong_SbS;
#endif
......
SC_CTOR(sc_pong_SbS_TB):clk("clk",100,SC_NS,0.5,0.0,SC_NS,false)
{
SC_THREAD(Test_Gen);
sensitive << clk;
// Instantiate DUT --------------------------------
#ifdef EMULATED_CO_SIM
u_pong_SbS = new Epong_SbS("u_pong_SbS");
#else
u_pong_SbS = new Vpong_SbS("u_pong_SbS");
#endif
u_pong_SbS->clk(clk);
u_pong_SbS->reset(reset);
u_pong_SbS->x_pos(x_pos);
u_pong_SbS->y_pos(y_pos);
u_pong_SbS->pixel(pixel);
u_pong_SbS->p_tick(p_tick);
u_pong_SbS->busy(busy);
u_pong_SbS->up(up);
u_pong_SbS->down(down);
......
}
};
#endif
에뮬레이션 하드웨어와 통신하는 대행자(proxy) 크래스는 다음과 같다. FPGA에 구현된 DUT를 감싸서 (wrapper) 외형적으로 동일한 모습을 띄도록 한다.
//
//Filename: emulation/Epong_SbS.h
//
#ifndef _Epong_SbS_H_
#define _Epong_SbS_H_
#include <systemc.h>
// Includes for accessing Arduino via serial port
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
SC_MODULE(Epong_SbS)
{
sc_in<bool> clk;
sc_in<bool> reset;
sc_out<bool> pixel;
sc_out<sc_uint<7> > x_pos;
sc_out<sc_uint<6> > y_pos;
sc_out<bool> p_tick;
sc_in<bool> busy;
sc_in<bool> up;
sc_in<bool> down;
#define N_TX 1
#define N_RX 2
// Emulation Transactor ---------------------------------------------
// DUT's input bitmap
// +-----+-+-+-+-+-+
// [0] |7 6 5|4|3|2|1|0|
// +-----+-+-+-+-+-+
// | | | | |
// | | | | +----clk
// | | | +---reset
// | | +---busy
// | +---up
// +---down
// DUT's output bitmap
// +-+-------------+
// [0] |7|6 5 4 3 2 1 0|
// +-+-------------+
// |
// +---x_pos[6:0]
// +-+-+-------+-+-+
// [1] |7|6|5 4 3 2 1 0|
// +-+-+-----------+
// | | |
// | | +---y_pos[5:0]
// | +---pixel
// +---p_tick
//
inline void _EMU_IO_(void)
{
uint8_t _Rx_, _Tx_, _txPacket_[N_TX], _rxPacket_[N_RX];
_txPacket_[0] = (uint8_t)clk.read()? 0x01:0x00;
_txPacket_[0]|= (uint8_t)reset.read()? 0x02:0x00;
_txPacket_[0]|= (uint8_t)busy.read()? 0x04:0x00;
_txPacket_[0]|= (uint8_t)up.read()? 0x08:0x00;
_txPacket_[0]|= (uint8_t)down.read()? 0x10:0x00;
// Send to Emulator
for (int i=0; i<N_TX; i++)
{
_Tx_ = _txPacket_[i];
while(write(fd, &_Tx_, 1)<=0) usleep(1);
}
// Receive from Emulator
for (int i=0; i<N_RX; i++)
{
while(read(fd, &_Rx_, 1)<=0) usleep(1);
_rxPacket_[i] = _Rx_;
}
x_pos.write((sc_uint<7>)(_rxPacket_[0] & 0x7F));
y_pos.write((sc_uint<6>)(_rxPacket_[1] & 0x3F));
pixel.write((_rxPacket_[1] & 0x40)? true:false);
p_tick.write((_rxPacket_[1] & 0x80)? true:false);
}
void pong_SbS_method(void)
{
_EMU_IO_();
}
void pong_SbS_thread(void)
{
while(true)
{
wait(clk.posedge_event());
_EMU_IO_();
}
}
// Arduino Serial IF
int fd; // Serial port file descriptor
struct termios options; // Serial port setting
sc_trace_file* fp; // VCD file
SC_CTOR(Epong_SbS): clk("clk")
{
SC_THREAD(pong_SbS_thread);
sensitive << clk;
// SC_METHOD(pong_SbS_method);
// sensitive << clk << reset << busy << up << down;
#ifdef VCD_TRACE_TEST_TB
// WAVE ----------------------------------------------------
fp = sc_create_vcd_trace_file("Epong_SbS");
sc_trace(fp, clk, "clk");
......
#endif
// Connecting Arduino DUT ----------------------------------- fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (fd < 0)
{
perror("Error opening serial port");
return;
}
// Set up serial port
options.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
// Apply the settings
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &options);
// Establish Contact
fprintf(stderr, "Request emulator connection......\n");
unsigned char _rx, _tx = 'A';
while(write(fd, &_tx, 1)<=0) usleep(10);
while(read(fd, &_rx, 1)<=0) usleep(10);
if (_rx=='A')
fprintf(stderr, "Connection established...\n");
else
{
fprintf(stderr, "Connection failed...\n");
sc_stop();
}
}
};
#endif
모델링 인터페이스 MI 는 소프트웨어 테스트벤치의 프록시와 통신한다. 전송받은 데이터를 DUT의 입력에 분배하고 출력을 취해 테스트벤치로 보낸다. DUT의 입출력 사양 변경에 수월하게 대응할 수 있도록 API 화 하였다.
/*
Co-Emulation Modeling Interface
Filename: emulation/PSCE-MI/Epong_SbS/Epong_SbS.ino
*/
// Standard Emulator ------------------------------------------------
#include "PSCE_Config.h"
// Co-Emulation interface -------------------------------------------
// Followings are DUT specific defs
#define DELAY_MICROS 1
// Emulation Transactor ---------------------------------------------
// DUT's input bitmap
// +-----+-+-+-+-+-+
// [0] |7 6 5|4|3|2|1|0|
// +-----+-+-+-+-+-+
// | | | | |
// | | | | +----clk
// | | | +---reset
// | | +---busy
// | +---up
// +---down
// DUT's output bitmap
// +-+-------------+
// [0] |7|6 5 4 3 2 1 0|
// +-+-------------+
// |
// +---x_pos[6:0]
// +-+-+-------+-+-+
// [1] |7|6|5 4 3 2 1 0|
// +-+-+-----------+
// | | |
// | | +---y_pos[5:0]
// | +---pixel
// +---p_tick
//
#define N_RX 1 // Number of byte to DUT's inputs
#define N_TX 2 // Number of byte from DUT's output
#define DUT_CLK_BYTE 0
//#define DUT_CLK_BITMAP 0x01 // Clock: METHOD emulation
#define DUT_CLK_BITMAP 0x00 // Clock: THREAD emulation
PSCE psce(DELAY_MICROS); // Std. API
void setup()
{
psce.init(); // BPS=115200
}
void loop()
{
psce.EMU_Blinker(0x80); // Blinker speed
psce.RxPacket(N_RX, DUT_CLK_BYTE, DUT_CLK_BITMAP); // CLK position
psce.TxPacket(N_TX);
}
MI는 표준화된 API를 통해 테스트벤치와 8비트 단위로 통신을 수행한다. 전송받은 입력 데이터를 사전 정의된 비트-맵에 맞춰 DUT에 주고 그 출력을 취해 테스트벤치로 전송한다. 트랜잭터 TRANS는 8비트 단위의 전송 데이터를 DUT의 입력에 맞춰 비트 수준으로 분할하고, DUT의 출력을 MI를 통해 전송 할 수 있도록 8비트 단위로 조립을 수행한다. DUT를 감싸는 베릴로그 트랜잭터 pong_SbS_wrapper.v 는 다음과 같다. 트랜잭터 모듈의 입출력은 MI의 API에 맞춰 표준화 되었다.
//
// Poorman's Standard-Emulator by GoodKook, goodkook@gmail.com
// Co-Emulation warapper for the "pong_SbS"
// Filename: emulation/pong_SbS_wrapper.v
//
module pong_SbS_wrapper(Din_emu, Dout_emu, Addr_emu, load_emu, get_emu, clk_emu, clk_dut);
input [7:0] Din_emu;
output [7:0] Dout_emu;
input [2:0] Addr_emu;
input load_emu, get_emu, clk_emu;
input clk_dut;
// Std. Emulation wrapper: Stimulus & Output capture for DUT
parameter NUM_STIM_ARRAY = 1,
NUM_OUT_ARRAY = 2;
reg [7:0] stimIn[0:NUM_STIM_ARRAY-1];
reg [7:0] vectOut[0:NUM_OUT_ARRAY-1];
reg [7:0] Dout_emu;
// DUT interface: registered input
reg reset;
reg busy;
reg up;
reg down;
// DUT interface: output wire. DUT's output will be captured
wire [6:0] x_pos;
wire [5:0] y_pos;
wire pixel;
wire p_tick;
// Emulation Transactor ---------------------------------------------
// DUT's input bitmap
// +-----+-+-+-+-+-+
// [0] |7 6 5|4|3|2|1|0|
// +-----+-+-+-+-+-+
// | | | | |
// | | | | +----clk
// | | | +---reset
// | | +---busy
// | +---up
// +---down
// DUT's output bitmap
// +-+-------------+
// [0] |7|6 5 4 3 2 1 0|
// +-+-------------+
// |
// +---x_pos[6:0]
// +-+-+-------+-+-+
// [1] |7|6|5 4 3 2 1 0|
// +-+-+-----------+
// | | |
// | | +---y_pos[5:0]
// | +---pixel
// +---p_tick
//
always @(posedge clk_emu)
begin
if (load_emu) // Input stimulus to DUT
begin
reset <= stimIn[0][1];
busy <= stimIn[0][2];
up <= stimIn[0][3];
down <= stimIn[0][4];
end
else if (get_emu) // Capure output from DUT
begin
vectOut[0][6:0] <= x_pos;
vectOut[1][5:0] <= y_pos;
vectOut[1][6] <= pixel;
vectOut[1][7] <= p_tick;
end
else
begin
stimIn[Addr_emu] <= Din_emu;
Dout_emu <= vectOut[Addr_emu];
end
end
// DUT
pong_SbS u_pong_SbS(
.clk(clk_dut), // Controlled Clock
.reset(reset),
.x_pos(x_pos),
.y_pos(y_pos),
.pixel(pixel),
.p_tick(p_tick),
.busy(busy),
.up(up),
.down(down));
endmodule
b. 전송 수준(Transaction Level)
장치 사이의 사이클 수준(또는 RTL)의 상세함이 항상 요구되는 것은 아니다. 사이클 상세 수준은 RTL 에 가까운 하드웨어 검증에 유용하지만 DUT와 테스트벤치 사이에 과도한 트래픽으로 인하여 에뮬레이션 속도를 심각히 저해한다. 전송 수준 설계의 경우 장치에서 처리한 내용을 일괄 전송하므로서 하드웨어와 소프트웨어 사이의 트랜잭션을 줄여 처리속도를 향상 시킬 수 있다.
- 클럭 소스: 하드웨어 클럭(MI 에서 클럭 생성)
- 장점: 테스트벤치 재사용, 대량의 DUT 출력 검증
- 단점: 클럭 상세 RTL 검증 불가
- 응용: DUT의 인터페이스 검증(BFM 수준)
"MyChip Co-Emulator" "Work Station"
+-------+ +--------+ +----------------+
| TRANS | | MI | | Testbench |
+--------+ | | | +-----+ +--------+
| DUT |Wrap | |I/F FW | |Proxy| |GLCD |
| | | |+-----+ | | <-> |(SDL2) |
| | |->|GMem ---......--------------> |
| | | |+-----+ | | | | |
| | <--|H/S | |<==USB==>| | | |
| | | |+-----+ | | | | |
| | |<---...------.....--------------Keyboard|
| | | | PSCE | | | +--------+
| | | | API | | | |
| clk_dut<------PWM | | | |
| | | |(1Mhz) | | | |
+--------+ | +--------+ +-----+ |
| | | |
+-------+ +---------------+
|<----FPGA---->|<--PICO-->| |<--SystemC/C++-->|
(Hardware) (Software)
Hardware
- DUT: pong_SbS.v
- TRANS: pons_SbS_wrapper.v, pong_SbS_wrapper.tcl
- MI: Epong_SbS.ino, PSCE_API.h
Software
- Proxy: Epong_SbS.h
- Testbench: sc_pong_SbS_TB.h, sc_pong_SbS_TB.cpp
sc_glcd128x64_TLM.h, sc_glcd128x64_TLM.cpp
USB-CDC
- UART: 115200bps
c. 시스템 응용 수준(System Application)
- 클럭 소스: 하드웨어 클럭
- 장점: 프로토 타이핑에 준하는 수준
- 용도: 응용 시스템 개발
DUT "탁구 게임기"의 출력을 실제 장치 OLED 에서 시현한다. 라즈베리 파이 피코 보드를 에뮬레이션 MI는 물론 RP2040가 갖추고 있는 듀올 코어를 사용한 시스템 응용 펌웨어 개발에 활용한다.
"MyChip Co-Emulator" "Work Station"
+-------+ +--------+ +----------------+
| TRANS | | MIMI | | Testbench |
+--------+ | | | +-----+ +--------+
| DUT |Wrap | |I/F FW | |Proxy| |GLCD |
| | | |+-----+ | | <-> |(SDL2) |
| | |->|GMem ---......--------------> |
| | | |+-----+ | | | | |
| | <--|H/S | |<==USB==>| | | |
| | | |+-----+ | | | | |
| | |<---...------.....--------------Keyboard|
| | | | PSCE- | | | +--------+
| | | | API | | | |
| clk_dut<------PWM | +-----+ |
| | | |(1Mhz) | | |
+--------+ | +--------+ +----------------+
| | |Core#2 |
+-------+ | | +---------+
| --->|OLED |
| | | Display |
+--------+ | |
+---------+
|<----FPGA---->|<--PICO-->| |<--SystemC/C++-->|
(Hardware) (Software)
Hardware
- DUT: pong_SbS.v
- TRANS: pons_SbS_wrapper.v, pong_SbS_wrapper.tcl
- MI: Epong_SbS.ino, PSCE_API.h
Software
- Proxy: Epong_SbS.h
- Testbench: sc_pong_SbS_TB.h, sc_pong_SbS_TB.cpp
sc_glcd128x64_TLM.h, sc_glcd128x64_TLM.cpp
USB-CDC
- UART: 115200bps
7-4. 실습 및 과제
a. 싸이클 상세(CA) 모드
실습 디렉토리 구성,
$ cd ~/ETRI050_DesignKit/Projects/RTL/pong_SbS/07_Co-Emulation_CA
$ tree
.
├── /pong_SbS
│ └── pong_SbS.v: DUT
├── /emulation: (Hardware)
│ ├── Makefile
│ ├── Epong_SbS.h: Proxy
│ ├── pong_SbS_wrapper.v: Transactor/Wrapper
│ ├── /PSCE-MI: (Poorman's Std. Co-Emulation Modeling Interface)
│ │ ├── Makefile
│ │ └── Epong_SbS
│ │ ├── Epong_SbS.ino: MI-Interface FW
│ │ ├── ......
│ │ ├── PSCE_APIs.cpp
│ │ └── PSCE_APIs.h: Std. Emulation API
│ └── /PSCE-TRANS: (Poorman's Std. Co-Emulation Transactor)
│ └── /Altera_Cmd
│ ├── Makefile
│ └── pong_SbS_wrapper.tcl: Quartus Project
└── /simulation: (Software)
├── Makefile
├── sc_glcd128x64_TLM.cpp
├── sc_glcd128x64_TLM.h
├── sc_main.cpp
├── sc_pong_SbS_TB.cpp
└── sc_pong_SbS_TB.h
에뮬레이션 디렉토리,
$ cd emulation
$ make
Makefile for Co-Emulation of "pong_SbS"
TOP_MODULE=pong_SbS VCD_TRACE=YES|[NO] make build
TOP_MODULE=pong_SbS make run
TOP_MODULE=pong_SbS make clean
make -C PSCE-MI build
make -C PSCE-MI upload
make -C PSCE-TRANS/Altera_Cmd build
make -C PSCE-TRANS/Altera_Cmd gen_rbf
make -C PSCE-TRANS/Altera_Cmd config
CC BY-NC, by GoodKook, goodkook@gmail.com
MI 빌드,
$ make -C PSCE-MI
Arduino-CLI for Emulation Modeling Interface of Epong_SbS
TOP_MODULE=pong_SbS MI=PI_PICO make build
TOP_MODULE=pong_SbS MI=PI_PICO make upload
TOP_MODULE=pong_SbS MI=PI_PICO make clean
CC BY-NC, GoodKook, goodkook@gmail.com
$ make -C PSCE-MI build
make: Entering '.../07_Co-Emulation/emulation/PSCE-MI'
arduino-cli compile --clean \
--fqbn rp2040:rp2040:rpipico Epong_SbS \
--build-path ./Epong_SbS/build \
--build-property compiler.cpp.extra_flags=\
"-DOLED_DISPLAY -DPI_PICO -DUART_BPS=115200 -DCYCLONE_IV"
Sketch uses 71796 bytes (3%) of program storage space. ...
Global variables use 10656 bytes (4%) of dynamic memory, ...
make: Leaving '.../07_Co-Emulation/emulation/PSCE-MI'
라즈베리 파이 피코를 이동식 드라이브로 인식 시킨다. WSL 환경일 경우 자동 마운트 되지 않을 경우 리눅스 파일 시스템에 마운트,
$ sudo mount -t drvfs f: /mnt/f
MI 펌웨어 업로드,
$ make -C PSCE-MI upload
make: Entering '.../07_Co-Emulation/emulation/PSCE-MI'
arduino-cli upload -p /dev/ttyACM0 \
--fqbn rp2040:rp2040:rpipico Epong_SbS \
--input-file ./Epong_SbS/build/Epong_SbS.ino.bin
Resetting /dev/ttyACM0
Converting to uf2, output size: 177664, start address: 0x2000
Scanning for RP2040 devices
Flashing /mnt/f (RPI-RP2)
Wrote 177664 bytes to /mnt/f/NEW.UF2
New upload port: /dev/ttyACM0 (serial)
make: Leaving '.../07_Co-Emulation/emulation/PSCE-MI'
TRANS 빌드,
$ make -C PSCE-TRANS/Altera_Cmd
Quartus for Emulation Transactor of pong_SbS_wrapper
TOP_MODULE=pong_SbS make build
TOP_MODULE=pong_SbS make gen_rbf
make config
CC BY-NC, GoodKook, goodkook@gmail.com
$ make -C PSCE-TRANS/Altera_Cmd build
make: Entering ... '.../emulation/PSCE-TRANS/Altera_Cmd'
quartus_sh -t pong_SbS_wrapper.tcl
.......
$ make -C PSCE-TRANS/Altera_Cmd gen_rbf
JTAG 다운로드 케이블(FT232H HS USB-FIFO IC) 확인,
$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 2e8a:000a Raspberry Pi Pico
Bus 001 Device 003: ID 0403:6014 FT232H Single HS USB-UART/FIFO IC
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root..
WSL 환경에서 USB 장치 공유,
PS > usbipd list
Connected:
BUSID VID:PID DEVICE STATE
... ......
2-9 8087:0a2b 인텔(R) 무선 Bluetooth(R) Not shared
... ... ...
4-1 2e8a:000a USB 직렬 장치(COM3) Shared
4-3 0403:6014 USB Serial Converter Shared
... ... ...
PS > usbipd attach --wsl --busid 4-3
usbipd: info: Using WSL distribution 'Ubuntu-24.04' to attach;
the device will be available in all WSL 2 distributions.
usbipd: info: Detected networking mode 'nat'.
usbipd: info: Using IP address 172.23.80.1 to reach the host.
FPGA 컨피규레이션,
$ make -C PSCE-TRANS/Altera_Cmd config
make: Entering '.../emulation/PSCE-TRANS/Altera_Cmd'
sudo openFPGALoader -c digilent_hs2 output_file.rbf
Jtag frequency : requested 6.00MHz -> real 6.00MHz
Load SRAM: [==================================================]
100.00%
Done
make: Leaving '.../emulation/PSCE-TRANS/Altera_Cmd'
에뮬레이터 빌드,
$ make build
clang++ -I/opt/systemc/include -L/opt/systemc/lib \
-I../emulation \
-I../simulation \
-DEMULATED_CO_SIM \
-lsystemc -lSDL2 \
-osc_pong_SbS_TB \
../simulation/sc_glcd128x64_TLM.cpp \
../simulation/sc_pong_SbS_TB.cpp \
../simulation/sc_main.cpp
에뮬레이터 실행,
$ make run
./sc_pong_SbS_TB
SystemC 3.0.2-Accellera --- Feb 5 2026 16:58:41
Copyright (c) 1996-2025 by all Contributors,
ALL RIGHTS RESERVED
Request emulator connection......
Connection established...
Frame[36]
b. 전송 수준(TL) 모드
실습 디렉토리 구성,
$ cd ~/ETRI050_DesignKit/Projects/RTL/pong_SbS/07_Co-Emulation_TL
$ tree
.
├── /pong_SbS
│ └── pong_SbS.v: DUT
├── /emulation: (Hardware)
│ ├── Makefile
│ ├── Epong_SbS.h: Proxy
│ ├── pong_SbS_wrapper.v: Transactor/Wrapper
│ ├── /PSCE-MI: (Poorman's Std. Co-Emulation Modeling Interface)
│ │ ├── Makefile
│ │ └── Epong_SbS
│ │ ├── Epong_SbS.ino: MI-Interface FW
│ │ ├── ......
│ │ ├── PSCE_APIs.cpp
│ │ └── PSCE_APIs.h: Std. Emulation API
│ └── /PSCE-TRANS: (Poorman's Std. Co-Emulation Transactor)
│ └── /Altera_Cmd
│ ├── Makefile
│ └── pong_SbS_wrapper.tcl: Quartus Project
└── /simulation: (Software)
├── Makefile
├── sc_glcd128x64_TLM.cpp
├── sc_glcd128x64_TLM.h
├── sc_main.cpp
├── sc_pong_SbS_TB.cpp
└── sc_pong_SbS_TB.h
에뮬레이션 디렉토리,
$ cd emulation
MI 빌드 및 펌웨어 업로드,
$ make -C PSCE-MI
$ make -C PSCE-MI build
$ make -C PSCE-MI upload
TRANS 빌드 및 FPGA 컨피규레이션*,
$ make -C PSCE-TRANS/Altera_Cmd
$ make -C PSCE-TRANS/Altera_Cmd build
$ make -C PSCE-TRANS/Altera_Cmd gen_rbf
$ make -C PSCE-TRANS/Altera_Cmd config
[*] DUT와 트랜잭터는 CA 모드 실험 때와 동일 하므로 다시 컨피규레이션 할 필요 없음.
에뮬레이터 실행,
$ make
$ make build
$ make run
CA 모드와 TL 모드 에뮬레이션 속도 비교:
c. 시스템 응용(SA) 모드
실습 디렉토리 구성,
$ cd ~/ETRI050_DesignKit/Projects/RTL/pong_SbS/07_Co-Emulation_SA
$ tree
.
├── /pong_SbS
│ └── pong_SbS.v: DUT
├── /emulation: (Hardware)
│ ├── Makefile
│ ├── Epong_SbS.h: Proxy
│ ├── pong_SbS_wrapper.v: Transactor/Wrapper
│ ├── /PSCE-MI: (Poorman's Std. Co-Emulation Modeling Interface)
│ │ ├── Makefile
│ │ └── Epong_SbS
│ │ ├── Epong_SbS.ino: MI-Interface FW
│ │ ├── ......
│ │ ├── PSCE_APIs.cpp
│ │ └── PSCE_APIs.h: Std. Emulation API
│ └── /PSCE-TRANS: (Poorman's Std. Co-Emulation Transactor)
│ └── /Altera_Cmd
│ ├── Makefile
│ └── pong_SbS_wrapper.tcl: Quartus Project
└── /simulation: (Software)
├── Makefile
├── sc_glcd128x64_TLM.cpp
├── sc_glcd128x64_TLM.h
├── sc_main.cpp
├── sc_pong_SbS_TB.cpp
└── sc_pong_SbS_TB.h
에뮬레이션 디렉토리,
$ cd emulation
MI 빌드 및 펌웨어 업로드,
$ make -C PSCE-MI
$ make -C PSCE-MI build
$ make -C PSCE-MI upload
[*] DUT와 트랜잭터는 CA 모드 실험 때와 동일 하므로 다시 FPGA를 컨피규레이션 할 필요 없음.
에뮬레이터 실행,
$ make
$ make build
$ make run
d. 과제
Accellera's SCE-MI 레퍼런스 매뉴얼[링크]
[과제1] 3장에 나열된 "용어의 정의"를 각자의 생각으로 정리하고 토론해보자.
[과제2] 4장에서 제시하는 "모델"과 "내 칩 에뮬레이션 키트"의 각 수준별 동작 모드를 비교 설명해 보라.
[과제3] 에뮬레이션의 목적으로 "빠른" 검증을 들 수 있다. 하드웨어를 활용한 에뮬레이션에서 속도 저하를 유발하는 요인에 대하여 토론해 보자.
[과제4] 아래의 두 동영상을 본 후 내용을 요약해 보라. 에뮬레이션으로 기대하는 성과에 대하여 토론해보자.
[유튜브]Advantages of SCE-MI based BFMs,https://youtu.be/f9VBsPye1ls
[유튜브]HES-DVM: SCE-MI 2 Emulation,https://youtu.be/7a0UDdVeSAA
-------------------------------------------------------------------------------------------
<8편: "내 칩">











댓글 없음:
댓글 쓰기