給大家推薦一款網頁版的 Verilog代碼編輯仿真驗證平台,這個平台是國外的一家開源FPGA學習網站,通過“https://hdlbits.01xz.net/wiki/Main_Page” 地址鏈接進入網頁,在該網頁上可以進行Verilog代碼的編寫、綜合,而且最后還能夠仿真出波形來驗證設計代碼的正確性,該驗證平台是基於Icarus Verilog(簡稱iVerilog,比較著名的開源HDL仿真工具,也有對應的安裝版本)的,讓你隨時隨地只需登錄網頁就能夠享受Verilog編程仿真的樂趣!
一、官方模板演示
1、首先打開“https://hdlbits.01xz.net/wiki/Main_Page”,打開后的界面如下圖所示,全英文顯示。如果感覺自己的英文水平欠佳,可以使用谷歌瀏覽器打開該網頁,並選擇在線翻譯功能,翻譯的正確率還是很高的。
2、點擊Simulation下的 ”Run a Simulation(lcarus Verilog)“。
3、打開后的界面如下圖所示,代碼編輯框中給出了一個簡單的例子。
4、點擊下面的“Submit(new window)“在新界面中進行仿真。
5、在新打開的界面中我們可以看到編譯的信息和仿真波形圖。
二、實例演示
雖然看完了官方的模板演示,但我們要想立刻仿真驗證自己設計的代碼並不是那么容易,需要進行一番摸索。下面就是大家進行一個呼吸燈的設計實例演示。
1、學習過FPGA的朋友都知道要想對FPGA邏輯進行仿真一定要具備兩個文件,一個是RTL代碼文件,用來綜合生成硬件電路的部分;第二個就是Testbench文件,用來驗證RTL代碼功能的仿真文件,這兩者缺一不可。
2、根據觀察發現官方模板中的代碼編輯部分有兩個module,大家也都知道一個.v 文件中只能有一個模塊,也就是只能有一個module,而這里面有兩個,那肯定就不對了。再仔細觀察會發現代碼編輯區域中的上半部分就是Testbench,而下半部分則是RTL代碼,再結合仿真出的波形來更看驗證了這個想法。原來 RTL 代碼和Testbench都寫在了一個編輯框里。
3、但是我們在提供的模板中發現一些我們平時幾乎沒有見過的新語法,如第4行的”initial `probe_start“、第6行的”`probe(clk)“、第26行的”`probe(in)“,通過模板的注釋和多次實驗發現這是官方定義的一個”宏“,也就是通過這個”宏“調用“probe”探針的功能,我們不用管這個”宏“是如何定義的,我們只需要會調用就可以了。
4、下面我們通過該網頁來仿真驗證一下自己設計的呼吸燈的例子。詳細代碼如下(呼吸燈邏輯和Testbench代碼的編寫方法這里我們不做講解,會在以后的文章中再進行詳細說明),下面代碼可以全部直接復制使用(代碼中的注釋請詳細閱讀)。
1 `timescale 1ns/1ns 2 3 //----------------Tesebench----------------- 4 module top_module; //仿真文件名必須是“top_module” 5 6 reg sclk; 7 reg rst_n; 8 9 wire led; 10 11 initial `probe_start; // Start the timing diagram 12 13 `probe(sclk); // Probe signal "clk",這是加載的系統時鍾,只能在Tesebench中加載 14 15 //初始化 16 initial begin 17 sclk = 1'b0; 18 rst_n <= 1'b0; 19 #200 20 rst_n <= 1'b1; 21 #5000 //一定要設置仿真停止時間,如果仿真結束時間太久會提示 22 $finish; 23 end 24 25 //產生20ns的時鍾 26 always #10 sclk = ~sclk; 27 28 //為了減少仿真時間我們在仿真中重定義參數,不影響RTL代碼中參數的值 29 defparam breath_led_inst.CNT_1US_MAX = 1; 30 defparam breath_led_inst.CNT_1MS_MAX = 2; 31 defparam breath_led_inst.CNT_1S_MAX = 2; 32 33 //----------------breath_led----------------- 34 breath_led breath_led_inst( 35 .sclk (sclk ), //input sclk 36 .rst_n (rst_n), //input rst_n 37 38 .led (led ) //output led 39 ); 40 41 endmodule 42 43 //----------------RTL----------------- 44 module breath_led 45 #( 46 parameter CNT_1US_MAX = 6'd49, 47 parameter CNT_1MS_MAX = 10'd999, 48 parameter CNT_1S_MAX = 10'd999 49 ) 50 ( 51 input wire sclk , 52 input wire rst_n , 53 54 output reg led 55 ); 56 57 reg [5:0] cnt_1us; 58 reg [9:0] cnt_1ms; 59 reg [9:0] cnt_1s; 60 reg cnt_1us_flag; 61 reg cnt_1ms_flag; 62 reg cnt_1s_flag; 63 64 //cnt_1us:1us計數器 65 always@(posedge sclk or negedge rst_n) 66 if(rst_n == 1'b0) 67 cnt_1us <= 6'b0; 68 else if(cnt_1us == CNT_1US_MAX) 69 cnt_1us <= 6'b0; 70 else 71 cnt_1us <= cnt_1us + 1'b1; 72 73 //cnt_1us_flag:1us計數器標志信號 74 always@(posedge sclk or negedge rst_n) 75 if(rst_n == 1'b0) 76 cnt_1us_flag <= 1'b0; 77 else if(cnt_1us == CNT_1US_MAX) 78 cnt_1us_flag <= 1'b1; 79 else 80 cnt_1us_flag <= 1'b0; 81 82 //cnt_1ms:1ms計數器 83 always@(posedge sclk or negedge rst_n) 84 if(rst_n == 1'b0) 85 cnt_1ms <= 10'b0; 86 else if(cnt_1ms == CNT_1MS_MAX && cnt_1us_flag == 1'b1) 87 cnt_1ms <= 10'b0; 88 else if(cnt_1us_flag == 1'b1) 89 cnt_1ms <= cnt_1ms + 1'b1; 90 91 //cnt_1ms_flag:1ms計數器標志信號 92 always@(posedge sclk or negedge rst_n) 93 if(rst_n == 1'b0) 94 cnt_1ms_flag <= 1'b0; 95 else if(cnt_1ms == CNT_1MS_MAX && cnt_1us_flag == 1'b1) 96 cnt_1ms_flag <= 1'b1; 97 else 98 cnt_1ms_flag <= 1'b0; 99 100 //cnt_1s:1s計數器 101 always@(posedge sclk or negedge rst_n) 102 if(rst_n == 1'b0) 103 cnt_1s <= 10'b0; 104 else if(cnt_1s == CNT_1S_MAX && cnt_1ms_flag == 1'b1) 105 cnt_1s <= 10'b0; 106 else if(cnt_1ms_flag == 1'b1) 107 cnt_1s <= cnt_1s + 1'b1; 108 109 //cnt_1s_flag:1s計數器標志信號 110 always@(posedge sclk or negedge rst_n) 111 if(rst_n == 1'b0) 112 cnt_1s_flag <= 1'b0; 113 else if(cnt_1s == CNT_1S_MAX && cnt_1ms_flag == 1'b1) 114 cnt_1s_flag <= ~cnt_1s_flag; 115 116 //led:一個LED燈 117 always@(posedge sclk or negedge rst_n) 118 if(rst_n == 1'b0) 119 led <= 1'b0; 120 else if((cnt_1s_flag == 1'b1 && cnt_1ms <= cnt_1s) || (cnt_1s_flag == 1'b0 && cnt_1ms > cnt_1s)) 121 led <= 1'b1; 122 else 123 led <= 1'b0; 124 125 //添加要觀察的信號名 126 `probe(rst_n ); // Sub-modules can also have `probe() 127 `probe(cnt_1us ); // Sub-modules can also have `probe() 128 `probe(cnt_1us_flag); // Sub-modules can also have `probe() 129 `probe(cnt_1ms ); // Sub-modules can also have `probe() 130 `probe(cnt_1ms_flag); // Sub-modules can also have `probe() 131 `probe(cnt_1s ); // Sub-modules can also have `probe() 132 `probe(cnt_1s_flag ); // Sub-modules can also have `probe() 133 `probe(led ); // Sub-modules can also have `probe() 134 135 endmodule
5、將上面編寫好的Testbench代碼和RTL代碼放到一個文件中(Testbench在上面,RTL代碼在下面,僅在該平台仿真時可以將兩種文件放在一起,在其他平台仿真時要獨立放到兩個.v文件中),然后復制粘貼到代碼編輯框中,點擊“Submit(new window)“執行仿真。
6、也可以將寫好的Testbench代碼和RTL代碼放到同一個.v文件中,然后點擊下面的代碼編輯框下面的“Upload a source file...”,在展開的界面中選擇添加.v文件后,再點擊”Upload and simulate”啟動仿真。
7、仿真波形如下所示,因為界面空間有限,拖動波形顯示框下面的滾動條,可以看到后面的波形顯示。
8、在波形顯示框中右擊鼠標可以選擇保存為PNG格式或SVG格式,將完整的波形信息保存下來。
9、保存為SVG格式后的完整波形圖如下所示。
10、如果我們在第58行處代碼設置一個錯誤后,再點擊執行仿真,此時在仿真窗口中不會顯示波形,而是提示錯誤的內容,將錯誤修改后再執行仿真即可。
11、該網頁還有其他更多有趣的功能,如組合邏輯代碼編寫訓練、時序邏輯代碼編寫訓練、單片機嵌入式仿真等等,有興趣的朋友可以自己探索,這里不再一一演示。
歡迎加入FPGA技術學習交流群,本群致力於為廣大FPGAer提供良好的學習交流環境,不定期提供各種本行業相關資料!
QQ交流群號:450843130