override功能是UVM中一个比较重要的功能,这个功能也是在factory里面实现的,我们会在env或者具体的case中使用override功能。
class case_x extends base_test;
    function void build_phase(uvm_phase phase);
       …
       set_type_override_by_type(my_driver::get_type(), new_driver::get_type());
    endfunction
endclass
在uvm_component中会有set_type_override_by_type接口函数,这个函数实际调用的是factory里面的对应函数。

用于override功能的数据结构:
factory机制的 override 功能是通过几个队列实现的。最重要一个队列如下:
protected uvm_factory_override m_type_overrides[$]; //这是一个记录override数组
     1. uvm_factory_override其实很简单,它是一个记录把一个已经注册的uvm_object_wrapper用另外一个uvm_object_wrapper来进行替代的数据结构,该结构记录了原wrapper名和对象,替换wrapper名和对象,full_inst_path来跟踪对象的位置
     2. 跟这个队列相关的task有两个set_type_override_by_type/set_type_override_by_name
     3. 首先分析set_type_override_by_type,可以设定一个override让一个wrapper取代另外一个wrapper,然后将该override压入数组,如果一个wrapper没有注册,函数中就将其注册。 
     4.  set_type_override_by_name() 让original_type_name的wrapper被override_type_name的wapper取代,在m_type_names[string]中查找出这两个名字的wrapper并声明一个override并压入m_type_overrides[$],override_type_name的wapper不能为空;original_type_name的wrapper可以为空,如果为空就在m_lookup_strs[original_type_name] = 1中记录这一个original_type_name的wrapper为null的情况,set_type_overide_by_name 与 set_type_override_by_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        //比较一下override 前后的两个类型是不是同一个类型,如果是同一类型就没有必要override
    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))       //检查一下输入的两个类型是不是已经在 factory 中注册过了,如果没有,那么就会注册。也就是说,要保证在 override 之前,这两种类型已经在factory的 m_types数组中存在了
    register(original_type); 
  if (!m_types.exists(override_type))
    register(override_type); 
  // check for existing type override
  foreach (m_type_overrides[index]) begin   //用于查看系统中已经有的override 信息
    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;
      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); //用于向m_type_overrides队列中插入一条记录。这条记录会调用uvm_factory_override的new函数来创建。在调用new的时候会输入几个参数
  end

endfunction


类型被override时实例的创建:
set_type_override_by_type(my_driver::get_type(), new_driver::get_type());分析当drv = my_driver::type_id::create(“drv”, this);会发生什么事情;
 这个create是属于 class uvm_component_registry #(my_driver,  “my_driver”)
在这里调用obj = f.create_component_by_type(get(),contxt,name,parent);

1. 传入的第一个参数是uvm_component_registry #(my_driver,  “my_driver”)中的静态成员变量me

  2.第二个参数是contxt,由上面的code得出这是”uvm_test_done.env.agent
  3.第三个参数是字符串“drv”
  4.第四个参数是parent,这里是this,指代的drv的父component

factory的create_component_by_type函数里面override功能的关键在下面的这一句:
   requested_type = find_override_by_type(requested_type, full_inst_path);
       1. 第一个参数是静态成员变量me,
       2. 第二个参数是full_inst_path

find_override_by_type函数如下:

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))        //requested_type == my_driver
    qc = m_inst_override_queues[requested_type];             //检查是否有具体的事例的override,由于 factory 的 override 有两种,一种是整个验证平台中相关类的所有实例都进行override,另外一种是只针对特定的实例进行 override。
  foreach (m_override_info[index]) begin  //这里防止形成环路的override
    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
        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)
            return requested_type;
          else
            return find_override_by_type(qc.queue[index].ovrd_type,full_inst_path);
        end
      end
    end
  // type override - exact match
  foreach (m_type_overrides[index]) begin                                     //检查 m_type_overrides中是否有对应 my_driver 的记录。恰好找到了一条,把这条记录放入 m_override_info 中                                                                               
    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)/////检查 m_type_overrides 中找到的这条记录中 ovrd_type 是不是就是要查找的类型,在本例中就相当于是看new_driver是不是等于my_driver,很显然是不等于的,所以会调用find_override_by_type函数,这相当于是递归调用,只是这次调用传入的第一个参数将会是代表 new_driver 的 uvm_component_registry#(new_driver, “new_driver”)的静态成员变量me,第二个参数是字符串my_driver。
          return requested_type;
        else
          return find_override_by_type(m_type_overrides[index].ovrd_type,full_inst_path);
      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  


这个 find_override_by_type 函数为什么要做成递归的方式呢?因为假设系统中有一个 A,结果使用 override 语句把 A 用 B 给 override 了,而后面又用 override 语
句把 B 用 C 给 override 了,此时创建 A 的实例,得到的应该是 C 的实例。只有在find_override_by_type 中递归调用,才能完整的实现这一功能。 

这是另外一个人给出来的函数分析,

    function uvm_object_wrapper uvm_factory::find_override_by_type
 
     argument:(uvm_object_wrapper requested_type, string full_inst_path);
 
     这个函数在m_type_overrides[index]和 m_inst_override_queues中查找requested_type类型的wrapper.
 
     该函数的算法实现比较有意思,做为一篇对uvm源码剖析的文章,不才索性分析一二。本函数的实现和使用和下一个函数的实现和使用紧密相连。由于存在着ab_override(a_wrapper-->b_wrapper),bc_override(b_wrapper-->c_wrapper),ca_override(c_wrapper-->a_wrapper)可见这些override构成了一个circle,我们的实现中需要找出这些circle并识别出来,找到最终的wrapper。这也是这个函数代码实现中最让人难理解的地方。
 
该函数的实现过程可以分量条线:
 
m_debug_pass=0:
 
      1. 取出qc=m_inst_override_queues[requested_type],在m_override_info[index]中记录了ab_override(a_wrapper-->b_wrapper),bc_override(b_wrapper-->c_wrapper),ca_override(c_wrapper-->a_wrapper) 这样的override链条,这样的链条是通过递归调用函数本身的方法生成的,开始时该记录为空,m_override_info[index]中元素的个数也记录了本次递归的深度。  
 
      2. 查询m_override_info[index]中每个override的org_type如何和本次查找的requested_type一样,则意味着出现了circle,报告出错。在初次调用中m_override_info[index]中为空,在递归调用中如果m_override_info[index]中有override的先后为ab_override,bc_override,对ca_override调用find_override_by_type(qc.queue[index].ovrd_type,full_inst_path)将会发现ca_override的a_wrapper已经在m_override_info[index]的ab_override中,导致返现circle报告出错。
 
      3.if(full_inst_path != "" && qc != null)则在inst override; return first match;并将match的override记录入m_override_info[index]。如果match的override.override_type==requested_type则意味着override.org_type==requested_type,return requested_type;否则递归调用find_override_by_type(qc.queue[index].ovrd_type,full_inst_path)
 
      4.递归调用的最后会发现qc=m_inst_override_queues[requested_type]中的qc为空,即某个不存在override的的叶子wrapper
 
      5.用同样的方法2,3,4查询m_type_overrides[index]
 
      6.最终返回一个wrapper
 
m_debug_pass=1:
 
      1.同上
 
      2.同上
 
      3.基本原理同上3,实现的时候略有不同,他首先查找qc中匹配的override写入在m_override_info[index]中,取出第一个override=override.over_type,然后取出m_type_overrides[index]中匹配的override写入m_override_info[index]。最后递归调用本函数 find_override_by_type(override,full_inst_path)override.over_type,在第2步的时候就会查询override是否已经是一个m_override_info[index]的override的org_type,这样就能很早就发现circle,而不用递归调用很久后发现。
 
      4.同上
 
      5.同上
 
      6.返回override中的叶子就是最后的wrapper
 
    function uvm_object_wrapper uvm_factory::find_override_by_name:
 
     argument:(string requested_type_name, string full_inst_path);
 
     这是uvm factory中的一个wrapper查找算法,该算法从m_wildcard_inst_overrides,m_inst_override_name_queues,m_inst_override_queues,m_type_overrides,m_types_names中查找出一个wrapper来产生我们希望的数据。
 
      对该算法的实现做详尽介绍:
 
     1.如果requested_type_name在 m_type_names[requested_type_name]中注册,则取出inst
 
     2.如果m_type_names[requested_type_name]不存在就从qc = m_inst_override_name_queues[requested_type_name];如果存在就从qc = m_inst_override_queues[rtype]
 
     3. m_debug_pass=0时,同上一个函数的第3步
 
     4. 查询m_wildcard_inst_overrides如果存在和requested_type_name匹配的则生成一个override加入m_inst_override_queues
 
     5. 同m_debug_pass=0时,同上一个函数的第5步查询m_type_overrides[index]
 
     6.返回一个叶子wrapper


  protected uvm_factory_queue_class m_inst_override_queues[uvm_object_wrapper];
          这个队列为需要的inst记录了一组override队列:
          set_inst_override_by_type():当设置了一个original_type和一个override_type的override,并将该override记录进对应original_type的队列。如果original_type和override_type都没有注册,则调用register()注册这些type。

设要替换的实例的路径为:env.agent.drv,则在某 case 的 build_pahse 进行如下的 override:
set_inst_override_by_type(“env.agent.drv”, my_driver::get_type(), new_driver::get_type ()); 通过最终调用下面的语句在m_inst_override_queues中增加一条记录。
 
m_inst_override_queues[original_type].queue.push_back(override);

当我们执行下面的override语句的时候:
set_inst_override_by_type(“env.agent.drv”, my_driver::get_type(), new_driver::get_type ());
调用的依然是find_override_by_type:执行这个函数里面// inst override; return first match; takes precedence over type overrides下面的语句

  protected uvm_factory_queue_class m_inst_override_name_queues[string];
    1. 这是一个记录仅有类型名字没有类型实例的数组,存在着将一个 original_type_name的null wrapper用一个original_type_name的wrapper取代的情况,这种情况的override记录在这个队列中。 
    2. set_inst_override_by_name()让original_type_name的wrapper被override_type_name的wapper取代,在m_type_names[string]中查找出这两个名字的wrapper并声明一个override并压入m_inst_override_queues。如果m_type_names[string]中找不到original_type_name的wrapper,则在m_inst_override_name_queues记录这个original_type为空的override;如果original_type_name中含有通配符,则找到m_type_names[string]中所有匹配的wrapper并为其建立override记录在m_inst_override_queues中。并把含有通配符的原始override记录在m_wildcard_inst_overrides[$]中。m_lookup_strs[original_type_name] = 1中记录这一个original_type_name的wrapper为null的情况
  protected uvm_factory_override    m_wildcard_inst_overrides[$];
     1. set_inst_override_by_name()中如果录入的original_type_name没有在m_type_names[string]存在,同时original_type_name中存在*和?则对应的override将被记录进这个队列中
  local uvm_factory_override     m_override_info[$];
  local static bit m_debug_pass;

 function void uvm_factory::set_inst_override_by_type (uvm_object_wrapper original_type,
                                                      uvm_object_wrapper override_type,
                                                      string full_inst_path);
  
  uvm_factory_override override;
  // register the types if not already done so
  if (!m_types.exists(original_type))
    register(original_type); 
  if (!m_types.exists(override_type))
    register(override_type); 
  if (check_inst_override_exists(original_type,override_type,full_inst_path))
    return;
  if(!m_inst_override_queues.exists(original_type))
    m_inst_override_queues[original_type] = new;
  override = new(.full_inst_path(full_inst_path),
                 .orig_type(original_type),
                 .orig_type_name(original_type.get_type_name()),
                 .ovrd_type(override_type));
  m_inst_override_queues[original_type].queue.push_back(override);

endfunction


   function void set_inst_override_by_name (     string      original_type_name,    string      override_type_name,    string      full_inst_path     )
   
    1. 当使用type 替换的时候 original_type和override_type都是指向types 代理对象的句柄,Preregistration is not required.
    2. 当使用name进行替换的时候,original_type_name要参考一个在factory里面预定义的type,Future calls to any of the create_* methods with the same string and matching instance path will produce the type represented by override_type_name, which must be preregistered with the factory.
   3. The full_inst_path is matched against the contentation of {parent_inst_path, “.”, name} provided in future create requests. 

4. When the factory processes instance overrides, the instance queue is processed in order of override registrations, and the first override match prevails.  Thus, more specific overrides should be registered first, followed by more general overrides.


function void set_type_override_by_type (     uvm_object_wrapper      original_type,     uvm_object_wrapper      override_type,      bit      replace)
function void set_type_override_by_name (     string      original_type_name,     string      override_type_name,      bit      replace      =      1     )

Creating:
function uvm_object uvm_factory::create_object_by_name (string requested_type_name,  
                                                        string parent_inst_path="",  
                                                        string name=""); 
  uvm_object_wrapper wrapper;
  string inst_path;
  if (parent_inst_path == "")
    inst_path = name;
  else if (name != "")
    inst_path = {parent_inst_path,".",name};
  else
    inst_path = parent_inst_path;
  m_override_info.delete();
  wrapper = find_override_by_name(requested_type_name, inst_path);//主要用override 发生的时候,应该使用 override 之后的类型来创建实例
  // if no override exists, try to use requested_type_name directly
  if (wrapper==null) begin
    if(!m_type_names.exists(requested_type_name)) begin //当 override 不存在的时候才会走的分支,它的主要作用就是到 m_type_names 这个数组中去寻找 requested_type_name,并把 m_type_names 中记录的内容作为wrapper的值。
      uvm_report_warning("BDTYP",{"Cannot create an object of type '",
      requested_type_name,"' because it is not registered with the factory."}, UVM_NONE);
      return null;
    end
    wrapper = m_type_names[requested_type_name];
  end
  return wrapper.create_object(name); //返回通过调用这个wrapper的create_object(name)所得到的这个代理表示的object或者component的值

endfunction

UVM基础之-------uvm factory机制override<博>的更多相关文章

  1. UVM基础之---------uvm factory机制register

    factory机制的一大特点就是根据类的名字来创建类的实例. factory 机制中根据类名来创建类的实例所用到的技术:一是参数化的类,二是静态变量和静态函数.这两者是factory机制实现的根本所在 ...

  2. UVM基础之---------uvm factory机制base

    从名字上面就知道,uvm_factory用来制造uvm_objects和component.在一个仿真过程中,只有一个factory的例化存在. 用户定义的object和component types ...

  3. UVM基础之------uvm phases机制

    代码的书写顺序会影响代码的实现,在不同的时间做不同的事情,这是UVM phase的设计哲学,UVM phase提供了一个通用的TB phase 解决方案.支持显示的隐式的同步方案,运行时刻的线程控制和 ...

  4. UVM基础之---------uvm report 机制分析

    uvm 中的信息报告机制相对来说比较简单,功能上来说主要分为两部分: 第一通过ID对component的信息报告冗余级别进行控制,针对每个冗余级别进行不同的行为控制.这部分工作主要由uvm_repor ...

  5. UVM基础之-------uvm report机制的使用

    后面的例子我会继续补充: 1. 因为uvm默认定义的message格式比较长,非常不利于debug过程中的分析使用,一般情况下,开始使用uvm,都要利用uvm_report_server重新定义mes ...

  6. UVM/OVM中的factory【zz】

    原文地址:http://bbs.eetop.cn/viewthread.php?tid=452518&extra=&authorid=828160&page=1 在新的项目中再 ...

  7. UVM的factory机制

    在UVM中使用工厂模式基本上分为三个步骤: 1. 注册 当定义一个类的时候,它的类型必须要注册,UVM已经提供了专用的宏. `uvm_component_utils(class_type_name) ...

  8. UVM中factory机制的使用

    UVM中的factory机制一般用在sequence的重载,尤其是virtual sequence.当Test_case变化时,通过virtual sequence的重载,可以很容易构建新的测试. 因 ...

  9. UVM中的factory机制实现

    首先在Systemverilog中便有对于重载的最基本的支持. 1)定义task/function时,使用virtual关键字.那之后在test_case中调用时,便使用句柄指向的对象的类型而不是句柄 ...

随机推荐

  1. iphone的ibooks如何导入pdf?

    使用QQ把pdf文档从电脑上发到手机上,使用手机的QQ打开文档,在手机QQ上,用其他应用打开文档,选择‘拷贝’到ibooks

  2. iOS 自己主动释放手动释放混编

    当项目为手动释放时,Build Settings中,Objective-c Automatic Reference Conting 为YES 时,想要手动管理一些文件,在CompileSources中 ...

  3. (6)文本挖掘(三)——文本特征TFIDF权重计算及文本向量空间VSM表示

    建立文本数据数学描写叙述的过程分为三个步骤:文本预处理.建立向量空间模型和优化文本向量. 文本预处理主要採用分词.停用词过滤等技术将原始的文本字符串转化为词条串或者特点的符号串.文本预处理之后,每个文 ...

  4. Hadoop之——HBASE结合MapReduce批量导入数据

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46463889 废话不多说.直接上代码,你懂得 package hbase; imp ...

  5. CentOS7.3编译安装Nginx设置开机启动

    起因 最近想玩nginx了,本来用yum -y install nginx安装也启动好了,但是买了本<Nginx高性能Web服务器详解>,我咋能辜负我的书费呢?于是我就直接ps -ef | ...

  6. [git push] rejecteded 问题的解决方法

    错误信息: hint: Updates were rejected because a pushed branch tip is behind its remote hint: counterpart ...

  7. C中 数组和指针的异同

    数组在很多情况下是和指针等价的,数组的下标运算和指针的解引用也有等价形式:arr[i] == *(arr + 1):但是也有一些情况下数组和指针是不一样的:extern int arr[]; exte ...

  8. CentOS常用基础命令大全

    这篇文章主要介绍了CentOS常用基础命令大全,学习centos的朋友需要掌握的知识,需要的朋友可以参考下 1.关机 (系统的关机.重启以及登出 ) 的命令shutdown -h now 关闭系统(1 ...

  9. 【POJ 3070】 Fibonacci

    [题目链接]            点击打开链接 [算法]           矩阵乘法快速幂 [代码] #include <algorithm> #include <bitset& ...

  10. [noip模拟赛]bird

    https://www.zybuluo.com/ysner/note/1295414 题面 \(R\)是一个猎人,他准备打猎,他站在平面直角坐标系的\((0,0)\)位置. 天上有\(n\)只小鸟从右 ...