Verilog Verification

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)

三、时钟生成

时钟可以有多种生成方式如

  1. 直接生成占空比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 thantimescale 1ns/10ps
A simulation using a timescale 10ns/10ns and withtimescale 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值