,对于default_sequence启动方式不太理解,今天随笔一下
start_phase_sequence
先在tc中set一个seq,set的方式可以是如下几种,可以例化后set也可以是不例化直接set,可以是uvm_config_db,也可以是uvm_resource_db
myseq_t myseq = new("myseq");
myseq.randomize() with { ... };
uvm_config_db #(uvm_sequence_base)::set(null, "top.agent.myseqr.main_phase",
"default_sequence",
myseq);
uvm_config_db #(uvm_object_wrapper)::set(null, "top.agent.myseqr.main_phase",
"default_sequence",
myseq_type::type_id::get());
The uvm_resource_db can similarly be used.
myseq_t myseq = new("myseq");
myseq.randomize() with { ... };
uvm_resource_db #(uvm_sequence_base)::set({get_full_name(), ".myseqr.main_phase",
"default_sequence",
myseq, this);
uvm_resource_db #(uvm_object_wrapper)::set({get_full_name(), ".myseqr.main_phase",
"default_sequence",
myseq_t::type_id::get(),
this );
type_id简单看一下,之前看的也不是很明白
类注册宏:首先myseq_t通过注册,会定义一个uvm_object_registry参数化的类,参数类型即myseq_t,该类的句柄就是type_id,get_type()是每个经过注册的类都有的一个函数。uvm_object_registry直接继承uvm_object_wrapper,其get()函数返回uvm_object_registry实例的句柄,所以set的是子类的句柄,在环境中将该子类句柄会赋值给父类句柄,得到一个指向子类对象的父类句柄wrapper。
`define uvm_object_utils(T) \
`uvm_object_utils_begin(T) \
`uvm_object_utils_end
`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)
`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
继而调用create_object_by_type,此时注意传入的wrapper是指向uvm_object_registry的wrapper句柄,接着调用wrapper的create_object,wrappe的create_object是虚函数,由于类的多态会调用子类的create_object,返回uvm_object类型句柄,但该句柄也是经过隐式转换的,本来是myseq_t类型的,uvm_object类型句柄指向的是myseq_t,接着继续进行显示类型转换,只有指向子类的父类句柄才能进行cast进行类型转换,因为uvm_sequence指向要大于uvm_sequence_base所以能够进行类型转换,关于类型转换有些忘记了,做个实验试试,可知是可以转换成功的。下图中seq_base是指向seq的句柄。
最后同理,seq指向的是myseq_t,调用strat执行seq,正因为uvm_sequence_base的body函数也是虚函数,所以seq句柄必须是指向的子类对象,否则调用到的只会是uvm_sequence_base的body函数。
下面模拟一下seq启动场景,start的是uvm_sequence_base类型句柄,但指向的是uvm_sequence,uvm_sequence继承于uvm_virtual,uvm_virtual继承于uvm_sequence_base,
module tb;
class uvm_object0;
virtual function base();
$display("this is uvm_obj0");
endfunction
endclass
class uvm_sequence_base0 extends uvm_object0;
virtual function base();
$display("this is uvm_sequence_base0");
endfunction
virtual function call();
$display("this is call in seq_base0");
endfunction
endclass
class uvm_virtual extends uvm_sequence_base0;
virtual function base();
$display("this is uvm_virtual_sequence");
endfunction
virtual function test();
$display("test_virtual");
endfunction
virtual function call();
$display("this is call in virtual seq0");
call_by_call();
endfunction
virtual function call_by_call();
$display("this is call_by_call in virtual seq0");
endfunction
endclass
class uvm_sequence0 extends uvm_virtual;
virtual function base();
$display("this is uvm_sequence0");
endfunction
virtual function test();
$display("test_virtual_sequenec");
endfunction
virtual function call();
$display("this is call in seq0");
super.call();
endfunction
virtual function call_by_call();
$display("this is call_by_call in seq0");
endfunction
endclass
uvm_object0 obj;
uvm_sequence_base0 seq_base;
uvm_sequence0 seq;
initial begin
seq = new();
seq_base = new();
obj = seq;
$display("fail? %d",$cast(seq_base,obj));
seq_base.base();
seq_base.call();
end
endmodule
this is uvm_sequence0
this is call in seq0
this is call in virtual seq0
this is call_by_call in seq0
如果注释掉sequence_base的call,则会报错,因为seq_base是指向子类对象的父类句柄,没法不通过多态访问到子类成员
// start_phase_sequence
// --------------------
function void uvm_sequencer_base::start_phase_sequence(uvm_phase phase);
uvm_object_wrapper wrapper;
uvm_sequence_base seq;
uvm_factory f = uvm_factory::get();
// default sequence instance?
if (!uvm_config_db #(uvm_sequence_base)::get(
this, {phase.get_name(),"_phase"}, "default_sequence", seq) || seq == null) begin
// default sequence object wrapper?
if (uvm_config_db #(uvm_object_wrapper)::get(
this, {phase.get_name(),"_phase"}, "default_sequence", wrapper) && wrapper != null) begin
// use wrapper is a sequence type
if(!$cast(seq , f.create_object_by_type(
wrapper, get_full_name(), wrapper.get_type_name()))) begin
`uvm_warning("PHASESEQ", {"Default sequence for phase '",
phase.get_name(),"' %s is not a sequence type"})
return;
end
end
else begin
`uvm_info("PHASESEQ", {"No default phase sequence for phase '",
phase.get_name(),"'"}, UVM_FULL)
return;
end
end
`uvm_info("PHASESEQ", {"Starting default sequence '",
seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_FULL)
seq.print_sequence_info = 1;
seq.set_sequencer(this);
seq.reseed();
seq.starting_phase = phase;
if (!seq.is_randomized && !seq.randomize()) begin
`uvm_warning("STRDEFSEQ", {"Randomization failed for default sequence '",
seq.get_type_name(),"' for phase '", phase.get_name(),"'"})
return;
end
fork
seq.start(this);
join_none
endfunction
今天想看这个是因为前几天遇到的一个问题,使用default_sequence时会触发多态,今天发现即使是直接start也会触发类的多态(前提是函数都是虚函数),是因为使用type_id例化seq所返回的类型应该也是隐藏了类型转换,seq句柄并不是单纯的指向seq本身。
具体下次再看
type::id::create
static function T create (string name="", uvm_component parent=null,
string contxt="");
uvm_object obj;
uvm_factory f = uvm_factory::get();
if (contxt == "" && parent != null)
contxt = parent.get_full_name();
obj = f.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