Testbench经验总结
(2011-10-26 22:54:18)
标签:
杂谈 |
分类: Dreamywork |
1.激励的设置
相应于被测试模块的输入激励设置为reg型,输出相应设置为wire类型,双向端口inout在测试中需要进行处理。
方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出使能控制传输方向。
eg:
inout [0:0]
wire
reg
reg
assign bi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'bz;
用bi_dir_port_oe控制端口数据方向,并利用中间变量寄存器改变其值。等于两个模块之间用inout双向口互连。往端口写(就是往模块里面输入)
方法2:使用force和release语句,这种方法不能准确反映双向端口的信号变化,但这种方法可以反映块内信号的变化。具体如示:
module test();
wire data_inout;
reg data_reg;
reg link;
#xx;
force data_inout=1'bx;
...............
#xx;
release data_inout;
endmodule
从文本文件中读取和写入向量
1)读取文本文件:用 $readmemb系统任务从文本文件中读取二进制向量(可以包含输入激励和输出期望值)。$readmemh 用于读取十六进制文件。例如:
reg
initial
initial
2)输出文本文件:打开输出文件用?$fopen 例如:
integer out_file;
out_file = $fopen ( " cpu.data " ); // cpu.data 是需要打开的文件,也就是最终的输出文本
设计中的信号值可以通过$fmonitor, $fdisplay,
2. Verilog和Ncverilog命令使用库文件或库目录
3.Verilog Testbench信号记录的系统任务:
在记录信号或者波形时需要指出被记录信号的路径,如:tb.module.u1.clk.
………………………………………………………………………………………………………
关于信号记录的系统任务的说明:
在testbench中使用信号记录的系统任务,就可以将自己需要的部分的结果以及波形文件记录下来(可采用sigalscan工具查看),适用于对较大的系统进行仿真,速度快,优于全局仿真。使用简单,在testbench中添加:initial begin
$shm_open("waves.shm");
$shm_probe("要记录信号的路径“,”AS“);
#10000
$shm_close; 即可。
4. ncverilog编译的顺序:
5. 信号的强制赋值force
6.加载测试向量时,避免在时钟的上下沿变化
为了模拟真实器件的行为,加载测试向量时,避免在时钟的上下沿变化,而是在时钟的上升沿延时一个时间单位后,加载的测试向量发生变化。如:
assign #5 c=a^b
……
@(posedge clk)
******************************************************************************
//testbench的波形输出
module top;
...
initial
begin
end
endmodule
//产生随机数,seed是种子
$random(seed);
ex: din <= $random(20);
//仿真时间,为unsigned型的64位数据
$time
ex:
...
time
...
condition_happen_time = $time;
...
$monitor($time,"data utput = %d", dout);
...
//参数
parameter
//显示任务
$display();
//监视任务
$monitor();
//延迟模型
specify
...
//describ pin-to-pin delay
endspecify
ex:
module nand_or(Y,A,B,C);
input A,B,C;
output Y;
endmodule
//时间刻度
`timescale
//文件I/O
1.打开文件
integer file_id;
file_id = fopen("file_path/file_name");
2.写入文件
//$fmonitor只要有变化就一直记录
$fmonitor(file_id, "%format_char", parameter);
eg:$fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);
//$fwrite需要触发条件才记录
$fwrite(file_id, "%format_char", parameter);
//$fdisplay需要触发条件才记录
$fdisplay(file_id, "%format_char", parameter);
$fstrobe();
3.读取文件
integer file_id;
file_id = $fread("file_path/file_name", "r");
4.关闭文件
$fclose(fjile_id);
5.由文件设定存储器初值
$readmemh("file_name", memory_name"); //初始化数据为十六进制
$readmemb("file_name", memory_name"); //初始化数据为二进制
//仿真控制
$finish(parameter); //parameter = 0,1,2
$stop(parameter);
//读入SDF文件
$sdf_annotate("sdf_file_name", module_instance, "scale_factors");
//module_instance: sdf文件所对应的instance名.
//scale_factors:针对timming delay中的最小延时min,典型延迟typ,最大延时max调整延迟参数
//generate语句,在Verilog-2001中定义.用于表达重复性动作
//必须事先声明genvar类型变量作为generate循环的指标
eg:
genvar i;
generate for(i = 0; i < 4; i = i + 1)
begin
end
endgenerate
//资源共享
always @(A or B or C or D)
//上面例子使用两个加法器和一个MUX,面积大
//下面例子使用一个加法器和两个MUX,面积小
always @(A or B or C or D)
begin
end
always @(tmp1 or tmp2)
******************************************************************************
模板:
module testbench;
reg ……
……
wire……
……
//在这里例化DUT
initial
begin
……
end
always……
initial
//在这里添加比较语句(可选)
end
initial
//在这里添加输出语句(在屏幕上显示仿真结果)
end
endmodule
一下介绍一些书写Testbench的技巧:
1.如果激励中有一些重复的项目,可以考虑将这些语句编写成一个task,这样会给书写和仿真带来很大方便。例如,一个存储器的testbench的激励可以包含write,read等task。
2.如果DUT中包含双向信号(inout),在编写testbench时要注意。需要一个reg变量来表示其输入,还需要一个wire变量表示其输出。
3.如果initial块语句过于复杂,可以考虑将其分为互补相干的几个部分,用数个initial块来描述。在仿真时,这些initial块会并发运行。这样方便阅读和修改。
4.每个testbench都最好包含$stop语句,用以指明仿真何时结束。
最后提供一个简单的示例(转自Xilinx文档):
DUT:
module shift_reg (clock, reset, load, sel, data, shiftreg);
always @ (posedge clock)
begin
end
endmodule
Testbench:
module testbench; // declare testbench name
// instantiation of the shift_reg design below
//this process block sets up the free running clock
initial begin
end
initial begin// this process block specifies the stimulus.
end
initial begin// this process block pipes the ASCII results to the
//terminal or text editor
end
endmodule
posted @ 2009-10-28 11:24 神一样驴子 阅读(508)
评论(1)
(转)verilog 中文件输入/输出任务
全文地址:http://hubeixunbaoren.blog.163.com/blog/static/111127004200982725032948
系统函数$fopen用于打开一个文件,并还回一个整数指针.然后,$fdisplay就可以使用这个文件指针在文件中写入信息,写完后,则可以使用$fclose系统关闭这个文件
例如:
integer write_out_file;//定义一个文件指针
integer write_out_file=$fopen("write_out_file.txt");
$fdisplay(write_out_file,"@%h\n%h",addr,da
$fclose("write_out_file");
以上语法是将addr,da
从文件中读取数据,可以用
$readmemb
reg[7:0] da
$readmemh("file_name.txt",da
就是将file_name.txt中的数据读入到da
@address_in_hexadecimal da
@2f 20
两个系统任务可以在仿真的任何时刻被执行使用,其使用格式共有以下六种:
在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置(空格,换行,制表格(tab)和form-feeds),注释行(//形式的和形式的都允许),二进制或十六进制的数字。数字中不能包含位宽说明和格式说明,对于$readmemb系统任务,每个数字必须是二进制数字,对于$readmemh系统任务,每个数字必须是十六进制数字。数字中不定值x或X,高阻值z或Z,和下划线(_)的使用方法及代表的意义与一般Verilog HDL程序中的用法及意义是一样的。另外数字必须用空白位置或注释行来分隔开。
在下面的讨论中,地址一词指对存贮器(memory)建模的数组的寻址指针。当数据文件被读取时,每一个被读取的数字都被存放到地址连续的存贮器单元中去。存贮器单元的存放地址范围由系统任务声明语句中的起始地址和结束地址来说明,每个数据的存放地址在数据文件中进行说明。当地址出现在数据文件中,其格式为字符“@”后跟上十六进制数。如:
@hh...h
对于这个十六进制的地址数中,允许大写和小写的数字。在字符“@”和数字之间不允许存在空白位置。可以在数据文件里出现多个地址。当系统任务遇到一个地址说明时,系统任务将该地址后的数据存放到存贮器中相应的地址单元中去。
对于上面六种系统任务格式,需补充说明以下五点:
1)
2)
3)
4)
5)
下面举例说明:
先定义一个有256个地址的字节存贮器 mem:
reg[7:0] mem[1:256];
下面给出的系统任务以各自不同的方式装载数据到存贮器mem中。
initial
initial
initial
第一条语句在仿真时刻为0时,将装载数据到以地址是1的存贮器单元为起始存放单元的存贮器中去。第二条语句将装载数据到以单元地址是16的存贮器单元为起始存放单元的存贮器中去,一直到地址是256的单元为止。第三条语句将从地址是128的单元开始装载数据,一直到地址为1的单元。在第三种情况中,当装载完毕,系统要检查在数据文件里是否有128个数据,如果没有,系统将提示错误信息。
"引用 参考"
1.打开文件
integer file_id;
file_id = fopen("file_path/file_name");
2.写入文件
//$fmonitor只要有变化就一直记录
$fmonitor(file_id, "%format_char", parameter);
eg:$fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);
//$fwrite需要触发条件才记录
$fwrite(file_id, "%format_char", parameter);
//$fdisplay需要触发条件才记录
$fdisplay(file_id, "%format_char", parameter);
$fstrobe();
3.读取文件
integer file_id;
file_id = $fread("file_path/file_name", "r");
4.关闭文件
$fclose(fjile_id);
5.由文件设定存储器初值
$readmemh("file_name", memory_name"); //初始化数据为十六进制
$readmemb("file_name", memory_name"); //初始化数据为二进制
转:
http://zengbo.blogbus.com/logs/19569780.htmlVerilog
提供了丰富的系统函数,这为Testbench的编写提供了方便。尤其是IEEE1364-2005,其系统级建模的能力更强。
`timescale 1 ns/1 ns
module FileIO_tb;
integer fp_r, fp_w, cnt;
reg [7:0] reg1, reg2, reg3;
initial begin
end
endmodule
integer file, char;
reg eof;
initial begin
end
`define SEEK_SET 0
`define SEEK_CUR 1
`define SEEK_END 2
integer file, offset, position, r;
r = $fseek(file, 0, `SEEK_SET);
r = $fseek(file, 0, `SEEK_CUR);
r = $fseek(file, 0, `SEEK_END);
r = $fseek(file, position, `SEEK_SET);
integer r, file, start, count;
reg [15:0] mem[0:10], r16;
r = $fread(file, mem[0], start, count);
r = $fread(file, r16);
integer file, position;
position = $ftell(file);
integer file, r, a, b;
reg [80*8:1] string;
file = $fopenw("output.log");
r = $sformat(string, "Formatted %d %x", a, b);
r = $sprintf(string, "Formatted %d %x", a, b);
r = $fprintf(file, "Formatted %d %x", a, b);
integer file, r;
file = $fopenw("output.log");
r = $fflush(file);
// This is a pattern file -
read_pattern.pat
// time bin dec hex
10: 001 1 1
20.0: 010 20 020
50.02: 111 5 FFF
62.345: 100 4 DEADBEEF
75.789: XXX 2 ZzZzZzZz
`timescale 1ns / 10 ps
`define EOF 32'hFFFF_FFFF
`define NULL 0
`define MAX_LINE_LENGTH 1000
module read_pattern;
integer file, c, r;
reg [3:0] bin;
reg [31:0] dec, hex;
real real_time;
reg [8*`MAX_LINE_LENGTH:0] line;
initial