一、TLM单向通信和多向通信
在之前的monitor到checker的通信,以及checker与reference model之间的通信,都是通过mailbox以及在上层进行其句柄的传递实现的。这次实验则使用TLM端口进行通信,做逐步的通信元素和方法的替换。
TLM通信结构框图
将monitor
中的用来与checker
中的mailbox
通信的mon_mb
句柄替换为对应的uvm_blocking_put_port
类型。
uvm_blocking_put_port #(mon_data_t) mon_bp_port;
在checker
中声明与monitor
通信的import
端口类型,以及reference model
通信的import
端口类型,由于checker
与多个monitor
以及reference model
通信,是典型的多方向通信类型,因此需要使用多端口通信的宏声明方法。在使用了宏声明端口类型之后,再在checker
中声明其句柄,并且完成例化。
//宏声明端口
`uvm_blocking_put_imp_decl(_chnl0)
`uvm_blocking_put_imp_decl(_chnl1)
`uvm_blocking_put_imp_decl(_chnl2)
`uvm_blocking_put_imp_decl(_fmt)
`uvm_blocking_put_imp_decl(_reg)
`uvm_blocking_get_peek_imp_decl(_chnl0)
`uvm_blocking_get_peek_imp_decl(_chnl1)
`uvm_blocking_get_peek_imp_decl(_chnl2)
`uvm_blocking_get_imp_decl(_reg)
//声明句柄
uvm_blocking_put_imp_chnl0 #(mon_data_t, mcdf_checker) chnl0_bp_imp;
uvm_blocking_put_imp_chnl1 #(mon_data_t, mcdf_checker) chnl1_bp_imp;
uvm_blocking_put_imp_chnl2 #(mon_data_t, mcdf_checker) chnl2_bp_imp;
uvm_blocking_put_imp_fmt #(fmt_trans , mcdf_checker) fmt_bp_imp ;
uvm_blocking_put_imp_reg #(reg_trans , mcdf_checker) reg_bp_imp ;
uvm_blocking_get_peek_imp_chnl0 #(mon_data_t, mcdf_checker) chnl0_bgpk_imp;
uvm_blocking_get_peek_imp_chnl1 #(mon_data_t, mcdf_checker) chnl1_bgpk_imp;
uvm_blocking_get_peek_imp_chnl2 #(mon_data_t, mcdf_checker) chnl2_bgpk_imp;
uvm_blocking_get_imp_reg #(reg_trans , mcdf_checker) reg_bg_imp ;
//例化
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);
reg_bp_imp = new("reg_bp_imp", this);
chnl0_bgpk_imp = new("chnl0_bgpk_imp", this);
chnl1_bgpk_imp = new("chnl1_bgpk_imp", this);
chnl2_bgpk_imp = new("chnl2_bgpk_imp", this);
reg_bg_imp = new("reg_bg_imp", this);
根据声明的import
端口类型,实现其对应的方法。
//实现put方法
task put_chnl0(mon_data_t t);
chnl_mbs[0].put(t);
endtask
task put_chnl1(mon_data_t t);
chnl_mbs[1].put(t);
endtask
task put_chnl2(mon_data_t t);
chnl_mbs[2].put(t);
endtask
task put_fmt(fmt_trans t);
fmt_mb.put(t);
endtask
task put_reg(reg_trans t);
reg_mb.put(t);
endtask
//实现get、peek方法
task peek_chnl0(output mon_data_t t);
chnl_mbs[0].peek(t);
endtask
task peek_chnl1(output mon_data_t t);
chnl_mbs[1].peek(t);
endtask
task peek_chnl2(output mon_data_t t);
chnl_mbs[2].peek(t);
endtask
task get_chnl0(output mon_data_t t);
chnl_mbs[0].get(t);
endtask
task get_chnl1(output mon_data_t t);
chnl_mbs[1].get(t);
endtask
task get_chnl2(output mon_data_t t);
chnl_mbs[2].get(t);
endtask
task get_reg(output reg_trans t);
reg_mb.get(t);
endtask
在mcdf_refmod
中声明用来与mcdf_checker
中的import
连接的端口,并且完成例化。完成声明和例化后,使用TLM端口呼叫方法。
//声明端口
uvm_blocking_get_port #(reg_trans) reg_bg_port;
uvm_blocking_get_peek_port #(mon_data_t) in_bgpk_ports[3];
//端口例化
reg_bg_port = new("reg_bg_port", this);
在mcdf_env
的connect_phase()
阶段,完成monitor
的TLM port与mcdf_checker
的TLM import的连接。
chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp);
chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp);
chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp);
reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp);
fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp);
在mcdf_env
的connect_phase()
阶段,完成refmod
的TLM port与mcdf_checker
的TLM import的连接。
refmod.in_bgpk_ports[0].connect(chnl0_bgpk_imp);
refmod.in_bgpk_ports[1].connect(chnl1_bgpk_imp);
refmod.in_bgpk_ports[2].connect(chnl2_bgpk_imp);
refmod.reg_bg_port.connect(reg_bg_imp);
二、TLM通信管道
TLM通信的优点:
- 通信函数可以定制化,例如可以定制
put()/get()/peek()
的内容和参数,这比mailbox的通信更加灵活。 - 将组件实现了完全的隔离,通过层次化的TLM端口连接,可以很好地避免直接将不同层次的数据缓存对象的句柄进行“空传递”。
如果使用TLM端口,并且不用实现具体的put()/get()/peek()
方法,可以使用uvm_tlm_fifo
类。
将原本在mcdf_refmod
中的out_mb
替换成uvm_tlm_fifo
类型,并且完成例化以及对应的变量名替换。
uvm_tlm_fifo #(fmt_trans) out_tlm_fifos[3];
//例化
foreach(out_tlm_fifos[i]) out_tlm_fifos[i] = new($sformatf("out_tlm_fifos[%0d]", i), this);
将原本在mcdf_checker
中的exp_mbs[3]
的邮箱句柄数组,替换为uvm_blocking_get_port
类型句柄数组,并且做相应的例化以及变量名替换。
uvm_blocking_get_port #(fmt_trans) exp_bg_ports[3];
在mcdf_checker
中,完成mcdf_checker
中的TLM port端口到mcdf_refmod
中的uvm_tlm_fifo
自带的blocking_get_export
端口的连接。
foreach(exp_bg_ports[i]) begin
exp_bg_ports[i].connect(refmod.out_tlm_fifos[i].blocking_get_export);
end
三、UVM回调类
将原有的mcdf_data_consistence_basic_test
和mcdf_full_random_test
的类库实现方式(即类继承方式)修改为毁掉函数的实现方式,所以类的复用除了可以使用继承,还可以使用回调函数。
在uvm_callback
类中,预先定义需要的虚方法。(定义)
typedef class mcdf_base_test;
class cb_mcdf_base extends uvm_callback;
`uvm_object_utils(cb_mcdf_base)
mcdf_base_test test;
function new (string name = "cb_mcdf_base");
super.new(name);
endfunction
virtual task cb_do_reg();
endtask
virtual task cb_do_formatter();
endtask
virtual task cb_do_data();
endtask
endclass
使用callback
对应的宏,完成目标uvm_test
类型与目标uvm_callback
类型的关联。(绑定)
`uvm_register_cb(mcdf_base_test, cb_mcdf_base)
在目标uvm_test
类型指定的方法中,完成uvm_callback
的方法回调指定。(插入)
// do register configuration
virtual task do_reg();
`uvm_do_callbacks(mcdf_base_test, cb_mcdf_base, cb_do_reg())
endtask
// do external formatter down stream slave configuration
virtual task do_formatter();
`uvm_do_callbacks(mcdf_base_test, cb_mcdf_base, cb_do_formatter())
endtask
// do data transition from 3 channel slaves
virtual task do_data();
`uvm_do_callbacks(mcdf_base_test, cb_mcdf_base, cb_do_data())
endtask
实现uvm_callback
和对应test
类的定义(添加)
class cb_mcdf_data_consistence_basic extends cb_mcdf_base;
`uvm_object_utils(cb_mcdf_data_consistence_basic)
function new (string name = "cb_mcdf_data_consistence_basic");
super.new(name);
endfunction
task cb_do_reg();
bit[31:0] wr_val, rd_val;
super.cb_do_reg();
// slv0 with len=8, prio=0, en=1
wr_val = (1<<3)+(0<<1)+1;
test.write_reg(`SLV0_RW_ADDR, wr_val);
test.read_reg(`SLV0_RW_ADDR, rd_val);
void'(test.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
// slv1 with len=16, prio=1, en=1
wr_val = (2<<3)+(1<<1)+1;
test.write_reg(`SLV1_RW_ADDR, wr_val);
test.read_reg(`SLV1_RW_ADDR, rd_val);
void'(test.diff_value(wr_val, rd_val, "SLV1_WR_REG"));
// slv2 with len=32, prio=2, en=1
wr_val = (3<<3)+(2<<1)+1;
test.write_reg(`SLV2_RW_ADDR, wr_val);
test.read_reg(`SLV2_RW_ADDR, rd_val);
void'(test.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
// send IDLE command
test.idle_reg();
endtask
task cb_do_formatter();
super.cb_do_formatter();
void'(test.fmt_gen.randomize() with {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;});
test.fmt_gen.start();
endtask
task cb_do_data();
super.cb_do_data();
void'(test.chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; });
void'(test.chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;});
void'(test.chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;});
fork
test.chnl_gens[0].start();
test.chnl_gens[1].start();
test.chnl_gens[2].start();
join
#10us; // wait until all data haven been transfered through MCDF
endtask
endclass: cb_mcdf_data_consistence_basic
//cb_mcdf_data_consistence_basic_test 中并没有实现do_reg()、do_formatter()、do_data(),
//运行test时会调用cb_mcdf_data_consistence_basic这个回调函数,这里面实现了那三种方法。
class cb_mcdf_data_consistence_basic_test extends mcdf_base_test;
cb_mcdf_data_consistence_basic cb;
`uvm_component_utils(cb_mcdf_data_consistence_basic_test)
function new(string name = "cb_mcdf_data_consistence_basic_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
cb = cb_mcdf_data_consistence_basic::type_id::create("cb"); //创建回调函数
uvm_callbacks#(mcdf_base_test)::add(this, cb); //添加回调函数
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
cb.test = this;
endfunction
endclass: cb_mcdf_data_consistence_basic_test
四、UVM仿真控制方法
在mcdf_base_test
类中添加新的phase函数end_of_elaboration_phase()
。同时利用uvm_root
类来将信息的冗余度设置为UVM_HIGH
,以此来允许更多低级别的信息打印出来。使用uvm_root::get().set_report_max_quit_count()
函数来设置仿真退出的最大数值,即如果uvm_error
数量超过其指定值,那么仿真就会退出。该变量默认数值为-1,表示仿真不会伴随uvm_error
退出。使用uvm_root::get().set_timeout()
设置仿真的最大时间长度,同时由于此功能的生效,可以清楚原有方法do_watchdog()
的定义和调用。
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);
uvm_root::get().set_report_max_quit_count(1);
uvm_root::get().set_timeout(10ms);
endfunction
---------------------
作者:煎丶包
来源:CSDN
原文:https://blog.csdn.net/qq_39794062/article/details/114236625
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件