学会使用Hdlbits网页版Verilog代码仿真验证平台
给大家推荐一款网页版的 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