본문으로 건너뛰기
Driver-RTL Co-simulation · 5/8

SystemC TLM 분석 — Transaction-Level Modeling으로 빠른 검증

· Hawk · 8분 읽기

cycle-accurate cosim은 RTL의 진실을 보여 주지만 느립니다. Hz~kHz 수준의 시뮬레이션 속도로는 Linux 한 번 boot시키기가 몇 시간이 걸리죠. driver의 상위 레이어(파일시스템 통합·user-space ioctl·multi-thread workload)를 검증하려면 이보다 천 배 빠른 환경이 필요합니다. 그 자리에 SystemC TLM(Transaction-Level Modeling)이 들어갑니다.

이 장은 SystemC와 TLM 2.0의 핵심 어휘, virtual platform이라는 개념, 그리고 cosim 환경에서 RTL 영역과 TLM 영역을 섞는 mixed-abstraction 패턴을 다룹니다.

#어떤 문제를 푸는가

Driver 개발에서 다음 검증 시나리오는 cycle-accurate cosim으로 풀기 어렵습니다.

  • Boot sequence — kernel boot + driver probe + module init 시퀀스
  • Multi-user/thread workload — 여러 task가 동시에 같은 디바이스 사용
  • End-to-end pipeline — application → user library → ioctl → driver → device
  • Long-running test — 24시간 stability, memory leak 검출

cycle-accurate에서는 Linux 한 번 boot에 수 시간~수일입니다. TLM은 transaction을 단위로 모델링해 같은 환경을 몇 분 안에 돌립니다.

#SystemC란 무엇인가

SystemCC++ class library + simulation kernel입니다. 별도 언어가 아니라, C++ 안에서 #include <systemc.h>로 쓰는 라이브러리. 핵심 어휘:

  • SC_MODULE — Verilog의 module에 대응. C++ 클래스 매크로.
  • SC_THREAD/SC_METHOD — 모듈 내 process. SC_THREAD는 시간 진행 가능, SC_METHOD는 0-time.
  • sc_signal<T> — 두 모듈을 잇는 신호. wire에 대응.
  • sc_clock — 클락 발생기.
  • sc_event — 명시적 wait/notify.
  • sc_time — 시간 단위(SC_NS, SC_PS 등).

작은 module 하나:

#include <systemc.h>
SC_MODULE(blink) {
sc_in<bool> clk;
sc_out<bool> led;
SC_CTOR(blink) {
SC_METHOD(toggle);
sensitive << clk.pos();
}
void toggle() {
led.write(!led.read());
}
};

SystemC 자체는 cycle-accurate에도 쓰일 수 있지만, 그 진가는 TLM과 결합할 때 나옵니다.

#TLM 2.0 — Transaction-Level Modeling

TLM 2.0(IEEE 1666)은 SystemC 위에 bus transaction을 추상화한 표준 API입니다. 핵심은 signal 한 토글 한 토글이 아니라 read/write 한 건을 단위로 모델링한다는 점입니다.

#두 가지 timing 추상

추상의미속도용도
LT (Loosely-Timed)transaction = 즉시 완료, 명목적 time annotation빠름(MHz~GHz 수준)software 검증, boot
AT (Approximately-Timed)request·response phase 분리, latency 모델링중간performance 평가

LT는 기능 정확하되 언제 일어났는가는 명목적입니다. driver가 register를 100개 write하면 100번 호출되지만, 실 시간 진행은 거의 없죠. boot/functional 검증에 충분합니다.

AT는 latency·throughput을 어느 정도 보여 줍니다. 실제 cycle은 아니지만 상대적 지연은 의미가 있습니다. performance modeling에 적합.

#핵심 어휘

#include <tlm.h>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
// Initiator (driver 역할)
SC_MODULE(driver_master) {
tlm_utils::simple_initiator_socket<driver_master> socket;
SC_CTOR(driver_master) : socket("socket") {
SC_THREAD(run);
}
void run();
};
// Target (device 역할)
SC_MODULE(device_target) {
tlm_utils::simple_target_socket<device_target> socket;
SC_CTOR(device_target) : socket("socket") {
socket.register_b_transport(this, &device_target::b_transport);
}
void b_transport(tlm::tlm_generic_payload &trans, sc_time &delay);
};

**tlm_generic_payload**가 transaction 본체입니다.

trans.set_command(tlm::TLM_WRITE_COMMAND);
trans.set_address(0x1000);
trans.set_data_ptr(reinterpret_cast<unsigned char *>(&value));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_byte_enable_ptr(nullptr);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
sc_time delay = SC_ZERO_TIME;
socket->b_transport(trans, delay);
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
SC_REPORT_ERROR("driver", "transaction failed");
}

#blocking vs non-blocking transport

TLM은 두 transport 방식을 제공합니다.

  • b_transport — blocking. 한 호출이 완료될 때까지 반환 안 함. LT에 자연스러움.
  • nb_transport_fw/nb_transport_bw — non-blocking. request·response가 분리, 중간에 BEGIN_REQ/END_REQ/BEGIN_RESP/END_RESP 4-phase로 진행. AT에 자연스러움.

대부분의 driver 검증은 b_transport로 충분합니다. AT가 필요한 시점은 bus contention/QoS를 보거나, NoC interconnect를 모델링할 때입니다.

#Virtual Platform — Linux를 boot시키다

Virtual Platform(VP)이란 CPU + 메모리 + 디바이스가 모두 SystemC/TLM으로 모델링된 환경입니다. ISS(Instruction Set Simulator) 또는 fast-model CPU 위에서 진짜 Linux kernel이 boot됩니다.

SystemC Virtual Platform

CPU 모델은 보통 QEMU의 TCG를 SystemC TLM bridge로 감싸 씁니다. ARM의 Fast Models가 이 패턴의 표준 도구이며, AMD/Intel의 internal VP도 비슷한 구조입니다.

이 환경에서는 driver 검증이 진짜 Linux 위에서 일어납니다. insmod my_driver.ko가 정상적으로 통하고, cat /proc/interrupts로 IRQ를 확인하고, user-space에서 ioctl을 호출할 수 있습니다. cycle-accurate가 아니지만 functional 검증에는 압도적입니다.

#Mixed-abstraction — TLM과 RTL 섞기

핵심 패턴: 디바이스 일부는 RTL로(verilator를 통해), 나머지는 TLM으로 두는 것.

SC_MODULE(my_device_target) {
tlm_utils::simple_target_socket<my_device_target> socket;
Vmy_rtl *rtl_block; // Verilator-generated DUT
SC_CTOR(my_device_target) : socket("socket") {
rtl_block = new Vmy_rtl();
socket.register_b_transport(this, &my_device_target::b_transport);
}
void b_transport(tlm::tlm_generic_payload &trans, sc_time &delay) {
if (is_critical_path_register(trans.get_address())) {
// 중요한 register는 실 RTL을 거침
rtl_block->addr = trans.get_address();
rtl_block->wdata = *reinterpret_cast<uint32_t *>(trans.get_data_ptr());
rtl_block->write_req = 1;
tick_rtl(); // 몇 cycle 진행
} else {
// 나머지는 빠른 functional model
do_functional_write(trans);
}
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
};

이로써 검증하고 싶은 모듈은 cycle-accurate RTL로, 나머지는 빠른 TLM으로 두는 절충이 가능합니다. NPU vendor가 연산 datapath만 RTL로 검증하고 control/memory subsystem은 TLM으로 가는 흐름이 그 예입니다.

#산업 표준 도구

상용·반공개 VP 도구의 큰 그림.

도구제공사특징
Fast ModelsArmCortex-A/M ISS + AMBA TLM. ARM SoC 표준
Synopsys Platform ArchitectSynopsysNoC·power 모델링 강화
QEMU SystemC bridgeXilinx/AMDQEMU TCG를 SystemC initiator로
Imperas riscvOVPsimSynopsysRISC-V ISS + TLM
OSCI ReferenceAccellera표준 reference impl

NPU/accelerator vendor 사이에서 Fast Models + 사내 RTL 조합이 de facto 표준이라 봐도 무리가 없습니다.

#NPU pre-RTL driver development

전형적 시나리오:

  1. 연산 spec 확정 → C reference model 작성.
  2. TLM device skeleton → register map 정의, b_transport에 reference model wiring.
  3. VP에 Linux boot → driver를 진짜 Linux kernel module로 빌드, insmod, ioctl 시험.
  4. RTL 도착 → critical register/datapath만 RTL로 교체, 나머지는 TLM 유지.
  5. End-to-end run → user-space inference app까지.

이 흐름이 RTL 도착 전에 driver의 상위 stack을 완전히 검증해 둡니다. 도착 뒤에는 register encoding/IRQ timing 같은 RTL boundary 버그만 남겨 cosim에서 잡으면 됩니다.

#흔한 함정

  • b_transportdelay — 인자로 받은 sc_time delay증가시킨 후 wait 해야 정상. 안 그러면 progress 0인 무한 호출.
  • DMI(Direct Memory Interface) — RAM 모델에서 빠른 접근을 위한 hint. driver가 DMA로 RAM에 접근할 때 DMI 허용 영역MMIO 영역을 구분해야 함.
  • endianness — TLM의 data_ptr은 host endian. 디바이스 endian이 다르면 byte swap 명시.
  • raceSC_THREAD 두 개가 같은 신호에 동시 접근하면 깨짐. sc_event로 직렬화.

#정리

  • SystemC는 C++ 라이브러리 + simulation kernel. TLM 2.0은 그 위의 transaction-level 표준 API.
  • LT(loosely-timed)는 기능, AT(approximately-timed)는 latency. 대부분 cosim은 LT.
  • 핵심: tlm_generic_payload·b_transport·initiator/target socket.
  • Virtual Platform은 CPU+RAM+디바이스가 모두 SystemC인 환경. 진짜 Linux가 boot되고 driver가 .ko로 로드됨.
  • Mixed-abstraction으로 중요한 영역은 RTL(Verilator), 나머지는 TLM. NPU vendor의 일반적 흐름.
  • 산업 표준: Arm Fast Models·Synopsys Platform Architect·QEMU SystemC bridge.
  • pre-RTL driver dev 5-step: spec → TLM skeleton → VP boot → RTL 교체 → end-to-end.

#다음 장 예고

다음 장은 RTL과 driver 사이의 세부 protocol을 캡슐화하는 BFM(Bus Functional Model)을 다룹니다. AXI/PCIe/AHB BFM이 어떻게 구성되고, protocol assertion·timing checker가 어떻게 testbench에 녹는지.

#관련 항목