FPGA 高手養(yǎng)成記-【很重要】Testbenth仿真全過程
掃描二維碼
隨時隨地手機看文章
文章目錄
-
前言
-
測試模塊設計
-
仿真全過程
模塊包含
定義頂層模塊
元件例化
測試激勵的書寫
波形仿真
系統(tǒng)任務仿真 -
總結
01. 前言
在FPGA 高手養(yǎng)成記-Test bench文件結構一覽無余 只是簡單的例舉了常用的 testbench 寫法,在工程應用中基本能夠滿足我們需求, 至于其他更為復雜的 testbench 寫法, 大家可參考其他書籍或資料。
testbench沒有像RTL代碼設計那樣嚴謹,我們可以在符合語法規(guī)則的前提下,隨意編寫我們的測試文件,有些在RTL代碼中不可綜合的語句,我們可以在testbench中實現(xiàn)。大體流程如下:
02. 測試模塊設計
要測試我們的cpu需要ROM和RAM模塊,這就需要我們先做好這兩個模塊
這里定義了一個 1024 x 8 的RAM
再定義一個8192 x 8 的ROM
ROM和RAM都還沒有裝入數(shù)據(jù),等會我們會調(diào)用函數(shù)給他們裝數(shù)據(jù),接下來是地址譯碼器,來控制ROM和RAM的打開與關閉。
各模塊建立好之后我們就開始仿真了。
03.仿真
這次教學我們用的是modelsim SE 10.0 版本進行教學,直接先在quartus II中建一個.v文件將其保存在原來的工程文件目錄中,并命名為cpu_top.v,直接在這里寫測試代碼
下面大家可以來完成cpu 的仿真過程了
3.1,模塊包含
首先,我們需要將我們剛寫好的那幾個模塊包含進去,即CPU模塊,ROM模塊,RAM模塊,地址譯碼器模塊,并寫好時間測量度,見下圖
3.2,定義頂層模塊
由于我們的設計只有兩個輸入,即時鐘模塊和復位模塊,凡是輸入信號在testbench中統(tǒng)一定義成reg型變量,凡是輸出或者雙向輸入輸出信號統(tǒng)一定義成wire型變量,我們的設計只有輸入沒有輸出,故只定義輸入和連線即可
下圖便是我們要組成的測試頂層模塊圖,我們定義的wire型變量,實際就是我們頂層模塊中,模塊模塊與模塊間的連線。而這些連線就是我們cpu的輸出,這樣我們就可以用我們的測試模塊來測試我們的cpu是否能正確工作
3.3. 元件例化
就是將各個模塊連接起來即可,這里就不做太多的說明了,因為以前都寫過很多次了
3.4.測試激勵的書寫
先寫好時鐘產(chǎn)生模塊和復位模塊.并將復位模塊用task任務封裝,這樣我們在測試過程中就可以隨時調(diào)用復位任務進行復位
時鐘為50Mhz,復位時間為20ns
然后,我們再用task封裝我們需要的模塊,我們來想一下,上電后,CPU會從ROM中讀兩個時鐘周期的數(shù)據(jù)是吧,但是我們的ROM現(xiàn)在還是空的,所以我們需要一個任務是往ROM中裝入程序,給ROM中裝數(shù)據(jù)我們可以用系統(tǒng)函數(shù)$readmemb,即打開一個文件,并將其中的數(shù)據(jù)送到我們之前定義的ROM中去
而test1.pro文件是需要我們自己定義的,我們可以在quartusII中再新建一個.v文件,在里面寫上我們自己定義的程序,并將其保存為.pro文件即可,至于寫什么程序,是我們隨便定義的.
裝完ROM和RAM的數(shù)據(jù)之后,按說就可以了進行波形仿真了,因為cpu是自動讀取數(shù)據(jù)的,下面我們先來做第一步仿真,我先把之后的代碼注釋掉,大家先看沒有被注釋掉的代碼
里面都是我們之前封裝好的函數(shù),剛開始進行復位,然后進行第一步測試,之后停止,將其保存之后,并默認為用其打開,打開后見下圖
然后,file——new——library——ok即建好一個庫
點擊左上角的編譯按鈕,將我們之前寫好的所有.v文件全部都編譯進去
看到transcript一欄顯示編譯成功后即可,若沒有transcript一欄,可以選擇菜單中的view——transcript即可,若顯示有紅色錯誤,那就請讀者按照它的要求進行修改代碼,這說明你的代碼有問題,一般是連接問題
3.5,波形仿真
編譯成功后,雙擊cpu_top就可以開始波形仿真了
進入仿真頁面后,我們右擊cpu模塊將其加入至波形
大家先看兩個圖,等會結合這兩個圖給大家細細講解仿真過程


我們先來看第一個過程
上電后,cpu先從ROM中讀回兩個周期的數(shù)據(jù),是從ROM的0地址開始的,再對比我們之前定義好的ROM,數(shù)據(jù)讀取正確,讀回的數(shù)據(jù)的前三位是111,即指令碼JMP,后13位003c為地址碼,JMP指令是將讀回的數(shù)據(jù)作為新的地址碼來讀取相應地址的數(shù)據(jù)。那么,下一步,cpu應該是從ROM的003c地址處讀數(shù)據(jù)才對,再看一下波形
對比波形后可知,cpu正好是從003c處讀取數(shù)據(jù),讀到的數(shù)據(jù)指令碼位111即JMP,地址碼位0006,再到ROM的0006地址處看
這次讀回的指令碼位101,即LDA,也就是說將后13位地址碼對應的RAM中的數(shù)據(jù)讀回,送到累加器中,想一下,這時的RAM應該是打開的,而且雙向輸入輸出口的數(shù)據(jù)總線上應該是來自RAM的8位數(shù)據(jù),由于ROM0006地址處的地址碼為1800是13位的,而RAM的地址是9位的,因此實際上我們從RAM中讀回的數(shù)據(jù)是從RAM的0地址讀回的,即我們之前給RAM寫好的0000_0000,再看一下波形
正如我們所想的一樣,數(shù)據(jù)總線上是0000_0000,RAM是打開的,地址為1800
就這樣,讀者可以自己再試一下,看看我們的cpu是不是按照我們之前給他的程序運行的,在這里我就不再給大家一一介紹了
雖然波形仿真很直觀,但是看久了就會令人眼花繚亂,尤其是數(shù)據(jù)很多的時候,我們只能看其中一部分,不能講所有數(shù)據(jù)看完整,這時候我們單單是用波形來仿真就遠遠不夠了,下面介紹用系統(tǒng)任務仿真的過程
3.6,系統(tǒng)任務仿真
再回到我們的代碼,注釋掉了一些代碼吧,我們把那些代碼給加上,以其中一個過程為例
假設讀回的指令碼位101,即LDA,如果我在fentch_8的高電平期間且在cpu輸出地址為奇數(shù)的時候記錄一下此時的時間、指令、地址、目的地址、數(shù)據(jù)的話就可以不用看波形,讓電腦來幫助我們來分析了,因此作如下處理
這里我延時60ns,是因為第一次記錄的時候數(shù)據(jù)總線上還沒有數(shù)據(jù),只有延時一會才會有數(shù)據(jù),即上面那張波形圖右邊那根黃色的線處記錄一下數(shù)據(jù),并將其顯示。我們也可以加上一下標注,來幫助我們觀察
這樣我們再來仿真的時候就不用看波形了,直接打開transcript一欄觀察記錄即可
這樣便可以為我們省下大量的仿真時間
04. 總結
這里提出以下幾點建議供大家參考:
-
封裝有用且常用的 testbench, testbench 中可以使用 task 或 function 對代碼進行封裝, 下次利用時靈活調(diào)用即可;
-
如果待測試文件中存在雙向信號(inout)需要注意, 需要一個 reg 變量來表示輸入, 一個 wire 變量表示輸出;
-
單個 initial 語句不要太復雜,可分開寫成多個 initial 語句, 便于閱讀和修改;
-
Testbench 說到底是依賴 PC 軟件平臺, 必須與自身設計的硬件功能相搭配。





