特权同学

Writing Testbench——结构化Testbench

0
阅读(3910)

特权同学为testbench的结构 化以及可重用性设计发愁许久,终于在《writing testbench》一书的ch6章节里找到了答案,可谓柳暗花明又一村。原来Testbench还是 可以做到可重用化的设计。下面以特权同学常用模块做一个结构化可重用的示例。

 

这是假设的待验证模块的顶层:

module prj_top(clk,rst_n,dsp_addr,dsp_data,dsp_rw……);

         input clk;

         input rst_n;

         input[23:0] dsp_addr;

         input dsp_rw;

         inout[15:0] dsp_data;

……

……

……

endmodule

 

这是testbench的顶层:

module tf_prj_top;

 

/*这个例化适用于被例化文件(这里是print_task.v)不对待验证模块接口进行控制*/

//print_task.v里包含常用信息打印任务封装

print_task         print();

 

/*这个例化适用于被例化文件需要对待验证模块接口进行控制,和通常RTL设计中例化方法时一样的*/

//sys_ctrl_task.v里包含系统时钟产生单元和系统复位任务

sys_ctrl_task   sys_ctrl(

                                                        .clk(clk),

                                                        .rst_n(rst_n)

                                               );

                                              

//dsp_ctrl_task.v包含DSP读写控制模拟

dsp_ctrl_task  dsp_ctrl(

                                                        .dsp_rw(DSP_RW),

                                                        .dsp_addr(dsp_addr),

                                                        .dsp_data(dsp_data),

                                                        ……

                                               );               

 

/*这里的端口例化需要注意的时,原来被测试模块的output为reg,如果被底层的例化模块所控制,那么这个reg要改为wire类型进行定义,而底层模块要将其定义为reg*/

         wire clk;

         wire rst_n;

         wire[23:0] dsp_addr;

         wire dsp_rw;

         wire[15:0] dsp_data;

         ……

 

//例化待验证工程顶层

prj_top              uut(

.clk(clk),

.rst_n(rst_n),

.dsp_addr(dsp_addr),

.dsp_data(dsp_data),

.dsp_rw(dsp_rw),

……

);

 

/*注意下面调用底层模块的任务的方式,例如sys_ctrl表示上面例化的sys_ctrl_task.v,sys_reset是例化文件中的一个任务,用”.”做分割*/

Initial begin

         sys_ctrl.sys_reset(32’d1000);                   //系统复位1000ns

         #1000;

         dsp_ctrl.task_dsp_write(SELECT_STRB0,24'h000001,16’h00ff);   //DSP写任 务调用

         #1000;

         dsp_ctrl.task_dsp_read(SELECT_STRB0,24'h000008,dsp_rd_data);     //DSP读 任务调用

……

print.terminate;

end

 

endmodule

 

//调用层1

module print_task;

 

//----------------------------------------------------------------------//

//常用信息打印任务封 装

//----------------------------------------------------------------------//           

//警告信息打印任务

task warning;

         input[80*8:1] msg;

         begin

                   $write("WARNING at %t : %s",$time,msg);

         end

endtask

 

//错误信息打印任务

task error;

         input[80*8:1] msg;

         begin

                   $write("ERROR at %t : %s",$time,msg);

         end

endtask

 

//致命错误打印并停止 仿真任务

task fatal;

         input[80*8:1] msg;

         begin

                   $write("FATAL at %t : %s",$time,msg);

                   $write("Simulation false\n");

                   $stop;

         end

endtask

 

//完成仿真任务

task terminate;       

         begin

                   $write("Simulation Successful\n");

                   $stop;               

         end

endtask   

                  

endmodule

 

 

//调用层2

module sys_ctrl_task(

                                               clk,rst_n

                                               );

 

output reg clk;//时钟信号

output reg rst_n;     //复位信号

 

parameter      PERIOD   = 20;                   //时钟周期,单位ns

parameter      RST_ING          = 1'b0;      //有效复位值,默认低电平复位                                   

 

//----------------------------------------------------------------------//

//系统时钟信号产生

//----------------------------------------------------------------------//           

initial begin

         clk = 0;

         forever

                   #(PERIOD/2) clk = ~clk;

end

                

//----------------------------------------------------------------------//

//系统复位任务封装

//----------------------------------------------------------------------//           

task sys_reset;

         input[31:0] reset_time; //复位时间输入,单位ns

         begin

                   rst_n = RST_ING;              //复位中

                   #reset_time;                      //复位时间

                   rst_n = ~RST_ING;            //撤销复位

         end

endtask            

                  

                  

endmodule

 

//调用层3

module dsp_ctrl_task(

                                               dsp_rw,dsp_strb0,dsp_strb1,dsp_iostrb,

                                               dsp_addr,dsp_data

                                               );

 

output reg dsp_rw;          //DSP读写信号,低--写,高--读

output reg dsp_strb0;     //DSP存储空间STRB0选通信号

output reg dsp_strb1;     //DSP存储空间STRB1选通信号

output reg dsp_iostrb;    //DSP存储空间IOSTRB选通信号

output reg [23:0] dsp_addr;    //DSP地址总线

 

inout wire [15:0] dsp_data;     //DSP数据总线

                  

//print_task.v里包含常用信息打印任务封装

print_task         print();              

                  

//----------------------------------------------------------------------//

//模拟DSP读写任务封装

//----------------------------------------------------------------------//  

//DSP地址空间选择//

parameter        SELECT_STRB0         = 2'd1,

                                     SELECT_STRB1         = 2'd2,

                                     SELECT_IOSTRB       = 2'd3;

                                    

reg[15:0] dsp_data_reg;//DSP数据总线寄存器

 

assign dsp_data = dsp_rw ? 16'hzz : dsp_data_reg;

 

reg rd_flag;      //任务忙标志位,用于防止同时调用该任务

reg wr_flag;     //任务忙标志位,用于防止同时调用该任务

 

initial begin

         rd_flag = 0;       //DSP读 任务不忙

         wr_flag = 0;      //DSP写 任务不忙 

         //DSP信号接口初始化

         dsp_rw = 1;

         dsp_data_reg = 16'hzzzz;

         dsp_addr = 24'hzzzzzz;

         dsp_strb0 = 1;

         dsp_strb1 = 1;

         dsp_iostrb = 1;

end

 

reg h1;     //DSP时钟模拟,h1为DSP指令周期

initial begin

         h1 = 1'b0;

         forever

         #20 h1 = ~h1;

end

 

//模拟DSP读FPGA任务

task task_dsp_read;

         input[1:0] tcs;           //片选输入

         input[23:0] taddr;    //地址输入

         output[15:0] tdata;//数据读出

         begin

                   ……

         end

endtask

 

//模拟DSP写FPGA任务

task task_dsp_write;

         input[1:0] tcs;           //片选输入

         input[23:0] taddr;    //地址输入

         input[15:0] tdata;    //数据写入

         begin

                   ……

         end

endtask            

                  

endmodule