编写testbench的主要目的是为了对使用的硬件描述语言设计的电路进行仿真验证。本系列的博客都是基于vivado 2017.4 Xilinx验证平台。采用的开发板为ZYNQ-7000系列的器件。

一、Testbench 的一般结构

一般编写的测试文件包含一下内容:

module Test_bench(); //通常无输入出 通常无输入出
	信号或变量声明定义
	逻辑设计中输入对应 reg型
	逻辑设计中输出对应 wire 型
	使用 initial  或 always语句产生激励 语句产生激励
	例化待测试模块
	监控和比较输出响应
endmodule

二、时钟激励编写

1. 时钟激励产生方法一:50%占空比

parameter ClockPerilod=10
initial
	begin
		clk_i=0;
		forever
		#(ClockPerilod/2) clk_i = ~clk_i;  //最常用的产生方式
	end

2. 时钟激励产生方法二:50%占空比

parameter ClockPerilod=10
initial
	begin
		clk_i=0;
		#(ClockPerilod/2) clk_i = ~clk_i;  
	end

3. 时钟激励产生方法三:固定数量的时钟脉冲

parameter ClockPerilod=10
initial
	begin
		clk_i=0;
		repeat (6)
		#(ClockPerilod/2) clk_i = ~clk_i;  
	end

3. 时钟激励产生方法四:产生非占空比为50%的时钟脉冲

parameter ClockPerilod=10
initial
	begin
		clk_i=0;
		forever
			begin
			#(ClockPerilod/2) clk_i = 0;  
			#((ClockPerilod/2)+2) clk_i = 1; 
			end 
	end

三、复位信号的编写

1. 复位信号产生方法一:异步复位

initial
	begin
		rst_n_i = 1;
		#100
		rst_n_i = 0;
		#100
		rst_n_i = 0;
	end

2. 复位信号产生方法二:同步复位

initial
	begin
		rst_n_i = 1;
		@(negedge clk_i)
		rst_n_i = 0;
		#100				//固定时间复位
		repeat(10) @(negedge clk_i); //固定周期数复位 
		@(negedge clk_i)
		rst_n_i = 1;
	end

3. 复位信号产生方法三:复位任务封装

将复位信号设计成可封装的模块。

task reset;   //关键词加task名字
	input [31:0] reset_time;  //复位时间可调,输入复位时间
	RST_ING = 0;   //复位方式可调,低电平或高电平
	begin
		rst_n = RST_ING; //复位中
		#reset_time;	//复位时间
		rst_n_i = ~RST_ING;  //撤销复位,复位结束
	end
endtask

四、双向信号的设计

1. 双向信号描述一:

// 为双向端口设置中间变量 inout_reg作为 inout的输出寄存,其中 的输出寄存,其中 inout变量定义为 wirewire 型,使用输出能控制传方向型
//inout bir_port;
wire bir_port;
reg bir_port_reg;
reg bi_port_oe;
assign bi_port = bi_port_oe ? bir_port_reg : 1'bz;

2. 双向信号描述二:强制force

// 当双向端口作为输出时,不需要对其进行初始化而只开通三态门
// 当双向端口作为输入时,只需要对其初始化并关闭三态门赋值// 使用 wirewire 型数据,通过 force命令来对双向端口进行输入赋值
//assign dinout = (!en) din : 16'hz;完成双向赋值
initial
	begin
		force dinout = 20;
		#200
		force dinout = dinout - 1;
	end

五、特殊信号的设计

1. 特殊激励信号描述一:输入信号任务封装

task i_data;
input [7:0] dut_data;
begin
	@(posedge data_en); send_data=0;
	@(posedge data_en); send_data=dut_data[0];
	@(posedge data_en); send_data=dut_data[1];
	@(posedge data_en); send_data=dut_data[2];
	@(posedge data_en); send_data=dut_data[3];
	@(posedge data_en); send_data=dut_data[4];
	@(posedge data_en); send_data=dut_data[5];
	@(posedge data_en); send_data=dut_data[6];
	@(posedge data_en); send_data=dut_data[7];
	#100
end
endtask  
// 调用方法: i_data(8'hXX);

2. 特殊激励信号描述二:多输入信号任务封装

task more_data;
input [7:0] a;
input [7:0] b;
input [31:0] times;
output [8:0] c;
begin
	repeat (times)  //等待times个时钟上升沿
		@(posedge clk_i)
			c=a+b;   // 时钟上升沿a,b相加
end
endtask
//调用方法: more_input(x,y,z);   //按照声明顺序

3. 特殊激励信号描述三:输入信号产生,一次SRAM写信号产生

initial
	begin
		cs_n = 1;		//片选无效
		wr_n = 1;		//写使能无效
		rd_n = 1;		//读使能无效
		addr = 8'hxx;	//地址无效
		data = 8'hzz;	//数据无效
		#100
		cs_n = 0;		//片选有效
		wr_n = 0;		//写使能有效
		addr = 8'hF1;	//写入地址
		data = 8'h2C;	//写入数据
		#100
		cs_n = 1;		
		wr_n = 1;
		#10
		addr = 8'hxx;
		data = 8'hzz;

4. testbench中@与wait

//@使用沿触发
//wait语句都是使用电平触发
initial
	begin
		start = 1'b1;
		wait(en = 1'b1);
		#10
		start = 1'b0;
	end