System C的模塊和過程

模塊和過程

本節包含一個完整的簡單設計,以演示SystemC中模塊和過程的使用。為了簡單起見,它是非常低的級別-而不是您通常期望的系統級別設計語言中的編碼樣式!

展示的要點是

建立階層

所述sc_signal原始信道

(專用)端口

進程(SC_METHOD,SC_THREAD,SC_CTHREAD)

一個簡單的測試臺

SystemC背景

為什麼要查看模塊和流程?原因是SystemC旨在應付硬件和軟件,並允許對大型系統進行建模。

進程是與其他進程同時運行的一小段代碼。幾乎所有已開發的高級系統級設計(SLD)工具都使用流程網絡的基礎模型。SystemC提供了支持獨立(並行/並行)代碼段網絡構建的過程。

SLD需要處理大型設計。為了解決這個問題,通常使用層次結構。層次結構是通過使用模塊在SystemC中實現的,該模塊可以使用端口鏈接到其他模塊。模塊允許單獨進行一項設計。模塊可以包含進程和其他模塊的實例。

實例設計

System C的模塊和過程

該設計包括一個EXOR門和四個NAND門。同樣,必須注意,這不是典型的設計風格-很好理解。設計看起來像這樣

第一步是對“與非”門建模。NAND門是組合電路;它的輸出純粹是輸入值的函數。它沒有內存,並且不需要時鐘。因此,模型可以使用最簡單的SystemC進程SC_METHOD。

SC_METHOD只是C ++函數。因此,SystemC類庫必須使它們的行為像進程一樣。尤其是

SystemC類庫包含一個仿真內核,這是一段代碼,用於模擬時間的流逝,並在函數的輸入發生更改時調用函數以計算其輸出。

該函數必須聲明為SC_METHOD,並且對其輸入敏感。

這是一個與非門的代碼,位於一個文件nand.h中

#include“ systemc.h”SC_MODULE(nand2)//聲明nand2 sc_module{

sc_in A,B; //輸入信號端口

sc_out F; //輸出信號端口

void do_nand2()//一個C ++函數

{

F.write(!(A.read()&& B.read()));

}

SC_CTOR(nand2)// nand2的構造函數

{

SC_METHOD(do_nand2); //向內核註冊do_nand2

敏感<< A << B; //敏感度列表

}};

SystemC中的層次結構是使用類sc_module創建的。sc_module可以直接使用,也可以使用宏SC_MODULE “隱藏” 。上面的示例SC_MODULE創建了一個名為nand2的sc_module類對象。

接下來是聲明的輸入和輸出端口。通常,使用類sc_port聲明端口。例如,將聲明 使用sc_signal的輸入端口

sc_port ,1> A,B;

但正如您所看到的,這是很多輸入。為了方便起見,還可以創建和使用專用端口。sc_in是sc_signal類的專用端口的示例。

端口可以是任何C ++或SystemC類型-該示例使用內置的C ++類型bool。

接下來,聲明完成工作的函數。輸入和輸出(專用)端口包括方法read()和write(),以允許讀寫端口。讀取A和B,計算NAND函數,然後使用write()方法將結果寫入F。

請注意,由於=運算符和類型轉換運算符已被重載,因此您通常可以不使用read()和write()方法而逃脫。所以你可以寫

F =!(A && B);

但是使用read()和write()是一個好習慣,因為它有助於C ++編譯器消除表達式的歧義。

編寫函數do_nand2()之後,將為sc_module實例nand2提供一個構造函數。SystemC使用宏SC_CTOR提供了一種簡便的方法。構造函數執行以下操作

創建層次結構(在這種情況下為無)

將功能註冊為模擬內核中的進程

也可以在此處初始化需要初始化的任何內容,例如,可以初始化類數據成員。

在上面的示例中,構造函數聲明do_nand2是SC_METHOD,並說端口A和B上的任何事件都必須使內核運行該函數(從而為F計算一個新值)。

層次結構

EXOR門由NAND門的四個副本(或實例)組成。這是通過使用EXOR門構造器連接NAND門實例來實現的。這是EXOR門的代碼

#include“ systemc.h”#include“ nand2.h”SC_MODULE(exor2){

sc_in A,B;

sc_out F;

nand2 n1,n2,n3,n4;

sc_signal S1,S2,S3;

SC_CTOR(exor2):n1(“ N1”),n2(“ N2”),n3(“ N3”),n4(“ N4”)

{

n1.A(A);

n1.B(B);

n1.F(S1);

n2.A(A);

n2.B(S1);

n2.F(S2);

n3.A(S1);

n3.B(B);

n3.F(S3);

n4.A(S2);

n4.B(S3);

n4.F(F);

}};

該開始看起來與NAND門非常相似,但請注意,它包括文件nand2.h。這允許訪問包含與非門的模塊。

創建模塊exor2,並聲明端口。請注意,由於這是層次結構的不同級別,因此允許重複使用名稱A,B 和F。

原始圖顯示了一些“線段”以連接NAND門。這些通過聲明創建 sc_signal小號S1, S2和S3。 sc_signal是帶有模板參數的類,該模板參數指定信號可以保存的數據類型- 在此示例中為bool。sc_signal是基本通道的一個示例,它是SystemC類庫中的內置通道。它的行為類似於VHDL中的信號。

EXOR門的構造函數比NAND門的構造函數複雜,因為它必須具有nand2的四個實例。在端口聲明之後,聲明瞭nand2的四個實例:n1,n2,n3和n4。必須為每個實例賦予標籤。通過使用exor2構造函數上的初始化器列表,將四個標籤“ N1”,“ N2”,“ N3”和“ N4”傳遞給nand2實例的構造函數。

最後,將端口連接起來。如圖所示,這是在構造函數中完成的。

試驗檯

為了測試設計,有一個激勵發生器。這是另一個模塊,與上面的非常相似。唯一重要的一點是,它使用線程(SC_THREAD),這是一種可以掛起的進程。這是stim.h的代碼

#include“ systemc.h”SC_MODULE(刺激){

sc_out <bool> A,B;/<bool>

sc_in <bool> Clk;/<bool>

無效StimGen()

{

A.write(false);

B.write(false);

等待();

A.write(false);

B.write(true);

等待();

A.write(true);

B.write(false);

等待();

A.write(true);

B.write(true);

等待();

sc_stop();

}

SC_CTOR(刺激)

{

SC_THREAD(StimGen);

敏感<< Clk.pos();

}};

請注意對sc_stop()的最終調用,這將使模擬停止。監視代碼看起來非常相似,因此被省略了-它位於mon.h文件中。

這是頂層-位於文件main.cpp中,該文件包含上述所有子模塊

#include“ systemc.h”#include“ stim.h”#include“ exor2.h”#include“ mon.h”int sc_main(int argc,char * argv []){

sc_signal <bool> ASig,BSig,FSig;/<bool>

sc_clock TestClk(“ TestClock”,10,SC_NS,0.5);

刺激Stim1(“ Stimulus”);

Stim1.A(ASig);

Stim1.B(BSig);

Stim1.Clk(TestClk);

exor2 DUT(“ exor2”);

DUT.A(ASig);

DUT.B(BSig);

DUT.F(FSig);

mon Monitor1(“ Monitor”);

Monitor1.A(ASig);

Monitor1.B(BSig);

Monitor1.F(FSig);

Monitor1.Clk(TestClk);

sc_start(); //永遠運行

返回0;}

包含模塊的頭文件,聲明進行連接的頂級信號以及使用sc_clock創建的時鐘;然後每個模塊都被實例化並連接。

此後,調用sc_start()將啟動模擬,並且模擬將永久運行(或者直到遇到刺激模塊中對sc_stop()的調用)。

這是此示例的輸出

時間ABF

0秒0 0 1

10 ns 0 0 0

20 ns 0 1 1

30 ns 1 0 1

40 ns 1 1 0

如果您看一下,您會發現一些很奇怪的東西-時間0的第一行說F為1(真),而A和B為0-這不是一個非常有說服力的EXOR門!到10 ns時,一切都應達到預期。在時間0發生了什麼事?

模擬

SystemC庫包含一個仿真內核。這決定了要運行的進程(軟件線程)。在時間0,所有SC_METHOD和SC_THREAD將以不確定的順序運行,直到它們暫停。然後,當出現時鐘沿時,SC_CTHREAD將運行。

上面的問題是由於多種情況造成的

所述sc_clock語句結果在上升沿在時間0,因此監視器和刺激的過程將運行(在未定義的順序,它不知道其將第一運行)

C ++中的變量並不總是具有定義的初始值(除非將其聲明為靜態)。因此,F持有的數據值恰好是從1開始(真)

所述do_nand2 SC_METHOD運行在時間0,和時間表˚F更新,但˚F是一個信號,它不能立即更新,因此該值1是仍然存在的監視處理運行時。

為了證明是這種情況,可以修改sc_clock語句以延遲時鐘的第一個邊沿,如下所示

sc_clock TestClk(“ TestClock”,10,SC_NS,0.5,1,SC_NS);

最後的1個SC_NS參數指定在第一個時鐘沿出現之前的1 ns延遲。現在時間已經過去,所以F將被更新。這是對應的輸出

時間ABF

1 ns 0 0 0

11 ns 0 0 0

21 ns 0 1 1

31 ns 1 0 1

41 ns 1 1 0

現在您可以看到F總是正確的。

結論

總結了模塊和流程的快速瀏覽。您已經瞭解了了解SystemC仿真內核的併發本質以及sc_signal基本通道的行為的重要性。

您還看到了一些在頂層模塊中實例化底層模塊的基本示例,以及如何使用sc_main。


分享到:


相關文章: