[UVM] factory

factory 的應用

1. simv  +UVM_TESTNAME=hello_world_test

   通過指定test case 的名字就可以運行,test 是怎麼被創建的呢?

        Actually call uvm_root::run_test(), where it

        1. gets test name from command line (+UVM_TESTNAME)

        2. construct a component of that type via uvm_factory 

            factory.create_component_by_name()

      其中,run_test()是定義在module top 外面的task(通過import uvm_pkg),故module top 可以調用它。

 

2. 就是大家熟知的override。

sw_driver::type_id::set_type_override(old_sw_driver::get_type(), 0);

Which one wins depends on “replace” bit

  • replace= 1(default): later override will replace previous one
  • replace=0: otherwise

Multiple inst override

first inst override wins due to uvm_factory’sreturn first match” when finding instance override type

Mixed type/inst override

inst override wins due to uvm_factory’sinst override takes precedence” policy

parent wins: 若頂層的覆蓋與底層的覆蓋衝突,則頂層的覆蓋會最終生效。


用法

inst override

     inst override by type:

          original_class::type_id::set_inst_override(override_class::get_type(),relative_path,this)

          factory.set_inst_override_by_type(original_class::get_type(), override_class::get_type(), full_inst_path);

          set_inst_override_by_type(relative_path,original_class::get_type(), override_class::get_type());

    inst override by name:

          factory.set_inst_override_by_name("original_class_name" , "override_class_name", full_inst_path );

          set_inst_override(relative_path,"original_class_name" , "override_class_name");

type override

     Type override by type:

          factory.set_type_override_by_type (original_class::get_type(), override_class::get_type(), 1);

          original_class::type_id::set_type_override (override_class::get_type());

          set_type_override_by_type (original_class::get_type(), override_class::get_type(), 1);

    Type override by name:

         factory.set_type_override_by_name ("original_class_name","override_class_name", 1);

         set_type_override ("original_class_name","override_class_name", 1);

 

example: in test中

set_inst_override_by_type("env.o_agt.mon",my_monitor::get_type(),new_monitor::get_type());


//in top module

initial begin
     factory.set_inst_override_by_type(my_monitor::get_type(),new_monitor::get_type(),"uvm_test_top.env.o_agt.mon");

end

How does UVM factory work

1. 註冊

class new_sw_driver extends uvm_component;
  `uvm_component_utils_begin(new_sw_driver)
    `uvm_field_int(frame_num)
    `uvm_field_int(port_num)
  `uvm_component_utils_end
endclass

 `uvm_*_utils 這個宏就是註冊到factory中,那它都做了些什麼呢(以component為例)?

`define uvm_component_utils(T) \
   `m_uvm_component_registry_internal(T,T) \
   `m_uvm_get_type_name_func(T) \

 

`define m_uvm_component_registry_internal(T,S) \
   typedef uvm_component_registry #(T,`"S`") type_id; \
   static function type_id get_type(); \
     return type_id::get(); \
   endfunction \
   virtual function uvm_object_wrapper get_object_type(); \
     return type_id::get(); \
   endfunction

 

  
 uvm_component_registry #(type T=uvm_component,string Tname="<unknown>") extends uvm_object_wrapper;
   typedef uvm_component_registry #(T,Tname) this_type;

  //ex: typedef uvm_component_registry #(sw_driver,"sw_driver") type_id;
   
  local static this_type me = get();//當靜態變量初始化時通過調用get函數註冊到factory中

  static function this_type get();
    if (me == null) begin
      uvm_factory f = uvm_factory::get();
      me = new;
      f.register(me);
    end
    return me;
  endfunction

  static function T create();//在build_phase 調用的create就是它 

從調用uvm_component_utils(T)可看出 T=Tname

factory 維護這一張註冊表(通過調用uvm_component_utils來把內容填入表中):

`uvm_component_utils(sw_driver)

`uvm_component_utils(new_sw_driver)

 

Index by name

                                                    protected uvm_object_wrapper m_type_names[string];(name)                                                   

Index

Value

sw_driver

sw_driver::type_id

new_sw_driver

new_sw_driver::type_id

當調用set_type_override_by_name和run_test時會查看此表

Index by type_id

                                                 

                                                           protected bit m_types[uvm_object_wrapper];(type)

Index

Value

sw_driver::type_id

1

new_sw_driver::type_id

1

當調用set_type_override_by_type時會查看此表

 

2. override

factory同樣也維護著一張關於override 信息的表,表中每一行包括以下內容:

class uvm_factory_override;
  string full_inst_path;
  string orig_type_name;
  string ovrd_type_name;
  bit selected;
  uvm_object_wrapper orig_type;
  uvm_object_wrapper ovrd_type;
  //…
endclass

通過調用factory.set_type_override_by_type(sw_driver::get_type(), new_sw_driver::get_type(), 1);把信息寫入表中

                                                         protected uvm_factory_override m_type_overrides[$];

 

[0]

orig_type

sw_driver::type_id

 

orig_type_name

sw_driver

 

ovrd_type

new_sw_driver::type_id

 

ovrd_type_name

new_sw_driver

 

full_inst_path

“*”

 

selected

0

 

當有多個type override的信息時,比如

      new1_sw_driver::type_id::set_type_override(sw_driver::get_type(), 1);

      new2_sw_driver::type_id::set_type_override(sw_driver::get_type(), 1);

      當replace =1 時,運行第二條語句時會把m_type_overrides[0](如上圖)中第一條語句產生的信息覆蓋掉,因為他們具有相同的orig_type。

     所以在m_type_overrides中具有相同orig_type的隊列元素只有一個。

function void uvm_factory::set_type_override_by_type (uvm_object_wrapper original_type,
                                                      uvm_object_wrapper override_type,
                                                      bit replace=1);
  bit replaced;

  // check that old and new are not the same
  if (original_type == override_type) begin
    if (original_type.get_type_name() == "" || original_type.get_type_name() == "<unknown>")
      uvm_report_warning("TYPDUP", {"Original and override type ",
                                    "arguments are identical"}, UVM_NONE);
    else
      uvm_report_warning("TYPDUP", {"Original and override type ",
                                    "arguments are identical: ",
                                    original_type.get_type_name()}, UVM_NONE);
    return;
  end

  // register the types if not already done so, for the benefit of string-based lookup
  if (!m_types.exists(original_type))
    register(original_type); 

  if (!m_types.exists(override_type))
    register(override_type); 


  // check for existing type override 如果第一次運行此函數不會執行這部分,因為m_type_overrides是空的
  foreach (m_type_overrides[index]) begin
    if (m_type_overrides[index].orig_type == original_type ||
        (m_type_overrides[index].orig_type_name != "<unknown>" &&
         m_type_overrides[index].orig_type_name != "" &&
         m_type_overrides[index].orig_type_name == original_type.get_type_name())) begin
      string msg;
      msg = {"Original object type '",original_type.get_type_name(),
             "' already registered to produce '",
             m_type_overrides[index].ovrd_type_name,"'"};
      if (!replace) begin
        msg = {msg, ".  Set 'replace' argument to replace the existing entry."};
        uvm_report_info("TPREGD", msg, UVM_MEDIUM);
        return;
      end
      msg = {msg, ".  Replacing with override to produce type '",
                  override_type.get_type_name(),"'."};
      uvm_report_info("TPREGR", msg, UVM_MEDIUM);
      replaced = 1;
      //把具有相同orig_type的覆蓋掉 
      m_type_overrides[index].orig_type = original_type; 
      m_type_overrides[index].orig_type_name = original_type.get_type_name(); 
      m_type_overrides[index].ovrd_type = override_type; 
      m_type_overrides[index].ovrd_type_name = override_type.get_type_name(); 
    end
  end

  // make a new entry
  if (!replaced) begin//第一次運行此函數會執行這部分
    uvm_factory_override override;
    override = new(.orig_type(original_type),
                   .orig_type_name(original_type.get_type_name()),
                   .full_inst_path("*"),
                   .ovrd_type(override_type));

    m_type_overrides.push_back(override);
  end

endfunction

 

 

 

當有多個inst override的信息時,比如

sw_driver::type_id::set_inst_override(new_sw_driver::get_type(), "env.driver[1]", this);

sw_driver::type_id::set_inst_override(new_sw_driver::get_type(), "env.driver[0]", this);

m_inst_override_queues[$]會產生兩組信息,而不是覆蓋掉原來的

 

                                                                  m_inst_override_queues[uvm_object_wrapper]

sw_driver::type_id

orig_type

sw_driver::type_id

sw_driver::type_id

orig_type_name

sw_driver

sw_driver

ovrd_type

new_sw_driver::type_id

new_sw_driver::type_id

ovrd_type_name

new_sw_driver

new_sw_driver

full_inst_path

uvm_test_top.env.driver[1]”

uvm_test_top.env.driver[0]”

selected

0

0

another type_id

orig_type

 

 

 

 

 

 

 

3. create 

    sw_driver::type_id::create(sw_driver",this)

    這句話都做了哪些事情呢?

function sw_driver create(
                   string name, 
                   uvm_component parent, 
                   string contxt="");

   if (contxt == "" && parent != null)
      contxt =parent.get_full_name()

   uvm_factory f = uvm_factory::get();

   uvm_object obj = f.create_component_by_type(type_id, contxt, name, parent)
   
   $cast(create, obj)//obj要和create是父子關係

function uvm_component create_component_by_type(
                       uvm_object_wrapper requested_type,
                       string parent_inst_path="“,
                       string name, 
                       uvm_component parent);
  
   string full_inst_path ;
   concatenate  full_inst_path;
   requested_type = find_override_by_type(requested_type, full_inst_path);//查表看看是否有override信息,若有則返回override的type
   return requested_type.create_component(name, parent);//把override type new出來


function uvm_object_wrapper uvm_factory::find_override_by_type(uvm_object_wrapper requested_type,
                                                               string full_inst_path);

  uvm_object_wrapper override;
  uvm_factory_queue_class qc = null;
  if (m_inst_override_queues.exists(requested_type))
    qc = m_inst_override_queues[requested_type];

  foreach (m_override_info[index]) begin
    if ( //index != m_override_info.size()-1 &&
       m_override_info[index].orig_type == requested_type) begin
      uvm_report_error("OVRDLOOP", "Recursive loop detected while finding override.", UVM_NONE);
      if (!m_debug_pass)
        debug_create_by_type (requested_type, full_inst_path);

      return requested_type;
    end
  end

  // inst override; return first match; takes precedence over type overrides
  if (full_inst_path != "" && qc != null)
    for (int index = 0; index < qc.queue.size(); ++index) begin
      if ((qc.queue[index].orig_type == requested_type ||
           (qc.queue[index].orig_type_name != "<unknown>" &&
            qc.queue[index].orig_type_name != "" &&
            qc.queue[index].orig_type_name == requested_type.get_type_name())) &&
          uvm_is_match(qc.queue[index].full_inst_path, full_inst_path)) begin
      //当orig_type 等于requested_type而且full_inst_path也match
        m_override_info.push_back(qc.queue[index]);
        if (m_debug_pass) begin
          if (override == null) begin
            override = qc.queue[index].ovrd_type;
            qc.queue[index].selected = 1;
          end
        end
        else begin
          if (qc.queue[index].ovrd_type == requested_type)//沒有發生override
            return requested_type;
          else
            return find_override_by_type(qc.queue[index].ovrd_type,full_inst_path);
            //遞歸調用,比如1 override 2,2 override 3,最終是1 override 3
        end
      end
    end

  // type override - exact match
  foreach (m_type_overrides[index]) begin
    if (m_type_overrides[index].orig_type == requested_type ||
        (m_type_overrides[index].orig_type_name != "<unknown>" &&
         m_type_overrides[index].orig_type_name != "" &&
         requested_type != null &&
         m_type_overrides[index].orig_type_name == requested_type.get_type_name())) begin
      m_override_info.push_back(m_type_overrides[index]);
      if (m_debug_pass) begin
        if (override == null) begin
          override = m_type_overrides[index].ovrd_type;
          m_type_overrides[index].selected = 1;
        end
      end
      else begin
        if (m_type_overrides[index].ovrd_type == requested_type)
          return requested_type;
        else
          return find_override_by_type(m_type_overrides[index].ovrd_type,full_inst_path);
          //遞歸調用,比如1 override 2,2 override 3,最終是1 override 3
      end
    end
  end

  // type override with wildcard match
  //foreach (m_type_overrides[index])
  //  if (uvm_is_match(index,requested_type.get_type_name())) begin
  //    m_override_info.push_back(m_inst_overrides[index]);
  //    return find_override_by_type(m_type_overrides[index],full_inst_path);
  //  end

  if (m_debug_pass && override != null)
    if (override == requested_type)
      return requested_type;
    else
      return find_override_by_type(override,full_inst_path);

  return requested_type;

endfunction
function uvm_component create_component(
                       string name,
                       uvm_component parent);
  T obj;
  obj = new(name, parent);
  return obj;
endfunction
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值