# SystemC - Intro ## Env ### Mac(apple silicon) #### SysC & C++17 ```shell brew install cmake tar -xvf systemc-3.0.2.tar.gz cd systemc-3.0.2 mkdir build && cd build cmake .. \ -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr/local/systemc-3.0.2 make -j8 sudo make install echo 'export SYSTEMC_HOME=/usr/local/systemc-3.0.2' >> ~/.zshrc echo 'export DYLD_LIBRARY_PATH=$SYSTEMC_HOME/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ``` - make ```shell g++ -std=c++17 hello.cpp -I$SYSTEMC_HOME/include \ -L$SYSTEMC_HOME/lib -lsystemc -o hello ``` ### WSL & Linux #### SysC & C++17 ```shell sudo apt update sudo apt install -y build-essential cmake cd ~/Downloads // cd to directory which file systemc-3.0.2.tar.gz in tar -xvf systemc-3.0.2.tar.gz cd systemc-3.0.2 mkdir build cd build cmake .. -DCMAKE_CXX_STANDARD=17 make -j$(nproc) sudo make install /usr/local/include/systemc /usr/local/lib/libsystemc.so ``` #### GTKwave ```shell sudo apt update sudo apt install gtkwave ``` - open simulation reslut ```shell gtkwave RESULT.vcd ``` :::info apple silicon 的 GTKwave 安裝比較複雜,可以上網看 github 別人的討論,這邊就先跳過 ::: ## Intro SystemC = 用 C++ 模擬 digital hardware 的 Library,是一組 C++ class。而為的就是在開發階段讓軟體可以加快跑模擬,不用等到硬體 layout 後才開始測試軟韌體,也因為抽象層級更高,比 Verilog 模擬還要快得多。 它讓你用 C++ 寫: - module - signal - clock - process - wave | SystemC component | C++ 實作 | | ------------ | ----------------------------- | | 模組(module) | `SC_MODULE()` | | 訊號(signal) | `sc_signal<int>` | | 執行緒(process) | `SC_THREAD()` 或 `SC_METHOD()` | | 時間(time) | `sc_time(10, SC_NS)` | | 模擬核心 | `sc_start();` | ### Concurrency systemC 是偽並行,同時只有一個 process 在執行,但會等到所有 processes 都完成後隨 clock 輸出。 ## SystemC modules 最基本的 SystemC module 結構: ```c++ SC_MODULE(MyModule) { // === 1. Ports === sc_in<bool> in; sc_out<bool> out; // === 2. Internal variables === int counter; // === 3. Process declarations === void do_work(); // === 4. Constructor === SC_CTOR(MyModule) { SC_THREAD(do_work); sensitive << in; } }; ``` 一般都是在 .h 中完成 module 的實作,可以另外在 cpp 中定義完整的 Process,然後在 sc_main (=top) 串接。 ### sc_module #### declare `struct module_name : public sc_module {}` = `SC_MODULE(module_name) {}` (this is define marcro) 每个 module 實體應傳入一個 string,通常同對應的 c++ var 名稱: ```c++ my_module m1("m1"); ``` **前面是變數名稱,後面是 SystemC 實例名**。因為SystemC 的模組會形成階層結構(hierarchy),像 Verilog 一樣,建立模擬階層、波形路徑。: ``` top ├── cpu0 └── mem0 ``` 這些 階層式名稱並不是 C++ 自然存在的(因為 C++ class 沒有 hierarchical namespace 這種概念)。 SystemC 需要你給它一個 string 來作為路徑名稱,例如 top.cpu0.alu0。 同時你也可以動態產生多個 instance: ```c++ for (int i = 0; i < 4; i++) { char name[10]; sprintf(name, "core_%d", i); cores[i] = new cpu(name); } ``` :::success SC_MODULE 中所有成員(ports、變數、方法)預設都是 public。 ::: ### Port - sc_in<data_type> - input signal - sc_out<data_type> - output signal - sc_inout<data_type> - 不推薦使用 - sc_signal<data_type> - 像 wire 也可能是 non-blocking 的 decript - sc_time - 宣告時間 - sc_clock - 在模擬中自動產生 clock signal e.g. `sc_in<sc_uint<10>> data_in;` `sc_in<int> data_in;` `sc_in<bool> clk;` `sc_out<bool> valid;` ` sc_time clkPrd(10, SC_NS);` #### sc_clock ```cpp sc_clock( constchar*name_, // unique module name double period_v_, // the time interval between two consecutive transitions from false to true, also equal to the time interval between two consecutive transitions from true to false. Greater than zero, default is 1 nanosecond. sc_time_unit period_tu_, // time unit, used for period double duty_cycle_, // the proportion of the period during which the clock has the value true. Between 0.0 and 1.0, exclusive. Default is 0.5. double start_time_v_, // the absolute time of the first transition of the value of the clock (false to true or true to false). Default is zero. sc_time_unit start_time_tu_, bool posedge_first_ = true ); // if true, the clock is initialized to false, and changes to true at the start time. Vice versa. Default is true. ``` `sc_clock clk("clk", 10, SC_NS);` - 名稱 `"clk"` = "clk" - 週期 `10, SC_NS` = 10 ns result: 0ns: clk=0 5ns: clk=1 10ns: clk=0 15ns: clk=1 ... ### process SystemC 有三種 process: - SC_METHOD — 像 combinational logic - SC_THREAD - 像 sequential logic - SC_CTHREAD #### SC_METHOD ```cpp SC_METHOD(process_name) sensitive << clk.pos(); ``` - 不可使用 wait() - 模擬更快 - 用來寫 combinational (無狀態) #### SC_CTHREAD ```cpp SC_CTHREAD(process_name, clock.pos()); reset_signal_is(start, true); ``` clock-driven sequential logic, - 沒有 sensitivity list - 只會被 clock(與 reset)觸發 - 用來寫 sequential (通常有狀態變化: counter, FSM, register update…) :::info reset_signal_is: SC_CTHREAD 專用的 reset 設定。 async_reset_signal_is / reset_signal_is 都是 SC_CTHREAD 專用的功能 ::: #### SC_THREAD ```cpp SC_THREAD(process_name) sensitive << clk.pos(); ``` - 可用 wait() - 可以用 while(true) - 用來寫 sequential (通常有狀態變化: counter, FSM, register update...) - 同時可以描述「同步邏輯」與「非同步行為」 #### wait() 只能在 SC_THREAD, SC_CTHREAD 使用 - `wait();`: 等待下一個 sensitive event,例如 clk.pos() e.g. ```cpp // SC_THREAD sensitivity SC_THREAD(run); sensitive << clk.pos(); ``` 則 `wait();` == `wait(clk.posedge_event());` - `wait(5, SC_NS);`: 等 5ns - `wait(clk.posedge_event());`: @(posedge clk); e.g. ```cpp SC_MODULE(Counter) { sc_in<bool> clk; sc_out<int> count; void run() { count.write(0); while (true) { wait(); // 等 posedge clk count.write(count.read() + 1); } } SC_CTOR(Counter) { SC_THREAD(run); sensitive << clk.pos(); } }; ``` 等價 verilog ```verilog always @(posedge clk) begin count <= count + 1; end ``` ### constructor + sensitivity list 在 SystemC 模組中: - constructor: 將 **process** 和 **sensitivity list** binding。 - sensitivity list: 決定 process 什麼時候會被觸發(like **always @(...)**) #### constructor - 登記 SC_METHOD / SC_THREAD - 指定 sensitivity(對哪些 signal 觸發) - 初始化變數 e.g. ```cpp #include <systemc> using namespace sc_core; // 1. constructor taking only module name SC_MODULE(MODULE_A) { SC_CTOR(MODULE_A) { //register member function to systemC simulation kernel, to be explained later. SC_METHOD(func_a); // sensitivity list here... } // a member function with no input, no output void func_a() { std::cout << name() << std::endl; } }; SC_MODULE(MODULE_B) { SC_CTOR(MODULE_B) { // register member function SC_METHOD(func_b); // sensitivity list here... } // declare function void func_b(); }; // define function outside class definition void MODULE_B::func_b() { std::cout << this->name() << std::endl; } // 2. constructor taking more arguments SC_MODULE(MODULE_C) { const int i; // explcit constructor SC_CTOR(MODULE_C, unsigned int a = 1) : // Default Argument: a as default input i(a) { SC_METHOD(func_c); // sensitivity list here... } void func_c() { std::cout << name() << ", i = " << i << std::endl; } }; int sc_main(int, char*[]) { MODULE_A module_a("module_a"); MODULE_B module_b("module_b"); MODULE_C module_c("module_c",1); sc_start(); return 0; } ``` **result** ``` module_a module_b module_c i = 1 ``` > Why example 2: 處理 const 變數:在 C++ 中,const 變數必須在初始化列表中賦值,不能在建構函式的大括號 {} 裡面賦值。 效能優化:這種寫法直接在變數建立時就完成初始化,比起在建構函式體內使用 = 賦值更有效率。 #### sensitivity list 前一個 logic 的觸發條件 e.g. ```cpp SC_METHOD(comb); sensitive << in1 << in2; ``` - when in1 or in2, trigger comb. - reset signal 只能有一個 #### SC_HAS_PROCESS(在 3.0.0 後改掉) 放在 construct 中,告訴 compiler 的一個 keyword,提醒他這個 constr 可以有多個 para。 ## SC_MAIN(TOP) ### Output vcd #### sc_trace_file #### sc_trace ### start ## Prefix ###