《UVM实战》学习笔记3

UVM中的TLM通信

一、基本概念

1)、put操作:通信的发起者A把一个transaction发送给B。在这个过程中,A称为“发起者”,而B称为“目标”。A具有的端口(用方框表示) 称为PORT,而B的端口(用圆圈表示) 称为EXPORT。这个过程中,数据流是从A流向B的。

2)、get操作:在这个过程中,A依然是“发起者”,B依然是“目标”,A上的端口依然是PORT,而B上的端口依然是EXPORT。这个过程中,数据流是从B流向A的。

3)、transport操作:transport操作相当于一次put操作加一次get操作,这两次操作的“发起者”都是A,目标都是B。A上的端口依然是PORT,而B上的端口依然是EXPORT。在这个过程中,数据流先从A流向B,再从B流向A。

《UVM实战》学习笔记3_第1张图片《UVM实战》学习笔记3_第2张图片

需要注意的是:在通信中port始终是发起者,EXPORT始终是被动接收的。

 

二、UVM中各种端口的互连

UVM中使用connect函数来建立连接关系。如A要和B通信( A是发起者) ,那么可以这么写:A.port.connect( B.export) ,但是不能写成B.export.connect( A.port) 。因为在通信的过程中,A是发起者,B是被动承担者。这种通信时的主次顺序也适用于连接时,只有发起者才能调用connect函数,而被动承担者则作为connect的参数。

但是直接用这种方法连接,编译器会报错不能通过。主要是PORT和EXPORT只是一个端口,不能存储transaction。要向连接成功需要加成IMP端口。

class B extends uvm_component;
   `uvm_component_utils(B)

   uvm_blocking_put_export#(my_transaction) B_export;
   uvm_blocking_put_imp#(my_transaction, B) B_imp;
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction
……//省略
function void B::build_phase(uvm_phase phase);
   super.build_phase(phase);
   B_export = new("B_export", this);
   B_imp = new("B_imp", this);
endfunction

function void B::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   B_export.connect(B_imp);
endfunction

function void B::put(my_transaction tr);//必须实例化的put函数
   `uvm_info("B", "receive a transaction", UVM_LOW) 
   tr.print();
endfunction

 

 

所以要实现连接通信,最核心是在B在实例化一个IMP,而且必须要在实现IMP的component中实现一个put函数/任务。在UVM中,只有IMP才能作为连接关系的终点。(其中对get操作必须实现一个get函数,对transport操作必须实现一个transport函数

 

 

nonbllocking是非阻塞的,必须用函数来实现而不能用任务实现。由于端口变成非阻塞的,所以再送出transaction之前需要调用can_put函数来确认是否能够执行put操作。can_put最终会调用B中的can_put。

A中的main函数:

task A::main_phase(uvm_phase phase);
   my_transaction tr;
   repeat(10) begin
      tr = new("tr");
      assert(tr.randomize());
      while(!A_port.can_put()) #10;
      void'(A_port.try_put(tr));
   end
endtask

 

B中的can_put和try_put

 

function bit B::can_put();
   if(tr_q.size() > 0)
      return 0;
   else 
      return 1;
endfunction

function bit B::try_put(my_transaction tr);
   `uvm_info("B", "receive a transaction", UVM_LOW) 
   if(tr_q.size() > 0)
      return 0;
   else begin
      tr_q.push_back(tr);
      return 1;
   end
endfunction

三、UVM中的通信方式

1)analysis端口

在默认情况下,一个analysis_port可以连接多个IMP,可以理解analysis_port是一个广播。所以因此也可以理解analysis_port没有阻塞和非阻塞之分。

class A extends uvm_component;
   `uvm_component_utils(A)

   uvm_analysis_port#(my_transaction) A_ap;//定义一个analysis_port
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction

   extern function void build_phase(uvm_phase phase);
   extern virtual  task main_phase(uvm_phase phase);
endclass
……
task A::main_phase(uvm_phase phase);
   my_transaction tr;
   repeat(10) begin
      #10;
      tr = new("tr");
      assert(tr.randomize());
      A_ap.write(tr);
   end
endtask

 

 

根据前面的IMP的要求,也是需要在实例化IMP的B中定义一个write函数。

 

 

 

2)使用FIFO通信

在通信汇中,单单使用PORT和EXPORT通信,始终有一方是处于主动地位,另一方处于被动地位。究竟有没有方法可以让双方都对数据主动接收呢?答案是使用FIFO。

《UVM实战》学习笔记3_第3张图片

FIFO的本质是一块缓存加两个IMP。

function void my_env::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   i_agt.ap.connect(agt_mdl_fifo.analysis_export);
   mdl.port.connect(agt_mdl_fifo.blocking_get_export);//i_agent和model连接
   for(int i = 0; i < 16; i++) begin
      mdl.ap[i].connect(mdl_scb_fifo[i].analysis_export);
      scb.exp_port[i].connect(mdl_scb_fifo[i].blocking_get_export);//model和scoreboard连接
   end
   o_agt.ap.connect(agt_scb_fifo.analysis_export);
   scb.act_port.connect(agt_scb_fifo.blocking_get_export); //o_agent和scoreboard连接
endfunction

 


实际上,虽然FIFO中的analysis_export有关键字export,但是其类型却是IMP。这点是FIFO设计隐藏了IMP,是对初学者的优化。

 

 

 

 

 

你可能感兴趣的:(UVM实战)