特权同学

Writing Testbench——结构化Testbench

0
阅读(3754)

特权同学为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

Baidu
map