快速 SystemC 之旅(一)

快速 SystemC 之旅(一)

  • 一、前言背景
  • 二、實驗環境
    • 1. 安裝步驟
    • 2. 驗證安裝
  • 三、RTL 級硬件描述
    • 1. 初看模塊
    • 2. 二輸入與非門


一、前言背景

因項目需求,近期開始開展電子系統級設計(ESL)進行事務級建模(TLM),方案上選擇了 NVIDIA 的開源架構 NVDLA 。
NVDLA
NVDLA 基于 GreenSocs 的 QBOX 框架,也是一種 QEMU 和 SystemC 聯合仿真的解決方案。為學習該開源框架,為深入理解該開源架構,筆者開始系統學習 QEMU 與 SystemC。本文為學習 SystemC 過程中記錄的筆記,一方面便于日后查閱,另一方面也希望對想要學習相關知識的朋友一些幫助。

實驗環境基于 NVDLA 框架適配版本:SystemC 2.3.0,使用 C++11 標準編譯。

二、實驗環境

本節介紹 SystemC 2.3.0 的安裝過程。SystemC 本質上是一個基于 C++ 的建模擴展庫。

1. 安裝步驟

使用以下命令完成 SystemC 2.3.0 的下載、編譯與安裝:

sudo wget -O systemc-2.3.0a.tar.gz http://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.0a.tar.gz
tar -xzvf systemc-2.3.0a.tar.gz
cd systemc-2.3.0a
sudo mkdir -p /usr/local/systemc-2.3.0/
mkdir objdir
cd objdir
../configure --prefix=/usr/local/systemc-2.3.0
make
sudo make install

2. 驗證安裝

安裝完成后,通過編寫一個簡單的 HelloWorld 項目驗證環境配置是否成功。

項目結構

.
├── CMakeLists.txt
└── main.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.12)# === 項目信息 ===
set(CMAKE_PROJECT_NAME demo_systemc)project(${CMAKE_PROJECT_NAME} VERSION 2025.06.13 LANGUAGES C CXX
)# === 構建類型 ===
if(NOT CMAKE_BUILD_TYPE)set(CMAKE_BUILD_TYPE Debug)
endif()# === 編譯配置 ===
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")# === 可執行目標 ===
add_executable(${CMAKE_PROJECT_NAME})# === 打印信息 ===
message(STATUS "[Build type]        :           ${CMAKE_BUILD_TYPE}")
message(STATUS "[C++ Standard]      :           C++${CMAKE_CXX_STANDARD}")
string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE_UPPER)
set(_CXXFLAGS "CMAKE_CXX_FLAGS_${BUILD_TYPE_UPPER}")
message(STATUS "[Compiler Flags]    :           ${${_CXXFLAGS}}")# === SYSTEMC庫 ===
set(SYSTEM_HOME /usr/local/systemc-2.3.0)
set(SYSTEMC_INCLUDE_DIR ${SYSTEM_HOME}/include)
set(SYSTEMC_LIBRARY ${SYSTEM_HOME}/lib-linux64/libsystemc.a)# === 源文件 ===
file(GLOB SOURCES CONFIGURE_DEPENDS${PROJECT_SOURCE_DIR}/*.cpp
)
target_sources(${CMAKE_PROJECT_NAME} PRIVATE${SOURCES}
)# === 頭文件目錄 ===
target_include_directories(${CMAKE_PROJECT_NAME}PRIVATE${SYSTEMC_INCLUDE_DIR}
)# === 宏定義 ===
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE# Add user defined symbols
)# === 鏈接庫 ===
target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE# Add user defined library search paths
)
target_link_libraries(${CMAKE_PROJECT_NAME}PRIVATE${SYSTEMC_LIBRARY}
)

main.cpp:

#include <systemc.h>SC_MODULE(Hello)
{SC_CTOR(Hello){SC_METHOD(run);}void run(){std::cout << "Hello SystemC" << std::endl;}
};int sc_main(int, char **)
{Hello hello("hello");sc_start();return 0;
}

編譯與運行

執行以下命令完成編譯與運行:

cmake . -B build/
cmake --build build/
./build/demo_systemc

運行結果如下,表明 SystemC 配置成功:

SystemC 2.3.0-ASI --- May 20 2025 10:22:36Copyright (c) 1996-2012 by all Contributors,ALL RIGHTS RESERVEDHello SystemC

三、RTL 級硬件描述

SystemC 目前能夠描述包括門級在內所有更高抽象級別的數字邏輯電路和軟件,在后續內容中,我們也主要討論基于 SystemC 的 RTL 級以上的硬件描述。但筆者認為 RTL 級建模是一個非常適合作為入門的 Demo,因此本節將用 RTL 級的實例幫助大家快速了解 SystemC 的基本語法與建模風格。

1. 初看模塊

回顧我們之前編寫的 HelloWorld 示例,這段簡潔的代碼已經體現出 SystemC 作為硬件描述語言的基本特征:其核心建模單元是模塊(SC_MODULE)。

SC_MODULE 是 SystemC 中的基本構建塊,用于表示一個硬件組件。其本質是一個宏定義,展開后為繼承自 sc_core::sc_module 的類(C++ 中,struct 的默認訪問類型是 publicclass 的默認訪問類型是 private):

#define SC_MODULE(user_module_name)                                           \struct user_module_name : ::sc_core::sc_module

模塊的構造函數通常通過 SC_CTOR 宏定義,該宏除了定義構造函數外,還進行了一些類型聲明:

#define SC_CTOR(user_module_name)                                             \typedef user_module_name SC_CURRENT_USER_MODULE;                          \user_module_name( ::sc_core::sc_module_name )

其中的 typedef 語句也可以通過單獨的 SC_HAS_PROCESS 宏顯式聲明:

#define SC_HAS_PROCESS(user_module_name)                                      \typedef user_module_name SC_CURRENT_USER_MODULE

SC_HAS_PROCESS 用于注冊 SystemC 的進程(如 SC_METHODSC_THREADSC_CTHREAD)到仿真內核。
例如,SC_METHOD(func) 用于將 func() 注冊為一個敏感事件觸發的仿真進程。

SystemC 提供了多個宏用于簡化模塊定義過程。根據模塊的構造方式和進程類型,選擇合適的宏可使代碼更簡潔:

  • 如果模塊不包含仿真進程,無需使用 SC_CTORSC_HAS_PROCESS
  • 如果模塊構造函數僅包含 sc_module_name,使用 SC_CTOR 即可。
  • 如果模塊構造函數包含額外參數,應使用 SC_HAS_PROCESS 并自行定義構造函數。

以下是一個帶額外參數和仿真進程的模塊示例:

SC_MODULE(module) {const int i;SC_HAS_PROCESS(module);module(sc_module_name name, int i) : i(i) {SC_METHOD(func);}void func() {cout << name() << ", addithonal input argument" << endl;}
};

這里我們僅做簡要介紹,意在帶大家快速上手,后續章節我們將進一步介紹 SystemC 中模塊、進程與敏感列表等關鍵概念。

2. 二輸入與非門

以一個典型的門級電路——二輸入與非門(NAND2)為例,展示 SystemC 在 RTL 級硬件建模中的基本用法。這可以更好的類比于其他的硬件描述語言,有助于大家快速建立認知。為簡潔起見,一些語法細節將于后續章節展開討論。

Nand2.h:

#ifndef NADN2_H
#define NADN2_H#include <systemc.h>SC_MODULE(Nand2)
{sc_in<bool>  input_a;    sc_in<bool>  input_b;sc_out<bool> output_x;   SC_CTOR(Nand2){SC_METHOD(do_nand);sensitive << input_a << input_b;}
private:void do_nand(){output_x.write(!(input_a.read() && input_b.read()));}
}; /* Nand2 */#endif /* NADN2_H */

該模塊實現了一個二輸入與非門:

  • input_ainput_bbool 型輸入端口。
  • output_xbool 型輸出端口。
  • 成員函數 do_nand() 作為一個 SC_METHOD 進程被注冊,其敏感列表包含 input_ainput_b,即在任一輸入變化時觸發該進程完成對輸出信號 output_x 的求值。

為驗證功能正確性,我們編寫一個測試模塊(Testbench):

tb/TB_Nand2.h:

#ifndef TB_NADN2_H
#define TB_NADN2_H#include <systemc.h>SC_MODULE(TB_Nand2)
{sc_out<bool> output_a;sc_out<bool> output_b;sc_in<bool>  input_x;sc_in_clk    clk;SC_CTOR(TB_Nand2){SC_CTHREAD(gen_input, clk.pos());SC_METHOD(display_variable);sensitive << input_x << output_a << output_b;dont_initialize();}private:void gen_input(){wait();output_a.write(0); output_b.write(0);wait();output_a.write(0); output_b.write(1);wait();output_a.write(1); output_b.write(0);wait();output_a.write(1); output_b.write(1);wait(100);}void display_variable(){cout << "A = " << output_a.read() << " "<< "B = " << output_b.read() << " "<< "X = " << input_x.read() << endl;}}; /* tb_nand2 */#endif /* TB_NADN2_H */

該測試模塊中包含:

  • 一個 SC_CTHREAD 進程 gen_input() 依時鐘 clk.pos() 生成所有輸入組合。
  • 一個 SC_METHOD 進程 display_output() 用于輸出當前輸入與輸出狀態。
  • dont_initialize() 意味著不要在仿真零時刻對 SC_METHOD 類型進程 display_output() 初始化。如果不使用該語句,運行結果將會出現 A = 0 B = 0 X = 0,這將不符合預期。

有了驗證程序,我們就可以在頂層模塊 Top 中將 Nand2TB_Nand2 進行例化,并連接各個信號,以驗證設計的正確性。

Top.h:

#ifndef TOP_H
#define TOP_H#include <systemc.h>
#include "Nand2.h"
#include "tb/TB_Nand2.h"SC_MODULE(Top)
{sc_signal<bool> sig_a, sig_b, sig_x;sc_in_clk clk;Nand2 na2;TB_Nand2 tb_na2;SC_CTOR(Top) : na2("NAND2"),tb_na2("TB_NAND2"){na2.input_a(sig_a);na2.input_b(sig_b);na2.output_x(sig_x);tb_na2.output_a(sig_a);tb_na2.output_b(sig_b);tb_na2.input_x(sig_x);tb_na2.clk(clk);}
}; /* Top */#endif /* TOP_H */

最后我們例化頂層模塊 Top ,并添加波形跟蹤:

main.cpp:

#include "Top.h"int sc_main(int, char **)
{Top top("TOP");sc_clock clk("CLK", 20, SC_NS);top.clk(clk);sc_trace_file *tf = sc_create_vcd_trace_file("Nand2");tf->set_time_unit(1, SC_NS);sc_trace(tf, top.sig_a, "A");sc_trace(tf, top.sig_b, "B");sc_trace(tf, top.sig_x, "X");sc_trace(tf, top.clk, "CLK");sc_start(200, SC_NS);sc_close_vcd_trace_file(tf);return 0;
}

運行結果:

$ ./build/demo_systemc SystemC 2.3.0-ASI --- May 20 2025 10:22:36Copyright (c) 1996-2012 by all Contributors,ALL RIGHTS RESERVEDNote: VCD trace timescale unit is set by user to 1.000000e-09 sec.
A = 0 B = 0 X = 1
A = 0 B = 1 X = 1
A = 1 B = 0 X = 1
A = 1 B = 1 X = 1
A = 1 B = 1 X = 0

輸出驗證了一個 NAND 門的真值功能。

生成的波形文件 Nand2.vcd 可通過以下命令轉換為 Modelsim 支持的格式:

vcd2wlf Nand2.vcd Nand2.wlf

然后在 Modelsim 中加載 Nand2.wlf 文件,即可查看波形:
vsim


Ref

[1] 李揮, 陳曦. SystemC電子系統級設計[M]. 北京: 科學出版社, 2010.
[2] LearnSystemC.com. Learn SystemC[EB/OL]. [2025-06-13]. https://www.learnsystemc.com/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87207.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87207.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決 Golang 下載golang.org/x包失敗方案

在 Golang 開發過程中&#xff0c;不少開發者都遇到過這樣的困擾&#xff1a;當試圖下載golang.org相關包時&#xff0c;會出現訪問失敗的情況&#xff0c;尤其是golang.org/x系列包&#xff0c;作為眾多第三方庫依賴的核心組件&#xff0c;其無法正常下載會嚴重影響項目的開發…

CppCon 2016 學習:BUILDING A MODERN C++ FORGE FOR COMPUTE AND GRAPHICS

你提供的這段文字是關于 設計一個精簡但足夠的 C 框架來驅動 Vulkan 的目標陳述&#xff0c;屬于項目文檔或演講的第一部分 “Goals”。我們可以把它逐項拆解并深入理解&#xff1a; PART (I – I): GOALS&#xff08;目標&#xff09; 總體目標&#xff1a; 構建一個最小但足…

# AI武裝大腦:技術管理者如何用人工智能重構認知與決策系統

作為一位經歷了15年技術管理實戰的老兵&#xff0c;我見過太多項目因為決策失誤、認知局限而陷入泥潭。直到我開始系統性地用AI武裝大腦&#xff0c;才真正找到了突破技術管理瓶頸的利器。今天&#xff0c;我要分享的不是那些泛泛而談的AI概念&#xff0c;而是如何用AI真正提升…

【Linux】UDP與TCP協議

目錄 UDP協議 1.1通信流程 1.2函數 socket bind sendto recvfrom close 1.3實現udp通信 TCP協議 1.1TCP頭部結構 1.2通信流程 三次握手 正式通信 四次揮手 1.3協議特性 面向字節流 可靠傳輸 序列號和確認號 重傳機制 流量控制和擁塞控制 1.4常用函數 s…

gbase8s之MyBatis批量update問題

源代碼 <update id"updateDynamicTableData"><foreach collection"mapList" item"map" separator";">UPDATE ${tableName} SET<foreach collection"map" item"value" index"key" separ…

博圖SCL中WHILE語句的使用詳解及案例

在西門子TIA Portal的SCL&#xff08;結構化控制語言&#xff09;編程中&#xff0c;WHILE循環是處理條件迭代任務的核心工具。它根據布爾表達式動態控制循環執行&#xff0c;適用于不確定循環次數的場景。下面從語法、執行流程、注意事項到實際案例全面解析。 一、WHILE循環基…

簡單聊聊JVM中的幾種垃圾收集算法

3.4、分代收集算法 分代收集算法&#xff0c;可以看成以上內容的延伸。它的實現思路是根據對象的生命周期的不同&#xff0c;將內存劃分為幾塊&#xff0c;比如把堆空間劃分為新生代和老年代&#xff0c;然后根據各塊的特點采用最適當的收集算法。 在新生代中&#xff0c;存在…

依賴已導入,已下載,無法使用問題

明明已經導入依賴&#xff0c;卻無法使用相關注解 于是&#xff0c;我使用 mvn dependency:tree -Dverbose 來查看是否有依賴沖突 [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal on project agileboot…

答題考試系統小程序ThinkPHP+UniApp

ThinkPHPUniapp開發的小程序答題考試系統&#xff0c;支持多種試題類型、多種試題難度、練題、考試、補考模式&#xff0c;提供全部前后臺無加密源代碼&#xff0c;支持私有化部署. 更新日志 V1.7.1修復一些問題 解決考場成績列表重復問題&#xff1b; 解決后臺材料題選擇子…

DHCP服務管理

目錄 DHCP協議 DHCP的優勢 DHCP的分配方式 應用場景 注意 工作流程 何時更新租約 當客戶端重啟后 客戶端類型 DCHP安裝與配置 網絡規劃&#xff1a; 配置 DHCP 作用域 啟動 DHCP 服務 配置路由器 配置路由器網卡 IP 開啟 IP 轉發&#xff08;確保跨網段通信&…

12.UDP客戶端

準備工作 硬件準備&#xff1a;確保你的STM32板子已經正確連接了DP83848網絡芯片。 軟件設置&#xff1a; 安裝好STM32CubeMX用于配置工程。 選擇合適的STM32 HAL庫版本。 如果可能的話&#xff0c;安裝LwIP庫支持TCP/IP協議棧。 步驟 1. 使用STM32CubeMX配置項目 打開…

希爾腳本簡介及常用命令代碼整理

一、Shell 腳本簡介 1. 定義 Shell 是用戶與操作系統內核交互的橋梁&#xff0c;常見類型有 Bash、Zsh、PowerShell 等。Shell 腳本則是一系列 Shell 命令的集合&#xff0c;通常保存為后綴為.sh 的文本文件。 2. 作用 類別描述自動化重復性任務例如定期備份數據、執行定時…

【人工智能下的智算網絡】廣域網優化

一、廣域網絡多路徑I/O寫的并行路徑優化方案 1.1、數學建模 網絡拓撲優化? 1. ?拓撲抽象與路徑發現? ?鄰接矩陣建模?&#xff1a; 將網絡節點抽象為圖頂點 G (V, E)&#xff0c;鏈路帶寬與延遲定義為邊權 w(e)。構造鄰接矩陣 A&#xff0c;其中元素 A_{ij} 表示節點 …

AI測試開發工程師如何用大模型調用工具:從入門到實踐

在軟件測試領域&#xff0c;測試工程師常常面臨測試用例設計復雜、數據生成繁瑣、結果驗證耗時等挑戰。隨著大語言模型&#xff08;LLM&#xff09;的迅速發展&#xff0c;Chat類大模型&#xff08;如GPT、LangChain支持的模型&#xff09;為測試開發提供了一種全新思路——工具…

遷移學習基礎

知識的“跨界復用” 你是一位經驗豐富的廚師&#xff08;源模型&#xff09;&#xff0c;尤其擅長做意大利菜&#xff08;源任務/源域&#xff09;。現在&#xff0c;老板讓你去新開的一家融合餐廳工作&#xff0c;需要你做亞洲菜&#xff08;目標任務/目標域&#xff09;。你…

AI醫生24小時在線:你的健康新‘算法監護人

2025年仲夏&#xff0c;中國醫療AI領域迎來爆發式突破&#xff1a;羅湖醫院集團率先部署"DeepSeek-騰訊混元"雙AI診療系統&#xff0c;實現患者15分鐘極速就診閉環&#xff1b;復旦大學研發的微量血液檢測技術取得重大突破&#xff0c;僅需數滴血樣即可篩查上千種疾病…

Java 中 DataSource-數據源 的基礎介紹

Java 中 DataSource-數據源 的基礎介紹 一、核心概念解析1.1 數據源&#xff08;Data Source&#xff09;1.2 數據庫連接池&#xff08;Connection Pool&#xff09;1.3 二者關系1.4 DataSource 接口 二、DataSource 解決的問題與優勢2.1 DataSource 的作用2.2 傳統方式的局限性…

Vue + Vite 項目部署 Docker 全攻略:原理、路由機制、問題排查與開發代理解析

Vue Vite 項目部署 Docker 全攻略&#xff1a;原理、路由機制、問題排查與開發代理解析 本文面向希望將 Vue 3 Vite 項目部署到生產環境&#xff08;Docker NGINX&#xff09;并深入理解路由行為、構建機制與常見問題排查的開發者。 &#x1f4e6; 一、項目準備 以 Vue 3 …

Vue3 + TypeScript 使用 v-bind() 在 <style scoped> 中動態設置 CSS 樣式值

使用要求&#xff1a; Vue 3.3 <style scoped>&#xff0c;Vue 的 v-bind() 在 CSS 中只支持在 scoped style 或 CSS Modules 中使用v-bind("cssVar") 雙引號包裹響應式變量&#xff0c;變量 cssVar 必須是 Vue 的響應式數據&#xff08;如 ref 或 reactive&…

php列表頭部增加批量操作按鈕,多選訂單數據批量微信退款(含微信支付SDK)

index_search.html data-table-id:表格id data-rule:需要傳輸的列表字段 data-action:控制器方法 <a class="layui-btn layui-btn-primary layui-btn-sm" style=