uvm sequence机制 sequence library机制 单例模式 starting_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_itemfinish_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()做的事情

  1. case中调用seq.start(seqr);
  2. start()内部调用set_item_context(parent_sequence,sequencer)m_sequencerm_parent_sequence赋值
  3. set_item_context内部执行set_sequencer (sequencer),set_sequencer内部执行m_sequencer = sequencer;把传入的sqr参数赋给m_sequencer
  4. 同时set_sequencer()会执行m_set_p_sequencer这个空虚函数。调用uvm_declare_p_sequencer这个宏,可以给p_sequencer赋值
  5. 接着start()会执行pre_start(),pre_body(),body()等方法
  6. 这里body()是重点,sequence需要重写body()

body()做的事情

  1. 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中的bodysequencer在哪个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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值