(10)UVM 层次化序列之Virtual Sequence


virtual sequence和Hierarchical Sequence一样,都是对于各个sequence的协调。但也存在不同点, hierarchical sequence面对的对象是同一个sequencer,即hierarchical sequence本身也会挂载到sequencer上面, 而对于virtual sequence而言,它内部不同的sequence可以允许面向不同的sequencer种类

Virtual Sequence介绍

在这里插入图片描述
就之前的sequence和sequencer而言,它们之间的差别在于:

  • virtual sequence可以承载不同目标sequencer的sequence群落,而组织协调这些sequence的方式则类似于高层次的hierarchical sequence。virtual sequence一般只会挂载到virtual sequencer上面
  • virtual sequencer与普通的sequencer相比有着很大的不同,它们起到了桥接其它sequencer的作用,即virtual sequencer是一个链接所有底层sequencer句柄的地方,它是一个中心化的路由器
  • 同时virtual sequencer本身并不会传送item数据对象,因此virtual sequencer 不需要与任何的driver进行TLM连接。所以 需要在顶层的connect阶段,做好virtual sequencer中各个sequencer句柄与底层sequencer实体对象的一一对接,避免句柄悬空

Virtual Sequence示例

接下来的示例用来表示element sequence/hierarchical sequence与virtual sequence的关系,以及底层sequencer与virtual sequencer的联系,同时也说明virtual sequence与virtual sequencer的挂载方法。

class mcdf_normal_seq extends uvm_sequence; 
	`uvm_object_utils(mcdf_normal_seq)
	`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
	...
	task body(); 
		clk_rst_seq clk_seq;
		reg_cfg_seq cfg_seq; 
		data_trans_seq data_seq; 
		fmt_slv_cfg_seq fmt_seq;
		//配置formatter slave agent 
		`uvm_do_on(fmt_seq,p_sequencer.fmt_sqr)
		//打开时钟并完成复位
		`uvm_do_on(clk_seq,p_sequencer.cr_sqr)
		//配置MCDF寄存器
		`uvm_do_on(cfg_seq,p_sequencer.reg_sqr)
		//传送channe1数据包
		fork
			`uvm_do_on(data_seq,p_sequencer.chnl_sqr0)
			`uvm_do_on(data seq,p sequencer.chnl_sqr1)
			`uvm_do_on(data_seq,p_sequencer.chnl_sgr2)
		join 
	endtask 
endclass

宏:完成了一个声明变量;父类句柄到子类句柄的转换
p_sequencer是一个子类句柄;
uvm_do_on其实就是区别virtual sequence和hierarchical sequence很大的一点不同;因为挂载目的地不一样,所有要用uvm_do_on挂载;

//子一级的sequencer和agent定义
//cr master_sequencer | cr_master_agent
//reg master sequencer | reg master agent
//chnl master sequencer | chnl master agent
//fmt slave sequencer | fmt slave agent 
class mcdf_virtual_sequencer extends uvm_sequencer; 
	cr_master_sequencer cr_agr; 
	reg_master_sequencer reg_sqr; 
	chnl_master_sequencer chnl_sqr0; 
	chnl_master_sequencer chnl_sqr1; 
	chnl_master_sequencer chnl_sqr2; 
	fmt_slave_sequencer fmt_sqr; 
	`uvm_component_utils(mcdf_virtual_sequencer)
	function new(string name, uvm_component parent); 
		super.new(name,parent); 
	endfunction 
endclass
class mcdf_env extends uvm_env; 
	cr_master_agent cr_agt; 
	reg_master_agent reg_agt; 
	chnl_master_agent chnl_agt0; 
	chnl_master_agent chnl_agt1; 
	chnl_master_agent chnl_agt2; 
	fmt_slave_agent fmt_agt; 
	mcdf_virtual_sequencer virt_sqr; 
	`uvm_component_utils(mcdf_env)
	function new(string name, uvm_component parent); 
		super.new(name, parent); 
	endfunction
	function void build_phase(uvm_phase phase); 
		cr_agt=cr_master_agent::type_id::create("cr_agt", this); 
		reg_agt=reg_master_agent::type_id::create("reg_agt", this); 
		chnl_agt0=chnl_master_agent::type_id::create("chnl_agt", this); 
		chnl_agt1=chnl_master_agent::type_id::create("chnl_agt", this); 
		chnl_agt2=chnl_master_agent::type_id::create("chnl_agt", this); 
		fmt_agt=fmt_slave_agent::type_id::create("fmt_agt", this);
		virt_sqr=mcdf_virtual_sequencer::type_id::create("virt_sqr", this); 
	endfunction 
	function void connect_phase(uvm_phase phase);
		//virtual sequencer connection
		//but no any TIM connection with sequencers 
		virt_sqr.cr_sqr=cr_agt.sqr; 
		virt_sqr.reg_sqr=reg_agt.sqr; 
		virt_sqr.chnl_sqr0=chnl_agt0.sqr; 
		virt_sgr.chnl_sqrl=chnl_agtl.sqr; 
		virt_sgr.chnl_sqr2=chnl_agt2.sqr; 
		virt_sqr.fmt_sqr=fmt_agt.sqr; 
	endfunction 
endclass: mcdf_env
class test1 extends uvm_test; 
	mcdf_env e; 
	...
	task run_phase(uvm_phase phase); 
		mcdf_normal_seq seq; 
		phase.raise_objection(phase); 
		seq=new(); 
		seq.start(e.virt_sqr); 
		phase.drop_objection(phase);
	endtask 
endclass:test1

在这里插入图片描述
对于virtual sequence mcdf_normal_seq而言,它可以承载各个子模块环境的element sequence,而通过最后挂载的virtual sequencer mcdf_virtual_sequencer中的各个底层sequencer句柄,各个element sequence可以分别挂载到对应的底层sequencer上

尽管在最后test1中,将virtual sequence挂载到了virtual sequencer上面,但是这种挂载的根本目的是为了提供给virtual sequence一个中心化的sequencer路由,而借助在virtual sequence mcdf_normal_seq中使用了宏`uvm_declare_p_sequencer,使得virtual sequence可以使用声明后的成员变量p_sequencer(类型为mcdf_virtual_sequencer),来进一步回溯到virtual sequencer内部的各个sequencer句柄。

在这里使用uvm_declare_p_sequencer是较为方便的,因为这个宏在后台,可以新创建一个p_sequencer变量,而将m_sequencer的默认变量(uvm_sequencer_base类型)通过动态转换,变为类型为mcdf_virtual_sequencer的p_sequencer。

只要声明的挂载sequencer类型正确,就可以通过这个宏,完成方便的类型转换,因此才可以通过p_sequence索引到在mcdf_virtual_sequencer中明的各个sequencer句柄。

需要理解virtual sequence的协调作用和virtual sequencer的路由作用,以及在顶层中需要完成virtual sequencer同底层sequencer的连接,并最终在test层实现virtual sequence 载到virtual sequencer上
这种中心化的协调方式使得顶层环境在场景创建和激励控制方面更加得心应手,而且在代码后期维护中,测试场景的可读性也得到了提高。

Virtual Sequence建议

一开始学习virtual sequence和virtual sequencer时容易出现编译错误和运行时句柄悬空的错误,还有一些概念上的偏差,在这里给出一些建议参考:

  • 需要区分virtual sequence同其它普通sequence(element sequence、hierarchical sequence)。
  • 需要区分virtual sequencer同其它底层负责传送数据对象的sequencer。
  • 在virtual sequence中记得使用宏uvm_declare_p_sequencer来创建正确类型的p_sequencer变量,方便接下来各个目标sequencer的索引。
  • 顶层环境中记得创建virtual sequencer,并且完成virtual sequencer中各个sequencer句柄与底层sequencer的跨层次链接

这篇笔记参考《UVM实战》、《芯片验证漫游指南》和某验证视频整理而成,仅作学习心得交流,如果涉及侵权烦请请告知,我将第一时间处理。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

数字ic攻城狮

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

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

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

打赏作者

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

抵扣说明:

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

余额充值