TLM端口实验学习

这篇博客详细介绍了如何在UVM验证环境中将mailbox替换为TLM端口进行通信,包括uvm_blocking_put_port和uvm_blocking_imp的使用,以及在不同组件间的连接和交互过程。内容涵盖了端口声明、例化、连接和数据传输的实现,强调了在多向通信中避免方法冲突的方法,并展示了在refmod和mcdf_checker中如何处理不同类型transaction的获取和比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验的整体架构如下:
在这里插入图片描述

实验首先是将mcdf_checker和monitor之间交流的mailbox修改为tlm端口。
tlm通信是基于transaction的一种通信方式,有port,export,imp三种。
reg_agent,fmt_agent,chnl_agent通过mailbox向mcdf_checker中传输transaction。我们暂时不将5个mailbox替换成tlm_fifo,仍保留为Mailbox。
在reg_agent,fmt_agent,chnl_agent中先声明了uvm_blocking_put_port,在build_phase方法中对port进行例化,由于uvm_port_base继承于uvm_void,采用new()进行声明。并且在run_phase中将mailbox的put方式修改为port的put方式。

mon_mb.put(m)
mon_bp_port.put(m);

同时,在mcdf_checker中声明了uvm_blocking_imp。这其中存在多个put方法相互干扰。应对这种多向通信,一般采用宏声明。SFX即是后缀,用以区分不同imp端口以及他们的put方法。这里注意的是,port引用put方法不需要加后缀,但是imp对于put方法的定义需要加后缀,要保持一致。

`uvm_blocking_put_port_decl(SFX)

在对于imp端口的声明中,由于理解模糊,犯了如下的错。

uvm_blocking_put_imp_chnl0 #(mon_data_t,this) chnl0_bp_imp;

对于imp的声明需要两个参数类,一个是传输的transaction的类型,一个是uvm_component的类型,this其实只得是当前所处的uvm_component的对象,导致了报错,后来修改成了如下。

uvm_blocking_put_imp_chnl0 #(mon_data_t,mcdf_checker) chnl0_bp_imp;

同样需要在build_phase中对imp端口进行例化,同时对于保留的mailbox也需要进行例化。
下图为imp的例化,arg分别为string和uvm_component

reg_bp_imp = new("reg_bp_imp",this);
chnl0_bp_imp = new("chnl0_bp_imp",this);
chnl1_bp_imp = new("chnl1_bp_imp",this);
chnl2_bp_imp = new("chnl2_bp_imp",this);
fmt_bp_imp = new("fmt_bp_imp",this);

对于mailbox的例化是之前的知识。对于imp方法的定义比较简单,就是将transaction写入到mailbox中。之后需要在更高一级的uvm_env中将众多agent的put_port和uvm_checker的put_imp端口进行连接,在connect_phase中进行。

this.reg_agt.monitor.mon_bp_port.connect(this.chker.reg_bp_imp);
this.fmt_agt.monitor.mon_bp_port.connect(this.chker.fmt_bp_imp);
this.chnl_agts[0].monitor.mon_bp_port.connect(this.chker.chnl0_bp_imp);
this.chnl_agts[1].monitor.mon_bp_port.connect(this.chker.chnl1_bp_imp);
this.chnl_agts[2].monitor.mon_bp_port.connect(this.chker.chnl2_bp_imp);

同样,在refmod中需要根据reg_mb获得的reg_transaction,从相应的chnl_mb中获得对应的chnl_transaction。我们现在refmod中将in_mb改成uvm_blocking_get_peek_port,需要注意reg_bp_port只需要get到事务transaction。

uvm_blocking_get_port #(reg_trans) reg_bg_port;
uvm_blocking_get_peek_port #(mon_data_t) chnl_bg_port[3];

在build_phase阶段对相应的port进行例化。

reg_bg_port = new("reg_bg_port",this);
chnl_bg_port[0] = new("chnl_bg_port[0]",this);
chnl_bg_port[1] = new("chnl_bg_port[1]",this);
chnl_bg_port[2] = new("chnl_bg_port[2]",this);

并且在run_phase阶段,通过一系列方法do_reg_update()和do_packet()获取mailbox中的transaction,存放在tlm_fifo中。
需要声明对应的uvm_get_peek_imp,这里要注意参数类。

uvm_blocking_get_peek_imp_chnl0 #(mon_data_t,mcdf_checker) chnl0_bg_imp;
uvm_blocking_get_peek_imp_chnl1 #(mon_data_t,mcdf_checker) chnl1_bg_imp;
uvm_blocking_get_peek_imp_chnl2 #(mon_data_t,mcdf_checker) chnl2_bg_imp;
uvm_blocking_get_imp #(reg_trans,mcdf_checker) reg_bg_imp;

之后在build_phase对imp进行例化,并对相应的get,peek方法进行定义。
上面提到的tlm_fifos,是继承于uvm_component,它自带uvm_blocking_put/get/peek_imp,名称为blocking_put/get/peek_port,tlm_fifos也可以使用new()函数进行例化,前提是不需要使用override()。

foreach(this.out_tlm_fifos[i]) this.out_tlm_fifos[i] = new($sformatf("out_tlm_fifos[%d]",i),this);

为了获取tlm_fifos中的transaction,在do_data_compare()中与fmt_mb中的transaction作比较,在mcdf_checker中声明了3个uvm_blocking_get_port。

uvm_blocking_get_port #(fmt_trans) exp_bg_ports[3];

在build_phase阶段例化了三个port。

foreach(this.exp_bg_ports[i]) this.exp_bg_ports[i] = new($sformatf("exp_bg_ports[%d]",i),this);

在connect_phase阶段连接了三个port和tlm_fifos的export端口的连接

foreach(this.exp_bg_ports[i]) this.exp_bg_ports[i].connect(this.refmod.out_tlm_fifos[i].blocking_get_export);

在run_phase中通过do_data_compare()方法实现从tlm_fifos中取出数据,与fmt_mb中的数据进行比较。

this.fmt_mb.get(mont);
this.exp_bg_ports[mont.ch_id].get(expt);

以上也是整个环境中tlm端口的实验
这里之前有个疑惑,关于从chnl_mb中获取transaction时,采用的是uvm_blocking_get_peek_imp,原本我觉得没有必要,但是后来在do_packet方法中发现代码如下

this.chnl_bg_port[id].peek(it);
ot = new();
ot.length = 4 << (this.get_field_value(id, RW_LEN) & 'b11);
ot.data = new[ot.length];
ot.ch_id = id;
foreach(ot.data[m]) begin
   this.chnl_bg_port[id].get(it);
   ot.data[m] = it.data;
 end

理解为先从chnl_bg_port中获取到目标transaction的复制,并且根据reg_trans提供的length对ot进行例化,再将it的data一个一个赋值给ot.data,之所以这么做,是因为chnl_bg_port的传输对象transaction是mon_data_t,而fmt_mb传输对象transaction是fmt_trans,是打包后的对象类型。

fmt_trans ot;
mon_data_t it;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值