UVM实战:UVM中的通信方式:UVM中的analysis端口

(1)UVM中的analysis端口

        UVM中还有两种 特殊的端口:analysis_port和analysis_export。这两者其实与put和get系列端口类似,都用于传递transaction。它们的区别是:
        第一,默认情况下,一个analysis_port(analysis_export)可以连接多个IMP,也就是说,analysis_port(analysis_export)与IMP 之间的通信是一对多的通信,而put和get系列端口与相应IMP的通信是一对一的通信(除非在实例化时指定可以连接的数量)。analysis_port(analysis_export)更像是一个广播
        第二,put与get系列端口都有阻塞和非阻塞的区分。但是对于analysis_port和analysis_export来说,没有阻塞和非阻塞的概念。 因为它本身就是广播,不必等待与其相连的其他端口的响应,所以不存在阻塞和非阻塞
        一个analysis_port可以和多个IMP相连接进行通信,但是IMP的类型必须是uvm_analysis_imp,否则会报错
        对于put系列端口,有put、try_put、can_put等操作,对于get系列端口,有get、try_get和can_get等操作。对于analysis_port和 analysis_export来说,只有一种操作:write。在analysis_imp所在的component,必须定义一个名字为write的函数

要实现图4-13中所示的连接关系,A的代码为:

`ifndef A__SV
`define A__SV
class A extends uvm_component;
   `uvm_component_utils(A)
	
	static integer fileA = $fopen("A.txt", "w" );



   uvm_analysis_port#(my_transaction) A_ap;
   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

function void A::build_phase(uvm_phase phase);
   super.build_phase(phase);
   A_ap = new("A_ap", this);
endfunction

task A::main_phase(uvm_phase phase);
   my_transaction tr;
   repeat(10) begin
      #10;
      tr = new("tr");
	  
      assert(tr.randomize());
	   $fdisplay (fileA, "tr.dmac = %h,tr.smac=%h ,tr.ether_type=%h ,tr.pload=%h ,tr.crc=%h \n", tr.dmac,tr.smac,tr.ether_type,tr.pload,tr.crc);
      A_ap.write(tr);
   end
endtask

`endif

        A的代码很简单,只是简单地定义一个analysis_port,并在main_phase中每隔10个时间单位写入一个transaction。 B的代码为:

`ifndef B__SV
`define B__SV
class B extends uvm_component;
   `uvm_component_utils(B)

   uvm_analysis_imp#(my_transaction, B) B_imp;
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction

	static integer fileB = $fopen("B.txt","w");
	
   extern function void build_phase(uvm_phase phase);
   extern function void connect_phase(uvm_phase phase);
   extern function void write(my_transaction tr);
   extern virtual  task main_phase(uvm_phase phase);
endclass

function void B::build_phase(uvm_phase phase);
   super.build_phase(phase);
   B_imp = new("B_imp", this);
endfunction

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

function void B::write(my_transaction tr);
   `uvm_info("B", "receive a transaction", UVM_LOW) 
    $fdisplay (fileB, "tr.dmac = %h,tr.smac=%h ,tr.ether_type=%h ,tr.pload=%h ,tr.crc=%h \n", tr.dmac,tr.smac,tr.ether_type,tr.pload,tr.crc);
   tr.print();
endfunction

task B::main_phase(uvm_phase phase);
endtask

`endif

        如前所述,B是B_imp所在的component,因此要在B中定义一个名字为write的函数。在B的main_phase中不需要做任何操作。 C的代码与B完全相似,只要把相应的B替换为C即可。
 

`ifndef C__SV
`define C__SV
class C extends uvm_component;
   `uvm_component_utils(C)

   uvm_analysis_imp#(my_transaction, C) C_imp;
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction

   extern function void build_phase(uvm_phase phase);
   extern function void connect_phase(uvm_phase phase);
   extern function void write(my_transaction tr);
   extern virtual  task main_phase(uvm_phase phase);
endclass

function void C::build_phase(uvm_phase phase);
   super.build_phase(phase);
   C_imp = new("C_imp", this);
endfunction

function void C::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
endfunction

function void C::write(my_transaction tr);
   `uvm_info("C", "receive a transaction", UVM_LOW) 
   tr.print();
endfunction

task C::main_phase(uvm_phase phase);
endtask

`endif

        env中的连接关系为:

`ifndef MY_ENV__SV
`define MY_ENV__SV

class my_env extends uvm_env;

   A   A_inst;
   B   B_inst;
   C   C_inst;
   
   
   function new(string name = "my_env", uvm_component parent);
      super.new(name, parent);
   endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);

      A_inst = A::type_id::create("A_inst", this);
      B_inst = B::type_id::create("B_inst", this);
      C_inst = C::type_id::create("C_inst", this);

   endfunction

   extern virtual function void connect_phase(uvm_phase phase);
   
   `uvm_component_utils(my_env)
endclass

function void my_env::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   A_inst.A_ap.connect(B_inst.B_imp);
   A_inst.A_ap.connect(C_inst.C_imp);
endfunction

`endif

        在env中,可以看到A_ap分别与B和C中相应的imp连接到了一起。上面只是一个analysis_port与IMP相连的例子。analysis_export和IMP也可以这样相连接,只需将上面例子中的 uvm_analysis_port改为uvm_analysis_export就可以。
        与put系列端口的PORT和EXPORT直接相连会出错的情况一样,analysis_port如果和一个analysis_export直接相连也会出错。只 有在analysis_export后面再连接一级uvm_analysis_imp,才不会出错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值