UVM TLM通信简介

1.UVM put/get通信

在UVM中一对一的TLM有很多种类型,以sequencer和driver为例。

driver是请求端,在driver列化了两种端口(在uvm_driver中列化,可直接使用):

1.uvm_seq_item_pull_port #(REQ, ESP)seq_item_port;

2.uvm_analysis_port #(RSP) rep_port;

而sequencer是接收端,同样在其侧例化了两个对应的端口

1.uvm_seq_item_pull_imp #(REQ, ESP,this_type)seq_item_export;

2.uvm_analysis_export #(RSP) rsp_export;

但是driver的port和sequencer的export的连接需要由用户完成:

driver::seq_item_port.connect(sequencer::seq_item_export);

另外,在sequencer这边,uvm_sequencer提供了多种方法(,不止pu()/get()),供driver使用,在driver中只需通过seq_item_port.mthod()的方式直接使用。

2 uvm analysis port

除了在sequencer与driver之间的通信是一对一的,在monitor,checker,reference model,scorboard之间的通信往往是一对多,因此在这些组件之间通行一般使用uvm analysis port;analysis port采用observer pattern来实现;

举例如下:

背景是sub_env_master中的mst_monitor在interface上监测到transaction后,将其以observer p

class sub_env_matser extends uvm_env;
    // variable define.
    uvm_analysis_port#(dram_intf_trans) dram_data_ap;           // 申明dram_data_ap
   
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ......
        dram_data_ap = new("dram_data_ap", this);               // 例化dram_data_ap
        mst_monitor = sub_monitor_master::type_id::create("mst_monitor", this);
        mst_checker = sub_checker_master::type_id::create("mst_checker", this);
        mst_monitor.dram_data_ap = dram_data_ap;                // 将例化的dram_data_ap的句柄赋值给mst_monitor
        ...... 
    endfunction

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        ......
        dram_data_ap.connect(mst_checker.dram_rdwr_data_imp);   // 将dram_data_ap与mst_checker中的dram_rdwr_data_imp相连
        ......
    endfunction

endclass

attern的形式发送给mst_checker,同时也发给sub_env_slave。

在sub_env_master中,需要做的事情是:

(1):申明dram_data_ap

(2):在build_phase中例化dram_data_ap

(3):由于是sub_env_master中的mst_monitor发送事务,而不是sub_env_master,因此需要将例化的dram_data_ap的句柄赋值给mst_monitor;

(4):在sub_env_master内部,需要mst_monitor需要将transaction传给mst_checker,因此需要将dram_data_ap与mst_checker中的dram_rdwr_data_imp相连;当然,在mst_checker中必定有function write_dram_rdwr_data(...)去接受transaction;

需要思考的是,明明是mst_monitor发送transaction,为什么要在sub_env_master中例化dram_data_ap,再赋值给mst_monitor?为什么不直接在mst_monitor中去例化dram_data_ap呢?

这是因为在top_env中,只会例化其下一层的组件,即sub_env_master和sub_env_slave;至于sub_env_master/sub_env_slave会不会例化其自己的agent/monitor/driver等组件,由sub_env_master/sub_env_slave自己决定,top_env并不知道;因此在top_env这层,只会将sub_env_master的ap和sub_env_slave的imp相连:sub_env_mst.dram_data_ap.connect(sub_env_slv.dram_wr_data_export),不会将sub_env_master的子组件与sub_env_slave相连。

因此作为transaction发送的起点,在mst_monitor的run_phase中,会通过dram_data_ap.write(m_trans)的方式将m_trans发送到与dram_data_ap相连接的imp端;

`uvm_analysis_imp_decl(_dram_wr_data)                            // 宏申明不同的imp方法
`uvm_analysis_imp_decl(_dram_rd_data)
class sub_env_slave extends uvm_env;
    //variable define.
    uvm_analysis_imp_dram_wr_data #(dram_intf_trans, sub_env_slave) dram_wr_data_export;
    uvm_analysis_imp_dram_rd_data #(dram_intf_trans, sub_env_slave) dram_rd_data_export;

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ......
        dram_wr_data_export = new("dram_wr_data_export", this); // 申明并例化dram_wr_data_export
        dram_rd_data_export = new("dram_rd_data_export", this); // 申明并例化dram_rd_data_export
        ......
    endfunction

    function void write_dram_wr_data(dram_intf_trans trans);    // 用来接收transaction的imp方法的实现
        // process write trans...
    endfunction

    function void write_dram_rd_data(dram_intf_trans trans);    // 用来接收transaction的imp方法的实现
        // process read trans...
    endfunction
endclass

在sub_env_slave中,需要做的事情是:

(1):由于在sub_env_slave中需要实现多个write方法,因此需要用宏`uvm_analysis_imp_decl(...)区分出不同类型的imp,然后分别用这些类型的imp去声明export;至于为什么叫dram_wr_data_export而不是叫dram_wr_data_imp?是因为m_trans传到write_dram_wr_data这里可能还不是终点,也许dram_wr_data_export还会作为producer继续将m_trans发送到下一个组件中,因此将其命名成dram_wr_data_imp并不合理;当然,这个名字可以随意命名,无需与`uvm_analysis_imp_decl(...)中的申明保持一致;

(2):在build_phase中例化dram_wr_data_export和dram_rd_data_export,

(3):write_dram_wr_data()和write_dram_rd_data()方法的实现;

需要说明的是,一般不直接在sub_env_slave中实现imp方法,而是在sub_env_slave的子组件中实现,这里只是为了阐述方便在sub_env_slave中实现;如果要在sub_env_slave的子组件slv_checker中实现,需要做的是:在slv_checker中申明并创建dram_wr_data_imp和dram_rd_data_imp,并且在sub_env_slave的connect_phase中将dram_wr_data_export与dram_wr_data_imp相连,将dram_rd_data_export与dram_rd_data_imp相连,如下:

dram_wr_data_export.connect(slv_checker.dram_wr_data_imp);

dram_rd_data_export.connect(slv_checker.dram_rd_data_imp);

class top_env extends uvm_env;
    ......
    function viod build_phase(uvm_phase phase);
        ......
        sub_env_mst = sub_env_master::type_id::create("sub_env_mst", this);
        sub_env_slv = sub_env_slave::type_id::create("sub_env_slv", this);
        ......
    endfunction

    function void connect_phase(uvm_phase phase);
        ......
        sub_env_mst.dram_data_ap.connect(sub_env_slv.dram_wr_data_export);
        sub_env_mst.dram_data_ap.connect(sub_env_slv.dram_rd_data_export);
        ......
    endfunction
    ......
endclass

在top_env中,需要做的事情是:

将sub_env_mst的connect_phase中的dram_data_ap与sub_env_slv中的dram_wr_data_exportdram_rd_data_export相连接,如上所述,只连接sub_env_mst和sub_env_slv这一层次的analysis port,不要连接到sub_env_mst和sub_env_slv的子组件中去,如果连接的子组件没有创建对象,VCS会报No Object Access。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值