(20)UVM sequencer的仲裁机制

sequencer的仲裁机制

sequencer的仲裁机制介绍

  • 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。

  • 这三种模式的区别在于,UVM_SEQ_ARB_WEIGHTED的授权可能会落到各个优先级sequence的请求上面,而UVM_SEQ_ARB_STRICT_RANDOM则只会将授权随机安排到最高优先级的请求上面,UVM_SEQ_ARB_STRICT_FIFO则不会随机授权,而是严格按照优先级以及抵达顺序来依次授权。
  • 没有特别的要求,用户不需要再额外自定义授权机制,因此使用UVM_SEQ_ARB_USER这一模式的情况不多见,其他模式可以满足绝大多数的仲裁需求。
  • 鉴于sequence传送的优先级可以影响sequencer的仲裁授权,我们有必要结合sequencer的仲裁模式和sequence的优先级给出一段例码。
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()方法来实现,这两种方法的区别在于:

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

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的死锁行为。

关注作者

  • 自述
    作者是一位中科大数字设计专业的研究生,水平有限,如有错误,请大家指正,想要与大家一同进步。
  • 经历
    曾获得国家奖学金,“高教社杯”数学建模国家二等奖等
  • 陆续更新:
    1.与UVM验证相关的system verilog后续内容;
    2.与verilog数字设计相关的一些基础模块设计,例如FIFO,UART,I2C等的书写。
    3.保研与竞赛经历等
  • 微信公众号
    欢迎大家关注公众号“数字IC小白的日常修炼”,期待与大家一同仗剑遨游数字IC世界。
  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数字IC小白的日常修炼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值