Verilog Verification
文章目录
前言
没有前言
一、线性 Testbench
initial begin
# 10 a = 0; b = 0 ; c = 0;
# 10 a = 0; b = 0 ; c = 1;
# 10 a = 0; b = 1 ; c = 0;
# 10 a = 0; b = 1 ; c = 1;
# 10 a = 1; b = 0 ; c = 0;
# 10 a = 1; b = 0 ; c = 1;
# 10 a = 1; b = 1 ; c = 0;
# 10 a = 1; b = 1 ; c = 1;
end
罗列出所有信号的输入,如一个3输入端口,输入状态有8种组合方式,分别为000、001、010、011、100、101、110、111,将其种所有方式进行罗列出来,这种就是线性写法,对于多输入端口将产生更多的组合方式,线性写法就不再适用。
二、文件导入
1.从txt中导入
module readmemh_demo;
reg [31:0] Mem [0:11];
initial $readmemh("data.txt",Mem);
integer k;
initial begin
#10;
$display("Contents of Mem after reading data file:");
for (k=0; k<6; k=k+1) $display("%d:%h",k,Mem[k]);
end
endmodule
EXAMPLE: data.txt file
234ac
23ca5
b3c34
23a4a
234ca
b3234
RESULT:
0:000234ac
1:00023ca5
2:000b3c34
3:00023a4a
4:000234ca
5:000b3234
验证部分算法,可以使用matlab生成txt数据,然后通过测试文件加载到逻辑中进行计算。数据文件必须与本例模块的.v文件在同一个目录下。
1.从.v文件中导入
module readmemh_demo;
reg [31:0] Mem [0:11];
`include "data.v"
integer k;
initial begin
#10;
$display("Contents of Mem after reading data file:");
for (k=0; k<6; k=k+1) $display("%d:%h",k,Mem[k]);
end
endmodule
EXAMPLE: data.v file
initial
begin
Mem[0] = 32'h234ac;
Mem[1] = 32'h23ca5;
Mem[2] = 32'hb3c34;
Mem[3] = 32'h23a4a;
Mem[4] = 32'h234ca;
Mem[5] = 32'hb3234;
end
RESULT:
0:000234ac
1:00023ca5
2:000b3c34
3:00023a4a
4:000234ca
5:000b3234
在模拟过程中对文件的读写对性能是有代价的,因为在操作系统完成与文件系统的每个事务时,模拟器必须暂停并等待。提高性能的一种方法是用HDL本身的常量表替换ASCII向量文件。
三、测试模块中状态机编写
always@(posedge clk)
case(state)
READ :
if(i < No_of_reads)begin
read_write = 0;
address = $random;
i=i+1;
end
else
$finish
WRITE :
if(j < no_of_writes)begin
read_write = 1;
address = $random;
data = $random;
j=j+1;
end
else
state = READ ;
endcase
initial begin
No_of_reads = 0;
No_of_writes = 10;
end
基于状态机的验证不能支持当前的验证需求。基于状态机的测试台现在已经很少见了。使用上面的testbench风格,可控性更少,并且很难更改代码来添加新特性,例如将上面的代码转换为交替的读写操作,这非常困难。
三、Task and Function
使用TASK进行模块化设计可以方便编写不同仿真程序进行移植。
–task和function区别
1、function只能与主模块共用一个仿真时间单位,而task可以定义自己的仿真时间单位。
2、function不能包含task,task可以包含其它的task和function。
3、function至少有一个输入变量,而task可以没有或者有多个任意类型的变量。
4、function返回一个值,而task则不返回值。
task write(input integer data,input integer address);
begin
@(posedge clock);
read_write = 1;
address = address;
data = data;
end
endtask
task read(input integer address,output integer data);
begin
@(posedge clock);
read_write = 0;
address = address;
data = $random;
// Do some operation to get data
end
endtask
1) 10 write operations.
initial
repeat(10)
write($random,$random);
2) Alternate read and write operations.
initial
repeat(10)
begin
write($random,$random);
read($random,data);
end
function [7:0] getbyte;
input [15:0] address;
begin
<说明语句> //从地址字中提取低字节的程序
getbyte = result_expression;
end
endfunction
![自动化读取测试结果以及自动化输入激励](https://img-blog.csdnimg.cn/20210329171803433.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM3NDk0Nzg=,size_16,color_FFFFFF,t_70)
三、时钟生成
时钟可以有多种生成方式如
- 直接生成占空比50%的时钟
initial clk = 0;
always #10 clk = ~clk;
always begin
clk = 0;#10;
clk = 1;#10;
end
always begin
clk = 0;
forever #10 clk = ~clk;
end
时间延时可以使用参数代替方便随时改
module Tb();
reg clock;
integer no_of_clocks;
parameter CLOCK_PERIOD = 5;//
// ·defin CLOCK_PERIOD 5
initial no_of_clocks = 0;
initial clock = 1'b0;
always #(CLOCK_PERIOD/2) clock = ~clock;
//always #(`CLOCK_PERIOD/2) clock = ~clock;
always@(posedge clock)
no_of_clocks = no_of_clocks +1 ;
initial begin
#50000;
$display("End of simulation time is %d , total number of clocks seen is %d expected is %d",$time,no_of_clocks,($time/5));
$finish;
end
endmodule
输出结果End of simulation time is 50000 , total number of clocks seen is 125000 expected is 10000
这是因为5/2结果为2,而不是2.5,此时周期为4,所以可以累加125000次
always #(CLOCK_PERIOD/2.0) clock = ~clock;
修改除数为2.0,此时会得到2.5,编译器会进行3舍5入,导致此时周期为6。所以最终显示结果为
End of simulation time is 50000 , total number of clocks seen is 8333 expected is 10000
`timescale time_unit base / precision base
time_unit base:时间单位
precision base:时间精度
`timescale 1ns/100ps
always begin
#(CLOCK_PERIOD/3.0) clock = 1'b0;
#(CLOCK_PERIOD - CLOCK_PERIOD/3.0) clock = 1'b1;
end
此时5/3约为1.666单位为1ns,所以周期为1.666ns,但是因为时间精度为0.1ns,所以最终结果为1.7ns
同理(CLOCK_PERIOD - CLOCK_PERIOD/3.0)为3.3ns最终用输出为End of simulation time is 50000 , total number of clocks seen is 9999 expected is 10000
NOTE: Simulation with timescale 1ns/1ns is faster than
timescale 1ns/10ps
A simulation using a timescale 10ns/10ns and with
timescale 1ns/1ns will take same time.
生成占空比不为50%,可以使用如下方式生成
parameter CLK_PERIOD = 10;
parameter DUTY_CYCLE = 60; //60% duty cycle
parameter TCLK_HI = (CLK_PERIOD*DUTY_CYCLE/100);
parameter TCLK_LO = (CLK_PERIOD-TCLK_HI);
reg clk;
initial
clk = 0;
always
begin
#TCLK_LO;
clk = 1'b1;
#TCLK_HI;
clk = 1'b0;
end
生成抖动时钟
initial clock = 1'b0;
always clock = #1 ~clock;
jitter = $random() % range;
assign jittered_clock = #(jitter) clock;
//With the above approace,over all clock period is increased. A better approach for clock divider is as follows
//
parameter DELAY = TIMEPERIOD/2.0 - range/2.0;
initial clock = 1'b0;
always
begin
jitter = $dist_uniform(seed,0,jitter_range);
#(DELAY + jitter) clock = ~clock;
end
EXAMPLE:Clock multipler with N times multiplication
initial i = 0;
always @( base_clock ) begin
i = i % N;
if (i == 0) derived_clock = ~derived_clock;
i = i + 1;
end
EXAMPLE:Clock division with N times division
initial begin
derived_clock = 1'b0;
period = 10; // for initial clock
forever derived_clock = #(period/(2N)) ~ derived_clock;
end
always@(posedge base_clock)
begin
T2 = $realtime;
period = T2 - T1;
T1 = T2;
end