UVM学习笔记(8)

学习目标

UVM入门和进阶部分8

学习内容

1.将sequence挂载到sequencer上:
uvm_sequence::start(uvm_sequencer_base sequencer,uvm_sequence_base parent_sequence=null,int this_priority=-1,bit call_pre_post=1)
用户首先应该指明sequencer的句柄,如果sequence是顶层sequence,则可以省略第二个参数parent_sequence的指定;
第三个参数的默认值为-1,会使得该sequence继承parent_sequence的优先级,若为顶层sequence,默认为100,用户也可以自定义优先级数值;
第四个参数建议使用默认值,为1时,uvm_sequence::pre_doby()和uvm_sequence::post_body()两个方法会在uvm_sequence::body()的前后执行

2.将item挂载到sequencer上:
uvm_sequence::start_item(uvm_sequence_item item,int set_priority=-1,uvm_sequencer_base sequencer=null);
uvm_sequence::finish_item(uvm_sequence_item item,int set_priority=-1);

3.对于一个item的完整传送,sequence要在sequencer一侧获得通过权限,才可以顺利将item发送至driver,具体步骤:
创建item
通过start_item()方法等待获取sequencer的授权许可,其后执行parent sequence的方法pre_do()
对item进行随机化处理
通过finish_item()方法在对item进行了随机化处理之后,执行parent sequence的mid_do(),以及调用uvm_sequencer::send_request()和uvm_sequencer::wait_for_item_done()来将item发送至sequencer再完成与driver之间的握手,最后执行了parent_sequence的post_do()

4.注意点:
sequence和item自身的优先级,可以决定什么时刻可以获得sequencer的授权
parent sequence的虚方法pre_do()、mid_do()和post_do()会发生在发送item的过程中间

5.start()的自然代码执行顺序和条件
在这里插入图片描述
6.start_item()/finish_item()的自然代码执行顺序和条件
在这里插入图片描述
7.发送序列的相关宏
在这里插入图片描述
8.uvm_sequencer类自建了仲裁机制,用来保证多个sequence在同时挂载到sequencer时,可以按照仲裁规则允许特定sequence中的item优先通过

9.通过uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)函数来设置仲裁模式

10.lock()和grab()锁定机制,grab()更为强势,只需要在sequencer下一次授权周期时就可以无条件得获得授权,可以无视同一时刻内发起传送请求的其他sequence,但是不能无视已经预先获得授权的其他lock或者grab的sequence

11.层次化sequence:hierarchical sequence(hierarchical等级制)、virtual sequence、layering sequence

12.hierarchical sequence例子

typedef  enum {CLKON,CLKOFF,RESET,WRREG,RDREG} cmd_t;
class bus_trans extends uvm_sequence_item;
	rand cmd_t cmd;
	rand int addr;
	rand int data;
	constraint cstr{
		soft addr=='h0;
		soft data=='h0;
	}
	...
endclass

class clk_rst_seq extends uvm_sequence;
	rand int freq;
	...
	task body();
		bus_trans req;
		'uvm_do_with(req,{cmd==CLKON;data==freq;})
		'uvm_do_with(req,{cmd==RESET;})
	endtask
endclass

class reg_test_seq extends uvm_sequence;
	rand int chnl;
	...
	task body();
		bus_trans req;
		//对wr寄存器读写测试
		'uvm_do_with(req,{cmd==WRREG;addr==chnl*'h4;})
		'uvm_do_with(req,{cmd==RDREG;addr==chnl*'h4;})
		//对rd寄存器读测试
		'uvm_do_with(req,{cmd==RDREG;addr==chnl*'h4+'h10;})
	endtask
endclass

class top_seq extends uvm_sequence;			//top_seq为hierarchical  sequence
	...										//clk_rst_seq、reg_test_seq为element sequence
	task body();
		clk_rst_seq clkseq;
		reg_test_seq regseq0,regseq1,regseq2;
		//打开150mhz时钟,重置断言
		'uvm_do_with(clkreq,{freq==150;})
		'uvm_do_with(regreq0,{chnl==0;})
		'uvm_do_with(regreq1,{chnl==1;})
		'uvm_do_with(regreq2,{chnl==2;})
	endtask
endclass

class  reg_master_sequencer extends uvm_sequencer;
	...
endclass

class reg_master_driver extends uvm_driver;
	...
	task run_hase(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 \n %s",req.sprint()),UVM_LOW)
			seq_item_port.item_done();
		end
	endtask
enclass

class reg_master_agent extends uvm_agent;
	reg_master_sequencer sqr;
	reg_master_driver drv;
	...
	function void build_phase(uvm_phase phase);
		sqr=reg_master_sequencer::type_id::create("seq",this);
		drv=reg_master_driver::type_id::create("drv",this);
	endfunction
	function void connect_phase(uvm_phase phase);
		drv.seq_item_port.connect(sqr.seq_item_export);
	endfunction
enclass

13.hierarchical sequence面向的对象是同一个sequencer,即hierarchical sequence本身也会挂载到sequencer上面,而对于virtual sequence而言,它内部不同的sequence可以允许面向不同的sequencer种类

14.virtual sequencer与普通的sequencer相比有着很大的不同,它们起到了桥接其他sequencer的作用,即virtual sequencer是一个链接所有底层sequencer句柄的地方,它是一个中心化的路由器;
virtual sequencer本身并不会传送item数据对象,因此virtual sequencer不需要与任何driver进行TLM连接,所以UVM用户需要在顶层的connect阶段,做好virtual sequencer中各个sequencer句柄与底层sequencer实体对象的一一对接,避免句柄悬空

15.virtual sequencer示例

class  mcdf_normal_seq extends uvm_sequence;
	'uvm_object_utils(mcdf_normal_seq)
	'uvm_declare_p_sequencer(mdcf_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;
		//配置fmt 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)
		//传送channel数据包
		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_sqr2)
		join
	endtask
endclass

//省略子一级的sequencer和agent定义

class mcdf_virtual_sequencer extends uvm_sequencer;
	cr_master_sequencer cr_sqr;
	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;
	cnl_master_agent chnl_agt0;
	cnl_master_agent chnl_agt1;
	cnl_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
	
	fucntion 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);
	enfunction
	
	funciton void connect_phase(uvm_phase phase);
		//virtual sequencer连接,但是不和sequencers进行任何TLM连接
		//virtual sequencer中各个sequencer句柄与底层sequencer的跨层次链接
		virt_sqr.cr_sqr=cr_agt.sqr;
		virt_sqr.reg_sqr=reg_agt.sqr;
		virt_sqr.chnl_sqr0=chnl_agt0.sqr;
		virt_sqr.chnl_sqr1=chnl_agt1.sqr;
		virt_sqr.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

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

virtual sequencer的路由作用,以及在顶层中需要完成virtual sequencer同底层sequencer的连接,并最终在test层实现virtual sequence挂载到virtual sequencer上

16.通过层次化的sequence可以分别构建transaction layer、transport layer和physical layer等从高抽象级到低抽象级的transaction转化,这种层次化的sequence构建方式,称之为layering sequence

17.layering sequence例子

typedef enum{CLKON,CLKOFF,RESET,WRREG,REREG} phy_cmd_t;
typedef enum{FREQ_LOW_TRANS,FREQ_MED_TRANS,FREQ_HIGH_TRANS} layer_cmd_t;
class bus_trans extends uvm_sequence_item;
	rand phy_cmd_t cmd;
	rand int addr;
	rand int data;
	constraint cstr{
		soft addr=='h0;
		soft data=='h0;
	}
	...
endclass

class packet_seq extends uvm_sequence;
	rand int len;
	rand int addr;
	rand int data[];
	rand phy_cmd_t cmd;
	constraint cstr{
		soft len inside{[30:50]};
		soft addr[31:16]=='hFF00;
		data.size()==len;
	}
	...
	task body()
		bus_trans req;
		foreach(data[i])
			'uvm_do_with(req,{cmd==local::cmd;
							  addr==local::addr;
							  data==local::data[i];})
	endtask
endclass

class layer_trans extends uvm_sequence_item;
	rand layer_cmd_t layer_cmd;
	rand int pkt_len;
	rand interestingpkt_idle;
	constraint cstr{
		soft pkt_len inside{[10:20]};
		layer_cmd==FREQ_LOW_TRANS->pkt_idle inside{[300:400]};
		layer_cmd==FREQ_MED_TRANS->pkt_idle inside{[100:200]};
		layer_cmd==FREQ_HIGH_TRANS->pkt_idle inside{[20:40]};
	}
	...
endclass

class adapter_seq extends uvm_sequence;
	'uvm_object_utils(adapter_seq)
	'uvm_declare_p_sequencer(phy_master_sequencer)
	...
	task body();
		layer_trans trans;
		packet_seq pkt;
		forever begin
			p_sequencer.up_sqr.get_next_item(req);
			void'($cast(trans,req));
			repeat(trans.pkt_len) begin
				'uvm_do(pkt)
				delay(trans.pkt_idle);
			end
			p_sequencer.up_sqr.item_done();
		end
	endtask
	virtual task delay(int delay);
	...
	endtask
endclass

class top_seq extends uvm_sequence;
	...
	task body();
		layer_trans trans;
		'uvm_do_with(trans,{layer_cmd==FREQ_LOW_TRANS;})
		'uvm_do_with(trans,{layer_cmd==FREQ_HIGH_TRANS;})
	endtask
endclass

class layering_sequencer extends uvm_sequencer;
	...
endclass

class phy_master_sequencer extends uvm_sequencer;
	layering_sequencer up_sqr;
	...
endclass

class phy_master_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 \n %s",req.sprint()),UVM_LOW)
			seq_item_port.item_done();
		end
	endtask
endclass

class phy_master_agent extends uvm_agent;
	phy_master_sequencer sqr;
	phy_master_driver drv;
	...
	function void build_phase(uvm_phase phase);
		sqr=phy_master_sequencer::type_id::create("sqr",this);
		drv=phy_master_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;
	layering_sequencer layer_sqr;
	phy_master_agent phy_agt;
	...
	function void build_phase(uvm_phase phase);
		layer_sqr=layering_sequencer::type_id::create("layer_sqr",this);
		phy_agt=phy_master_agent::type_id::create("phy_agt",this);
	endfunction
	function void connect_phase(uvm_phase phase);
		phy_agt.sqr.up_sqr=layer_sqr;
	endfunction
	task run_phase(uvm_phase phase);
		top_seq seq;
		adapter_seq adapter;
		phase.raise_objection(phase);
		seq=new();
		adapter=new();
		fork
			adapter.start(phy_agt.sqr);
		join_none
		seq.start(layer_sqr);
		phase.drop_objection(phase);
	endtask
endclass

学习问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值