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; //时钟上升沿ab相加

end

endtask

//调用方法:more_input(x,y,t,z);  //按声明顺序

/*----------------------------------------------------------------

双向信号描述一:inouttestbench中定义为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,12不同,输出仿真信息

$finish   //结束运行仿真,不可继续仿真

$finish(n)  //带参数系统任务,根据参数0,12不同,输出仿真信息

//0:不输出任何信息

//1:输出当前仿真时刻和位置

//2:输出当前仿真时刻、位置和仿真过程中用到的memory以及CPU时间的统计

$random //产生随机数

$random % n //产生范围-nn之间的随机数

{$random} % n //产生范围0n之间的随机数

/*----------------------------------------------------------------

仿真终端显示描述

----------------------------------------------------------------*/

$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];//声明88位存储单元

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写法,大家可参考其他书籍或资料。

这里提出以下几点建议供大家参考:

封装有用且常用的testbenchtestbench中可以使用taskfunction对代码进行封装,下次利用时灵活调用即可;

如果待测试文件中存在双向信号(inout)需要注意,需要一个reg变量来表示输入,一个wire变量表示输出;

单个initial语句不要太复杂,可分开写成多个initial语句,便于阅读和修改;

• Testbench说到底是依赖PC软件平台,必须与自身设计的硬件功能想搭配。

posted @ 2016-10-24 22:00  毛小子  阅读(1625)  评论(0)    收藏  举报