Testbench设计
转米联客,地址:http://www.osrc.cn/forum.php?mod=viewthread&tid=1006
下面列举出一些常用的封装子程序,这些是常用的写法,在很多应用中都能用到。
|
/*---------------------------------------------------------------- 时钟激励产生方法一:50%占空比时钟 ----------------------------------------------------------------*/ parameter ClockPeriod=10; initial begin clk_i=0; forever #(ClockPeriod/2) clk_i=~clk_i; end /*---------------------------------------------------------------- 时钟激励产生方法二:50%占空比时钟 ----------------------------------------------------------------*/ initial begin clk_i=0; always #(ClockPeriod/2) clk_i=~clk_i; end /*---------------------------------------------------------------- 时钟激励产生方法四:产生固定数量的时钟脉冲 ----------------------------------------------------------------*/ initial begin clk_i=0; repeat(6) #(ClockPeriod/2) clk_i=~clk_i; end /*---------------------------------------------------------------- 时钟激励产生方法五:产生非占空比为50%的时钟 ----------------------------------------------------------------*/ initial begin clk_i=0; forever begin #((ClockPeriod/2)-2) clk_i=0; #((ClockPeriod/2)+2) clk_i=1; end end /*---------------------------------------------------------------- 复位信号产生方法一:异步复位 ----------------------------------------------------------------*/ initial begin rst_n_i=1; #100; rst_n_i=0; #100; rst_n_i=1; end /*---------------------------------------------------------------- 复位信号产生方法二:同步复位 ----------------------------------------------------------------*/ 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 /*---------------------------------------------------------------- 复位信号产生方法三:复位任务封装 ----------------------------------------------------------------*/ task reset; input [31:0] reset_time; //复位时间可调,输入复位时间 RST_ING=0; //复位方式可调,低电平或高电平 begin rst_n=RST_ING; //复位中 #reset_time; //复位时间 rst_n_i=~RST_ING; //撤销复位,复位结束 end endtask /*---------------------------------------------------------------- 特殊激励信号产生描述一:输入信号任务封装 ----------------------------------------------------------------*/ 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]; @(posedge data_en); send_data=1; #100; end endtask //调用方法:i_data(8'hXX); /*---------------------------------------------------------------- 特殊激励信号产生描述二:多输入信号任务封装 ----------------------------------------------------------------*/ task more_input; 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,t,z); //按声明顺序 /*---------------------------------------------------------------- 双向信号描述一:inout在testbench中定义为wire型变量 ----------------------------------------------------------------*/ //为双向端口设置中间变量inout_reg作为inout的输出寄存,其中inout变 //量定义为wire型,使用输出使能控制传输方向 //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; /*---------------------------------------------------------------- 双向信号描述二:强制force ----------------------------------------------------------------*/ //当双向端口作为输出口时,不需要对其进行初始化,而只需开通三态门 //当双向端口作为输入时,只需要对其初始化并关闭三态门,初始化赋值需 //使用wire型数据,通过force命令来对双向端口进行输入赋值 //assign dinout=(!en) din :16'hz; 完成双向赋值 initial begin force dinout=20; #200 force dinout=dinout-1; end /*---------------------------------------------------------------- 特殊激励信号产生描述三:输入信号产生,一次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; end /*---------------------------------------------------------------- Testbench中@与wait ----------------------------------------------------------------*/ //@使用沿触发 //wait语句都是使用电平触发 initial begin start=1'b1; wait(en=1'b1); #10; start=1'b0; end /*---------------------------------------------------------------- 仿真控制语句及系统任务描述 ----------------------------------------------------------------*/ $stop //停止运行仿真,modelsim中可继续仿真 $stop(n) //带参数系统任务,根据参数0,1或2不同,输出仿真信息 $finish //结束运行仿真,不可继续仿真 $finish(n) //带参数系统任务,根据参数0,1或2不同,输出仿真信息 //0:不输出任何信息 //1:输出当前仿真时刻和位置 //2:输出当前仿真时刻、位置和仿真过程中用到的memory以及CPU时间的统计 $random //产生随机数 $random % n //产生范围-n到n之间的随机数 {$random} % n //产生范围0到n之间的随机数 /*---------------------------------------------------------------- 仿真终端显示描述 ----------------------------------------------------------------*/ $monitor //仿真打印输出,大印出仿真过程中的变量,使其终端显示 /* $monitor($time,,,"clk=%d reset=%d out=%d",clk,reset,out); */ $display //终端打印字符串,显示仿真结果等 /* $display(” Simulation start ! "); $display(” At time %t,input is %b%b%b,output is %b",$time,a,b,en,z); */ $time //返回64位整型时间 $stime //返回32位整型时间 $realtime //实行实型模拟时间 /*---------------------------------------------------------------- 文本输入方式:$readmemb/$readmemh ----------------------------------------------------------------*/ //激励具有复杂的数据结构 //verilog提供了读入文本的系统函数 $readmemb/$readmemh("<数据文件名>",<存储器名>); $readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>); $readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>,<结束地址>); $readmemb:/*读取二进制数据,读取文件内容只能包含:空白位置,注释行,二进制数 数据中不能包含位宽说明和格式说明,每个数字必须是二进制数字。*/ $readmemh:/*读取十六进制数据,读取文件内容只能包含:空白位置,注释行,十六进制数 数据中不能包含位宽说明和格式说明,每个数字必须是十六进制数字。*/ /*当地址出现在数据文件中,格式为@hh...h,地址与数字之间不允许空白位置, 可出现多个地址*/ module reg [7:0] memory[0:3];//声明8个8位存储单元 integer i; initial begin $readmemh("mem.dat",memory);//读取系统文件到存储器中的给定地址 //显示此时存储器内容 for(i=0;i<4;i=i+1) $display("Memory[%d]=%h",i,memory); end endmodule /*mem.dat文件内容 @001 AB CD @003 A1 */ //仿真输出为 Memory[0] = xx; Memory[1] = AB; Memory[2] = CD; Memory[3] = A1; |
上面只例举了常用的testbench写法,在工程应用中基本能够满足我们需求,至于其他更为复杂的testbench写法,大家可参考其他书籍或资料。
这里提出以下几点建议供大家参考:
• 封装有用且常用的testbench,testbench中可以使用task或function对代码进行封装,下次利用时灵活调用即可;
• 如果待测试文件中存在双向信号(inout)需要注意,需要一个reg变量来表示输入,一个wire变量表示输出;
• 单个initial语句不要太复杂,可分开写成多个initial语句,便于阅读和修改;
• Testbench说到底是依赖PC软件平台,必须与自身设计的硬件功能想搭配。

浙公网安备 33010602011771号