---
# System prepended metadata

title: SystemC - Intro

---

# 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

### 




