UVM 基础入门(一)

UVM 基础入门

一、框架

框架一

UVM 基础入门(一)

构成环境的组件都从uvm_component类继承而来,这是因为它们都从uvm_component类继承了phase机制,都会经历各个phase阶段。常见组件如下:

  • uvm_sequencer:所有的sequencer都要派生自uvm_sequencer。
          sequencer功能:组织管理sequence,driver申请数据时,它就把sequence生成的sequence_item发给driver

  • uvm_driver:所有的driver都要派生自uvm_driver。
         driver功能:向sequencer申请sequence_item(数据包),并将包里的信息按照总线协议规定驱动到DUT的端口上。

    //uvm_driver定义
    class uvm_driver #(type REQ=uvm_sequence_item,type RSP=REQ) extends uvm_component;
    
  • uvm_monitor:所有的的monitor都要派生自uvm_monitor。
         monitor功能:为了检测接口数据,从DUT接收数据,并将其转成transaction级别的sequence_item,发送给scoreboard,供其比较

  • uvm_agent:所有的agent要派生自uvm_agent。
         agent功能:将sequencer、driver和monitor封装在一起,agent模块的使用提高了代码的可重用性
         (UVM_ACTIVE/UVM_PASSIVE、两种模式)

  • uvm_scoreboard:一般的scoreboard都要派生自uvm_scoreboard。
         scoreboard功能:比较reference model和monitor分别发送来的数据,根据比较结果判断DUT是否正确工作。

  • uvm_env:所有的env要派生自uvm_env。
         env功能:将平台上的component组件封装在一起,实现一个环境多个用例。运行不同用例时,在其中实例化env即可。可以看做一个结构化的容器。

  • uvm_test:所有的测试用例要派生自uvm_test或其派生类
         任何一个派生的测试用例中,都要实例化env。这样,当用例运行时,才能把数据发给DUT,并接收DUT的数据。

  • reference model:UVM中并没有针对reference model定义一个类。通常,reference model直接派生自uvm_component
         作用就是模仿DUT,完成与DUT相同的功能。DUT是用Verilog写成的时序电路,而reference model则可以直接使用SystemVerilog高级语言的特性,同时还可以通过DPI等接口调用其他语言来完成与DUT相同的功能。

框架二

UVM 基础入门(一)

框架三

UVM 基础入门(一)

二、各组建关系

component与object是UVM中最基本的两个概念

uvm_object是UVM中最基本的类,几乎全部的类都是由uvm_object类派生出来,其中包含uvm_component。

uvm_object 提供的核心方法主要提供与数据操作的相关服务,CopyCloneComparaPrintpack/unpack

uvm_component有两大特性是uvm_object所不具备的。

  • **一是通过在new的时候必须要指定parent参数来产生一种树形的组织结构
  • 是具有phase的自动执行特点所有的UVM树的结点都是由uvm_component构成的,只有基于uvm_component派生出的类才有可能是UVM树的结点。UVM中一些常见类的继承关系如图3所示。

UVM 基础入门(一)

三、uvm_object类

类的预定义

预定义uvm_object的相关扩展类,以便在uvm_object的相关方法中调用:

typedef class uvm_report_object;
typedef class uvm_object_wrapper;
typedef class uvm_objection;          // uvm_object类中未使用
typedef class uvm_component;          // uvm_object类中未使用
typedef class uvm_status_container;

类的方法

类的声明

virtual class uvm_object extends uvm_void;
endclass

变量声明

  // 静态变量,决定是否使能UVM中的播种机制,影响全局的reseed()方法;
  static bit use_uvm_seeding = 1;
  
  // 局部变量,通过new函数将类的实例化名传递给该变量,变量对子类及外部不可见;
  local string m_leaf_name;

  // 局部变量,使用new()函数实例化类时,m_inst_count自动加1并传递给该局部变量,用于返回实例化id,变量对子类及外部不可见;
  local int m_inst_id;

  // 静态局部变量,用于返回实例化次数,该局部变量对子类可见,对外部不可见;
  static protected int m_inst_count;

  static uvm_status_container __m_uvm_status_container = new;
  
  // 查找表,用于copy()函数的实现;
  local static uvm_object uvm_global_copy_map[uvm_object];

方法声明

extern function new (string name="");
    
extern function void copy (uvm_object rhs);

extern virtual function void do_pack (uvm_packer packer);

extern function int unpack (ref bit  bitstream[],
                             input uvm_packer packer=null);
//其他见UVM参考手册

方法的实现

  • new()函数:通过给定的字符串名称创造该类的实例化对象,如果名字没有给定,那么该对象无名。字符串名传递给局部变量m_leaf_name,实例化 m_inst_id 通过静态局部变量m_inst_count计数的方式指定。
function uvm_object::new (string name="");
  m_inst_id = m_inst_count++;
  m_leaf_name = name;
endfunction
  • clone ()函数:虚方法,创建并返回待clone对象的副本。

    function uvm_object uvm_object::clone();
      uvm_object tmp;
      tmp = this.create(get_name());    // 调用create()方法,创建实例
      if(tmp == null)
        uvm_report_warning("CRFLD", $sformatf("The create method failed for %s,  object cannot be cloned", get_name()), UVM_NONE);
      else
        tmp.copy(this);                // 调用uvm_object中的copy函数
      return(tmp);
    endfunction
    123456789
    
  • print ()函数:方法以给定的 printer 参数控制的格式和方式深度打印该对象的属性。如果参数没有指定,那么使用全局的<uvm_default_printer>所定义的输出格式。

    function void uvm_object::print(uvm_printer printer=null);
      if (printer==null)              // 检查是否给定uvm_printer参数,c如果没有指定参数,使用默认的uvm_default_printer;
        printer = uvm_default_printer;
      if (printer == null)            // 检查uvm_default_printer是否为空;
        `uvm_error("NULLPRINTER","uvm_default_printer is null")
      // 其中printer.knobs.mcd=UVM_STDOUT=1
      $fwrite(printer.knobs.mcd,sprint(printer));   // 使用$fwrite调用sprint函数将类对象的属性打印至标准输出。
    endfunction
    12345678
    
  • sprint ()函数: 与 print() 函数类似,但 sprint() 函数返回字符串而不是显示到标准输出。因此该函数被print()函数调用。

    非虚函数,不可被重载,继承子类必须重写do_print()函数,并且使用提供的printer策略来格式化输出。

    function string uvm_object::sprint(uvm_printer printer=null);
      bit p;
    
      if(printer==null)
        printer = uvm_default_printer;   // 同样的,调用该方法时如果没有指定参数,那么使用默认的uvm_default_printer;
    
      // not at top-level, must be recursing into sub-object
      if(!printer.istop()) begin
        __m_uvm_status_container.printer = printer;
        __m_uvm_field_automation(null, UVM_PRINT, "");
        do_print(printer);
        return "";
      end
      
      printer.print_object(get_name(), this);
      
      // 如果printer对象中的m_string字符串非空,那么返回该非空字符串,不再调用emit()方法;
      if (printer.m_string != "")
        return printer.m_string;
    
      return printer.emit();
    
    endfunction
    

    输出如下表格形式字符串:

      ---------------------------------------------------
      Name        Type            Size        Value
      ---------------------------------------------------
      c1          container       -           @1013
      d1          mydata          -           @1022
      v1          integral        32          'hcb8f1c97
      e1          enum            32          THREE
      str         string          2           hi
      value       integral        12          'h2d
      ---------------------------------------------------
    
  • copy ()函数:拷贝一份备份到指定对象,用于实例的复制,使用B.copy(A)的方式将A的实例拷贝到B的实例中,此时B的实例已经分配好了内存空间。该函数没有使用关键字virtual,不可被子类覆盖(override)。

    function void uvm_object::copy (uvm_object rhs);
      // For cycle checking
      static int depth;
      
      // 如果copy对象非空且已经存在于局部变量uvm_global_copy_map中,此时已经保存了该对象的备份,那么直接返回;
      if((rhs !=null)  && uvm_global_copy_map.exists(rhs)) begin
        return;
      end
      
      // 如果copy对象为空,那么给出警告并返回;
      if(rhs==null) begin
        uvm_report_warning("NULLCP", "A null object was supplied to copy; copy is ignored", UVM_NONE);
        return;
      end
      
      // 如果对象非空且没有被保存,那么将该类对象保存到uvm_global_copy_map且深度+1
      uvm_global_copy_map[rhs]= this; 
      ++depth;
     
      __m_uvm_field_automation(rhs, UVM_COPY, "");   // 调用虚函数,没有被重写时无返回值;
      do_copy(rhs);                                  // 调用虚函数,没有被重写时无返回值;
    
      --depth;                                       // 调用完毕后深度计数递减并删除copy至uvm_global_copy_map的对象;
      if(depth==0) begin
        uvm_global_copy_map.delete();
      end
    endfunction
    
  • do_copy ()函数:无任何返回值,由于copy()函数不可被override(没有用virtual关键字),因此do_copy()函数被用来copy一个子类域。

    function void uvm_object::do_copy (uvm_object rhs);
      return;
    endfunction
    

    实现方式如下:子类必须调用父类的do_copy()函数,且必须在copy之前使用$cast进行类型转换。

    class mytype extends uvm_object;
     ...
     int f1;
     virtual function void do_copy (uvm_object rhs);
       mytype rhs_;
       super.do_copy(rhs);
       $cast(rhs_,rhs);
       field_1 = rhs_.field_1;
     endfunction
    
  • compare ()函数:深度比较此数据对象的成员与rhs(right hand side)中提供的对象的成员。匹配返回1,否则返回0。

    function bit  uvm_object::compare (uvm_object rhs,
                                       uvm_comparer comparer=null);
      ...
      if(!done) begin
        comparer.compare_map[rhs]= this;
        __m_uvm_field_automation(rhs, UVM_COMPARE, "");
        dc = do_compare(rhs, comparer);    // 返回dc显示调用do_compare()方法;
      end
      ...
      return (comparer.result == 0 && dc == 1);
    endfunction
    
    
  • pack ()函数:将对象的属性按位串接在bit数组中;

    function int uvm_object::pack (ref bit bitstream [],
                                   input uvm_packer packer =null );
      m_pack(packer);
      packer.get_bits(bitstream);
      return packer.get_packed_size();
    endfunction
    
  • pack_bytes ()函数:将对象的属性按位串接在byte数组中;

  • pack_ints ()函数:将对象的属性按位串接在int数组中;

  • unpack ()函数:从bit数组中提取对象的属性值。

    function int uvm_object::unpack (ref    bit        bitstream [],
                                     input  uvm_packer packer=null);
      m_unpack_pre(packer);
      packer.put_bits(bitstream);
      m_unpack_post(packer);
      packer.set_packed_size();
      return packer.get_packed_size();
    endfunction
    
  • unpack_bytes ()函数:从byte数组中提取对象的属性值。

  • unpack_ints ()函数:从int数组中提取对象的属性值。

  • m_pack ()函数:uvm_object类内部方法,不能直接使用。

    function void uvm_object::m_pack (inout uvm_packer packer);
    
      // 参数如果是null,那么使用默认uvm_default_packer,这与uvm_printer使用类似;
      if(packer!=null) 
        __m_uvm_status_container.packer = packer;
      else  
        __m_uvm_status_container.packer = uvm_default_packer;
        
      packer = __m_uvm_status_container.packer;
    
      packer.reset();     // 初始化变量
      packer.scope.down(get_name());   // 将实例化对象的字符串名称push到packer的局部变量m_stack中;
    
      __m_uvm_field_automation(null, UVM_PACK, "");
      do_pack(packer);    // 调用do_pack()方法;
    
      packer.set_packed_size();        // 设置包的大小
    
      packer.scope.up();               // 将m_stack队列出栈并进行其他操作;
    
    endfunction
    

    参考:

Mr.翟的博客

UVM学习之:uvm_object类

上一篇:算法训练 开心的金明


下一篇:小甲鱼-C++快速入门笔记 26 之运算符重载2