UVM源码探索之Factory(下篇)

[TOC]

到下篇的时候, 我们来探索一下UVM的Factory的另外一个主要功能, 那就是重载. 说起来, 重载功能跟Factory这个设计模式已经没有关系了. 而且, 这里的”重载”跟常见的重载的意义也不一样, 这里的重载准确的描述的话是类”替换”.

在UVM里面使用重载的大致流程如下:

  1. 对需要重载的类使用uvm_*_util进行类型注册, 原始类和重载类都需要注册;
  2. 设置重载, 设置原始类”替换”为重载类;
  3. 使用Factory的create创建原始类对象, 返回的是重载类对象.

步骤1我们在上篇已经讲过了, 步骤2跟3的在上篇其实也有相关的代码展示, 不过我们略过了. 现在到了下篇, 我们的主要任务就是把上面流程中的2跟3的源码实现给搞清楚.

重载的设置

在上篇, uvm_*_registry的类定义里面有这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
extends uvm_object_wrapper;
...
static function void set_type_override (uvm_object_wrapper override_type,
bit replace=1);
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
factory.set_type_override_by_type(get(),override_type,replace);
endfunction
static function void set_inst_override(uvm_object_wrapper override_type,
string inst_path,
uvm_component parent=null);
string full_inst_path;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
if (parent != null) begin
if (inst_path == "")
inst_path = parent.get_full_name();
else
inst_path = {parent.get_full_name(),".",inst_path};
end
factory.set_inst_override_by_type(get(),override_type,inst_path);
endfunction
endclass

set_type_overrideset_inst_override就是设置重载的两个函数了, 这两个函数都是基于类型的重载函数, 第一个参数是需要重载的类型. 后面的函数, 从内容上来看, 是为了支持UVM的component树的特定节点的重载的, 这个就要跟component扯上关系了, 所以先不细究了(UVM的component代码很多的, 光是uvm_component.svh这个文件里面, 只有一个类定义, 就有3000多行, 而且内容很杂, 我也很无奈~).

所以, 我们就把重点放在set_type_override上面来吧. 这个函数里面, 调用的其实是Factory里定义的set_type_override_by_type()这个方法, 第二个参数就是uvm_object_registry里面set_type_override方法的第一个参数, 就是重载的类型, 而第一个参数是uvm_object_registry里面get方法的返回值, 也就是本类型的单例对象. 第三个参数replace的默认值是1, 这个参数是什么用的, 这里还体现不出来. set_type_override这个函数要做的就是就是通过Factory的set_type_override_by_type方法把本类型替换为指定的重载类型, 具体怎么重载的呢就要看Factory的代码了.

这个部分代码有点长, 我们要慢慢看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function void uvm_default_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);
end
...

第一部分, 是输入检查, 如果类型相同的话输出一个告警.

1
2
3
4
5
6
7
8
9
10
11
12
function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type,
uvm_object_wrapper override_type,
bit replace=1);
bit replaced;
...
// 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);
...
endfunction

第二部分, 是类型注册检查. 还记得m_types[$]这个bit类型的哈希表吗, 上篇中说过, 这个表记录了类型是否已注册. 在此之前, 我们知道类型的注册发生在第一次使用Factory的create的时候. 在这里我们要思考一下了, 重载的设置, 其实是应该发生在create之前的是不是, 所以这里也是需要保证类型注册的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type,
uvm_object_wrapper override_type,
bit replace=1);
bit replaced;
...
// check for existing type override
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;
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
...
endfunction

接着往下看, 这里是一个表的搜索操作. m_type_overrides显然是一个重载的记录表了, 这段代码字面上看是要先查找记录表中是不是已经有输入参数original_type的重载记录了, 如果有的话需要把记录表中的ovrd_type的信息赋值为输入参数override_type的相关信息. 中间的if表达式需要对第三个输入参数replace做检查, 不为0的时候就直接返回, 不进行后面的override_type的记录表赋值操作了. 这样看来, UVM的Factory是支持重载的改写操作的, replace参数设为1的话就可以实现先把A类型重载为B类型, 之后再把A类型重新重载为C类型.

这个部分其实挺复杂的, 而且我们对m_type_overrides这个数据结构其实一无所知. 现在先假定我们是第一次进入这个方法, 所以这个m_type_overrides表是空的, 这样, 我们就可以先看看这个方法的最后一部分是什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type,
uvm_object_wrapper override_type,
bit replace=1);
bit replaced;
...
// 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

这里是一个创建重载对象的操作, 使用uvm_factory_override这个类型的数据来保存重载信息: 原始类型和重载类型. 然后把这个记录插入到m_type_overrides这个表里. repalced这个变量在上面的重载改写的时候会置1, 有重复记录的表项不设置改写的时候会直接返回, 所以, 插入的表项都是之前没有重载记录的表项.

重载的支持数据结构

到这里来讲, 我们的重载设置这块任务已经算完成的差不多了. 重载设置函数内容上看还是挺简单的, 不过出现了之前没有见过的数据结构. 在重载应用的时候, 这些数据结构也是要发挥作用的, 这里我们还是先了解一下这些数据结构为好.

uvm_default_factory类里面的主要数据成员如下:

1
2
3
4
5
6
7
8
9
10
11
protected bit m_types[uvm_object_wrapper];
protected bit m_lookup_strs[string];
protected uvm_object_wrapper m_type_names[string];
protected uvm_factory_override m_type_overrides[$];
protected uvm_factory_queue_class m_inst_override_queues[uvm_object_wrapper];
protected uvm_factory_queue_class m_inst_override_name_queues[string];
protected uvm_factory_override m_wildcard_inst_overrides[$];
local uvm_factory_override m_override_info[$];

里面有老相识m_typesm_type_names, 还有之前见过的列表m_type_overrides和他的类型uvm_factory_override, 这里可以看到还有新的类型uvm_factory_queue_class和这个类型的3个成员m_inst_override_queues, m_inst_override_name_queuesm_wildcard_inst_overrides, 这三个成员分别是key为uvm_object_wrapper的联合数组, key为字符串的联合数组和队列.

uvm_factory_queue_class的定义在uvm_factory.svh文件的开头部分, 可以先瞄一眼.

1
2
3
class uvm_factory_queue_class;
uvm_factory_override queue[$];
endclass

这个uvm_factory_queue_class这个数据竟然还是uvm_factory_override的队列, 这三个m_inst_*成员还真是复杂的很啊.

这里没有注释, 不过从变量的命名和空行分隔排列来看, uvm_factory_queue_class的3个成员是用来管理component树节点重载的数据. 之前说过先不管基于component节点的重载真是先见之明啊.

然后我们来看看uvm_factory_override的类定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class uvm_factory_override;
string full_inst_path;
string orig_type_name;
string ovrd_type_name;
bit selected;
int unsigned used;
uvm_object_wrapper orig_type;
uvm_object_wrapper ovrd_type;
function new (string full_inst_path="",
string orig_type_name="",
uvm_object_wrapper orig_type=null,
uvm_object_wrapper ovrd_type);
if (ovrd_type == null) begin
uvm_report_fatal ("NULLWR", "Attempting to register a null override object with the factory", UVM_NONE);
end
this.full_inst_path= full_inst_path;
this.orig_type_name = orig_type == null ? orig_type_name : orig_type.get_type_name();
this.orig_type = orig_type;
this.ovrd_type_name = ovrd_type.get_type_name();
this.ovrd_type = ovrd_type;
endfunction
endclass

就是一些基本的数据, 两个类型数据orig_typeovrd_type和这两个类型对应的类型名字符串orig_type_nameovrd_type_name. 虽然我们是不管component树节点重载了, 但是uvm_factory_override还是要给它提供支持的, full_inst_path看起来就是支持这个的. 然后selectedused是之前没有出现过的, 这个是怎么用的要看后面了.

这个类的数据成员都是公用的, 也只提供了new这一个方法, new方法也只是用来给成员赋值用的, 只是做了一些小小的空指针检查. 这个类看起来是一副要做大事的样子啊…

重载的实现

好了, 现在我们开始研究重载的最后一步吧. 在上篇中我们讲到:

用Factory创建对象的调用栈为: user_object::type_id::create("name")—>uvm_object_registry#(user_object, "uvm_object")::create("name")—>factory.create_object_by_type(), 最后返回了对象.

重载的实现就隐藏在factory.create_object_by_type()里了, 我们再来恢复一下现场看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function uvm_object uvm_default_factory::create_object_by_type (uvm_object_wrapper requested_type,
string parent_inst_path="",
string name="");
string full_inst_path;
if (parent_inst_path == "")
full_inst_path = name;
else if (name != "")
full_inst_path = {parent_inst_path,".",name};
else
full_inst_path = parent_inst_path;
m_override_info.delete();
requested_type = find_override_by_type(requested_type, full_inst_path);
return requested_type.create_object(name);
endfunction

这里的requested_type = find_override_by_type(requested_type, full_inst_path);这一句就是重载函数了, 字面上看就是在重载表里对requested_type进行查找, 然后返回重载记录表的结果, 然后用返回的结果来创建对象. 按照之前的参数传递, 这里传入的full_inst_path是传入的字符串名name, 而传入的requested_typeuvm_object_registry#(user_object, "user_object")的单例对象. 剩下的秘密, 尽在find_override_by_type这个方法了.

这个方法的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
uvm_factory_queue_class qc;
qc = m_inst_override_queues.exists(requested_type) ?
m_inst_override_queues[requested_type] : null;
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);
m_override_info[index].used++;
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;
lindex=qc.queue[index];
end
end
else begin
qc.queue[index].used++;
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
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;
lindex=m_type_overrides[index];
end
end
else begin
m_type_overrides[index].used++;
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);
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) begin
lindex.used++;
if (override == requested_type) begin
return requested_type;
end
else
return find_override_by_type(override,full_inst_path);
end
return requested_type;
endfunction

这个代码量也是相当的恐怖, 我们还是来分段看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
uvm_factory_queue_class qc;
qc = m_inst_override_queues.exists(requested_type) ?
m_inst_override_queues[requested_type] : null;
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);
m_override_info[index].used++;
return requested_type;
end
end
...
endfunction

最前面的部分, 就出现了uvm_factory_queue_class类型的qc和之前只提到过的m_override_info的操作. 这真是尴尬, 现在我们只好先假定我们用的很克制, m_inst_override_queues里面什么都没有, 然后qc就是个空指针啦. 上篇出现的m_override_info的时候, 都是只有delete操作, 然后这里也就假定这个列表是空吧. 蛤蛤, 先硬着头皮继续往下看.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
uvm_factory_queue_class qc;
...
// 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;
lindex=qc.queue[index];
end
end
else begin
qc.queue[index].used++;
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
...
endfunction

第二部分看起来也是来者不善啊, 不过好在这一段全是基于qc非空的行为, 所以, 还是可以再跳一段…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
uvm_factory_queue_class qc;
...
// 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;
lindex=m_type_overrides[index];
end
end
else begin
m_type_overrides[index].used++;
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);
end
end
end
...
endfunction

终于好像到了我们最关注的部分了. 这里是对m_type_overrides的搜索操作, 成功条件是记录表中一个成员的orig_typerequested_type, 或者记录表中成员的orig_type_namerequested_typetype_name相等. 咦, 会出现这种情况吗?

这里面的第一步就是把这条记录插入到m_override_info这个表里面了, 这~~~看来还是不能不管m_override_info这个东西啊. 不过还是先把这部分看完先, 下面出现了m_debug_pass, 这个变量也先假定为0好了, 然后看后面的else分支. 这里先是把记录表里面的used变量加1, 然后判断requested_type是不是跟记录表里的ovrd_type一致, 一致的话就返回requested_type.

我们的输入就是requested_type啊, 这里的意思似乎是说设置的重载类型就是原始类型? 会这么傻吗? 不过再看到后面的分支, 这还是个递归函数呢, 牛逼. 现在假定我们是一个正常的调用, 也就是说requested_typeovrd_type是不一样的, 这里就会使用m_type_overrides表里的ovrd_type作为requested_type参数进行递归, 再到开头的那里, 就不能跳过m_override_info的处理啦:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
...
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);
m_override_info[index].used++;
return requested_type;
end
end
...

这里要的搜索操作要检查的是记录表m_override_info的成员的orig_type是不是requested_type, 这里的requested_type就是之前ovrd_type, 这个检查为真的话说明真的是有重载类和原始类相同的重载设置操作啦, 然后这里就先输出一个Error. 后面的m_debug_pass值是0, 所有要先做一个debug_create_by_type的操作, 不过我过代码, 这里没有对requested_type做改动. 之后就是对used计数加1, 然后返回啦.

因为正常调用的话这里是不会执行到了(蛤蛤, 尴尬), 所以还是要继续往下执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
...
// 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
...
else begin
m_type_overrides[index].used++;
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);
end
end
end
...
endfunction

还是在这里, 这里的requested_type其实是之前的记录表中的ovrd_type, 所以跟所有的orig_type是不相等的, 而且orig_type_namerequested_typetype_name也是不一样的, 所以这里就要跳过了…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
...
// 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) begin
lindex.used++;
if (override == requested_type) begin
return requested_type;
end
else
return find_override_by_type(override,full_inst_path);
end
return requested_type;
endfunction

然后就到了最后了, 中间的一段注释不管了, 然后m_debug_pass的分支也不管了, 直接就返回了requested_type, 也就是之前传入的ovrd_type. 看起来一次重载查找操作至少要调用两次这个方法呢…

插播一点点, 关于链式重载

回到第二次调用, 这里的requested_type其实是之前的记录表中的ovrd_type, 我们之前是假定这个requested_type是不会跟任何的orig_type相等的, 然后就往下执行了. 正常使用的时候会不会出现requested_typeorig_type相等呢?

仔细考虑一下其实是会出现的. 比如过, 我们先设置A重载为B, 再设置B重载为C, 然后我们调用Factory的create创建A的句柄, 这个时候, 在调用到find_override_by_type的时候, 就会出现orig_type为B类型的重载记录, 这个时候需要继续执行, 这一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type,
string full_inst_path);
uvm_object_wrapper override;
uvm_factory_override lindex;
...
// 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
...
else begin
m_type_overrides[index].used++;
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);
end
end
end
...
endfunction

也就是说, 需要传入B类型的requested_type再次调用find_override_by_type.

总共经过3次调用之后, Factory实际上生成的是C类型的对象, 这样就实现了类型的链式重载.

总结

到这里为止, Factory的重载功能也介绍完了, 我们来总结一下吧:

  1. UVM里面使用Factory重载的流程为: 使用uvm_*_util进行注册, 设置重载, 使用create创建对象;
  2. 为重载提供支持的数据结构是uvm_factory_override类型;
  3. UVM的Factory支持多级链式重载.

然后, 我们的Factory源码探索也就结束了. Factory源码的内容不止这么多, 比如我们在上篇只讲了uvm_object的Factory实现没讲uvm_component的, 在下篇只讲了type_override没有将基于component的inst_override. 另外, 从接口上调用不到的很多代码也没有讲到. 不过, 这两篇读下来, 然后再看剩下的代码相信就没什么难度了.