UVM中的sequence

1. sequence的由来

激励最初产生在driver中,如下所示:

task driver::main_phase(uvm_phase phase);
    transaction tr;
    phase.raise_objection(this);
    tr = new;
    assert(tr.randomize);
    drive_one_tr(tr);
    phase.drop_objection(this);
endtask

当只施加一种激励时,上述方法是可行的。但是如果需要对DUT施加不同的激励时,就需要对上述的main_phase进行修改。每次修改会很容易将之前对的地方改错,所以这种方法是不可取的,因为其扩展性太差。
想要实现上述目标,就应该将修改的部分从driver中独立出去,这时就引入了sequence机制。在不同的测试用例中,将不同的sequence设置成sequencer的main_phase的default_sequence。当sequencer执行到main_phase时,发现有default_sequence,那么它就会启动sequence。

2. sequence的启动与执行

启动方法一:sequence定义后,使用start任务启动:

sequence seq;
seq = sequence::type_id::create("seq");
seq.start(sequencer);

启动方法二:使用default_sequence启动:

uvm_config_db(uvm_object_wrapper)::set(this,
									   "env.i_agt.sqr.main_phase",
									   "default_sequence",
									   case_sequence::type_id::get());

或者:

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()。

3. sequence的仲裁机制

(1)同一sequencer上启动多个sequence
UVM支持在同一时刻在同一sequencer上启动多个sequence:

task my_case::main_phase(uvm_phase phase);
	sequence0 seq0;
	sequence1 seq1;
	seq0 = new("seq0");
	seq1 = new("seq1");
	seq0.start_phase = phase;
	seq1.start_phase = phase;
	fork
		seq0.start(env.i_agt.sqr);
		seq1.start(env.i_agt.sqr);
	join
endtask

运行上述代码后,两个sequence会交替产生transaction。那么sequencer会根据什么选择使用哪个sequence的transaction呢?这就涉及到sequence的仲裁问题。sequence的仲裁算法包括:

SEQ_ARB_FIFO          // 遵循先入先出顺序,不考虑优先级         
SEQ_ARB_WEIGHTED      // 加权的仲裁
SEQ_ARB_RANDOM        // 完全随机选择
SEQ_ARB_STRICT_FIFO   // 严格按照优先级
SEQ_ARB_STRICT_RANDOM // 严格按照优先级,当有多个同一优先级的sequence时,随机从最高优先级中选择
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

start任务的第三个参数是优先级。对sequence设置优先级其本质上是对其产生的transaction设置优先级。

4. sequencer的lock操作

lock操作的应用场景:某个sequence一旦开始执行,那么它所有的transaction必须连续交给driver,如果中间夹杂其他sequence的transaction,就会发生错误。
lock,即sequence向sequencer发送一个请求,并与其他sequence发送的transaction请求一起被放入sequencer的仲裁队列中。当其前面的所有请求被执行完毕后,sequencer开始响应该lock请求,此后sequencer会一直连续发送该sequence的transaction,直到unlock操作被调用。lock操作实例如下:

class sequence extends uvm_sequence #(transaction);
	virtual task body();		
		lock();
		repeat(3) begin
			`uvm_do_with(my_trans);
		end	
		unlock();
	endtask
endclass

如果两个sequence都在使用lock任务来获取sequencer的所有权时,先获得使用权的sequence在执行完毕后才会将所有权交还给另外一个sequence。

5. sequence的grab操作

与lock操作一样,grab操作同样用于获取sequencer的所有权,只是grab操作优先级比lock操作更高。lock请求是被插入sequencer仲裁队列的最后面,等前面的仲裁请求都执行完毕之后才会响应lock操作。而grab请求则被放入sequencer仲裁队列的最前面,它几乎一发出就获得了sequencer的所有权。grab操作实例如下:

class sequence extends uvm_sequence #(transaction);
	virtual task body();		
		grab();
		repeat(3) begin
			`uvm_do_with(my_trans);
		end	
		ungrab();
	endtask
endclass

如果两个sequence都在使用grab任务来获取sequencer的所有权时,先获得使用权的sequence在执行完毕后才会将所有权交还给另外一个sequence。
如果一个sequence在使用grab任务获得sequencer的所有权前,另一个sequence已经使用lock任务获得了sequencer的所有权,这时grab任务会一直等待lock操作的释放。

6. sequence的有效性

当有多个sequence同时在一个sequencer上启动时,所有的sequence都将会参与仲裁。如果想要在某一时间内sequence不参与仲裁,UVM可以通过重载is_relevant函数来使sequence失效,通过重载wait_for_relevant()任务使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在发送完6个transaction后开始失效,1000个时间单位后恢复有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值