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