【UVM】TLM通信之scorboard与reference_model


本文目标

使用 TLM端口 实现 scoreboard 组件与 reference_model 组件之间的连接!


一、总体 / 局部结构

UVM验证平台总体框图如下所示,紫色圆圈包围的即是本文探讨的唯一重点:
在这里插入图片描述

1、总体结构分析

自动比对 是验证流程中不可或缺的一项重要功能。其具体 实现方法 结合图示为:

1. 在 master_agent 中的 monitor 是将 DUT 端口上的输入信号进行采集并在 reference_model中通过计算输出结果;
2. 得到的输出结果经过 r2s_fifo (reference to scoreboard 各取首字母发音即 r2s ) 缓存并送至 Scoreboard ;
3. 另一方面在 slave_agent 中的 monitor 是将 DUT 端口上的输出信号进行采集并缓存至 s_a2s_fifo (slave_agent to scoreboard 各取首字母发音即 s_a2s );
4. 将 s_a2s_fifo 中 DUT 的输出数据也传入至 Scoreboard 并与第 2 步的数据进行自动比对

2、局部结构分析

在这里插入图片描述

Tips:(编号1~12后文会使用)

  1. m2s_port [ monitor(out) to scoreboard—port]
  2. s_a2s_export [slave_agent to scoreboard—export]
  3. s_a2s_fifo.blocking_put_export [此处是 put 模式—注意是import ]
  4. s_a2s_fifo.blocking_get_export [此处是 get 模式—注意是import ]
  5. s_a2s_port [slave_agent to scoreboard—port]
  6. m2r_port [ monitor(in) to reference_model—port]
  7. m_a2r_export [master_agent to reference_model—export]
  8. m_a2r_imp [master_agent to reference_model—import]
  9. ref_model.r2s_port [reference_model to scoreboard—port]
  10. r2s_fifo.blocking_put_export [此处是 put 模式—注意是import ]
  11. r2s_fifo.blocking_get_export [此处是 get 模式—注意是import ]
  12. sb.r2s_port [reference_model to scoreboard—port]

一、输入 端口路线分析(紫色箭头
- < ① > DUT -> monitor 是由 interface 产生的 virtual 句柄进行的数据传递,此处不在讨论范围内;
- < ② > 我们应首先主动地将数据发送至 reference_model 中,此时 monitor 为主动发起者, reference_model 为被动接收方,控制流为 monitor (port)流向 reference_model ,数据流 为 monitor 流向 reference_model ,在数据由 monitor 传向 reference_model 的过程中,需穿越 master_agent (export),因此需在 master_agent.sv 中将二者进行连接,即 m_moni.m2r_port.connect(this.m_a2r_export);编号6~7】;
- < ③ > 将经过 master_agent (export)传出的数据传入至 reference_model (import)中,因其二者需在 env.sv 中进行连接,即 m_agent.m_a2r_export.connect(ref_model.i_m2r_imp)编号7~8】;
- < ④ > 从 reference_model (port)中传出的数据通过 put() 方法传入至 r2s_fifo (import)中,此时 reference_model 为主动发起者, r2s_fifo 为被动接收方,控制流为 reference_model (port)流向 r2s_fifo (import),数据流 为 reference_model 流向 r2s_fifo ,因此这里使用 put() 方法。因其二者是在 env.sv 中进行连接,即 ref_model.r2s_port.connect(this.r2s_fifo.blocking_put_export)编号9~10】;
- < ⑤ > 存放在 r2s_fifo 中的数据不会主动传递至 scoreboard ,而是需等待(阻塞)scoreboard 的命令后才会将数据发送出去,此时 scoreboard 是主动方, r2s_fifo 为被动方, 控制流 为 scoreboard (port)流向 r2s_fifo (import),数据流 为r2s_fifo 流向 scoreboard ,因此应使用 get() 方法。其二者是在 env.sv 中进行连接,即 sb.r2s_port.connect(this.r2s_fifo.blocking_get_export);编号11~12】。

二、输出 端口路线分析(绿色箭头
- < ① > DUT -> monitor 是由 interface 产生的 virtual 句柄进行的数据传递,此处不在讨论范围内;
- < ② > 我们应首先主动将数据存入至 FIFO 中,此时 monitor 为主动发起者,s_a2s_fifo 为被动接收方,控制流为 monitor (port)流向 s_a2s_fifo ,数据流 为 monitor 流向 s_a2s_fifo ,在数据由 monitor 传向 s_a2s_fifo 的过程中,需穿越 slave_agent (export),因此在 slave_agent.sv 中将二者进行连接,即 m_moni.m2s_port.connect(this.s_a2s_export);编号1~2】;
- < ③ > 从 slave_agent (export)中传出的数据通过 put() 方法传入至 s_a2s_fifo (import)中,其二者是在 env.sv 中进行连接,即 s_agent.s_a2s_export.connect(this.s_a2s_fifo.blocking_put_export);编号2~3】;
- < ④ > 存放在 s_a2s_fifo 中的数据不会主动传递至 scoreboard ,而是需等待(阻塞)scoreboard 的命令后才会将数据发送出去,此时 scoreboard 是主动方, s_a2s_fifo 为被动方, 控制流 为 scoreboard (port)流向 s_a2s_fifo (import),数据流 为 s_a2s_fifo 流向 scoreboard ,因此应使用 get() 方法。其二者是在 env.sv 中进行连接,即 sb.s_a2s_port.connect(this.s_a2s_fifo.blocking_get_export);编号4~5】。

二、通信步骤

1、输入路线

1)新建in_monitor.sv文件(输入路线①)

代码如下(示例):

//in_monitor扩展于uvm_monitor
class in_monitor extends uvm_monitor;

//添加port(参数为传输事务的类型)
	uvm_blocking_put_port #(my_transaction) m2r_port;

//实例化port对象
	function new(string name = "",uvm_component parent);
		super.new(name , parent);
		this.m2r_port = new("m2r_imp",this);
	endfunction

//将monitor发送的事务打印出来
	virtual task run_phase(uvm_phase phase);
		....//循环发送至reference_model
		`uvm_info("Monitor","Now monitor send the transaction to the reference model!",UVM_MEDIUM)

//调用put()方法发送transaction	
		this.m2r_port.put(tr);
	endtask
	
endclass

2)新建master_agent.sv文件(输入路线②)

代码如下(示例):

//master_agent扩展于uvm_agent
class master_agent extends uvm_agent;
	...
//添加export(参数为传输事务的类型)
	uvm_blocking_put_export #(my_transaction) m_a2r_export;

//实例化export对象
	function new(string name = "",uvm_component parent);
		super.new(name , parent);
		this.m_a2r_export = new("m_a2r_export",this);
	endfunction

//连接monitor的port和master_agent的export
	virtual function void connect_phase(uvm_phase phase);
		if(is_active == UVM_ACTIVE)
			m_driv.seq_item_port.connect(m_seqr.seq_item_export);
			m_moni.m2r_port.connect(this.m_a2r_export);//核心
	endtask
	
endclass

3)新建my_reference_model.sv文件(输入路线③)

class my_reference_model extends uvm_component;
	
	`uvm_component_utils(my_reference_model)
	
	uvm_blocking_put_imp #(my_transaction,my_reference_model) i_m2r_imp;
	uvm_blocking_put_port #(my_transaction) r2s_port;
	my_transaction	item;
	
	function new(string name = "",uvm_component parent);
		super.new(name,parent);
		this.i_m2r_imp 	= new("i_m2r_imp",this)	;
		this.r2s_port 	= new("r2s_port",this)	;
	endfunction

	task put(my_transaction tr);
		`uvm_info("REF_REPORT",{"\n","master agent have been sent a transaction :\n",tr.sprint()},UVM_MEDIUM);
		this.r2s_port.put(tr);
	endtask
endclass 

4)新建my_env.sv文件(输入路线④、⑤)

代码如下(示例):

class my_env extends uvm_env;
	`uvm_component_utils(my_env)
	
	master_agent 	m_agent		;
	slave_agent		s_agent		;	
	env_config		m_env_cfg	;
	
	my_reference_model ref_model;
	my_scoreboard	sb;
	
	uvm_tlm_analysis_fifo#(my_transaction) r2s_fifo		;
	uvm_tlm_analysis_fifo#(my_transaction) s_a2s_fifo	;
	
	function new(string name = "",uvm_component parent);
		super.new(name,parent);
		this.r2s_fifo 	= new("r2s_fifo",this)	;
		this.s_a2s_fifo = new("s_a2s_fifo",this);
	endfunction

	virtual function void build_phase(uvm_phase phase);
		super.bulid_phase(phase);
		
		if(!uvm_config_db#(env_config)::get(this,"","env_cfg",m_env_cfg))begin
			`uvm_fatal("CONFIG_FATAL","ENV can not get the configuration !!!")
		end
		uvm_config_db#(agent_config)::set(this,"m_agent","m_agent_cfg",m_env_cfg.m_agent_cfg);
		uvm_config_db#(agent_config)::set(this,"s_agent","m_agent_cfg",m_env_cfg.m_agent_cfg);
		
		if(m_env_cfg.is_coverage)begin
			`uvm_info("COVERAGE_ENABLE","The function coverage is enable for this testcase",UVM_MEDIUM)
		end
		if(m_env_cfg.is_check)begin
			`uvm_info("CHECK_ENABLE","The check function is enable for this testcase",UVM_MEDIUM)		
			sb = my_scoreboard::type_id::create("sb",this);
		end
		
		m_agent = master_agent::type_id::create("m_agent",this);
		s_agent = slave_agent::type_id::create("s_agent",this);
		ref_model = my_reference_model::type_id::create("ref_model",this);
	endfunction
	
	virtual function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		`uvm_info("ENV","Connect the agent and reference model...",UVM_MEDIUM)
		m_agent.m_a2r_export.connect(ref_model.i_m2r_imp);
		s_agent.s_a2s_export.connect(this.s_a2s_fifo.blocking_put_export);
		ref_model.r2s_port.connect(this.r2s_fifo.blocking_put_export); //输入4
		if(m_env_cfg.is_check)begin
			sb.r2s_port.connect(this.r2s_fifo.blocking_get_export); //输入5
			sb.s_a2s_port.connect(this.s_a2s_fifo.blocking_get_export);
		end
	endfunction
endclass

2、输出路线

1)新建out_monitor.sv文件(输出路线①)

代码如下(示例):

class out_monitor extends uvm_monitor;  //out_monitor:DUT输出端口传输至的组件
	`uvm_component_utils(out_monitor)  //是组件,就要注册
		//用于连接DUT的输出端口
		virtual dut_interface m_vif;
		//添加port
		uvm_blocking_put_port #(my_transaction) m2s_port; //monitor to scoreboard
		
		function new(string name = "",uvm_component parent);
			super.new(name,parent);
			this.m2s_port = new("m2s_port",this);
		endfunction
		
		virtual function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			`uvm_info("TRACE",$sformatf("%m"),UVM_HIGH)
			if(!uvm_config_db#(virtual dut_interface)::get(this,"","vif",m_vif))begin
				uvm_fatal("CONFIG_FATAL","Out Monitor can not get the interface !!!")
			end
		endfunction
		//监测DUT输出信号
		virtual task run_phase(uvm_phase phase);
			my_transaction tr;
			int 		active_port	;
			logic [7:0] temp		;
			int 		count		;
			
			forever begin
				active_port = -1;
				count		= 0	;
				
				tr = my_transaction::type_id::create("tr");
				
				//wait for bus active
				while(1)begin
					@(m_vif.omonitor_cb);
					foreach(m_vif.omonitor_cb.frameo_n[i])begin
						if(m_vif.omonitor_cb.frameo_n[i] == 0)begin
							active_port = i;
						end
					end
					if(active_port != -1)begin
						break;
					end
				end
				//Active port has been Detected
				tr.da = active_port;
			end
			
			forever begin
				if(m_vif.omonitor_cb.valido_n[tr.da] == 0)begin
					temp[count] = m_vif.omonitor_cb.dout[tr.da];
					count++;
					if(count == 8)begin
						tr.payload.push(temp);
						count = 0;
					end
				end
				if(m_vif.omonitor_cb.frameo_n[tr.da])begin
					if(count != 0)begin
						tr.payload.push_back(temp);
						`uvm_warning("PAYLOAD_WARNING","Payload not byte aliged!!!")
					end
					break;
				end
				@(m_vif.omonitor_cb);
			end
			
			`uvm_info("Out_Monitor",{"\n","Out monitor Got An Output Transaction: \n",tr.sprint()},UVM_MEDIUM)
			`uvm_info("Out_Monitor","Now Out monitor send the transaction to the Scoreboard",UVM_MEDIUM)
			this.m2s_port.put(tr);
		endtask
endclass

2)新建salve_agent.sv文件(输出路线②)

class slave_agent extends uvm_agent;
	`uvm_component_utils(slave_agent) //注册
		
		out_monitor m_moni;   //声明 out_monitor 句柄
		
		agent_config m_agent_cfg;
		
		uvm_blocking_put_export #(my_transaction) s_a2s_export;  //slave_agent to scoreboard
		
		function new(string name = "",uvm_component parent);
			super.new(name,parent);
			this.s_a2s_export = new("s_a2s_export",this);
		endfunction
		
		virtual function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			
			if(!uvm_config_db#(agent_config)::get(this,"","m_agent_cfg",m_agent_cfg))begin
				`uvm_fatal("CONFIG_FATAL","slave_agent can not get the configuration !!!")
			end
			
			uvm_config_db#(virtual dut_interface)::set(this,"m_moni","vif",m_agent_cfg.vif);
			
			m_moni = out_monitor::type_id::create("m_moni",this);
		endfunction
		
		virtual function void connect_phase(uvm_phase phase);
			m_moni.m2s_port.connect(this.s_a2s_export);
		endfunction
endclass

3)新建my_scoreboard.sv文件(输出路线④)

class my_scoreboard extends uvm_scoreboard;
	
	`uvm_component_utils(my_scoreboard)

		uvm_blocking_get_port #(my_transaction) r2s_port	;
		uvm_blocking_get_port #(my_transaction) s_a2s_port	;
		
		function new(string name = "",uvm_component parent);
			super.new(name,parent);
			r2s_port 	= new("r2s_port",this)	;
			s_a2s_port 	= new("s_a2s_port",this);
		endfunction
		
		virtual task run_phase();
			my_transaction		dut_output_tr	;
			my_transaction		expected_tr		;
			forever begin
				`uvm_info("SCOREBOARD","Now waiting for getting the transaction from slave agent and reference model",UVM_MEDIUM)
				fork
					r2s_port.get(expected_tr);
					s_a2s_port.get(dut_output_tr);
				join
				`uvm_info("CHECK","Dut has completed a transaction.Now check the output ...",UVM_MIDIUM)
				
				if(expected_tr.compare(dut_output_tr))begin
					`uvm_info("CHECK","Check is done.The result matches the expected value!",UVM_MEDIUM)
				end
				else begin
					`uvm_info("CHECK_ERROR","Checking is done.But the result does not match the expected value!Please check your DUT!",UVM_MEDIUM)
				end
			end
		endtask
endclass

4)新建my_env.sv文件(输出路线③、④)

代码如下(示例):

class my_env extends uvm_env;
	`uvm_component_utils(my_env)
	
	master_agent 	m_agent		;
	slave_agent		s_agent		;	
	env_config		m_env_cfg	;
	
	my_reference_model ref_model;
	my_scoreboard	sb;
	
	uvm_tlm_analysis_fifo#(my_transaction) r2s_fifo		;
	uvm_tlm_analysis_fifo#(my_transaction) s_a2s_fifo	;
	
	function new(string name = "",uvm_component parent);
		super.new(name,parent);
		this.r2s_fifo 	= new("r2s_fifo",this)	;
		this.s_a2s_fifo = new("s_a2s_fifo",this);
	endfunction

	virtual function void build_phase(uvm_phase phase);
		super.bulid_phase(phase);
		
		if(!uvm_config_db#(env_config)::get(this,"","env_cfg",m_env_cfg))begin
			`uvm_fatal("CONFIG_FATAL","ENV can not get the configuration !!!")
		end
		uvm_config_db#(agent_config)::set(this,"m_agent","m_agent_cfg",m_env_cfg.m_agent_cfg);
		uvm_config_db#(agent_config)::set(this,"s_agent","m_agent_cfg",m_env_cfg.m_agent_cfg);
		
		if(m_env_cfg.is_coverage)begin
			`uvm_info("COVERAGE_ENABLE","The function coverage is enable for this testcase",UVM_MEDIUM)
		end
		if(m_env_cfg.is_check)begin
			`uvm_info("CHECK_ENABLE","The check function is enable for this testcase",UVM_MEDIUM)		
			sb = my_scoreboard::type_id::create("sb",this);
		end
		
		m_agent = master_agent::type_id::create("m_agent",this);
		s_agent = slave_agent::type_id::create("s_agent",this);
		ref_model = my_reference_model::type_id::create("ref_model",this);
	endfunction
	
	virtual function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		`uvm_info("ENV","Connect the agent and reference model...",UVM_MEDIUM)
		m_agent.m_a2r_export.connect(ref_model.i_m2r_imp);
		s_agent.s_a2s_export.connect(this.s_a2s_fifo.blocking_put_export);//输出3
		ref_model.r2s_port.connect(this.r2s_fifo.blocking_put_export);
		if(m_env_cfg.is_check)begin
			sb.r2s_port.connect(this.r2s_fifo.blocking_get_export);
			sb.s_a2s_port.connect(this.s_a2s_fifo.blocking_get_export);//输出4
		end
	endfunction
endclass

三、生成 .log 文件

在这里插入图片描述

  • 10
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的砰砰砰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值