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’s “return first match” when finding instance override type
Mixed type/inst override
inst override wins due to uvm_factory’s “inst 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