數字邏輯系統(tǒng)的設計實際上包含兩個相關又獨立的領域:設計與測試。這套書重點是設計,因為老衲對于測試不在行,所謂“藏拙”者也。但是完全不介紹測試也不成:這樣設計出來的代碼不知道對錯了。所以,今晚給大伙兒講點皮毛。
但凡人造系統(tǒng)都是有輸入輸出的,要不然這個系統(tǒng)對設計者或者用戶沒有用場,沒人無聊去設計 ---- 即使是魯布·戈德堡機械 。前面介紹的數字邏輯電路是通過芯片的管腳實現輸入輸出的,無論進出的信號都是數字信號。仿真代碼理論上實在計算機上面運行的,和程序語言類似;所以,仿真部分的輸入輸出也和程序語言類似,是各種計算機的輸入輸出設備,包括文件。
1. 時鐘復位,自己編程
當設計的單元簡單、輸入輸出關系明確的時候,可以由設計者直接設計測試向量完成驗證。這也是大多數資料里面介紹的方法,其中內容不必詳述。比如,你做一個計數器,然后你做一下 reset 和 clock 信號,于是在 reset 不生效之后,輸出就是 1-2-3…了,OK,恭喜啊,你得設計正確。再如,你設計一個加法器,你就需要做不同的加數和被加數的組合,如果得到 0 + 1 = 1,1 + 1 =2, 1 + 2= 3…那么就可以交貨了。
時鐘信號無疑是最重要,但是也是最簡單的信號之一了。50%占空比的時鐘信號的代碼見例 8.19。其他占空比的時鐘稍稍麻煩一些,forever 塊需要兩個時延和兩次賦值。實際上,占空比并不會影響數字邏輯系統(tǒng)的性能,所以盡量用 50%占空比的時鐘就好了。
【例 8.19】時鐘生成部分代碼
…
parameter DELAY;
…
reg clk;
…
begin
//Clock generation
initial
begin
clk = 0;
//Reset
forever
begin
#DELAY clk = !clk;
//Reverse the clock in each 10ns
end
end
…
據說時鐘產生有多種方法的,和“‘回’字的三種寫法”道理一樣。咱們不是孔乙己類似的腐儒,會一種用熟了就好了。
復位信號也不復雜,開機的復位代碼見例 8.20 所示(高電平復位)。其他時刻的復位,就是再外加一個時延的問題,施主們自便。
【例 8.20】開機復位的代碼
…
parameter RESET_PERIOD;
…
reg clk;
…
//Reset operation
initial
begin
reset = 0;
//Reset enable
# RESET_PERIOD reset = 1;
//Counter starts
end
…
2. 外部芯片,討要廠家
當設計了一個對于復雜芯片的接口或者控制器,你就需要外部芯片的行為模型配合你得測試了。舉個例子,你需要設計一個 SDRAM 的控制器,用來控制大容量的 SDRAM 來存儲數據。首先,你會得到一個對應 RAM 的 datasheet(數據手冊),里面會有芯片的電氣特征啊什么的,數字邏輯設計不感興趣的內容。大家需要注意的就是讀寫的時序,還有 SDRAM 的刷新要求(不懂這個?沒關系了,就是一個例子。等到你做的時候,自然就了解了。如果還是不懂,那么等著丟數據吧,別抱怨我沒說過)。這個控制器基本就是一個狀態(tài)機。在設計完之后,需要進行驗證的時候,問題來了:“如何測試這種系統(tǒng)呢?”。豎起耳朵聽著,找供貨商要對應芯片的行為模型,這個可以有的。
事實上,在選擇芯片的時候,有沒有這種模型是很重要的一個指標,必須向采購要求。叫甲方們在吃回扣之余,一定要選擇有行為模型的芯片。要不然,邏輯設計的工作量就是加倍了。而且即使我們按照自己的理解設計了外部芯片的行為,還不能保證我們做的模型是完全正確的。這就陷入了驗證 - 再驗證的死循環(huán)了,命苦啊。
這種驗證最簡單,除了時鐘、復位什么的以外,就需要構建幾個線型變量,把我們的設計和片外芯片鏈接在一起就好了。簡單說,就是實例化外部新片、實例化設計的系統(tǒng)加上連線,三步走。
3. 復雜處理,文件讀取
在數字信號處理類的系統(tǒng)驗證的時候,一般需要算法工程師一起來聯(lián)合工作。例如:通訊里面的發(fā)射機、接收機等。和我們一樣辛勞的算法工程師們,需要給我們提供測試向量。這種向量一般是以文件形式提供的,里面有輸入和輸出數據,一般是十六進制的幾列。大家需要利用文件讀寫函數,讀取輸入(可能也要輸出)數據,輸入需要驗證的系統(tǒng),來考察設計是否正確。
這里主要涉及到了 Verilog 語言的文件操作的系統(tǒng)任務,下面給大伙兒做一個介紹。Verilog 語言里面的文件操作基本是照搬 C 語言里面的,有打開文件、讀文件、寫文件和關閉文件等功能。最后啰嗦一句:全部文件操作都不能綜合。常用任務見表 8.10 所示。
表 8.10 常用文件有關的系統(tǒng)任務
功能 |
格式 |
打開文件 |
integer file_id = $fopen ( " file_name " ); integer file_id = $fopen ( " file_name ", type ); |
關閉文件 |
$fclose (file_id); |
寫文件 |
$fdisplay(file_id , list_of_arguments); $fwrite(file_id , list_of_arguments); $fstrobe(file_id , list_of_arguments); $fmonitor(file_id , list_of_arguments); |
寫數據的格式 |
$swrite(output_reg, list_of_arguments); $sformat(output_reg, format_string, list_of_arguments); |
讀一個字符 |
c = $fgetc ( file_id ); |
讀一行 |
integer code = $fgets ( str, file_id ); |
按照格式讀 |
integer code = $fscanf ( file_id, format, args ); |
讀二進制文件 |
integer code = $fread( myreg, file_id); integer code = $fread( mem, file_id); integer code = $fread( mem, file_id, start); integer code = $fread( mem, file_id, start, count); integer code = $fread( mem, file_id, , count); |
文件位置操作 |
integer pos = $ftell ( fIle_id ); code = $fseek ( file_id, offset, operation ); code = $rewind ( file_id ); |
文件調入內存 |
$readmemb ( " file_name " , memory_name , start_addr , finish_addr ) ; $readmemh ( " file_name " , memory_name , start_addr , finish_addr ) ; |
文件操作狀態(tài) |
integer errno = $ferror ( file_id, str ); |
表 8.11 打開文件中的打開方式
字符串 |
含義 |
字符串 |
含義 |
"r" 或者"rb" |
只讀 |
"w" 或者 "wb" |
調整長度為 0 或者建立新文件,用于寫 |
"a" 或者 "ab" |
讀,打開文件在末尾寫或者新文件,用于寫 |
"r+","r+b"或者 "rb+" |
更新 |
"w+","w+b"或者 "wb+" |
調整長度為 0 或者或者建立新文件,用于寫 |
"a+", "a+b"或者"ab+" |
讀,打開文件或者新建文件,在文件末尾寫 |
寫文件任務中 display、monitor 和 strobe 和顯示任務對應功能類似。
雖然 Verilog 里面基本繼承了有關文件的全部操作,但是一般沒人會聰明到用 Verilog 語言來拷貝一個文件什么的,雖然這個真的可以做到。前面說了,這些任務中最常用的是有打開文件、讀文件、寫文件和關閉文件等功能。
使用 Verilog 語言進行系統(tǒng)仿真或者驗證的時候,最常用的文件處理有兩種。其一是讀取需要輸入系統(tǒng)的或者用于系統(tǒng)輸出對比用的測試向量,在仿真環(huán)境中檢驗系統(tǒng)設計是否正確;還有就是把系統(tǒng)的輸出寫入文件里面,用外面的程序調用來測試性能。
讀取文件中測試向量數據一般使用 ---- 針對二進制數值以 ASCII 碼存儲的文本文件的$readmemb,或者針對十六進制數值以 ASCII 碼存儲的文本文件的$readmemh 。它們針對的文件中數據格式不同,但是基本功能相同。參數中,“file_name”為需要讀的文件名;“memory_name”是數值在 Verilog 代碼中的存儲位置,一般為數組;“start_addr ”和“finish_addr”為開始讀取和結束讀取的位置,可以忽略(此時從頭到尾地讀文件)。
讀取的文本文件中,只允許存在空白符號(空格、換行、tab 或者制表符)、注釋(兩種格式均可)和二進制 / 十六進制數值。
文件中的數據由開始到結束,存儲到以“memory_name”命名的存儲單元從最小標號開始的順序空間中。如果存儲單元對應的區(qū)域不夠存儲全部數據的時候,系統(tǒng)會給出警告。
4. 更加復雜,外部接口
Verilog 語言的基本語法部分,前面已經竹筒倒豆子地交代給施主們了。在目前介紹過的語言體系下,完成上面所說的完全依賴機器進行的測試和驗證,還是有難度的。所以,Verilog 語言標準里面最后面的大約三分之一的章節(jié),都在介紹一種 Verilog 和高級語言(標準里主要指 C 語言)的接口機制 ---- 這個機制就是 PLI。當然靠這里的幾頁紙的介紹,不可能教會大伙兒如何使用這個高級玩意兒。貧道的目的是叫到家知道 PLI 這回事,萬一急需時候不會茫無頭緒。
PLI 提供一種接口,將用戶編寫的 C 或 C++程序連接到 Verilog 仿真器上,實現 Verilog 仿真器的功能擴展和定制。
PLI 接口主要提供以下三種功能。
首先, PLI 接口允許用戶編寫自定義的系統(tǒng)任務與函數。用戶寫出相應的 PLI 程序并連接到仿真器后,就可以在自己寫的代碼中使用這些系統(tǒng)任務與函數了。一旦這些在仿真過程中被調用,仿真器就會找到對應的用戶編寫的 PLI 程序來執(zhí)行,從而實現仿真 器的定制。
其次,PLI 接口還允許用戶在自己的 PLI 程序中與仿真器中實例化的 Verilog 硬件進行交互,比如讀一個信號的值,給一組觸發(fā)器寫值,設置一個單元的時延等。對于 PLI 程序而言,仿真器中的 Verilog 實例完全是透明的。在不改變系統(tǒng)結構的前提下。用戶想對這些硬件做什么 操作都可以。
最后,某些特定的操作需要對仿真過程中一些信號的變化做出響應。雖然我們可以用 always 來監(jiān)控少量信號的變化,但如果需要監(jiān)測大量信號,這種機制并不現實。PLI 接口提供了一種函數回調機制解決這個問題。用戶可以將某個信號掛上一個 PLI 程序中的 C 函數,以后每當該 信號變化,這個 C 函數都會被調用,從而很方便地實現信號監(jiān)測。
除了上面所說的這些機制外,PLI 還能讓用戶控制仿真的過程,比如暫停,退出,往 log 文件里寫信息等。還可以采集仿真過程的數據,比如當前仿真時間等等。實際的 PLI 程序中這些功能同樣少不了。
PLI 的典型應用主要包括:
第一, 實現 Verilog 模型和 C 模型的共同仿真。對于比較復雜的系統(tǒng),開發(fā)者經常需要首先制作一個能夠工作的 C 模型,然后逐模塊地將其改寫為 Verilog。這樣可以實現一個比較安全、漸進的開發(fā)過程。還有一些比較復雜的硬件單元庫,尤其是定制的浮點單元庫,其仿真模型都是 C 模型。這時也必須 使用 PLI 來連接兩種模型。
其次,產生測試激勵,產生驗證矢量或直接進行驗證。這是 PLI 程序最常用也是最主要的功能。比較復雜的系統(tǒng)經常需要根 據上一個激勵的響應決定下一個激勵,這就要求過程控制做得很好。可是,大家用過 Verilog 的都知道,Verilog 的過程控制非常弱,很難在 測試代碼中寫出復雜的程序控制。而 C 在這一點上有絕對的優(yōu)勢。因此,使用 PLI 可以取長補短,實現一個高效的仿真系統(tǒng)。
第三,捕獲仿真過程和結果,并以用戶易于接受的方式輸出。舉一個典型的例子,打波形就是這種應用。
第四,分析仿真過程,計算性能參數。例如功耗分析的實現方式,就是用 PLI 紀錄每個單元的翻轉情況,然后根據翻轉次數計算功耗。
最后, 軟硬件聯(lián)合仿真?,F在,純以硬件方式工作的芯片已經不多了,大量的芯片工作時都需要軟件的參與和控制。離開這些控制軟件進行仿真,工作環(huán)境不真實,可能造 成激勵模式的遺漏。如果不用 PLI,我們就只能用 Verilog 來在測試代碼中模擬軟件控制,但 Verilog 可能根本描述不了復雜的控制。使 用 PLI 連接控制軟件和仿真器,我們就能夠模擬實際的芯片工作環(huán)境和過程。另外還有一個額外的好處:控制軟件本身也能在這個過程中進行調試。
到 1995 年 Verilog 成為 IEEE 標準時,就停止發(fā)展了,而 VPI 從此時開始誕生,到現在也還在演化。IEEE Verilog 工作組的本意是從那以后逐步使用 VPI 替代 PLI 1.0,但這個目標到現在也沒有實現,而且還看不到實現的希望。
在使用上,PLI 和 VPI 各有特點。PLI 的 API 又多又全又亂,而 VPI 的 API 就非常精煉,一個詞,漂亮。常用的 PLI 的函數集中恐怕至少有近百個,寫程序時不查手冊幾乎不可能;而且,很多 API 是重復的。而 VPI 是標準組織制訂出來的,而且融入了相當多的面向思想,因此在精煉方面顯然遠遠超過 PLI。整個 VPI 的函數集才二十來個函數。但是,VPI 并不好 學,因為它的結構遠比 PLI 復雜。VPI 最大的弱點還是仿真器對其支持不好。很多 03 年出的仿真器都還不敢聲稱自己很好地支持 VPI。
電子產品有關的市場早就進入了白熱化的競爭階段,一個效果總會有很多不同的方案來競爭。說老實話,Verilog 語言用于測試和驗證不是十分方便,所以有了 SystemVerilog 語言來占領這個領域。PLI 在 Verilog 語言里面也是很麻煩的部分,對應 SystemVerilog 里面的 DPI(Direct Programming Interface,直接編程接口)就簡單多了。
SystemVerilog 是一種由 Verilog 發(fā)展而來的硬件描述、硬件驗證統(tǒng)一語言,前一部分基本上是 2005 年版 Verilog 的擴展,而后一部分功能驗證特性則是一門面向對象程序設計語言。面向對象特性很好地彌補了傳統(tǒng) Verilog 在芯片驗證領域的缺陷,改善了代碼可重用性,同時可以讓驗證工程師在比寄存器傳輸級更高的抽象級別,以事務而非單個信號作為監(jiān)測對象,這些都大大提高了驗證平臺搭建的效率。
SystemVerilog DPI,是 SystemVerilog 與其他外來編程語言的接口。能夠使用的語言包括 C 語言、C++、SystemC 等。直接編程接口由兩個層次構成:SystemVerilog 層和外來語言層。兩個層次相互分離。對于 SystemVerilog 方面,另一邊使用的編程語言是透明的,但它并不關注這一點。SystemVerilog 和外來語言的編譯器各自并不需要分析另一種語言的代碼。由于不觸及 SystemVerilog 層,因此支持使用不同的語言。不過,目前 SystemVerilog 僅為 C 語言定義了外來語言層。
凡是 PLI 可以做的事情,DPI 都可以做;凡是 PLI 可以應用的場合,DPI 都可以應用。比較而言,DPI 具有很大的優(yōu)勢:它允許用戶調用現有的 C 代碼,而不需要 Verilog 語言 PLI 或者 VPI 接口。它還提供了一種替代的、簡單的方式調用,雖然不能完成全部 PLI 的功能。但是 DPI 實現了最有用的部分。用 C 實現的函數,在可以使用“引入 DPI”聲明后,在 SystemVerilog 代碼中調用。只需在 SystemVerilog 里面簡單聲明,即可使用這些函數作為輸入的任務和函數。
看到前面的說法,很多施主會認為 DPI 比起 PLI 來簡單。這個結論對也不對。如果您老熟悉 SystemVerilog 這門語言,這句話沒錯:原來 PLI 里面幾十行的代碼,在 DPI 里面一般也就只要幾行就完成了。但是,如果貴客還沒學習過 SystemVerilog 語言,那就要重新學習了。而且,對于設計、驗證雙肩挑的工程師而言,這還意味著要在兩種語言之間不停切換。這個大概相當于雙手互博的難度,很考驗功力的。
DPI 還有一個問題就是支持的軟件有限。例如:Windows 平臺下 Modelsim 對 DPI 支持就不好。這個情況也限制了它的推廣。
這正是:
“
凡人總有出錯時,代碼怎能無問題?欲要系統(tǒng)能跑起,仿真驗證是真諦。
測試系統(tǒng)自動機,信號產生不離棄。文件讀寫取數值,外部模塊來聯(lián)系。
”
與非網原創(chuàng)內容,謝絕轉載!
系列匯總: