SystemC FIFO 之模組化經驗談
SystemC 中的 FIFO 在寫中大型的電路的 approximate timing model 相當好用,幾乎可以只用 FIFO 就建構出整個 model。此外,用 FIFO 建構出來的 SystemC module 可以 1-to-1 的轉換成 Verilog module(這篇)。然而,SystemC 裡面有 sc_fifo_in
, sc_fifo_out
, sc_fifo
三者,這篇文章分享了作者的經驗,如何使用這三者,寫出來的 module 會比較好模組化。
在最簡單的情形下,可以只用 sc_fifo
就建構出一個 sc_module
(為了簡化程式碼,沒有寫出 constructor)。
1struct Top: public class sc_module {
2 sc_fifo<int> data_in_;
3 sc_fifo<int> data_middle_;
4 sc_fifo<int> data_out_;
5 void ScThread1() {
6 int count;
7 while (count = data_in_.read())
8 for (int i = 0; i < count; ++i)
9 data_middle_.write(i);
10 }
11 void ScThread2() {
12 int num;
13 while (num = data_middle_.read())
14 data_out_.write(num+1);
15 }
16};
「圖!!!!!!!!!!」
然而這個 Top
有兩個 SystemC threads,如果我們將他們拆分在成兩個 module 的話 (Module1
, Module2
),就出現了一個問題:FIFO 要放在哪裡其實有三個選項:
- 放在
Module1
- 放在
Module2
- 放在
Top
「圖!!!!!!!!!!」
從 SystemC 的設計上來看,應該是 Top
,而這也就是 sc_fifo_in
, sc_fifo_out
存在的原因。他們可以視為指向 sc_fifo
的 pointer,但是 sc_fifo_in
只能允使用讀取資料的功能,sc_fifo_out
只能使用寫入資料的功能。
其對應之程式碼如下:
1struct Module1: public class sc_module {
2 sc_fifo_in<int> data_in_;
3 sc_fifo_out<int> data_out_;
4 void ScThread() {
5 int count;
6 while (count = data_in_.read())
7 for (int i = 0; i < count; ++i)
8 data_out_.write(i);
9 }
10};
11struct Module1: public class sc_module {
12 sc_fifo_in<int> data_in_;
13 sc_fifo_out<int> data_out_;
14 void ScThread() {
15 int num;
16 while (num = data_in_.read())
17 data_out_.write(num+1);
18 }
19};
20struct Top: public class sc_module {
21 sc_fifo<int> data_in_;
22 sc_fifo<int> data_middle_;
23 sc_fifo<int> data_out_;
24 Module1 u_m1_;
25 Module2 u_m2_;
26 // These lines in constructor
27 u_m1_.data_in_ (data_in_ );
28 u_m1_.data_out_(data_middle_);
29 u_m2_.data_in_ (data_middle_);
30 u_m2_.data_out_(data_out_ );
31};
Unittest 中,不需要測試所有 Output Port 時…
然而,在一些錯誤嘗試下,作者覺得放在 Module1
是一個不錯的選擇。更精準的說,作者覺得只使用 sc_fifo_in
跟 sc_fifo
的話可以少寫一點 code。一個很大的原因是 SystemC 中,如果沒有把所有的 FIFO port 接起來,是無法跑模擬的。
這導致了一個問題:當我們要單獨測試每個 module 的正確性時,如果說 Module1
是一個更複雜的 module,有多個 output port,但是我們只想測試其中一個 port 的話,就必須寫額外的很多 FIFO,把所有的 port 都接上才能使用,造成不少麻煩。因此,我才會認為 module 需要提供「可以選擇是否使用 output FIFO」的選擇權。這只需要一點小小的改動,把所有 sc_fifo_out
改成 sc_fifo
,並加上「是否使用 output FIFO」的 flag:
1struct Module1: public class sc_module {
2 sc_fifo_in<int> data_in_;
3 bool data_out_enabled_ = false;
4 sc_fifo<int> data_out_;
5 void ScThread() {
6 int count;
7 while (count = data_in_.read())
8 for (int i = 0; i < count; ++i)
9 if (data_out_enabled)
10 data_out_.write(i);
11 }
12};
用 Accessor 自動開啟 Output Port
一般來說,當有人呼叫 FIFO 的時候,就是這個 FIFO 有被用到的時機。因此,合理的作法可以透過 accessor 來自動決定要不要 enable output FIFO,節省使用者手動修改 enable flag 的需要。
1struct Module1: public class sc_module {
2private:
3 sc_fifo_in<int> data_in_;
4 bool data_out_enabled_ = false;
5 sc_fifo<int> data_out_;
6public:
7 sc_fifo<int>& get_data_out() {
8 data_out_enabled_ = true;
9 return data_out_;
10 }
11};