本题链接:
https://hdlbits.01xz.net/wiki/Tb/clock
为你提供了一个具有以下声明的模块:
module dut ( input clk ) ;
编写一个testbench,创建一个模块 dut 实例(具有任何实例名称),并创建一个时钟信号来驱动模块的 clk 输入。 时钟的周期为 10 ps。 时钟应初始化为零,且其第一次转换为从 0 到 1。


题目
module top_module ( );

答案
module top_module ( );
parameter time_period = 10;
reg clk;
initial clk = 0;
always begin
#(time_period / 2) clk = ~clk;
end
dut dut1(clk);
endmodule

输出波形
testbench


testbench 一般结构如下:

其实 testbench 最基本的结构包括信号声明、激励和模块例化。
根据设计的复杂度,需要引入时钟和复位部分。当然更为复杂的设计,激励部分也会更加复杂。根据自己的验证需求,选择是否需要自校验和停止仿真部分。
当然,复位和时钟产生部分,也可以看做激励,所以它们都可以在一个语句块中实现。也可以拿自校验的结果,作为结束仿真的条件。
1)信号声明
testbench 模块声明时,一般不需要声明端口。因为激励信号一般都在 testbench 模块内部,没有外部信号。
声明的变量应该能全部对应被测试模块的端口。当然,变量不一定要与被测试模块端口名字一样。但是被测试模块输入端对应的变量应该声明为 reg 型,如 clk,rstn 等,输出端对应的变量应该声明为 wire 型,如 dout,dout_en。
2)时钟生成
利用取反方法产生时钟时,一定要给 clk 寄存器赋初值。
利用参数的方法去指定时间延迟时,如果延时参数为浮点数,该参数不要声明为 parameter 类型。
3)复位生成
复位逻辑比较简单,一般赋初值为 0,再经过一段小延迟后,复位为 1 即可。
4)激励部分
激励部分该产生怎样的输入信号,是根据被测模块的需要来设计的。
当数据量相对较少时,可以利用 Verilog 中的系统任务 $readmemh 来按行直接读取 16 进制数据
5)模块例化
利用 testbench 开始声明的信号变量,对被测试模块进行例化连接。
6)自校验
如果设计比较简单,完全可以通过输入、输出信号的波形来确定设计是否正确,此部分完全可以删除。如果数据很多,有时候拿肉眼观察并不能对设计的正确性进行一个有效判定。此时加入一个自校验模块,会大大增加仿真的效率。
实例中,我们会在数据输出使能 dout_en 有效时,对输出数据 dout 与参考数据 read_temp(激励部分产生)做一个对比,并将对比结果置于信号 err_cnt 中。最后就可以通过观察 err_cnt 信号是否为 0 来直观的对设计的正确性进行判断。
7)结束仿真
如果我们不加入结束仿真部分,仿真就会无限制的运行下去,波形太长有时候并不方便分析。Verilog 中提供了系统任务 $finish 来停止仿真。
停止仿真之前,可以将自校验的结果,通过系统任务 $display 在终端进行显示。
参考内容:
6.6 Verilog 仿真激励 | 菜鸟教程 (runoob.com):
https://www.runoob.com/w3cnote/verilog-testbench.html