一、全加器DUT Code
module adder32( //Verilog——2001语法
input wire [31:0] a_in,
input wire [31:0] b_in,
input wire [0:0] c_in, //carry in,进位位
output reg [31:0] sum_out,
output reg [0:0] c_out //carry out
);
assign {c_out,sum_out} = a_in + b_in + c_in;
endmodule
二、Testbench Code
自动化验证testbench结果可以减少人工检查的时间和可能犯的失误,尤其对于比较大的设计。目前普遍使用两种自动化testbench验证方法:
- 波形比较:将testbench输出波形与预期波形作比较。不过目前由于该方法很少使用。
- 自动比对testbench设计:与前种方法不同,该方法实时检查预期结果和实际结果,效率较高,可缩短调试时间。
Testbench仿真一般包含以下几个过程:
- 从脚本中获取随机种子和激励数量;
- 通过随机种子产生激励;
- 将激励发送至DUT;
- 将激励发送至Golden model;
- 获取DUT输出;
- 将DUT输出和Golden model进行一一比较
上述32位加法器的Testbench代码如下:
module adder32_tb_rand(); //testbench不需要列出端口列表
reg [31:0] a_in;
reg [31:0] b_in;
reg [0:0] c_in; //carry in,进位位
wire[31:0] sum_out;
wire[0:0] c_out; //carry out
int seed; //随机种子,用以产生随机激励
int stimulus_num; //发送激励的数量,即要发送多少激励
reg [32:0] data_in[3]={33'h0,33'h0,33'h0};//定义3个激励,并初始化为0,位宽33bit,最高位后边赋0处理
reg sti_gen; //该信号为一个flag,相当于clk
reg [32:0] gld_sum[$]; //该队列用于存储所有的golden model,用于check
reg [32:0] dut_sum[$]; //该队列用于存储所有的DUT输出,用于和Golden model比对
reg [32:0] gld_sum_rslt; //**临时变量,存储单一golden model(一一比对)**
reg [32:0] dut_sum_rslt; //**临时变量,存储单一DUT输出,和golden model进行一一比对**
event sti_end; //控制激励,使激励完全发送完毕再进行比对
int err_cnt; //标志信号,记录比对的错误数量
//1.Get random seed and stimulus numbers from external scripts
initial begin
if(!$value$plusargs("seed=%0d",seed))begin //获取由脚本传递进来的随机种子
seed = 100;
end
else begin
$display("@%0t: seed = %0d",$time,seed);
end
if(!$value$plusargs("stimulus_num=%0d",stimulus_num))begin //获取由脚本传递进来的激励数量
stimulus_num = 50;
end
else begin
$display("@%0t: stimulus_num = %0d",$time,stimulus_num);
end
end
//2.Generate stimulus with random seed
initial begin
sti_gen = 1'b0; //flag初始化
repeat(stimulus_num)begin
sti_gen = 1'b0;
#10; //每隔10个时间单位产生一组激励
data_in[0][31:0] = $random(seed); //产生的激励为32bit,(a_in)
data_in[1][31:0] = $random(seed); //产生的激励为32bit, (b_in)
data_in[2] = 1'b0; //相当于第33bit进位位,直接置0
#10; //该延迟为了保证激励稳定后才被收集
sti_gen = 1'b1; //flag, 通知采集模块可以采集激励结果,并将其存放到队列中了
#10;
end
->sti_end; //保证激励发送完毕后,再触发事件,进行数据比对
end
//3.Send stimulus to DUT
always @(*) begin
a_in = data_in[0]; //将激励发送进入DUT中
b_in = data_in[1];
c_in = data_in[2];
//$display("@%0t: a_in=%0h, b_in=%0h, data_in[0]=%0h,data_in[1]=%0h",a_in,b_in,data_in[0],data_in[1]);
//在此处可添加打印信息,以检查输入激励是否有错误
end
//4.Send stimulus to Golden model
initial begin
repeat(stimulus_num)begin
@(posedge sti_gen)
gld_sum.push_back(data_in.sum); //SV语法,gld_sum队列的内置函数push_back()
end // 即,将data_in求和后,push_back函数将和放入队列gld_sum中
end
//5.Capture DUT output
initial begin
repeat(stimulus_num)begin
@(posedge sti_gen)
dut_sum.push_back({c_out,sum_out}); //SV语法,dut_sum队列的内置函数push_back()
end // 即,DUT输出后,push_back函数将输出结果放入队列dut_sum中
end
//6.Check result
initial begin
gld_sum_rslt = 'h0; //临时变量,初始化,用于采集单一的golden model
dut_sum_rslt = 'h0; //临时变量,初始化,用于采集单一的DUT输出
err_cnt = 'h0; //比对错误统计,初始化
@sti_end; //等待所有的激励全部发送完毕后,才触发事件,进行比对
repeat(stimulus_num)begin
gld_sum_rslt = gld_sum.pop_front(); //队列的pop_front()函数会弹出一个golden model存入临时变量
dut_sum_rslt = dut_sum.pop_front(); //队列的pop_front()函数会弹出一个DUT输出存入临时变量
if( gld_sum_rslt != dut_sum_rslt ) begin
$display("@%0t:EEROR::gld_sum!=dut_sum,gld_sum=%0h,dut_sum=%0h",$time,gld_sum_rslt,dut_sum_rslt);
//打印错误的golden model与DUT输出的比对结果
err_cnt++; //统计错误比对的数量
end
end
end
if(err_cnt == 'h0)begin //如果比对无误,则检测通过
$display("***********************************");
$display("***********************************");
$display("************TEST PASS************");
$display("***********************************");
$display("***********************************");
end
finish(); //结束仿真
endmodule
三、Makefile脚本编译
文件名:Makefile.rand
all: compile simulate
seed = $(shell date +%s); //随机种子格式
stimulus_num = 100; //仿真时可在外部改变激励个数
//上述两个变量可通过脚本传入Testbench中
compile:
vcs -sverilog adder32.v adder32_tb_rand.v -debug_all -l comp.log
simulate:
./simv -l sim_$(seed).log +plusargs_save +seed=$(seed) +stimulus_num=$(stimulus_num)
编译命令:make -f Makefile.rand
对于Makefile中各个参数的解释:
- vcs: 编译工具vcs;
- -sverilog:Testbench中用到sv语法;
- adder32:当前目录下的DUT文件;
- adder32_tb_rand.v:当前目录下的Testbench文件;
- debug_all:习惯性加上;
- -l comp.log:将编译结果记录在comp.log文件中
- ./simv:vcs编译完毕会自动产生simv目录;
- -l sim_$(seed).log:记录仿真结果记录在该文件中;
- +plusargs_save:将种子seed和激励stimulus_num等变量植入testbench中;
- +seed=$(seed):植入变量seed,前一个seed为tb中的seed,后一个seed为脚本中的变量seed;
- +stimulus_num=$(stimulus_num):植入变量stimulus_num,同seed;