玩轉Zynq連載26——Vivado中PL的功能仿真 更多資料共享 騰訊微云鏈接:https://share.weiyun.com/5s6bA0s 百度網(wǎng)盤(pán)鏈接:https://pan.baidu.com/s/1XTQtP5LZAedkCwQtllAEyw 提取碼:ld9c ![]() 騰訊微云鏈接:https://share.weiyun.com/5s6bA0s 百度網(wǎng)盤(pán)鏈接:https://pan.baidu.com/s/1XTQtP5LZAedkCwQtllAEyw 提取碼:ld9c 仿真測試是FPGA設計流程中必不可少的步驟。尤其在FPGA規模和設計復雜性不斷提高的今天,畫(huà)個(gè)簡(jiǎn)單的原理圖或寫(xiě)幾行代碼直接就可以上板調試的輕松活兒已經(jīng)一去不復返。一個(gè)正規的設計需要花費在驗證上的工作量往往可能會(huì )占到整個(gè)開(kāi)發(fā)流程的70%左右。驗證我們通常分為仿真驗證和板級驗證,在設計初步完成功能甚至即將上板調試前,通過(guò)EDA仿真工具模擬實(shí)際應用進(jìn)行驗證是非常有效可行的手段,它能夠盡早的發(fā)現設計中存在的各種大小bug,避免設計到了最后一步才返工重來(lái)。因此,仿真在整個(gè)驗證中的重要性可見(jiàn)一斑。 提到仿真,我們通常會(huì )提testbench的概念。所謂testbench,即測試平臺,詳細的說(shuō)就是給待驗證的設計添加激勵,同時(shí)觀(guān)察它的輸出響應是否符合設計要求。如圖所示,測試平臺就是要模擬一個(gè)和待驗證設計相連接的各種外圍設備。 ![]() 初學(xué)者在剛接觸仿真這個(gè)概念的時(shí)候,可能以為仿真只是簡(jiǎn)單的用一些開(kāi)發(fā)軟件自帶的波形發(fā)生器產(chǎn)生一些激勵,然后觀(guān)察一下最后的波形輸出就完事了。但是對于大規模的設計,用波形產(chǎn)生激勵是不現實(shí)的,觀(guān)察波形的工作量也是可想而知的。例如,對于一個(gè)16位的輸入總線(xiàn),它可以有65536種組合,如果每次隨機產(chǎn)生一種輸入,那用波形豈不累死人。再說(shuō)輸出結果的觀(guān)察,對應65536種輸入的65536種輸出,看波形肯定讓人花眼繚亂。所以,testbench應該有更高效的測試手段。對于FPGA的仿真,使用波形輸入產(chǎn)生激勵是可以的,觀(guān)察波形輸出以驗證測試結果也是可以的,波形也許是最直觀(guān)的測試手段,但絕不是唯一手段。 如圖所示,設計的測試結果判斷不僅可以通過(guò)觀(guān)察對比波形,而且可以靈活的使用腳本命令將有用的輸出信息打印到終端或者產(chǎn)生文本進(jìn)行觀(guān)察,也可以寫(xiě)一段代碼讓他們自動(dòng)比較輸出結果?傊,testbench的設計是多種多樣的,它的語(yǔ)法也是很隨意的,不像RTL級設計代碼那么多講究,它是基于行為級的語(yǔ)法,很多高級的語(yǔ)法都可以在腳本中使用。因為它不需要實(shí)現到硬件中,它是運行在PC機上的一段腳本,所以相對RTL級可以做得更容易更靈活一些。但是,使用Verilog的驗證腳本也有很多需要設計者留意的地方,它是一種基于硬件語(yǔ)言但是又服務(wù)于軟件測試的語(yǔ)言,所以它常常游離于并行和順序之間讓人琢磨不透。不過(guò),只要掌握好了這些關(guān)鍵點(diǎn),是可以很好的讓它服務(wù)于我們的測試。 ![]() Testbench的編寫(xiě)其實(shí)也沒(méi)有想象中那么神秘,筆者簡(jiǎn)單的將其歸納為3個(gè)步驟。 ①對被測試設計的頂層接口進(jìn)行例化。 ②給被測試設計的輸入接口添加激勵。 ③判斷被測試設計的輸出響應是否滿(mǎn)足設計要求。 相對而言,最后一步還要復雜一些,有時(shí)不一定只是簡(jiǎn)單的輸出觀(guān)察,可能還需要反饋一些輸入值給待測試設計。 例化的目的就是把待測試設計和testbench進(jìn)行對接,和FPGA內部的例化是一個(gè)概念。那么如何進(jìn)行例化呢?下面用一個(gè)簡(jiǎn)單實(shí)例來(lái)說(shuō)明。 //待測試的設計 module fpga_design( clk,rst_n,a,b,c,d ); input clk; input rst_n; input a,b,c; output d; always @(posedgeclk or negedgerst_n) begin if(!rst_n) d <= 1’b0; else d <= a & b & c; end endmodule 對于上面這個(gè)待測試的設計,testbench中的例化應該把input轉換成reg,因為待測試設計的輸入值是由testbench決定的。相應的output就應該轉換成wire,因為待測試設計的輸出值不是由testbench決定的。如果是inout端口,在例化中也是一個(gè)wire類(lèi)型,在testbench中使用時(shí)和RTL代碼設計中使用是一樣的。 //例化待測試設計 reg clk; reg rst_n; reg a,b,c; wire d; fpga_design( .clk(clk), .rst_n(rst_n), .a(a), .b(b), .c(c), .d(d) ); 對于激勵的產(chǎn)生,只提最基本的時(shí)鐘信號和復位信號的產(chǎn)生。時(shí)鐘信號產(chǎn)生方式有很多,使用initial和always語(yǔ)句都是可以的。下面列出比較典型的兩種產(chǎn)生方式供大家參考。 //時(shí)鐘產(chǎn)生 parameter PERIOD = 20; //定義時(shí)鐘周期為20ns,已定義“`timescale 1ns/1ps” initial begin clk = 0; forever #(PERIOD/2) clk = ~clk; end //時(shí)鐘產(chǎn)生 parameter PERIOD = 20; //定義時(shí)鐘周期為20ns,已定義“`timescale 1ns/1ps” always begin #(PERIOD/2) clk = 0; #(PERIOD/2) clk = 1; end 復位信號的產(chǎn)生也很簡(jiǎn)單,比較常用的做法是封裝成一個(gè)task,直接在需要復位的時(shí)候調用即可。 //復位產(chǎn)生 initial begin reset_task(100); //復位100ns,已定義“`timescale 1ns/1ps” …… end task reset_task; input[15:0] reset_time; //復位時(shí)間 begin reset = 0; #reset_time; reset = 1; end endtask 至于對測試的響應如何進(jìn)行觀(guān)察處理,這里不作太多描述,大家隨便找本verilog語(yǔ)法方面的書(shū)籍都會(huì )有相應的行為級語(yǔ)法的部分,只要依葫蘆畫(huà)瓢就能學(xué)會(huì )。 對于這個(gè)簡(jiǎn)單的設計,有a、b和c三個(gè)輸入,他們相與的結果d每個(gè)時(shí)鐘周期輸出一次最新的結果。因此,我們可以預見(jiàn),若想完全覆蓋這個(gè)設計的測試分支,那么要產(chǎn)生8個(gè)不同的測試項,即分別改變a、b和c的取值,觀(guān)察他們輸出的結果是否符合預期。測試腳本的編寫(xiě)如下所示。 //復位產(chǎn)生 timescale 1ns/1ps module tb_fpga_design; //例化待測試設計 reg clk; reg rst_n; reg a,b,c; wire d; fpga_design( .clk(clk), .rst_n(rst_n), .a(a), .b(b), .c(c), .d(d) ); initial begin reset_task(100); //復位100ns,已定義“`timescale 1ns/1ps” @(posedgeclk); #2; a = 1’b0; b = 1’b0; c = 1’b0; @(posedgeclk); #2; a = 1’b0; b = 1’b0; c = 1’b1; @(posedgeclk); #2; a = 1’b0; b = 1’b1; c = 1’b0; @(posedgeclk); #2; a = 1’b0; b = 1’b1; c = 1’b1; @(posedgeclk); #2; a = 1’b1; b = 1’b0; c = 1’b0; @(posedgeclk); #2; a = 1’b1; b = 1’b0; c = 1’b1; @(posedgeclk); #2; a = 1’b1; b = 1’b1; c = 1’b0; @(posedgeclk); #2; a = 1’b1; b = 1’b1; c = 1’b1; @(posedgeclk); #2; $stop; end task reset_task; input[15:0] reset_time; //復位時(shí)間 begin reset = 0; #reset_time; reset = 1; end endtask //時(shí)鐘產(chǎn)生 parameter PERIOD = 20; //定義時(shí)鐘周期為20ns,已定義“`timescale 1ns/1ps” always begin #(PERIOD/2) clk = 0; #(PERIOD/2) clk = 1; end endmodule 使用這個(gè)腳本對設計進(jìn)行仿真,我們觀(guān)察結果輸出,在8種不同的設計輸入情況下,輸出是否和預期一致。若一致,則可以繼續后面的設計流程完成設計,若不一致,則設計中一定存在問(wèn)題,需要查找問(wèn)題原因并對設計進(jìn)行修改直到仿真結果達到預期結果。 以zstar_ex01為例,如圖所示,選中Project Manager à Simulation Sources à sim_1,右鍵點(diǎn)擊彈出菜單后,選中Add Sources…。
![]() 圖新建仿真文件菜單 接著(zhù)如圖所示,使用默認選項Add or create simulation sources。 ![]() 如圖所示,單擊Create File按鈕。 ![]() 如圖所示,設置創(chuàng )建的文件類(lèi)型(File type)為Verilog;文件名(File name)為sim_zstar;文件路徑(File location)為默認的 ![]() 圖設置新建文件名稱(chēng)和路徑 最后點(diǎn)擊Finish按鈕完成仿真測試文件的創(chuàng )建。 隨后彈出模塊端口定義的界面,可以直接點(diǎn)擊OK不做設定。 ![]() 如圖所示,雙擊Simulation Sources下剛剛創(chuàng )建好的sim_zstar.v文件,里面也只有一個(gè)Verilog模塊框架,有待內容填充。 ![]() 如圖所示,將這個(gè)實(shí)例的仿真測試腳本寫(xiě)入這個(gè)文件中。 ![]() 下面我們看看如何使用Vivado自帶的仿真工具實(shí)現功能仿真。如圖所示,單擊Project Manager à Simulation àSimulation Settings,彈出選項卡中,設置目標仿真器(Target Simulator)為Vivado Simulator,仿真語(yǔ)言(Simulation language)為Mixed,仿真集(Simulation set)為sim_1,仿真頂層模塊名(Simulation top module name)為sim_zstar。 ![]() 如圖所示,點(diǎn)擊Run Simulation,接著(zhù)彈出菜單中再點(diǎn)擊Run Behavioral Simulation進(jìn)行功能仿真。 ![]() 彈出仿真界面如圖所示,3個(gè)窗口從左到右依次是模塊及層次顯示窗口、信號顯示窗口和波形窗口。 ![]() 如圖所示,點(diǎn)擊Run All按鈕。 ![]() 此時(shí),如圖所示,仿真運行中。 ![]() 如圖所示,可以點(diǎn)擊波形界面右上角的Float按鈕,將波形界面從Vivado中獨立出來(lái),這樣可以滿(mǎn)屏顯示波形,看到更多的波形細節。 ![]() 如圖所示,在仿真結束后,我們可以點(diǎn)擊Zoom Fit按鈕將所有的仿真波形縮放到可視界面中。 ![]() 如圖所示,這是該工程仿真的波形。beep信號一直是10%占空比的1Hz PWM信號。 ![]() |