phase机制
uvm单例模式
问
:uvm中的共享资源对象,怎么让组件可以使用?答
:导入类然后在组件中例化。
问
:有没有更好办法?答
:单例模式
class resource;
static local resource r; //静态局部变量
extern protected function new();
extern static function resource get(); //静态方法,获取局部变量句柄
endclass
static function resource resource::get();
if(r == null)begin
r = new();
end
return resource; //实例化了就返回,没有就new
endfunction
class xxx;
resource re = resource::get(); //其他地方调用
endclass
调用get时碰到竞争怎么办?
方案一:初始化时就创建对象
const resource rq = resource::get();
单例模式在uvm中的应用:
uvm root
uvm factory
uvm pool
uvm resource pool
uvm global report server
uvm command line processor
sequence机制
sequence产生激励(transaction),sequencer从sequence获取激励传送给driver,driver从sequencer获取到激励发给DUT。
sequence无phase机制,需要挂在到sequencer上启动。
执行顺序:
在case
中调用start(seqr)
,start(seqr)
会调用sequence
中的body()
,body()
执行的底层代码是start_item
和finish_item()
。(start_item和finish_item调用的方法不深究)
//以下有误
start()传参是transaction时,调用start_item和finish_itme
start()传参是sequence时, 调用sequence的start任务,start会调用sequence的pre_body,body,post_body。如果子sequence的body中的uvm_do系列宏传参是transaction,会调用start_item和finish_item
start_item和finish_item传参必须是transaction,不能是sequence
sequence的body中的内容,产生transaction和发送
start()做的事情
- 在
case
中调用seq.start(seqr);
start()
内部调用set_item_context(parent_sequence,sequencer)
给m_sequencer
和m_parent_sequence
赋值set_item_context
内部执行set_sequencer (sequencer)
,set_sequencer
内部执行m_sequencer = sequencer;
把传入的sqr参数赋给m_sequencer
。- 同时
set_sequencer()
会执行m_set_p_sequencer
这个空虚函数。调用uvm_declare_p_sequencer
这个宏,可以给p_sequencer
赋值 - 接着
start()
会执行pre_start()
,pre_body()
,body()
等方法 - 这里
body()
是重点,sequence需要重写body()
body()做的事情
body()
主要执行uvm_do
系列
start源码如下
class uvm_sequence_base extends uvm_sequence_item;
virtual task start (
uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
//...);
set_item_context(parent_sequence, sequencer);
//...
if(...) seq.body();
//...
endtask
endclass
class uvm_sequence_item extends uvm_transaction;
protected uvm_sequencer_base m_sequencer;
function void set_item_context(uvm_sequence_base parent_seq,
uvm_sequencer_base sequencer = null);
set_sequencer(sequencer);
endfunction
virtual function void set_sequencer(uvm_sequencer_base sequencer);
m_sequencer = sequencer;
m_set_p_sequencer();
endfunction
virtual function void m_set_p_sequencer();
return;
endfunction
endclass
`define uvm_declare_p_sequencer(SEQUENCER) \
SEQUENCER p_sequencer; \
virtual function void m_set_p_sequencer();\
super.m_set_p_sequencer(); \
if(!$cast(p_sequencer,m_sequencer)) \
//...
endfunction
启动与挂载
1.启动: 指用哪种方式调用body()
。
2.挂载: sequence
需要与sequencer
挂载,对于transaction,需要先发送给sequencer,再发送给driver。(无论是transaction还是sequence,挂载的本质是给uvm_sequence_item
的成员变量m_sequencer
赋值,transaction和sequence都继承于uvm_sequence_item
。
启动sequence
启动方式1:start()
//在testcase中先用工厂机制实例化,再raise_objection,再start()。最后drop_objection
function void case_name1:build_phase(uvm_phase phase);
super.build_phase(phase);
ms = my_sequence::type_id::create("ms"); //实例化sequence
endfunction
function void case_name1:run_phase(uvm_phase phase);
phase.raise_objection(this);
ms.start(my_sequencer); //my_sequencer是sequencer的实例化路径。也可以使用m_sequencer,如果该sequence实例化在sequencer下,也可以用this
phase.drop_objection(this);
endfunction
启动方式2:uvm_config_db#()::set()
uvm_config_db最后也是调用start()方法
//UVM1.2不建议用default_phase方式,因为2.0配置default_phase后starting_phase不会自动赋值
//不实例化sequence
uvm_config_db#(uvm_object_wrapper)::set(this,"my_env.my_agent.my_sequencer.main_phase","default_sequence",my_sequence::type_id::get());
uvm_config_db #(uvm_object_wrapper)::set(this,"my_env.my_agent.my_sequencer.main_phase","default_sequence",my_sequencer.get_type());
//不实例化sequence
function void my_case0::build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_config_db#(ubm_object_wrapper)::set(this, // 第一个参数是指定seqr的路径
"env.in_agent.sqr.main_phase", // 第二个参数是指定要执行的phase阶段
"default_sequence", // 第三个参数是指定你的seq
sequence_base::type_id::get()); // uvm_config_db设置default_sequencer
endfunction
//实例化sequence
function void my_case0::build_phase(uvm_phase phase);
case0_sequence cseq; //
super.build_phase(phase);
cseq = new("cseq"); //这里错误,应该用factory机制实例化
uvm_config_db#(uvm_sequence_base)::set(this, //
"env.i_agt.sqr.main_phase", //
"default_sequence", //
cseq); //
endfunction
具体start做的事情可以参考UVM之sequence的启动:start()与宏uvm_do详解_uvm sequence start-CSDN博客
`define uvm_send(SEQ_OR_ITEM) \
`uvm_send_pri(SEQ_OR_ITEM,-1)
`define uvm_send_pri(SEQ_OR_ITEM, PRIORITY) \
begin \
uvm_sequence_base __seq; \
if (!$cast(__seq,SEQ_OR_ITEM)) begin \
start_item(SEQ_OR_ITEM, PRIORITY);\
finish_item(SEQ_OR_ITEM, PRIORITY);\
end \
else __seq.start(__seq.get_sequencer(), this, PRIORITY, 0);\
end
`define uvm_do_on_pri_with(SEQ_OR_ITEM,SEQR,PRIORITY,CONSTRAINTS) \
begin\
uvm_sequence_base __seq; \
`uvm_create_on(); \
if (!$case(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM,PRIORITY);\
if ((__seq == null || !__seq.do_not_randomize)&& !SEQ_OR_ITEM.randomize() with CONSTRAINTS) begin\
`uvm_warning("RNDFLD","Randomization failed in uvm_do_with action") \
end\
if (!$cast(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM,PRIORITY);\
else __seq.start(SEQR,this,PRIORITY,0);\
end
`define uvm_create_on(SEQ_OR_ITEM, SEQR) \
begin \
uvm_object_wrapper w_; \
w_ = SEQ_OR_ITEM.get_type(); \
$cast(SEQ_OR_ITEM , create_item(w_, SEQR, `"SEQ_OR_ITEM`"));\
end
`define uvm_create(SEQ_OR_ITEM) \
`uvm_create_on(SEQ_OR_ITEM,m_sequence)
重写body()
重写body()方式一:`uvm_do系列宏
`uvm_do(seqr);
重写body()方式二:
uvm_create()
uvm_send()
重写body方式三:
`uvm_create_on();
start_item();
randomize();
finish_item();
virtual task body();
my_transaction tr;
repeat(10) begin
tr = new("tr"); //这里错误,应该用factory机制实例化
assert(tr.randomize() with {tr.pload.size == 200;});
start_item(tr);
finish_item(tr);
end
uvm_do系列宏介绍
uvm_do宏
uvm_do宏做的事
`uvm_create_on();
start_item();
randomize();
finish_item();
//| sequencer.wait_for_grant(prior) (task) \ start_item \
//| parent_seq.pre_do(1) (task) / \
//| `uvm_do* macros
//| parent_seq.mid_do(item) (func) \ /
//| sequencer.send_request(item) (func) \finish_item /
//| sequencer.wait_for_item_done() (task) /
//| parent_seq.post_do(item) (func) /
uvm_do系列
`uvm_do(SEQ_OR_ITEM)
`uvm_do_with(SEQ_OR_ITEM,{CONSTRAINT}
`uvm_do_pri(SEQ_OR_ITEM,PRIORITY)
`uvm_do_pri_with(SEQ_OR_ITEM,PRIORITY,{CONSTRAINTS})
uvm_do_on系列宏
`uvm_do_on(SEQ_OR_ITEM,SEQR)
`uvm_do_on_with(SEQ_OR_ITEM,SEQR,{CONSTRAINTS})
`uvm_do_on_pri(SEQ_OR_ITEM,SEQR,PRIORITY)
`uvm_do_on_pr_with(SEQ_OR_ITEM,SEQR,PRIORITY,{CONSTRAINTS})
上述2个系列底层都是uvm_do_on_pri_with(SEQ_OR_ITEM,SEQR,PRIORITY,CONSTRAINTS)
类图
uvm_void
|
uvm_object
/ \
uvm_transaction uvm_report_object
| |
uvm_sequence_item uvm_component
| |
uvm_sequence_base uvm_sequencer_base //m_sequencer
| |
uvm_sequence uvm_sequencer //p_sequencer
sequence、sequencer、driver三者关系
sequence | sequencer | driver
create_item()
|
start_item() --------------> arbitration<------get_next_item
| | |
randomize() | |
| <-----------------| |
finish_item() ------------------------------------>got item
| | |
NO Rsp | |
| get_response(RSP)<-------------------------------|
| | |
loop finish <-------------------------------------- item_done(RSP)
driver:
driver执行seq_item_port.get_next_item(req); //请求item
driver执行相关操作
driver执行seq_item_port.item_done(); //执行结束
sequence:
重写body()这个task。
方式一:在body()中调用`uvm_do系列宏。 //自动产生item
方式二:在body()中手动执行产生item。
从默认的m_sequencer启动,即从seq.start函数传递的sqr指针。指定在哪个sequencer启动
uvm_sequence_library
class my_sequence extends uvm_sequence#(my_transaction);
class sa6_sequence extends my_sequence;
`uvm_add_do_seq_lib(sa6_sequence,my_sequence_lib)
//注册到my_sequence_lib
endclass
class sa3_sequence extends my_sequence;
`uvm_add_do_seq_lib(sa3_sequence,my_sequence_lib)
//注册到my_sequence_lib
endclass
class sa6_sa3_sequence extends my_sequence;
`uvm_add_do_seq_lib(sa6_sa3_sequence,my_sequence_lib)
//注册到my_sequence_lib
endclass
class my_sequence_lib extends my_sequence_library #(my_transaction);
//my_sequence_library 本质是一个sequence
//my_sequence_lib.start 是默认行为
//每次启动sequence从被注册的sequence中随机选取(sa3/sa6/sa6_sa3)
`uvm_sequence_library_utils(my_sequence_lib)
function new(...);
//....
init_sequence_library();
endfunction
endclass
class my_test extends uvm_test;
my_sequence_lib.add_typewide_sequence(da3_sequence::get_type()); //临时注册da3这个3sequence。
my_sequence_lib msl = my_sequence_lib::type_id::create();
uvm_config_db#(uvm_object_wrapper).set(this,"*.m_seqr.run_phase","default_sequence",my_sequence_lib::get_type());
uvm_config_db#(uvm_sequence_base).set(this,"*.m_seqr.run_phase","default_sequence",msl);
endclass
selection_mode 选择算法
UVM_SEQ_LIB_RAND
UVM_SEQ_LIB_RANDC
UVM_SEQ_LIB_ITEM
UVM_SEQ_LIB_USER
min_random_count 最小执行个数
max_random_count 最大执行个数
sequence_count 自定义执行个数
selection/min/max都可用uvm_config_db进行配置
virtual_sequence
virtual_sequencer
RAL
class config_reg_c extends uvm_reg;
rand uvm_reg_field f1;
rand uvm_reg_field f2;
rand uvm_reg_field f3;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
f1 = uvm_reg_field::type_id::create(…);
f1.config(…);
endfunction
`uvm_object_utils(config_reg_c)
function new(string name = “”);
super.new(…);
endfunction
endclass
sequencer:
查看是否配置了default_sequence
配置default_sequence
设置 starting_phase
随机化sequence
调用sequence的start()方法启动sequence //start执行body方法
sequence:
start()执行body()方法
产生items并将items放入对应的sequencer中
等待driver返回完成标志
`uvm_do();
执行完成就退出
driver:
请求事务
等待获取事务
seq_item_port.get_next_item(req);
处理事务
完成事务后给出标志
seq_item_port.item_done();
`uvm_do(REQ_OR_ITEM)
根据传入的句柄创建该句柄类型的对象
start_item(tr);
randomize();
finish_item(tr);
启动sequence
1.自动(使用uvm_config_db配置default_sequence)
2.手动启动
实例化sequence
phase.raise_objection
start(路径.m_seqr);
phase.drop_objection
获取响应
seq_item_port.get_next_item(req);
$cast(rsp,req.clone());
rsp.set_id_info(req);
seq_item_port.put_response(rsp);
seq_item_port.item_done();
get_response(rsp);//获取响应
rsp.sprint(); //打印出响应
rsp.set_id_info(req);
driver
//这里packet是什么?
uvm_driver 成员变量req rsp
class uvm_driver #(type REQ = uvm_sequence_item,type RSP = REQ) extends uvm_component;
//…
packet req = packet::type_id::create("req",this);
uvm_seq_item_pull_port #(REQ,RSP) seq_item_port;
uvm_analysis_port #(RSP) rsp_port;
REQ req;
RSP rsp;
endclass
task uvm_root::run_test(string test_name = “”);
t
e
s
t
p
l
u
s
a
r
g
(
)
i
f
(
test_plusarg() if(
testplusarg()if(value$plusarg(“UVM_TESTNAME=s%”,test_name))
class new_comp extends old_comp;
//…
endclass
class test_new extends test_base;
set_inst_override_by_type(“”,old_comp::get_type(),new_comp::get_type());
endclass
starting_phase
uvm_phase
类型,uvm_sequence
中的一个变量,用来在sequence
中控制验证平台的关闭
sequence
中的body
被sequencer
在哪个phase中启用,sequence中的start_phase
就等于该phase值
给starting_phase赋值方式
task demo::();
endtask
starting phase的赋值发生的机制是
1.run_test()->excute_phases()->traverse->excute()sqr.start_phase_sequence();
2.start_phase_sequence()中会通过uvm_config_db::get 得到default_sequence的名字,如果get 到了default sequence的名字就会create default_sequence,并且将当前phase(uvm_main_phase或者uvm_run_phase)的句柄赋值给starting phase,如果没有get 到就会直接return退出当前函数;
3.由于uvm_config_db::set default sequence只针对的是virtual sequencer,当执行你调用的子sequencer的时候由于没有uvm_config_db::get到default sequence的名字,所以会直接退出return;
4.所以如果使用了default_sequence机制,并且default sequence中有子sequence,这个时候要在子sequence使用starting_phase.raise_object要非常小心;
class uvm_sequence_base extends uvm_sequence_item;
uvm_phase starting_phase;
endclass