uvm-1.2 examples —— 2.9 factory

2.9 factory



前言

本文以uvm-1.2/examples/simple/factory为例,通过代码了解UVM中factory机制的一些用法。通过这个例子可以基本了解以下知识点:

  • 如何将组件注册到UVM的factory机制中
  • 如何利用UVM的factory机制实现组件的重载
  • 如何利用virtual关键字实现类方法的重载

一、基本介绍

在张强的《UVM实战》的第8章中,对UVM的factory机制已经有了比较详细的介绍。这里主要结合代码介绍一下,如何将UVM的组件注册到UVM的factory机制中,以及利用UVM的factory机制实现组件的重载。
首先,介绍一下如何将UVM的组件注册到UVM的factory机制中。在UVM中的组件主要分为两大类,一类是uvm_object,另一类是uvm_component,他们之间的关系在张强《UVM实战》的3.1节有比较详细的介绍。针对这两大类的组件,UVM分别提供了两个宏来处理factory注册的问题。其中派生自uvm_object和uvm_component的组件,通过以下宏实现注册。

 `uvm_object_utils         //注册不带参数的uvm_object
 `uvm_object_param_utils   //注册带参数的uvm_object
 `uvm_component_utils      //注册不带参数的uvm_component
 `uvm_component_param_utils//注册不带参数的uvm_component

其次,介绍一下如何利用UVM的factory机制实现组件的重载。重载的意思是重新载入,重载要实现的功能是,在不影响其他组件正常工作的前提下,将某一类或者某一个组件,利用新的组件重新载入进去,替换掉原有的组件,从而实现新的功能。UVM提供了以下两类重载函数,具体的使用方法可以参考张强《UVM实战》8.2节。值得注意的是,重载与被重载组件之间必须是父子关系,或者关系比较近的继承关系。

set_type_override()   //类型重载。不管例化的路径和次数,都会被重载。
set_inst_override()   //例化重载。只有一个组件会被重载,需要提供被替换组件的路径。

最后,在类方法前面加上virtual关键字后,子类声明与父类名字相同的方法时,会重载父类的方法。

二、代码分析

这个测试用例包括四个文件:test.sv、env_pkg.sv、gen_pkg.sv、packet_pkg.sv。test.sv中主要实现了顶层的封装以及组件的重载;env_pkg.sv中主要封装了环境;gen_pkg.sv和packet_pkg.sv中,分别实现了uvm_object和uvm_component的factory注册。

2.1 test.sv

/*
About: factory

This example will illustrate the usage of uvm_factory methods.



To get more details about the factory related methods, check the file:
	- uvm/src/base/uvm_factory.svh


*/



module top;
  import uvm_pkg::*;
  import packet_pkg::*;
  import gen_pkg::*;
  import env_pkg::*;

  `include "uvm_macros.svh"
  env e;  //you need to use something from the package to have the
          //factory registration occur.

  class mygen extends gen;
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction

    function packet get_packet();
      `uvm_info("PKTGEN", $sformatf("Getting a packet from %s (%s)", get_full_name(), get_type_name()),UVM_MEDIUM)
      return super.get_packet();
    endfunction

    //Use the macro in a class to implement factory registration along with other
    //utilities (create, get_type_name). To just do factory registration, use the
    //macro `uvm_object_registry(mygen,"mygen")
    `uvm_component_utils(mygen)

  endclass

  class mypacket extends packet;
    constraint ct10 { addr >= 0 && addr <= 10; }

    //Use the macro in a class to implement factory registration along with other
    //utilities (create, get_type_name).
    `uvm_object_utils(mypacket)

  function new(string name="mypacket");
     super.new(name);
  endfunction

  endclass

  initial begin automatic uvm_coreservice_t cs_ = uvm_coreservice_t::get();

    uvm_factory factory;
    factory = cs_.get_factory();
    gen::type_id::set_inst_override(mygen::get_type(), "uvm_test_top.gen1");
    packet::type_id::set_type_override(mypacket::get_type());

    factory.print(1);

    //If a string is used to run_test, run_test will used the string based factory
    //create method to create an object of the desired type.
    run_test("env");
  end

endmodule 

17到20行,分别导入了UVM的包,三个在其他文件中封装的包。

23行声明了env,env的实现在env_pkg.sv文件中。

26到41行,声明了一个继承自gen的类mygen,gen的实现在gen_pkg.sv文件中。在mygen中,重新写了一个get_packet()的方法,打印相关的信息,返回并调用了父类的get_packet()方法。其中,通过打印的信息可以了解到gen组件是否被重载。
39行通过调用`uvm_component_utils,实现了mygen的注册。

43到54行,声明了一个继承自packet的类mypacket,packet的实现在packet_pkg.sv文件中。在mypacket中,增加了一个约束,并在48行通过`uvm_object_utils,实现了mypacket的注册。

56到68行,通过一个initial-end模块实现仿真。
56到59行获取当前环境的factory;
60行通过调用set_inst_override()方法,实现了gen的重载;
61行通过调用set_type_override()方法,实现了packet的重载;
63行调用print函数,打印factory的基本信息,包括注册了哪些组件,哪些组件被重载;
67行执行仿真。

2.2 env_pkg.sv

package env_pkg;
  import uvm_pkg::*;
  import packet_pkg::*;
  import gen_pkg::*;

  `include "uvm_macros.svh"
  
  class env extends uvm_env;
    gen gen1;

    //Use the macro in a class to implement factory registration along with other
    //utilities (create, get_type_name). For only factory registration, use the
    // macro `uvm_component_registry(env,"env").
    `uvm_component_utils(env)
    
    function new (string name, uvm_component parent);
      uvm_component cmp;
      super.new(name, parent);
     
      //use the factory to create the generator
      gen1 = gen::type_id::create("gen1", this);

    endfunction

    task run_phase(uvm_phase phase);
      packet p;
      phase.raise_objection(this);
      uvm_default_tree_printer.knobs.separator = "";
      repeat(5) begin
        #15 p = gen1.get_packet();
        `uvm_info("PKTGEN", $sformatf("Got packet: %s", p.sprint(uvm_default_tree_printer)), UVM_NONE)
      end
      #15;
      phase.drop_objection(this);
    endtask
  endclass
endpackage

8到36行封装了env的类。
9行声明了gen;
14行调用`uvm_component_utils将env注册到UVM的factory机制中;
21行利用factory机制,创建了一个gen;
25到35行,在run_phase中,利用UVM的objection机制(参考张强《UVM实战》5.2节),通过“举手”和“放手”启动仿真,在仿真中,重复5次调用gen中的get_packet()方法,并打印packet的信息,通过打印的信息可以判断packet是否被重载。

2.3 gen_pkg.sv

package gen_pkg;
  import uvm_pkg::*;
  import packet_pkg::*;

  `include "uvm_macros.svh"
  class gen extends uvm_component;

    //Use the macro in a class to implement factory registration along with other
    //utilities (create, get_type_name). To do only factory registration, use
    //the macro `uvm_component_utils(gen,"gen").
    `uvm_component_utils(gen)
    
    function new (string name, uvm_component parent);
      super.new(name, parent);
    endfunction

    virtual function packet get_packet();
      packet p;

      //use the factory to generate a package
      p = packet::type_id::create("p", this);
     
      //randomize it
      void'(p.randomize());      
     
      return p; 
    endfunction
  endclass
endpackage

6到28行封装了gen。
11行通过`uvm_component_utils实现了将gen注册到UVM的factory机制中;
17到27行定义了gen的get_packet方法,其中方法前加了一个virtual关键字,这个关键字表明这是一个虚方法,可以被子类重构,也就是说,子类可以通过定义一个名字一样的方法,替换父类的方法。
21行利用UVM的factory机制创建了一个packet;
24行对创建的packet进行随机;
26行返回随机后的packet。

2.4 packet_pkg.sv

package packet_pkg;
  import uvm_pkg::*;
  `include "uvm_macros.svh"

  class packet extends uvm_object;
    rand int addr;
    rand int data;

    //Use the macro in a class to implement factory registration along with other
    //utilities (create, get_type_name). For only factory registration, use
    //the macro `uvm_object_registry(packet,"packet").
    `uvm_object_utils(packet)
    
    //Base constraints
    constraint c1 { addr inside { ['h0:'h40], ['h100:'h200], ['h1000: 'h1fff], ['h4000: 'h4fff] }; }
    constraint c2 { (addr <= 'h40) -> (data inside { [10:20] } ); }
    constraint c3 { (addr >= 'h100 && addr <= 'h200) -> (data inside { [100:200] } ); }
    constraint c4 { (addr >= 'h1000 && addr <= 'h1fff) -> (data inside { [300:400] } ); }
    constraint c5 { (addr >= 'h4000 && addr <= 'h4fff) -> (data inside { [600:800] } ); }

    //do printing, comparing, etc. These functions can also be automated inside
    //the `uvm_object_utils_begin/end macros if desired. Below show the manual 
    //approach.
    function void do_print(uvm_printer printer);
      printer.print_field("addr", addr, $bits(addr));
      printer.print_field("data", data, $bits(data));
    endfunction
    function bit do_compare(uvm_object rhs, uvm_comparer comparer);
      packet rhs_;
      if(rhs==null || !$cast(rhs_, rhs)) return 0;
      do_compare = 1;  
      do_compare &= comparer.compare_field("addr", addr, rhs_.addr, $bits(addr));
      do_compare &= comparer.compare_field("data", data, rhs_.data, $bits(data));
    endfunction
    function void do_copy(uvm_object rhs);
      packet rhs_;
      if(rhs==null || !$cast(rhs_, rhs)) return;
      addr = rhs_.addr;
      data = rhs_.data;
    endfunction

  function new(string name="packet");
     super.new(name);
  endfunction

  endclass
endpackage

5到46行封装了packet。
下面主要提以下几个比较重要的代码。
12行通过`uvm_object_utils,实现了packet的注册;
15到19行,分别对addr和data进行了约束;
24到40行,分别声明了一些方法,这些方法可以通过UVM中的field机制来实现,具体可以参考张强《UVM实战》3.3节。


总结

通过这个例子,主要可以学习到,如何实现UVM factory机制的注册,以及如何利用UVM factory机制对组件进行重载,另外,可以稍微了解以下virtual关键字的用法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值