1 工厂机制

文章目录

1 工厂机制

  • UVM工厂的存在是为了更方便地替换验证环境中的示例或注册了的类型。
  • UVM验证环境构成可以分为环境层级环境属性(例如配置)和数据传输。分别通过uvm_component和uvm_object类完成,这两种类是进出工厂的主要模具生产对象
  • 三个核心要素:注册、创建、覆盖

1.1 uvm_component & uvm_object

作用:

  • uvm_component:构建验证环境,包括环境层次组件
  • uvm_object:构建测试场景,包括环境属性和数据传输,动态产生。

注册:

  • 使用注册宏,将类注册到factory中。

  • 使用注册,是通过例化该类的对象来完成。

注册组件类uvm_component:````uvm_component_utils```

注册核心基类uvm_object:````uvm_object_utils```

构建函数:

class comp1 extends uvm_component;        //组件注册和构建
    `uvm_component_utils(comp1)          //使用宏注册
    function new(string name = "comp1",uvm_component parent=null);   //构建函数,parent指当前类的上一层
        super.new(name, parent);
        $display($sformatf("%s is created",name));
    endfunction:new

    function void build_phase(uvm_phase phase);    //先不看
        super.build_phase(phase);
    endfunction:build_phase
endclass
class obj1 extends uvm_object;        //object注册和构建
    `uvm_object_utils(obj1)
    function new(string name = "obj1");     //只有一个参数
        super.new(name);
        $display($sformatf("%s is created",name));
    endfunction:new
endclass

创建(create):

uvm_component:

comp_type::type_id::create(string name, uvm_component parent)

​ comp_type指要创建的类,type_id指注册到工厂的类型,调用create方法(后台是利用工厂来做创建)

uvm_object:

object_type::type_id::create(string name)

1.2 uvm_coreservice_t类

  1. 该类内置了UVM世界核心的组件和方法,主要包括:

    • 唯一uvm_factory,该组件用来注册、覆盖和例化
    • 全局report_server,该组件用来做消息统筹报告
    • 全局tr_database,该组件用来记录transaction记录
    • get_root()方法用来返回当前UVM环境的结构顶层对象 (root是UVM结构的顶层)
  2. 该类并不是uvm_component或者uvm_object,它也没有例化在UVM环境中,而是独立在UVM环境之外的。

  3. uvm_coreservice_t 会被UVM系统在仿真开始时例化一次

1.3 注册机制

1 工厂机制

  • uvm_default_factory::register():该方法在该类没有被注册过或者覆盖过时,会将该类例化过的对象句柄放置到factory内的类型字典(关联数组)uvm_default_factory::m_type_names中,同时将对象句柄作为uvm_default_factory::m_types字典的索引键,而键值设置为1。

  • uvm_default_factory::create_component_by_type(): 首先检查处在该层次路径中需要被例化的对象,是否受到了“类型覆盖”或者“实例覆盖”的影响,进而将最终类型对应的对象句柄(正确的产品模板)交给工厂。有了正确地产品模板,接下来就可以通过**uvm_component_registry::create_component()**来完成例化。实际上,uvm_component_registry::create_component()内部就是直接通过调用uvm_component的构建函数new(name, parent)来实现的。

  • uvm_component和uvm_object的区别:

    • 工厂创建出的uvm_component是表示在UVM层次结构中的,而uvm_object则不会显示在层次结构中。
    • uvm_component::new(name,parent)通过parent参数,能够将UVM结构一层层串起来;
    • uvm_object::new(name)只能作为configuration或者transaction等用来做传递的配置结构体抽象数据传输的结构体,成为uvm_component的成员变量

1 工厂机制

  • 在注册过程中,uvm_component_registry或者uvm_object_registry(均继承于uvm_object_wrapper)来分别注册uvm_component和uvm_object。
  • 以uvm_component_registry来说明,对于这样一种专门用来注册的类而言,它们自身的方法是专门为配合factory的注册、创建和覆盖而生的,这些方法分别是:
    • create()
    • create_component()
    • get()
    • get_type_name()
    • set_inst_override()
    • set_type_override()
      1 工厂机制

每一个uvm_component的类在注册时都定义了一个新的uvm_component_registry类,该类的形式定义为:
typedef uvm_component_registry #(T,Tname) this_type;

1.4 覆盖方法

factory提供覆盖特性,覆盖机制可以将原来所属的类型替换为另一个新的类型

  • 无需修改原始代码,保证了原有代码的封装性;

  • 做顶层修改很方便;允许灵活的配置,例如可以用子类覆盖原本的父类;可使用不同的对象来修改其代码行为;

  • 要想实现覆盖特性,原有类型新类型均需要注册;

  • 覆盖发生时,可以使用“类型覆盖”或者“实例覆盖”;

    • 类型覆盖:指UVM层次结构下的所有类型都被覆盖类型所替换;
    • 实例覆盖:指某些位置中的原有类型会被覆盖类型所替换

1.4.1 类型覆盖 & 实例覆盖

类型覆盖(set_type_override):

static function void set_type_override (uvm_object_wrapper override_type, bit replace=1);
  • uvm_object_wrapper override_type是注册后的某一类在工厂注册时的句柄
  • bit replace=1:如果已经有覆盖存在,新覆盖会替代旧覆盖
  • bit replace=0:如果已经有覆盖存在,那么该覆盖将不会生效
  • set_type_override是一个静态函数
orig_type::type_id::set_type_override (new_type::get_type())

实例覆盖(set_inst_override):

static function void set_inst_override (uvm_object_wrapper override_type, string inst_path, uvm_component parent=null);
  • string inst_path指向组件结构的路径;
  • uvm_component parent=null
    • 如果缺省,表示使用inst_path为绝对路径
    • 如果有值传递,则使用{parent.get_full_name(),’.’,inst_path}作为目标路径
orig_type::type_id::set_inst_override (new_type::get_type(), "orig_inst_path")

上面这两种方法由类型箱子uvm_component_registry和uvm_object_registry来提供。

1.4.2 覆盖实例

module factory_override;
  import uvm_pkg::*;
  `include "uvm_macros.svh"      //inst_path
  class comp1 extends uvm_component;
    `uvm_component_utils(comp1)
    function new(string name="comp1", uvm_component parent=null);
      super.new(name, parent);
      $display($sformatf("comp1:: %s is created", name));
    endfunction: new 
      virtual function void hello(string name);           //注意virtual
      $display($sformatf("comp1:: %s said hello!", name));
    endfunction
  endclass
    
  class comp2 extends comp1;
    `uvm_component_utils(comp2)
    function new(string name="comp2", uvm_component parent=null);
      super.new(name, parent);
      $display($sformatf("comp2:: %s is created", name));
    endfunction: new
    function void hello(string name);
      $display($sformatf("comp2:: %s said hello!", name));
    endfunction
  endclass
    
  comp1 c1, c2;
  initial begin
    comp1::type_id::set_type_override(comp2::get_type());
    c1 = new("c1");
    c2 = comp1::type_id::create("c2", null);
    c1.hello("c1");
    c2.hello("c2");
  end
endmodule

输出结果为:

comp1::c1 is created
comp1::c2 is created
comp2::c2 is created
comp1::c1 said hello!
comp2::c2 said hello!

结果分析:

  1. 只有c2所属类型改变,说明:factory覆盖机制只会影响通过factory注册并创建的对象。
  2. 在例化之前类型替换;
  3. c2句柄类型仍为comp1,但却指向了comp2类型的对象。因此要求comp2是comp1的子类。
  4. c2在调用hello()方法时,由于首先是comp1类型,那么会查看comp1::hello(),又由于该方法定义时被指定为虚函数,这就通过了多态性的方法调用,转而又调用了comp2::hello()函数。

1.4.3 确保正确覆盖的代码要求

  1. 将UVM环境中所有的新类都注册到工厂中,并通过工厂来创建对象
  2. 在使用某些类的时候,确保该类已经被导入到当前域中
  3. 通过工厂创建对象时,句柄名称应该同传递到create()方法中的字符串名称相同(c2)
  4. 由于覆盖是采用parent wins模式,因此要注意在同一个顶层build_phase()中覆盖方法应发生在对象创建之前
  5. 为了尽量保证运行时覆盖类可以替换原始类,覆盖类最好是原始类的子类,而调用成员方法也应当声明为虚方法
    厂中,并通过工厂来创建对象
  6. 在使用某些类的时候,确保该类已经被导入到当前域中
  7. 通过工厂创建对象时,句柄名称应该同传递到create()方法中的字符串名称相同(c2)
  8. 由于覆盖是采用parent wins模式,因此要注意在同一个顶层build_phase()中覆盖方法应发生在对象创建之前
  9. 为了尽量保证运行时覆盖类可以替换原始类,覆盖类最好是原始类的子类,而调用成员方法也应当声明为虚方法
  10. 另外一种确保运行时覆盖类句柄类型正确的方式,则需要通过$cast()进行动态类型转换
上一篇:failed to register layer: Error processing tar file(exit status 1): archive/tar: invalid tar header


下一篇:(7)UVM objection机制