object object什么意思_读UVM源代码(五)uvm_object宏对factory的调用

本文重点讲解包含uvm_field的uvm_object宏如何调用factory。从sequence类开始,探讨type_id来源,分析uvm_object_utils_begin宏的作用,深入研究uvm_object_registry类及其get、create函数,还提及factory类的register函数,最后记录了对wrapper类和factory表用法的疑问。

其实这一篇在逻辑上应该是放在第一篇之后的,因为第一篇总结了uvm_field宏的内容,而这一篇重点讲的是包含了uvm_field的uvm_object宏如何调用factory的故事。

这次把总结的图先放出来吧,对照着图盘逻辑比较清晰一点。

b0ae7876120cddf04366e1d6d55feb2e.png

故事是从第二篇里提到的sequence类开始的,先把sequence部分的代码重新放一次在下面:

class one_jelly_bean_sequence extends uvm_sequence#(jelly_bean_transaction);
`uvm_object_utils(one_jelly_bean_sequence)

function new(string name = "");
super.new(name);
endfunction: new

task body();
jelly_bean_transaction jb_tx;
jb_tx = jelly_bean_transaction::type_id::create(.name("jb_tx"), .contxt(get_full_name()));
start_item(jb_tx);
assert(jb_tx.randomize());
finish_item(jb_tx);
endtask: body
endclass: one_jelly_bean_sequence

这次我们就只关注下面这句话,代码里其它部分前几篇讲过了,

jb_tx = jelly_bean_transaction::type_id::create(.name("jb_tx"), .contxt(get_full_name()));

首先的一个问题,type_id是哪来的?

答:来源于uvm_sequence_item中uvm_object_utils_begin这个宏拓展的代码。先重新看一眼读UVM代码(一)里提到的uvm_sequence_item里,用于注册元素的内容:

`uvm_object_utils_begin(jelly_bean_transaction)
`uvm_field_enum(flavor_e, flavor, UVM_ALL_ON)
`uvm_field_enum(color_e, color, UVM_ALL_ON)
`uvm_field_int(sugar_free, UVM_ALL_ON)
`uvm_field_int(sour, UVM_ALL_ON)
`uvm_field_enum(taste_e, taste, UVM_ALL_ON)
`uvm_object_utils_end

在(一)中我们知道了uvm_field_utils_begin到uvm_field_utils_end以及中间的一些列uvm_field宏的作用是组成了一个叫某某automation的函数,而这一系列的宏完成的不止于此。因为uvm_field_utils_begin是uvm_object_utils_begin这个宏的最后一句话,从uvm_object_utils_begin开始到uvm_field_utils_begin,中间系统还做了很多其它的事情。我们通过源代码来看一下中间做了什么:

`define uvm_object_utils_begin(T) 
`m_uvm_object_registry_internal(T,T) 
`m_uvm_object_create_func(T) 
`m_uvm_get_type_name_func(T) 
`uvm_field_utils_begin(T) //在网上的官方库里只有搜这个才能搜出来上面几句所在的位置

最后一句`uvm_field_utils_begin(T)我们很熟悉了,现在来看中间三句话:

第一句:

// m_uvm_object_registry_internal
// ------------------------------

//This is needed due to an issue in of passing down strings
//created by args to lower level macros.
`define m_uvm_object_registry_internal(T,S) 
typedef uvm_object_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

这里干了两件事:

1.获取我们通过`uvm_object_utils_begin(jelly_bean_transaction)传进来的jelly_bean_transaction这个类,然后声明了一个该类型的uvm_object_registry类,同时把这个uvm_object_registry起个别名叫type_id。

2.声明了两个函数,最终效果是调用了type_id,也就是uvm_object_registry这个类型中的get函数。

下面我们去uvm_object_registry看看这是个什么,先看简介:

c83fc49f448ee291d11fdc3f3193e72f.png

接着来看看uvm_object_registry类里面的get()函数是怎么回事:

class uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
extends uvm_object_wrapper;
typedef uvm_object_registry #(T,Tname) this_type;

local static this_type me = get();

// Function: get
//
// Returns the singleton instance of this type. Type-based factory operation
// depends on there being a single proxy instance for each registered type.

static function this_type get();
if (me == null) begin
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
me = new;
factory.register(me);
end
return me;
endfunction

为了方便看我把类的开头也截了一点放进来,重点看get函数,干了两件事,一个是new了一个自己这种uvm_object_registry类,另外一个是弄了个factory类,同时调用了factory里面的register函数。

接下来就去到factory类里面去看看register是怎么回事,进去一看发现factory里的register是个纯虚函数,它的具体实现是在factory下面的一个子类uvm_default_factory里完成的,代码如下:

function void uvm_default_factory::register (uvm_object_wrapper obj);
if (obj == null) begin
uvm_report_fatal ("NULLWR", "Attempting to register a null object with the factory", UVM_NONE);
end
if (obj.get_type_name() != "" && obj.get_type_name() != "<unknown>") begin
if (m_type_names.exists(obj.get_type_name()))
uvm_report_warning("TPRGED", {"Type name '",obj.get_type_name(),
"' already registered with factory. No string-based lookup ",
"support for multiple types with the same type name."}, UVM_NONE);
elsem_type_names[obj.get_type_name()] = obj;
end
if (m_types.exists(obj)) begin
if (obj.get_type_name() != "" && obj.get_type_name() != "<unknown>")
uvm_report_warning("TPRGED", {"Object type '",obj.get_type_name(),
"' already registered with factory. "}, UVM_NONE);
end
else begin
m_types[obj] = 1;
// If a named override happens before the type is registered, need to copy
// the override queue.
// Note:Registration occurs via static initialization, which occurs ahead of
// procedural (e.g. initial) blocks. There should not be any preexisting overrides.
if(m_inst_override_name_queues.exists(obj.get_type_name())) begin
m_inst_override_queues[obj] = new;
m_inst_override_queues[obj].queue = m_inst_override_name_queues[obj.get_type_name()].queue;
m_inst_override_name_queues.delete(obj.get_type_name());
end
if(m_wildcard_inst_overrides.size()) begin
if(! m_inst_override_queues.exists(obj))
m_inst_override_queues[obj] = new;
foreach (m_wildcard_inst_overrides[i]) begin
if(uvm_is_match( m_wildcard_inst_overrides[i].orig_type_name, obj.get_type_name()))
m_inst_override_queues[obj].queue.push_back(m_wildcard_inst_overrides[i]);
end
end
end
endfunction

重点是加粗部分那句话,这里面的m_type_names是一个wrapper类型的数组,obj.get_type_name是uvm_object下的一个函数,作用是返回用string表达的object类型。所以可以理解成register是在uvm_factory里面做了一张叫m_type_names的表,这个表的索引是各种object的type字符串,内容就是这些object对应的registry。


接下来看第二句:

// m_uvm_object_create_func
// ------------------------


`define m_uvm_object_create_func(T) 
function uvm_object create (string name=""); 
T tmp; 
`ifdef UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR 
tmp = new(); 
if (name!="") 
tmp.set_name(name); 
`else 
if (name=="") tmp = new(); 
else tmp = new(name); 
`endif 
return tmp; 
endfunction

就是个new函数。

第三句:

// m_uvm_get_type_name_func
// ----------------------


`define m_uvm_get_type_name_func(T) 
const static string type_name = `"T`"; 
virtual function string get_type_name (); 
return type_name; 
endfunction

就是用string返回了类型名称。

这两句倒不是很重要233


现在我们知道了type_id是什么,它就是一个registry类,也知道了uvm_object_utils_begin干了什么,但我们对registry了解还是不足,下面深入看一下这里面的create函数,提前总结吧,这是个三层套娃的过程。

1.create(属于uvm_object_registry )

typedef uvm_object_registry #(T,Tname) this_type;

// Function: create
//
// Returns an instance of the object type, ~T~, represented by this proxy,
// subject to any factory overrides based on the context provided by the
// ~parent~'s full name. The ~contxt~ argument, if supplied, supersedes the
// ~parent~'s context. The new instance will have the given leaf ~name~,
// if provided.

static function T create (string name="", uvm_component parent=null,
string contxt="");
uvm_object obj;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
if (contxt == "" && parent != null)
contxt = parent.get_full_name();
obj = factory.create_object_by_type(get(),contxt,name);
if (!$cast(create, obj)) begin
string msg;
msg = {"Factory did not return an object of type '",type_name,
"'. A component of type '",obj == null ? "null" : obj.get_type_name(),
"' was returned instead. Name=",name," Parent=",
parent==null?"null":parent.get_type_name()," contxt=",contxt};
uvm_report_fatal("FCTTYP", msg, UVM_NONE);
end
endfunction

可以看到核心是调用了factory的create_object_by_type。

2.create_object_by_type(属于factory)

// create_object_by_type
// ---------------------

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是一个wrapper,这是registry的父类,并且wrapper本身是个虚类,我们就理解成是一个registry好了,所以这个create在factory的create_object_by_type里绕了一圈之后,回到了registry的另外一个函数create_object里面。说实话我不理解为什么UVM的代码要搞得这么绕来绕去233

3.create_object(属于uvm_object_registry )

// Function: create_object
//
// Creates an object of type ~T~ and returns it as a handle to a
// <uvm_object>. This is an override of the method in <uvm_object_wrapper>.
// It is called by the factory after determining the type of object to create.
// You should not call this method directly. Call <create> instead.

virtual function uvm_object create_object(string name="");
T obj;
`ifdef UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR
obj = new();
if (name!="")
obj.set_name(name);
`else
if (name=="") obj = new();
else obj = new(name);
`endif
return obj;
endfunction

搞了半天create最后就是一个new。


最后是记两个我自己目前还好奇的地方,1.为什么要有个wrapper类?2.factory里面那个表的用法?以后明白了再回来总结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值