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()
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
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 |
|
當有多個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[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//檢查override type 和original type是否相同
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)//沒有發生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);
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