UVM实战 卷I学习笔记9——UVM中的sequence(3)


sequence相关宏及其实现

uvm_do系列宏

uvm_do系列宏主要有以下8个:

`uvm_do(SEQ_OR_ITEM)
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR)
`uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)
`uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS)
`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)

其中uvm_do、uvm_do_with、uvm_do_pri、uvm_do_pri_with在前面已经提到过。UVM实战 卷I学习笔记9——UVM中的sequence(1)

介绍另4个:
uvm_do_on用于显式地指定使用哪个sequencer发送此transaction。它有两个参数:transaction的指针和sequencer的指针。当在sequence中使用uvm_do等宏时,其默认sequencer就是此sequence启动时为其指定的sequencer,sequence将这个sequencer的指针放在其成员变量m_sequencer中。事实上uvm_do等价于:`uvm_do_on(tr, this.m_sequencer)

在这里看起来指定使用哪个sequencer似乎并没有用,它的真正作用要在virtual sequence中得到体现(见后文)。
uvm_do_on_pri,有三个参数:transaction的指针、sequencer的指针和优先级
uvm_do_on_with,有三个参数:transaction的指针、sequencer的指针和约束
uvm_do_on_pri_with,四个参数:transaction的指针、sequencer的指针、优先级和约束
如:`uvm_do_on_pri_with(tr, this, 100, {tr.pload.size == 100;}) //注意约束得加花括号

uvm_do系列的其他七个宏其实都是用uvm_do_on_pri_with宏来实现的。如uvm_do宏:

`define uvm_do(SEQ_OR_ITEM) \
	`uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -1, {})

*uvm_create与uvm_send

除了使用uvm_do宏产生transaction,还可使用uvm_create宏与uvm_send宏来产生

class case0_sequence extends uvm_sequence #(my_transaction);
	…
	virtual task body();
		int num = 0;
		int p_sz;repeat (10) begin
			num++;
			`uvm_create(m_trans)
			assert(m_trans.randomize());
			p_sz = m_trans.pload.size();
			{m_trans.pload[p_sz - 4],
		 	 m_trans.pload[p_sz - 3],
			 m_trans.pload[p_sz - 2],
			 m_trans.pload[p_sz - 1]}
			 = num;
			`uvm_send(m_trans)
		end
		…
	endtask
	…
endclass

uvm_create宏的作用是实例化transaction。当一个transaction被实例化后,可以对其做更多的处理,处理完毕后使用uvm_send宏发送出去。这种使用方式比uvm_do系列宏更加灵活。如在上例中,就将pload的最后4个byte替换为此transaction的序号。

事实上,在上述代码中也完全可以不使用uvm_create宏,而直接调用new进行实例化:

virtual task body();
	…
	m_trans = new("m_trans");
	assert(m_trans.randomize());
	p_sz = m_trans.pload.size();
	{m_trans.pload[p_sz - 4],
	 m_trans.pload[p_sz - 3],
	 m_trans.pload[p_sz - 2],
	 m_trans.pload[p_sz - 1]}
	 = num;
	`uvm_send(m_trans)
	… 
endtask

除了uvm_send外还有uvm_send_pri宏,作用是将transaction交给sequencer时设定优先级

virtual task body();
	…
	m_trans = new("m_trans");
	assert(m_trans.randomize());
	p_sz = m_trans.pload.size();
	{m_trans.pload[p_sz - 4],
	 m_trans.pload[p_sz - 3],
	 m_trans.pload[p_sz - 2],
	 m_trans.pload[p_sz - 1]}
	 = num;
	`uvm_send_pri(m_trans, 200)
	…
endtask

*uvm_rand_send系列宏

uvm_rand_send系列宏有如下几个:

`uvm_rand_send(SEQ_OR_ITEM)
`uvm_rand_send_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_rand_send_with(SEQ_OR_ITEM, CONSTRAINTS)
`uvm_rand_send_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)

uvm_rand_send宏与uvm_send宏类似,唯一的区别是它会对transaction进行随机化。这个宏使用的前提是transaction已经被分配了空间,即已经实例化了

m_trans = new("m_trans");
`uvm_rand_send(m_trans)

uvm_rand_send_pri宏用于指定transaction的优先级。它有两个参数:transaction的指针和优先级
uvm_rand_send_with宏用于指定使用随机化时的约束,它有两个参数:transaction的指针和约束
uvm_rand_send_pri_with宏用于指定优先级和约束,它有三个参数:transaction的指针、优先级和约束
如:m_trans = new(“m_trans”);
`uvm_rand_send_pri_with(m_trans, 100, {m_trans.pload.size == 100;}) //注意约束得加花括号

uvm_rand_send系列宏及uvm_send系列宏的意义主要在于如果一个transaction占用的内存比较大,那么很可能希望前后两次发送的transaction都使用同一块内存,只是其中的内容可以不同,这样比较节省内存

*start_item与finish_item

前面一直使用宏产生transaction。宏隐藏了细节,方便了用户的使用,但也给用户带来了困扰:宏到底做了什么事情?

不使用宏产生transaction的方式要依赖于start_item和finish_item。在使用这两个任务前,必须要先实例化transaction后才可以调用这两个任务

tr = new("tr");
start_item(tr);
finish_item(tr);

完整使用如上两个任务构建的一个sequence如下:

virtual task body();
	repeat(10) begin
		tr = new("tr");
		start_item(tr);
		finish_item(tr);
	end
endtask

代码并没有对tr进行随机化。可以在transaction实例化后、finish_item调用前对其进行随机化

class case0_sequence extends uvm_sequence #(my_transaction);
	…
	virtual task body();repeat (10) begin
			tr = new("tr");
			assert(tr.randomize() with {tr.pload.size == 200;});
			start_item(tr);
			finish_item(tr);
		end
		…
	endtask
	…
endclass

上述assert语句也可以放在start_item之后、finish_item之前。uvm_do系列宏其实是将下述动作封装在了一个宏中:

virtual task body();
	…
	tr = new("tr");
	start_item(tr);
	assert(tr.randomize() with {tr.pload.size() == 200;});
	finish_item(tr);
	…
endtask

如果要指定transaction的优先级,那么要在调用start_item和finish_item时都要加入优先级参数:

virtual task body();start_item(tr, 100);
	finish_item(tr, 100);
	…
endtask

如果不指定优先级参数,默认的优先级为-1

*pre_do、 mid_do与post_do

uvm_do宏封装了从transaction实例化到发送的一系列操作,封装的越多则其灵活性越差。

为了增加uvm_do系列宏的功能,UVM提供了三个接口:

  • pre_do是在start_item中被调用的任务在start_item返回前执行的最后一行代码,在它执行完毕后才对transaction进行随机化
  • mid_do是位于finish_item最开始的函数执行完此函数后finish_item才进行其他操作
  • post_do也是位于finish_item中的函数,它是finish_item返回前执行的最后一行代码

它们的执行顺序大致为:
在这里插入图片描述
wait_for_grant、send_request及wait_for_item_done都是UVM内部的一些接口。这三个接口函数/任务的使用示例如下:

class case0_sequence extends uvm_sequence #(my_transaction);
	my_transaction m_trans;
	int num;
	…
	virtual task pre_do(bit is_item);
		#100;
		`uvm_info("sequence0", "this is pre_do", UVM_MEDIUM)
	endtask
	virtual function void mid_do(uvm_sequence_item this_item);
		my_transaction tr;
		int p_sz;
		`uvm_info("sequence0", "this is mid_do", UVM_MEDIUM)
		void'($cast(tr, this_item));
		p_sz = tr.pload.size();
		{tr.pload[p_sz - 4],
		 tr.pload[p_sz - 3],
		 tr.pload[p_sz - 2],
		 tr.pload[p_sz - 1]} = num;
		tr.crc = tr.calc_crc();
		tr.print();
	endfunction
	virtual function void post_do(uvm_sequence_item this_item);
		`uvm_info("sequence0", "this is post_do", UVM_MEDIUM)
	endfunction
	virtual task body();repeat (10) begin
			num++;
			`uvm_do(m_trans)
		end
		…
	endtask
	…
endclass

pre_do的参数:用于表明uvm_do宏是在对一个transaction还是在对一个sequence进行操作

mid_do和post_do的两个参数是正在操作的sequence或者item的指针,但是其类型是uvm_sequence_item类型。通过cast可以转换成目标类型(示例中为my_transaction) 。

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值