首先要明白测试代码的作用,这点其实很重要!测试代码其实就是通过代码模拟产生测试的环境,然后测试自己编写的模块代码是否正确。这可以指导我们在编写代码过程中决定某一些控制信号该如何产生,比如用于控制产生测试信号的控制信号,可以在一个 initial 模块里去改变这个值,而测试信号中的控制信号,应该在时钟下产生。
1、 将测试代码模块命名为 sim_crc_to_ram, 并且不需要任何输入信号。
module sim_crc_to_ram;
2、 定义变量类型
一般将输入信号定义为reg类型的;将输出信号定义为wire类型的;
reg clk_60M;
reg reset;
reg flag_din;
reg din;
wire clk_5k;
wire data_sys, data_inter;
3、例化模块,并将输入输出的信号和 2 中定义的变量进行关联。
crc_to_ram uut (
.clk_60M(clk_60M),
.reset(reset),
.start(flag_din),
.din(din),
.clk_5k(clk_5k),
.data_sys(data_sys),
.data_inter(data_inter)
);
4、 产生时钟模块。
根据需要产生一个或多个时钟。一般可以产生一个系统时钟即可,其他时钟由这个时钟分频产生即可。下面代码表示延迟8ns以后clk_60M信号取反,即周期为16ns的方波信号。
always #8 clk_60M = ~clk_60M;
5、 时钟控制和reset信号的控制
一般放在initial模块里,跟据具体需要对reset信号进行编辑;并注意时钟信号的初始化,否则无法产生正常的时钟信号(若不初始化,clk可能默认为x状态,~x状态仍为x,即不会产生时钟驱动)。
reg data_ready;
integer counti;
initial begin
// Initialize Inputs
clk_60M = 0;
reset = 0;
flag_din = 0;
din = 0;
counti = 0;
$readmemb("C:/src.txt", mem);
// Wait 100 ns for global reset to finish
data_ready = 0;
#100;
reset = 1;
#100;
data_ready = 1;
// Add stimulus here
// #(1600 * 10 * 1000); // 4 frame 100k
#(1600 * 1 * 1000); // 4 frame 1M
// #(400 * 1000); // 1 frame 1MHz
data_ready = 0;
end
6、 初始化文件操作
基本的文件操作包括读和写,下面是我产生输入信号的代码附带其他标记信号,略显繁琐,自己写时采用一个for循环即可。
parameter read_idle = 2'b00,
read_begin = 2'b01,
read_end = 2'b10;
reg [1 : 0] state_read;
always@(posedge clk_5k or negedge reset)
begin
if(!reset)
state_read <= read_idle;
else
begin
case (state_read)
read_idle:
begin
if(data_ready == 1'b1)
begin
counti <= 0;
state_read <= read_begin;
end
else
state_read <= read_idle;
end
read_begin:
begin
if (counti <= 1023) // 1 frames
begin
din <= mem[counti];
counti <= counti + 1;
state_read <= read_begin;
if ((counti == 0) || (counti == 1024) || (counti == 2048) || (counti == 3072))
flag_din<= 1'b1;
else
flag_din<= 1'b0;
end
else
state_read <= read_end;
end
read_end:
begin
state_read <= read_idle;
end
default:
begin
state_read <= read_idle;
end
endcase
end
end
写操作需要一个文件句柄,还要注意仿真结束前关闭文件操作,默认路径在.sim\sim_1\behav中(后仿在 .sim\sim_1\impl \timing中)。
integer fid;
fid = $fopen("resut.txt");
.........
$fclose(fid);
7、 控制信号和输出结果的编程
根据具体的实例对控制信号进行编程,并采集其输出结果,分多个initial模块进行。要形成很强的时序观念,并尽量使每个initial模块结构相对单一,也可以在always块中随着时钟clk将数据写入文本文件中。一般调用文件写操作保存仿真结果,fid 是文件操作符,直接使用如下语句完成输出即可。
......
$fdisplay(fid,"%b",data_out);
......
8、 结束testbench程序的运行
用$stop 或$finish结束程序的运行,另起一个initial。例如
initial
begin
#(1000000*CYCLE);
$ stop;
end