异步fifo的UVM验证(最终最终版)

写在前文:我胡汉三又来更新csdn了。今年的秋招真的一言难尽啊。。。面了好多公司,可惜本人是个社恐,一跟面试官聊天就啥也不会了。。。到现在还是0 offer。。。哎,后面的阶段就准备去做几个fpga的项目实在不行卷fpga岗不去卷ic岗了。。。

好了,现在说一下本次更新的主要内容:

  • 更新底层的driver,monitor代码,优化了一些之前的逻辑,提高代码可读性。
  • 更新了refermodule,scoreboard

 更新后的driver代码:

`ifndef FIFO_DRIVER__SV
`define FIFO_DRIVER__SV
`include "fifo_transaction.sv"
  
class fifo_driver extends uvm_driver#(fifo_transaction);
	virtual fifo_if vif;
	
	`uvm_component_utils(fifo_driver)
	
	function new(string name = "fifo_driver",uvm_component parent = null);
		super.new(name,parent);
	endfunction
	
	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		`uvm_info("fifo_driver","build_phase is called",UVM_LOW)
		if(!uvm_config_db#(virtual fifo_if)::get(this,"","vif",vif))
		`uvm_fatal("fifo_driver","vif must be set")
	endfunction
  
	extern task main_phase(uvm_phase phase);
	extern task drive_one_pkt(fifo_transaction);
	
endclass

task fifo_driver::main_phase(uvm_phase phase);
	`uvm_info("fifo_driver","main_phase is called",UVM_LOW)
	
	while(1) begin
	  @(posedge vif.wclk);
	  if(!vif.wfull && vif.wreset_b == 1) begin
		seq_item_port.get_next_item(req);
		drive_one_pkt(req);
		//`uvm_info("fifo_driver",$sformatf("drive one data:%d at %d",vif.wdata,$time),UVM_LOW)
		seq_item_port.item_done();
	  end
	  else begin
		vif.wdata <= vif.wdata;
	  end
	end
	
endtask

task fifo_driver::drive_one_pkt(fifo_transaction tr);
	
	bit[31:0] data_q;
	
	data_q 		= tr.data;
	vif.wdata	= data_q ;
	
endtask
`endif

更新后的monitor代码:

`ifndef FIFO_MONITOR__SV
`define FIFO_MONITOR__SV
`include "fifo_transaction.sv"

class fifo_monitor extends uvm_monitor;
	
	`uvm_component_utils(fifo_monitor)
	virtual fifo_if vif;
	
	uvm_analysis_port#(fifo_transaction) ap;
	
	function new(string name = "fifo_monitor",uvm_component parent = null);
		super.new(name,parent);
	endfunction
	
	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		`uvm_info("fifo_monitor","build_phase is called",UVM_LOW)
		if(!uvm_config_db#(virtual fifo_if)::get(this,"","vif",vif))
			`uvm_fatal("fifo_monitor","vif must be set")
		ap = new("ap",this);
	endfunction
	
	extern task main_phase(uvm_phase phase);
	extern task collect_one_pkt(fifo_transaction);
endclass


task fifo_monitor::main_phase(uvm_phase phase);
	fifo_transaction tr;
	
	/* repeat(100) begin
	tr = new("tr");
	collect_one_pkt(tr);
	end */
	
	while(1) begin
		@(posedge vif.wclk);
		#0.001;
		if(!vif.wfull && vif.wreset_b == 1) begin
			tr = new("tr");
			collect_one_pkt(tr);
			#0.004;
			ap.write(tr);
		end
	end
	
endtask

task fifo_monitor::collect_one_pkt(fifo_transaction tr);
	
	bit[31:0] data_q;
	
	data_q  = vif.wdata ;
	tr.data = data_q    ;
	//tr.my_print();
endtask


//---------------------------------------------------------

class fifo_monitor_out extends uvm_monitor;
	`uvm_component_utils(fifo_monitor_out)
	virtual fifo_if vif;
	uvm_analysis_port#(fifo_transaction) ap;
	function new(string name = "fifo_monitor_out",uvm_component parent = null);
		super.new(name,parent);
	endfunction
	
	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		`uvm_info("fifo_monitor_out","build_phase is called",UVM_LOW)
		if(!uvm_config_db#(virtual fifo_if)::get(this,"","vif",vif))
			`uvm_fatal("fifo_monitor_out","vif must be set")
		ap = new("ap",this);
	endfunction
	
	extern task main_phase(uvm_phase phase);
	extern task collect_one_pkt(fifo_transaction);
endclass

task fifo_monitor_out::main_phase(uvm_phase phase);
	fifo_transaction tr;
	
	/* repeat(100) begin
	tr = new("tr");
	collect_one_pkt(tr);
	end */
	
	while(1) begin
		@(posedge vif.rclk);
		#0.001;
		if(!vif.rempty && vif.rreset_b == 1) begin
			tr = new("tr");
			collect_one_pkt(tr);
			ap.write(tr);
		end
	end
	
endtask

task fifo_monitor_out::collect_one_pkt(fifo_transaction tr);
	
	bit[31:0] data_q;

	data_q  = vif.rdata ;
	tr.data = data_q    ;
	//tr.print();

endtask
`endif

对于driver的更新主要是由于之前的逻辑很混乱,有很多的逻辑判断是重复无效的。这次变得简洁一点。

对于monitor的更新是之前直接输出vif.rdata,现在采用接受fifo_transaction的方式来收集数据。

fifo_refermodule

`ifndef FIFO_REFERMODULE__SV
`define FIFO_REFERMODULE__SV
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "fifo_transaction.sv"
class fifo_refermodule extends uvm_component;

	`uvm_component_utils(fifo_refermodule)
	
	uvm_blocking_get_port#(fifo_transaction) port;
	uvm_analysis_port#(fifo_transaction)	 ap  ;
	
	function new(string name = "fifo_refermodule",uvm_component parent = null);
		super.new(name,parent);
	endfunction
	
	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		port = new("port",this);
		ap = new("ap",this);
	endfunction
	
	virtual task main_phase(uvm_phase phase);
		fifo_transaction tr		;
		fifo_transaction tr_out	;
		super.main_phase(phase);
		while(1)begin
			port.get(tr);
			tr_out = new("tr_out");
			tr_out.copy(tr);
			//tr_out.mdl_print();
			#0.001;
			ap.write(tr_out);
		end
	endtask
endclass



`endif

refermodule的代码逻辑比较简单,从输入agent中,接收到一个data,然后复制到一个新的tr中,直接发送给scoreboard当作期望值 

fifo_scoreboard

`ifndef FIFO_SCOREBOARD__SV
`define FIFO_SCOREBOARD__SV
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "fifo_transaction.sv"
class fifo_scoreboard extends uvm_scoreboard;

	`uvm_component_utils(fifo_scoreboard)
	
	uvm_blocking_get_port#(fifo_transaction) exp_port;
	uvm_blocking_get_port#(fifo_transaction) act_port;
	
	fifo_transaction expect_quene[$];
	
	function new(string name =  "fifo_scoreboard",uvm_component parent = null);
		super.new(name,parent);
	endfunction
	
	virtual function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		exp_port = new("exp_port",this);
		act_port = new("act_port",this);
	endfunction
	
	virtual task main_phase(uvm_phase phase);
		fifo_transaction  get_expect,get_actual,tmp_exp;

		bit result;
		super.main_phase(phase);
		fork
			while(1) begin
				exp_port.get(get_expect);
				expect_quene.push_back(get_expect);

			end 
			
			while(1) begin
				//exp_port.get(get_expect);
				//expect_quene.push_back(get_expect);
				act_port.get(get_actual);
				//`uvm_info("fifo_scoreboard",$sformatf("get actual is %d at %d",get_actual.data,$time),UVM_LOW)
				if(expect_quene.size() && get_actual.data > 0) begin
					tmp_exp = expect_quene.pop_front();
					result = get_actual.compare(tmp_exp);
					if(result)
						`uvm_info("fifo_scoreboard","compare successful!",UVM_LOW)
					else begin
						`uvm_info("fifo_scoreboard","compare falled!",UVM_LOW)
						$display("the expect data is:");
						tmp_exp.my_print();
						$display("the actual data is:");
						get_actual.my_print();
					end	
				end // expect_quene.size > 0
				else begin
					`uvm_error("fifo_scoreboard","expect_quene is empty!")
					$display("the actual data is:");
					//tmp_act.my_print();
				end
			end
		join
	endtask
endclass

`endif

scoreboard的作用是接收refermodule的数据作为期望值,接收输出agent的值作为实际值,进行比较,为1则输出successful,否则输出fall。这里有一个注意的点是我的dut在reset之后,rdata有一个初始的值0,所以我加入了一个判断条件get_actual.data > 0 ,但这样的问题是假如后续传输值有0 会产生判断错误。这个bug还没修。。。

逻辑比较简单,这里面主要用到的知识还是tlm通信的内容。

我才用了这几个类型的port:

analysis port

blocking get port

tlm_fifo port

我个人是把tlm_fifo当作一个万能转接头。如果你用analys或者bg port 需要写一个write函数。用tlm_fifo口的话代码看着也整洁,还省事。

analysis主要是作为一个广播口,不需要考虑阻塞非阻塞,也没有put get操作,只有一个write函数。用起来很方便。

当然直接用put get 端口也能连,我测试过是可以用的,效果也不错。根据个人爱好以及实际使用需求来更改即可。

然后别的东西也有一些小的改动就不全部放了,有需要的可以去我的gitee上自取。

最后的最后,后续看情况会更新一个covergroup吧~

祝各位秋招顺利~

  • 6
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 46
    评论
异步FIFO是一种常见的硬件设计模块,用于在不同的时钟域之间传输数据。UVM(Universal Verification Methodology)是一种用于验证硬件设计的方法学。在UVM验证中,验证工程师可以使用UVM中提供的各种类和方法来验证异步FIFO的功能和正确性。 下面是一个简单的UVM验证异步FIFO的示例: 首先,我们需要创建一个Transaction类来表示FIFO中的数据项。这个类可以包含需要验证的数据字段。 然后,我们创建一个Agent类来模拟FIFO的发送和接收端。这个Agent类可以包含两个接口,一个用于发送数据到FIFO,另一个用于从FIFO接收数据。Agent类还可以包含一个Monitor来监视FIFO的状态,并将收到的数据转换为Transaction对象。 接下来,我们创建一个Sequencer类来生成数据项并将其发送到FIFO的发送端口。Sequencer类可以使用UVM提供的随机化机制来生成不同的数据项。 然后,我们创建一个Driver类来驱动Sequencer生成的数据项,并将其发送到FIFO的发送端口。 最后,我们可以创建一个Test类来实例化和连接上述组件,并编写测试用例来验证异步FIFO的功能和正确性。 在验证过程中,我们可以使用UVM提供的各种断言和功能覆盖率工具来验证异步FIFO的正确性。通过生成不同的测试用例和使用各种场景和边界条件,我们可以尽可能地覆盖所有可能的情况,并验证异步FIFO的正确性。 需要注意的是,上述只是一个简单的UVM验证异步FIFO的示例,实际的验证过程可能更为复杂,需要根据具体的设计和需求进行调整和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值