系列文章 : simulation / emulation 學習筆記
這邊嘗試使用 SystemC 去實作一個全加器。
在很久之前,有用 Verilog 寫過了 ( 程式碼 : http://github.com/TommyWu-fdgkhdkgh/simple-mips/blob/main/adder/full_adder.v )
在這邊,嘗試用 SystemC 撰寫一個 cycle-accurate 的全加器 !
git clone git@github.com:TommyWu-fdgkhdkgh/SystemC_example.git
cd SystemC_example/adder
# clone SystemC library 的 source code
# 並 checkout 到 2.3.4
make systemc/clone
# 編譯 SystemC library
# 並將 library 安裝到 systemc-install
make systemc/build
# 編譯 hello_world 範例
make adder/build
# 運行 hello_world 範例
make adder/run
運行完後,會產生 wave.vcd,可以用 gtkwave 觀察一下產生的波形圖!!
https://github.com/TommyWu-fdgkhdkgh/SystemC_example/blob/main/adder/adder.h
實作加法器的邏輯。
SC_CTOR(full_adder) {
SC_METHOD(do_add);
sensitive << a << b << cin;
}
do_add : 加法器的組合邏輯
sensitive : 代表只要 a, b, cin 有任何變動的時候,就會觸發 do_add 這個 SC_METHOD。
https://github.com/TommyWu-fdgkhdkgh/SystemC_example/blob/main/adder/driver.h
使用 SC_THREAD 去產生訊號,產生出的訊號會交給 do_add。
當執行 wait 的時候,SC_THREAD 這個 fiber 會自願把 CPU 的時間交給其他的 SC_THREAD。等到時間推進到 wait 結束的時間,並且執行中的 SC_THREAD 呼叫了 wait ( 這個 SC_THREAD 也可能是自己! ),才會回到該 SC_THREAD 繼續執行。
https://github.com/TommyWu-fdgkhdkgh/SystemC_example/blob/main/adder/monitor.h
每當訊號發生變化的時候,就 print 出訊號的值,方便我們對訊號進行觀察。
https://github.com/TommyWu-fdgkhdkgh/SystemC_example/blob/main/adder/main.cpp
將所有 components 接在一起,並且在執行的過程中錄製波形圖。
SC_THREAD 會產生一個 fiber ( user-mode-thread, coroutine ),每一個 fiber 會有自己的 stack,所以在 fiber 間進行切換時,會需要進行 context switch。
但不同於一般的 process scheduling,fiber 不會去 搶占( preempt ) 別人的 CPU,而是必須執行中 的 fiber 願意 自願地讓出 CPU,其他的 fiber 才有辦法執行。
所以當有一個 fiber 很霸道,一直站著 CPU 的時候,其他的 fiber 就準備餓死了!
而這種機制又被稱為 cooperative multitasking。
當 SC_THREAD 呼叫 wait 的時候,會把執行權限主動讓出來,讓其他事件可以執行。
而假如當一個 SC_THREAD 進入了一個無窮迴圈,而沒有 wait 的時候,其他事件都沒得執行了,就會卡在這一個 SC_THREAD 裡面。
SC_METHOD 不會產生 fiber,所以不會有自己的 stack,也沒辦法進行 context switch,所以也就 沒辦法 wait。當 SC_METHOD 被觸發的時候,就會一口氣的完成。
所以 SC_METHOD 才被拿來模擬 combinational logic 這種不會有任何延遲的電路。
雖然在這一篇的範例 ( full adder ) 實在太簡單了,無法體會到 SystemC 的優勢。
但假如硬體比較複雜,例如有一個硬體行為需要多個 cycle,且需要用到很多 gate 跟 wire 的時候,SystemC or gem5 就能展現價值了。
假如實作得當的話,可以得到跟實際的 RTL 相似的效能數據,並且不用像 RTL 那樣在每個 cycle 去 evaluate 每一個線路的 true & false,只需要在 SC_METHOD 寫下 combinational logic 的行為,因此節省了大量的時間。
於是假如實作的好的話, SystemC or gem5 可以...