其他分享
首页 > 其他分享> > (19)UVM 史上最强sequence相关宏操作总结

(19)UVM 史上最强sequence相关宏操作总结

作者:互联网

史上最强sequence相关宏操作总结

文章目录

一、序列宏

下面一段代码是对start()方法执行过程的自然代码描述,可以看出它们执行的顺序关系和条件:

sub_seq.pre_start()       (task)
sub_seq.pre_body()        (task) if call_pre_post==1
	parent_seq.pre_do(0)  (task) if parent_sequence!=null
	parent_seq.mid_do(this) (func) if parent_sequence!=null
sub_seq.body               (task) YPUR STIMULUS CODE
	parent_seq.post_do(this) (func) if parent_sequence!=null
sub_seq.post_body()        (task) if_call_pre_post==1
sub_seq.post_start()       (task)

下面是start_item()/finish_item()的自然代码描述,来表示执行发送item时的相关方法执行顺序:

sequencer.wait_for_grant(prior) (task)
parent_seq.pre_do(1)            (task)
parent_seq.mid_do(item)         (func)
sequencer.send_request(item)    (func)
sequencer.wait_for_item_done()  (task)
parent_seq.post_do(item)        (func)

在这里插入图片描述

正是通过几个sequence/item宏来打天下的方式,用户可以通过

`uvm_do/`uvm_do_with

来发送无论是sequence还是item。这种不区分对象是sequence还是item的方式,带来了不少便捷,但也容易引起verifier们的惰性。所以在使用它们之前,需要先了解它们背后的sequence和item各自发送的方法。

不同的宏,可能会包含创建对象的过程也可能不会创捷对象。例如

`uvm_do/`uvm_do_with

会创建对象,而`uvm_send则不会创建对象,也不会将对象做随机处理,因此要了解它们各自包含的执行内容和顺序。

此外还有其他的宏,例如,将优先级作为参数传递的

`uvm_do_pri/`uvm_do_on_prio

等,还有专门针对sequence的

`uvm_create_seq/`uvm_do_seq/`uvm_do_seq_with

等宏。
on作用,表示我们要特定地把当前这个seq挂载到某一个sqr上面

二、序列宏的实例

class child_seq extends uvm_sequence;
	...
	task body();
		bus_trans req;
		`uvm_create(req)
		`uvm_rand_send_with(req,{data==10;})
	endtask
endclass

class top_seq extends uvm_sequence;
	...
	task body();
		child_seq cseq;
		bus_trans req;
		`uvm_do(cseq)
		`uvm_do_with(req,{data==20;})
	endtask
endclass

最后给出的关于发送sequence/item的几点建议:

三、为什么会锁住sqr?

因为start_item的时候,都会wait_for_grant,一旦你拿到权限,而没有返回,在中间暴力的disable整个seq,那么可能来不及给sqr释放权限,那么可能sqr被死锁。

四、sequencer的仲裁机制

class bus_trans extends uvm_sequence_item;
	rand bit data;
	...
endclass

class child_seq extends uvm_sequence;
	rand int base;
	...
	task body();
		bus_trans req;
		repeat(2) `uvm_do_with(req,{data inside {[base:base+9]};})
	endtask
endclass

class top_seq extends uvm_sequence;
	...
	task body();
	child_seq seq1,seq2,seq3;
	m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);
	fork
		`uvm_do_pri_with(seq1,500,{base==10;})
		`uvm_do_pri_with(seq2,500,{base==20;})
		`uvm_do_pri_with(seq3,300,{base==30;})
	join
	endtask
endclass

class sequencer extends uvm_sequencer;
	...
endclass

class driver extends uvm_driver;
	...
	task run_phase(uvm_phase phase);
		REQ tmp;
		bus_trans req;
		forever begin
			seq_item_port.get_next_item(tmp);
			void'($cast(req,tmp));
			`uvm_info("DRV",$sformatf("got a item %0d from parent sequence %s",req.data,req.get_parent_sequence().get_name()),UVM_LOW)
			seq_item_port.item_done();
		end
	endtask
endclass

class env extends uvm_env;
	sequencer sqr;
	driver drv;
	...
	function void build_phase(uvm_phase phase);
		sqr=sequencer::type_id::create("sqr",this);
		drv=driver::type_id::create("drv",this);
	endfunction
	function void connect_phase(uvm_phase phase);
		drv.seq_item_port.connect(sqr.seq_item_export);
	endfunction
endclass

class test1 extends uvm_test;
	env e;
	...
	task run_phase(uvm_phase phase);
	top_seq seq;
	phase.raise_objection(phase);
	seq=new();
	seq.start(e.sqr);
	phase.drop_objection(phase);
	endtask
endclass

五、sequencer的锁定机制

uvm_sequencer提供了两种锁定机制,分别通过lock()和grab()方法来实现,这两种方法的区别在于:

六、sequencer的锁定示例

class bus_trans extends uvm_sequence_item;
	...
endclass

class child_seq extends uvm_sequence;
	...
endclass

class lock_seq extends uvm_sequence;
	...
	task body();
		bus_trans req;
		#10ns;
		m_sequencer.lock(this);
		`uvm_info("LOCK",get exclusive access by lock()",UVM_LOW)
		repeat(3) #10ns `uvm_do_with(req,{data inside {[100:110]};})
		m_sequencer.unlock(this);
	endtask
endclass

class grab_seq extends uvm_sequence;
	...
	task body();
	bus_trans req;
	#20ns;
	m_sequencer.grab(this);
	`uvm_info("GRAB","get exclusive access by grab()",UVM_LOW)
	repeat(3) #10ns `uvm_do_with(req,{data inside {[200:210]};})
	m_sequencer.ungrab(this);
	endtask
endclass

class top_seq extends uvm_sequence;
	...
	task body();
		child_seq seq1,seq2,seq3;
		lock_seq locks;
		grab_Seq grabs;
		m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);
		fork
			`uvm_do_pri_with(seq1,500,{base==10;})
		    `uvm_do_pri_with(seq2,500,{base==20;})
			`uvm_do_pri_with(seq3,300,{base==30;})
			`uvm_do_pri(locks,300)
			`uvm_do(grabs)
		join
	endtask
endclass

在这里插入图片描述
这里的child_seq中,虽然和上面一样也发送2个item,但每个item之间有10ns的间隔。发送第一个item也延迟10ns

七、sequencer的锁定示例解析

结合例码和输出结果,我们从中可以发现如下几点:
1.对于sequence locks,在10ns时跟其它几个sequence一同向sequencer发起请求,按照仲裁模式,sequencer先后授权给seq1,seq2,seq3,最后才授权给locks。
2.而locks在获得授权之后,就可以一直享有权限而无需担心权限被sequencer收回,locks结束前,用户需要通过unlock()方法返回权限。
3.对于sequence grabs,尽管它的20ns时就发起了请求权限(实际上seq1、seq2、seq3也在同一时刻发起了权限请求),而由于权限已经被locks占用,所以它也无权收回权限。
4.因此只有当locks在40ns结束时,grabs才可以在sequencer没有被锁定的状态下获得权限,而grabs在此条件下获取权限是无视同一时刻发起请求的其他sequence的。
5.同样地,在grabs结束前,也应当通过ungrab()方法释放权限,防止sequencer的死锁行为。

关注作者

标签:do,seq,sequence,19,item,uvm,sequencer,UVM
来源: https://blog.csdn.net/qq_42419590/article/details/121393762