# 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
###