《UVM实战》笔记——第6章 sequence机制

一、sequence的启动与执行

  • 启动方法一:sequence定义后,使用start任务启动:
sequence seq;
seq = sequence::type_id::create("seq");
seq.start(sequencer);
  • 启动方法二:使用default_sequence启动:
  • 可以在不同的地方通过default_sequence来启动sequence,比如在env中,第一个参数是this,第二个是相对于第一个参数的相对路径,路径需要指定到phase一级,比如main_phase,第三个和第四个参数纯属规定,照抄就行。
function void my_case::build_phase(uvm_phase phase);
	case_sequence seq;
	super.build_phase(phase);
	seq = new("seq");
	uvm_config_db(uvm_object_wrapper)::set(this,
									   "env.i_agt.sqr.main_phase",
									   "default_sequence",
									   seq);

  • sequence启动后或自动执行sequence的body任务,除此之外还会自动调用sequence的pre_body和post_body:
class case_sequence extends uvm_sequence #(transaction);
	virtual task pre_body();

	endtask

	virtual task post_body();
	
	endtask

	virtual task body();

	endtask
	`uvm_object_utils(case_sequence);
endclass

三个函数的执行顺序是:pre_body() -> body() -> post_body()

二、sequencer的仲裁机制

2.1 item/sequence的优先级

  • uvm_sequencer类自建了仲裁机制用来保证多个sequence在同时挂载到sequencer时,可以按照仲裁规则允许特定sequence中的item优先通过。

  • 在实际使用中,我们可以通过uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)函数来设置仲裁模式,这里的仲裁模式UVM_SEQ_ARB_TYPE有下面几种值可以选择。

1.**UVM_SEQ_ARB_FIFO**:            默认模式。来自于sequences的发送请求,按照FIFO先进先出的方式被依次授权,和优先级没有关系。
2.**UVM_SEQ_ARB_WEIGHTED**:        不同sequence的发送请求,将按照它们的优先级权重随机授权。
3.**UVM_SEQ_ARB_RANDOM**:          不同的请求会被随机授权,而无视它们的抵达顺序和优先级。
4.**UVM_SEQ_ARB_STRICT_FIFO**:     不同的请求,会按照它们的优先级以及抵达顺序来依次授权,因此与优先级和抵达时间都有关。
5.**UVM_SEQ_ARB_STRICT_RANDOM**:  不同的请求,会按照它们的最高优先级随机授权,与抵达时间无关。
6.**UVM_SEQ_ARB_USER**:            用户可以自定义仲裁方法user_priority_arbitration()来裁定那个sequence的请求被优先授权。

在上面的仲裁模式中,与priority有关的模式有UVM_SEQ_ARB_WEIGHTED、UVM_SEQ_ARB_STRICT_FIFO和UVM_SEQ_ARB_STRICT_RANDOM。

m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO); 
//设置sqr仲裁算法
  • 这三种模式的区别在于,UVM_SEQ_ARB_WEIGHTED的授权可能会落到各个优先级sequence的请求上面,而UVM_SEQ_ARB_STRICT_RANDOM则只会将授权随机安排到最高优先级的请求上面,UVM_SEQ_ARB_STRICT_FIFO则不会随机授权,而是严格按照优先级以及抵达顺序来依次授权。

  • 没有特别的要求,用户不需要再额外自定义授权机制,因此使用UVM_SEQ_ARB_USER这一模式的情况不多见,其他模式可以满足绝大多数的仲裁需求。

  • transaction优先级设置:当使用uvm_do或者uvm_do_with宏时,产生的transaction的优先级是默认的优先级,即-1,可以通过uvm_do_pri及uvm_do_pri_with设置所产生的transaction的优先级。uvm_do_pri与uvm_do_pri_with的第二个参数是优先级,这个数值必须是大于等于-1的整数,数字越大,优先级越高。

  • sequence优先级设置:

task my_case::main_phase(uvm_phase phase);
	env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);
	fork
		seq0.start(env.i_agt.sqr, null, 200);
		seq1.start(env.i_agt.sqr, null, 400);
	join
endtask

UVM中的sequence

2.2 sequencer的锁定机制

有的sequence还会要求一旦它拿到sequencer的控制权 ,就要把它里面的transaction全部传输出去,中间不允许被打断,这时就要使用锁定操作来解决

  • lock()与unlock()这一对方法可以为sequence提供排外的访问权限,但前提条件是,该sequence首先需要按照sequencer的仲裁机制获得授权。而一旦sequence获得授权,则无需担心权限被收回,只有该sequence主动解锁(unlock)它的sequencer,才可以释放这一锁定的权限。lock()是一种阻塞任务,只有获得了权限,它才会返回。
class sequence extends uvm_sequence #(transaction);
	virtual task body();		
		lock();
		repeat(3) begin
			`uvm_do_with(my_trans);
		end	
		unlock();
	endtask
endclass
  • grab与ungrab()也可以为sequence提供排外的访问权限,而且它只需要在sequencer下一次授权周期时就可以无条件地获得授权。与lock方法相比,grab方法无视同一时刻内发起传送请求的其他sequence,而唯一可以阻值它的只有已经预先获得授权的其他lock或者grab的sequence。
  • 这里需要注意的是,由于"解铃还须系铃人",如果sequence使用了lock()或者grab()方法,必须再sequence结束前调用unlock()或者ungrab()方法来释放权限,否则sequencer会进入死锁状态而无法继续为其余sequence授权。
class sequence extends uvm_sequence #(transaction);
	virtual task body();		
		grab();
		repeat(3) begin
			`uvm_do_with(my_trans);
		end	
		ungrab();
	endtask
endclass

2.3 sequence的有效性

除了独占sequencer的控制权外,也可以通过重载is_relevant函数,放弃sequencer的控制权,即让特定的sequence不参与sequencer的仲裁。返回值如果为1,说明sequence有效,否则无效

class ssequence extends uvm_sequsence #(transaction);
	transaction m_trans;
	int num;
	virtual function bit is_relevant();
		if(delay_en == 1) return 0;
		else return 1;
	endfunction

	virtual task wait_for_relevant();
		#1000;
		delay_en = 0;
	endtask
	
	virtual task body();
		fork
			repeat(10) begin				
				`uvm_do(m_trans);
				num++;
				if(num == 6) delay_en = 1;
			end
		join
	endtask
endclass

三、sequence相关宏

在这里插入图片描述

四、virtual sequencer

4.1 何时使用virtual sequencer/sequence

如果只有一个激励驱动的 agent,则不需要virtual sequencer。如果你有多个驱动agent,但不需要激励之间的协调(在设计上是相互独立的),则不需要virtual sequencer。如果您有多个驱动 agent并且需要激励间的协调,则需要一个virtual sequencer。如果测试平台将来需要扩展成有多个agent,或者多个独立激励的测试平台需要设计成相互协调的激励,那么环境就要更新到包括一个或多个virtual sequencer。

在这里插入图片描述

  • virtual sequence:承载不同目标sequencer的sequence群落,实现sequence同步;virtual sequence一般只会挂载到virtual sequencer上,且没有自己的sequence_item,只用于控制其他的sequence执行顺序,起统一调度作用。
  • virtual sequencer:桥接其它sequencer,即连接所有底层sequencer的句柄(指针),是一个中心化的路由器。virtual sequencer本身并不传送item数据对象,因此不需要与driver进行TLM连接。所以用户需在顶层的connect阶段做好virtual sequencer中各个sequencer句柄与sequencer实体对象的一一连接,避免句柄悬空。

4.2 实现virtual sequencer

  1. 在virtual sequencer中定义指向其他真实sequencer句柄指针;
  2. 在virtual sequence中定义sequence句柄,在body( )任务中控制这些序列;
  3. 通过宏`uvm_declare_p_sequencer( )来绑定virtual sequencer同时声明p_sequencer,并操作virtual sequencer中的内容;
  4. 通过宏`uvm_do_on( )将虚序列器句柄与虚序列句柄相连接;
  5. 注意区别:virtual_sequence中嵌套的sequence和普通sequence中嵌套sequence。普通sequence中嵌套的sequence都在同一个sequencer上启动(通过sequencer仲裁决定);而在virtual sequence中嵌套的sequence可以在不同sequencer实体上同时启动。
class virtual_sequencer extends uvm_sequencer;
   bfm_sequencer   bfm0_sqr;            //1.插入虚序列器句柄,指向真实sequencer
   bfm_sequencer   bfm1_sqr;  
   function new(string name, uvm_component parent);
      super.new(name,parent);
   endfunction
endclass

class virtual_sequence extends uvm_sequence;
   `uvm_object_utils(virtual_sequence)
   `uvm_declare_p_sequencer(virtual_sequencer)         //1.声明p_sequencer,操作virtual sequencer中的内容
   bfm_sequence   bfm0_seq;                            //2.插入序列句柄
   bfm_sequence   bfm1_seq;                            //序列seq可由不同的seqr启动
   virtual task body();
      `uvm_do_on(bfm0_seq,p_sequencer.bfm0_sqr);       //3. 将虚序列器句柄与虚序列句柄相连接
      `uvm_do_on(bfm1_seq,p_sequencer.bfm1_sqr);
   endfunction
endclass

4.2.1 关于p_sequencer的说明:

sequence类里有一个uvm_sequencer_base类型m_sequencer指针,当sequence和sequencer关联后,m_sequencer会自动指向该sequencer,但通过m_sequencer不能直接使用seqr里的变量,否则会出现编译错误。只能使用cast强制向子类转换后,才能通过m_sequencer.xxx来访问该seqr内的xxx变量。
  
UVM引入p_sequencer,可以自动的实现上面所述的cast动作,从而可以在sequence中自由使用关联sequencer内的变量。

p_sequencer并不是UVM自动地在sequence的创建的,需要用户使用uvm_declare_p_sequencer宏声明,之后UVM会自动实现指向seqr及cast的动作。

4.3 在环境/测试用例中连接sequencer到virtual sequencer

  • 在build_phase阶段创建并例化virtual sequencer;将不同agt场景下的sqr发送的default sequence设置为null,关闭相应的sequence;
  • 在connect_phase阶段,将被控制的sequencers与virtual sequencer关联一起;
  • `在env或test中配置virtual_sequence为default sequence,在需要的phase阶段执行virtual sequence;
class top_env extends uvm_env;
   virtual_sequencer       v_sqr;     //and subenvs
   ...
   virtual funvtion void build_phase(uvm_phase phase);
      super.build_phase(phase);
      ...
      v_sqr = virtual_sequencer::type_id::create("v_sqr",this);
      uvm_config_db#(uvm_object_wrapper)::set(this,"subenv0.bfm0_agt.sqr.main_phase","default_sequence",null);
      uvm_config_db#(uvm_object_wrapper)::set(this,"subenv0.bfm1_agt.sqr.main_phase","default_sequence",null);
      uvm_config_db#(uvm_object_wrapper)::set(this,"v_sqr.main_phase","default_sequence",virtual_sequence::get_type());
   endfunction
   
   virtual function void connect_phase(uvm_phase phase);
      v.sqr.bfm0_sqr = bfm_agt0.bfm0_sqr;        //将被控制的真实sequencers赋给virtual sequencer的指针,建立连接
      v.sqr.bfm1_sqr = bfm_agt1.bfm1_sqr;
   endfunction
endclass

五、sequence library

参考文章:
UVM sequencer的仲裁机制
UVM中的sequence
UVM——虚序列器与虚序列(virtual sequencer与virtual sequence)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值