UVM(3)TLM通信

基本定义

A的方框称之为PORT,B的圆圈称之为EXPORT

要注意:无论是get还是put操作, 其发起者拥有的都是PORT端口, 而不是EXPORT

transport操作, 如 transport操作相当于一次put操作加一次get操作,  数据流先从A流向B, 再从B流向A。 

//put
uvm_blocking_put_port#(T);
uvm_nonblocking_put_port#(T);
uvm_put_port#(T);
//get
uvm_blocking_get_port#(T);
uvm_nonblocking_get_port#(T);
uvm_get_port#(T);
//peek
uvm_blocking_peek_port#(T);
uvm_nonblocking_peek_port#(T);
uvm_peek_port#(T);
//get peek
uvm_blocking_get_peek_port#(T);
uvm_nonblocking_get_peek_port#(T);
uvm_get_peek_port#(T);
//transport
uvm_blocking_transport_port#(REQ, RSP);
uvm_nonblocking_transport_port#(REQ, RSP);
uvm_transport_port#(REQ, RSP);

在这种控制流中, PORT具有高优先级, 而EXPORT具有低优先级。 只有高优先级的端口才能向低优先级的端口发起三种操作。

还有一个imp:中转站

uvm_blocking_put_imp#(T, IMP);
uvm_nonblocking_put_imp#(T, IMP);
uvm_put_imp#(T, IMP);

uvm_blocking_get_imp#(T, IMP);
uvm_nonblocking_get_imp#(T, IMP);
uvm_get_imp#(T, IMP);

uvm_blocking_peek_imp#(T, IMP);
uvm_nonblocking_peek_imp#(T, IMP);
uvm_peek_imp#(T, IMP);

uvm_blocking_get_peek_imp#(T, IMP);
uvm_nonblocking_get_peek_imp#(T, IMP);
uvm_get_peek_imp#(T, IMP);

uvm_blocking_transport_imp#(REQ, RSP, IMP);
uvm_nonblocking_transport_imp#(REQ, RSP, IMP);
uvm_transport_imp#(REQ, RSP, IMP);

互连

class A extends uvm_component;
    `uvm_component_utils(A)
    uvm_blocking_put_port#(my_transaction) A_port;
endclass

function void A::build_phase(uvm_phase phase);
    super.build_phase(phase);
    A_port = new("A_port", this);  //第二个参数是父节点
endfunction

task A::main_phase(uvm_phase phase);
endtask

A中要定义端口,要在build phase中例化,不在new中。

但是不能在env层直接进行链接

function void my_env::connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    A_inst.A_port.connect(B_inst.B_export);
endfunction

需要加入imp

我们需要在B例化一个imp、链接。然后在B实现put

B_export.connect(B_imp);
然后在

结构函数定义

  1. 当A_port的类型是nonblocking_put,B_imp的类型是nonblocking_put时,那么就要在B中定义一个名字为try_put的函数和一个名为can_put的函数。
  2. 当A_port的类型是put,B_imp的类型是put时,那么就要在B中定义3个接口,一个是put任务/函数,一个是try_put函数,一个是can_put函数。
  3. 当A_port的类型是blocking_get,B_imp的类型是blocking_get时,那么就要在B中定义一个名字为get的任务/函数
  4. 当A_port的类型是nonblocking_get,B_imp的类型是nonblocking_get时,那么就要在B中定义一个名字为try_get的函数和一个名为can_get的函数。
  5. 当A_port的类型是get,B_imp的类型是get时,那么就要在B中定义3个接口,一个是get任务/函数,一个是try_get函数,一个是can_get函数。
  6. 当A_port的类型是blocking_peek,B_imp的类型是blocking_peek时,那么就要在B中定义一个名字为peek的任务/函数。
  7. 当A_port的类型是nonblocking_peek,B_imp的类型是nonblocking_peek时,那么就要在B中定义一个名字为try_peek的函数和一个名为can_peek的函数。
  8. 当A_port的类型是peek,B_imp的类型是peek时,那么就要在B中定义3个接口,一个是peek任务/函数,一个是try_peek函数,一个是can_peek函数。
  9. 当A_port的类型是blocking_get_peek,B_imp的类型是blocking_get_peek时,那么就要在B中定义一个名字为get的任务/函数,一个名字为peek的任务/函数。
  10. 当A_port的类型是nonblocking_get_peek,B_imp的类型是nonblocking_get_peek时,那么就要在B中定义一个名字为try_get的函数,一个名为can_get的函数,一个名字为try_peek的函数和一个名为can_peek的函数。
  11. 当A_port的类型是get_peek,B_imp的类型是get_peek时,那么就要在B中定义6个接口,一个是get任务/函数,一个是try_get函数,一个是can_get函数,一个是peek任务/函数,一个是try_peek函数,一个是can_peek函数。
  12. 当A_port的类型是blocking_transport,B_imp的类型是blocking_transport时,那么就要在B中定义一个名字为transport的任务/函数。
  13. 当A_port的类型是nonblocking_transport,B_imp的类型是nonblocking_transport时,那么就要在B中定义一个名字为nb_transport的函数。
  14. 当A_port的类型是transport,B_imp的类型是transport时,那么就要在B中定义两个接口,一个是transport任务/函数,一个是nb_transport函数。

对于所有blocking系列的端口,可以定义函数or任务,但是nonblocking只能定义函数。

注意port和port可以连接、export和export也可以连接

不过通信的话还是要挂载imp

blocking get

get依旧是在A实现imp和export的链接,并且实现get函数,作为动作的接收者。数据的发起者。

transport

analysis port

一个analysis_port( analysis_export) 可以连接多个IMP(uvm_analysis_imp),一对多传输

不存在阻塞的概念,因为是广播。

对于analysis_port和analysis_export来说, 只有一种操作: write。


与put系列端口的PORT和EXPORT直接相连会出错的情况一样, analysis_port如果和一个analysis_export直接相连也会出错。 只有在analysis_export后面再连接一级uvm_analysis_imp, 才不会出错
 

链接

在agent中声明一个ap, 但是不实例化它, 让其指向monitor中的ap。 在env中可以直接连接agent的ap到scoreboard的imp。

这样简单又不会显得层次复杂。

class my_agent extends uvm_agent ;
    uvm_analysis_port #(my_transaction) ap;
    …
    function void my_agent::connect_phase(uvm_phase phase);
        ap = mon.ap;
        …
    endfunction
endclass

function void my_env::connect_phase(uvm_phase phase);
    o_agt.ap.connect(scb.scb_imp);
endfunction

广播机制的write要实现不同的write函数,格式如下,imp_decl()声明imp端口,

使用FIFO

FIFO的本质是一块缓存加两个IMP
monitor中依然是analysis_port, FIFO中是uvm_analysis_imp, 数据流和控制流的方向相同。 在scoreboard与FIFO的连接关系中, scoreboard中使用blocking_get_port端口
等于说ap先写fifo,sb再get。

链接

实际上, FIFO中的analysis_export和blocking_get_export虽然名字中有关键字export, 但是其类型却是IMP。 UVM为了掩饰IMP的存在

所以要这样来链接。

i_agt.ap.connect(agt_mdl_fifo.analysis_export);
mdl.port.connect(agt_mdl_fifo.blocking_get_export);
。。。连两个就行了

上述是FIFO的诸多端口,export依旧是imp

注意

get任务被调用时, FIFO内部缓存中会少一个transaction

peek被调用时, FIFO会把transaction复制一份发送出去, 其内部缓存中的transaction数量并不会减少
 

put_ap:当FIFO上的blocking_put_export或者put_export被连接到一个blocking_put_port或者put_port上时, FIFO内部被定义的put任务被调用, 这个put任务把传递过来的transaction放在FIFO内部的缓存里, 同时, 把这个transaction通过put_ap使用write函数发送出去

get_ap:当FIFO的get任务被调用时, 同样会有一个transaction从get_ap上发出

除此之外, FIFO的get_export、 get_peek_export和blocking_get_peek_export被相应的PORT或者EXPORT连接时, 也能会调用FIFO的get任务

FIFO or AP

fifo在使用的时候可以for循环,ap只能一个一个链接。但是FIFO增加了env的代码复杂度
 

  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值