1 UVM组件

1.1 vif(virtual interface)

从根本上来说,应该尽量杜绝在验证平台中使用绝对路径。避免绝对路径的另外一种方式是使用interface。

例:定义了interface后,在top_tb中实例化DUT时,就可以直接使用。

# xxx_if.sv
interface xxx_if;
  logic sig_clk;
  logic sig_rst;
  logic sig_data;
  
  logic [6:0] sig_crc;
endinterface: xxx_if

# top_tb.sv
crc7 dut(vif.sig_clk,
  vif.sig_rst,
  vif.sig_data,
  vif.sig_crc);

在driver中使用interface需要声明virtual interface

  virtual xxx_if vif;

之后就可以在main_phase中使用vif类来驱动其中的信号。

  virtual task drive();
    ...
      
    vif.data = 1'b0;
    vif.rst = 1'b0;
    
    ...
  endtask: drive

1.2 transaction

transaction是一个抽象的概念。

一般来说,物理协议中的数据交换都是以帧或者包为单位的,通常在一帧或者一个包中要定义好各项参数,每个包的大小不一样。

很少会有协议是以bit或者byte为单位来进行数据交换的。

  • my_transaction的基类是uvm_sequence_item。在UVM中,所有的transaction都要从uvm_sequence_item派生,只有uvm_sequence_item派生的transaction才可以sequence机制。
  • 没有使用uvm_component_utils宏而是使用了uvm_object_utils来实现factory机制。从本质上来说,transaction与 driver是有区别的,在整个仿真期间,my_driver是一直存在的,my_transaction则有生命周期。它在仿真的某一时间产生,处理运行之后其生命周期就结束了。派生自uvm_object的类都要使用 uvm_object_utils宏来实现。

1.3 agent

1.3.1 agent:env

env是一个容器类,在这个容器类中实例化drivermonitorreference modelscoreboard等。

class xxx_env extends uvm_env;
    `uvm_component_utils(my_env)
       my_driver drv;

    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);
          drv = my_driver::type_id::create("drv", this); 
       endfunction

endclass: xxx_env

实例化组件时没有直接调用其new函数,而是使用了一种古怪的方式。这种方式就是factory机制带来的独特的实例化方式。只有使用factory机制注册过的类才能使用这种方式实例化。才能使用factory机制中最为强大的重载功能。

验证平台中的组件在实例化时都应该使用type_name::type_id::create的方式。

在drv实例化时,传递了两个参数,一个是名字,另外一个是this指针,表示my_env:

c7_agent = crc7_agent::type_id::create
    (.name("c7_agent"), .parent(this));
c7_sb = crc7_scoreboard::type_id::create
    (.name("c7_sb"), .parent(this));

同时,top_tb.svrun_test的参数也从my_driver变为了my_env

1.3.2 agent:monitor

验证平台必须监测DUT的行为,只有知道DUT的Input/Output变化之后,才能根据这些信号变化来判定DUT的行为是否正确。

class my_monitor extends uvm_monitor;

   virtual my_if vif;

   `uvm_component_utils(my_monitor)
   function new(string name = "my_monitor", uvm_component parent = null);
      super.new(name, parent);
   endfunction

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

       task main_phase(uvm_phase phase);
    ...
    endtask:main_phase

    task collect_one_pkt(my_transaction tr);
    ...
    endtask:collect_one_pkt
endclass

uvm_monitor在整个仿真中是一直存在的,所以它是一个component,要使用uvm_component_utils宏注册。

1.3.3 agent

drivermonitor之间存在联系,因为两者之间的代码高度相似。其本质是因为二者

处理的是同一种协议,在同样一套既定的规则下做着不同的事情。

class my_agent extends uvm_agent ;
  `uvm_component_utils(my_agent)
    
   my_driver     drv;
   my_monitor    mon;
   
   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction 
   
   ...
   
endclass 

由于agent的加入,driver和monitor的层次结构改变了,在top_tb中使用config_db设置if时要注意改变路径。

UVM中约定俗成的还是在build_phase中完成实例化工作。因此,强烈建议仅在build_phase中完成实例化。

1.4 reference model

reference model用于完成和DUT相同的功能。

reference model的输出被scoreboard接收,用于和DUT的输出相比较。DUT如果很复杂,那么reference model也会相当复杂。

my_scoreboard要比较的数据来源:

  • 一是来源于reference model
  • 二是来源于dut输出数据后的的monitor(monitor_before)。

前者通过exp_port获取,而后者通过act_port获取。

最后修改:2022 年 03 月 28 日
如果觉得我的文章对你有用,请随意赞赏