电力电子转战数字IC20220725day56——sequence层次化

目录

sequencer和sequence

sequencer的仲裁特性

sequence的层次化

hierarchical sequence

virtual sequence

layering sequence


sequencer和sequence

  • 目的:sequence挂载到sequencer上的方法和宏
class bus_trans extends uvm_sequence_item;
	rand int data;
	...//注册,域的自动化,例化
endclass

class child_seq extends uvm_sequence;//扁平类seq
	...//注册,例化
	task body();
		uvm_sequence_item tmp;
		bus_trans req;
		tmp=create_item(bus_trans::get_type(), m_sequencer, "req");
		void'($cast(req,tmp));
		start_item(req);
		req.randomize with{data==10;};
		finish_item(req);
	endtask
endclass

class env extends uvm_env;
	sequencer sqr;
	driver drv;
	..//注册例化
	function void build_phase(u p);
	sqr=sequencer::type_id::create("sqr", this);
	drv=driver::type_id::create("sqr", this);
	endfunction
	function void connect_phase(u p);
	drv.seq_item_port.connect(sqr.seq_item_export);
	endfunction
endclass

class top_seq extends uvm_sequence;
...//注册,例化
	task body();
		uvm_sequence_item tmp;
		child_seq cseq;
		bus_trans req;
		cseq=child_req::type_id::create("cseq");//包含了子seq
		req=create_item(bus_trans::get_type(), m_sequencer, "req");
		cseq.start(m_sequencer, this);//发送cseq
		void'($(req, tpm));
		start_item(req);
	endtask
endclass

class sequencer extends uvm_sequencer;
...//注册,例化
endclass

class driver extends uvm_driver;
...//注册,例化
	task run_phase(u p);
		REQ tmp;
		bus_trans req;
		forever begin
		seq_itme_port.get_next_item(tmp);
		void'($cast(req,tmp));
		`uvm_info("", $sformatf("got a item"), )
		seq_item_port.item_done();
		end
	endtask
endclass

class test1 extends uvm_test;
env e;
...//注册,例化
	function void build_phase(u p);
	e=env::type_id::create("e", this)
	endfunction
	task run_phase(u p);
		top_seq seq;
		phase.raise_objection(p);
		seq=new();
		seq.start(e.sqr);
		phase.drop_objection(p);
	endtask
endclass
  • 发送sequencen/item的方法
    • uvm_sequence::start(uvm sequencer_base sequencer, uvm_sequence_base parent_sequence=null, int this priotiry=-1, bit call_pre_post=1)
    • 其中,第一个参数是sequencer的句柄,如果是顶部sequence,可以省略对第二个参数的指定,第三个参数-1默认使该sequence如果有parent_sequence会继承上层的优先级,如果是顶部root sequence,优先级自动设为100;第四个参数建议使用默认值1,这样uvm_sequence::pre_doby()和uvm_sequence::post_body()两个方法会在uvm_sequence::body()前后执行,其实就是预定义的body的回调函数
    • 针对将item挂载到sequencer上:
      • uvm_sequence::start_item(uvm_sequence_item, int set_priority=-1, uvm_sequencer_base sequencer=null);//第三个参数注意是否要将item挂载到“非当前parent sequence挂载的sequencer”
      • uvm_sequence::finish_item(uvm_sequence_item item, int set_priority=-1);
  • item完整传送的步骤
    • 创建item
    • start_item()方法等待获得sequencer的许可,然后执行parent sequence的方法pre_do()
    • 随机化item
    • finish_item()方法在随机化后执行parent sequence的mid_do()。以及调用uvm_sequencer::send_request()和uvm_sequencer::wait_for_item_done()将item发送到sequencer完成与driver的握手。最后执行parent_sequence的post_do()

 

 

class child_seq extends uvm_sequence;
...
task body();
bus_trans req;
`uvm_create(req)
`uvm_rand_send_with(req, {data==10;})
//查表,当然可以合成一个`uvm_do_with(req, {data==10;})
endtask
endclass

class top_seq extends uvm_sequence;
...
`uvm_do(cseq)
`uvm_do_with(req, {data==20;})
endtask
endclass
  • 建议
    • 无论seq处于什么层次,都应该在test结束前执行完毕,一般来说还要保留出一部分时间供dut将所有发送的激励处理完毕,进入空闲状态才可以结束测试
    • 避免使用fork join_any和fork join_none来控制seq的发送顺序。用disable终止seq线程时可能会在不恰当的时间锁住sequencer,则接下来再也无法发送其他seq

sequencer的仲裁特性

  • 多个seq同时挂载到sequencer上时,按照仲裁规则通过特定seq中的item

  • uvm_sequence::set_arbitration(UVM_SEQ_ARB_TYPE val)设置仲裁模式,UVM_SEQ_ARB_TYPE有以下选择
    • UVM_SEQ_ARB_FIFO:默认模式,按照fifo先进先出依次授权,与seq优先级无关
    • UVM_SEQ_ARB_WEIGHTED:对不同seq的发送请求,按照优先级权重随机授权
    • UVM_SEQ_ARB_RANDOM:不同的请求会被随机授权,无视抵达顺序和优先级
    • UVM_SEQ_ARB_STRICT_FIFO:按照优先级和抵达顺序依次授权
    • UVM_SEQ_ARB_STRICT_RANDOM:按照最高优先级随机授权
    • UVM_SEQ_ARB_USER:用户自定义仲裁方法user_priority_arbitration()
class bus_trans extends uvm_sequence_item;
	rand int data;
...endclass

class child_seq extends uvm_sequence;
	rand int base;
	...
	task body();
	bus_trans req;//1个seq发送2个item
	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);//假设已经挂载在sequencer上
	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(u p);
		REQ tmp;
		bus_trans req;
		forever begin
			seq_item_port.get_next_item(tmp);
			void'($cast(req, tmp));
			`uvm_info("got a item")
			seq_item_port.item_done();
		end
	endtask 
endclass

class test1 extends uvm_test;
env e;
...
task run_phase(u p);
top_seq seq;
phase.raise_objection(p);
seq=new();//不可以用`uvm_do,只能在seq的class中才可以调用
seq.start(e.sqr);
phase.drop_objection(p);
endtask 
endclass

输出结果:0时刻依次完成seq1的16,seq2的22,seq1的19,seq2的23,seq3的33和32。

由于1和2的优先级相同,传送完seq1的第一个item后seq2的第一个item已经在等待发送,所以先发送seq2的第一个的item

  • 如何让相同优先级的seq发送完item后再发送下一个seq的?
    • uvm_sequencer提供了锁定机制:lock()和grab()方法
  • lock()和unlock():对seq提供排外的访问权限,前提条件是该seq按照sequencer的仲裁机制获得授权;是一种阻塞任务,只有获得权限才会返回
  • grab()和ungrab():对seq提供排外的访问权限,只需要在sequencer下一次授权周期时无条件获得授权,区别:无视同一时刻内发起传送请求的其他seq,唯一可以阻止它的只有已经预先获得授权的其他lock或者grab的seq
  • 如果使用了这两种锁定方法,必须在seq结束前调用un()来释放权限,否则sequencer会进入死锁状态,不能为其他seq授权
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);//都在等待权限时才可以用lock争取过来
`uvm_info()
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()
repeat(3) #10ns `uvm_do_with(req, {data inside {[200:210]};})

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)//lock优先级300
		`uvm_do(grabs)//grab没有优先级
	join
endtask
endclass

输出结果:10ns处,这也是零时刻,首先seq1,2,3依次拿到item16,22,33,此时lock也期望拿到权限,同时等待的有seq1-2-3和locks;由于locks的优先级300对应seq3,随后lock拿到3个item108,110,101,且每个都有10ns延迟,所以分别是20ns,30ns,40ns处;20ns时刻grab开始等待权限,此时是被lock拿着,40ns时seq1-3也在等待,所以40ns时grab拿到权限,发送3个item;此时是70ns,才轮到seq1,2,3去拿到权限

  • seq默认的优先级是100

sequence的层次化

  • 验证的复用
    • 水平复用:在各个子模块的验证语境中,利用已有资源完成高效的激励场景创建
    • 垂直复用:子系统验证中完成结构复用和激励场景复用
  • 激励场景的复用很大程度上取决于如何设计seq,使底层seq实现合理的粒度

hierarchical sequence

对于寄存器模块来说,测试场景可以拆分为:

  • 设置时钟和复位
  • 测试ch1,2,3的控制寄存器和只读寄存器
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;//底层seq1,也叫element seq
	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;//底层seq2
	rand int chnl;
	...
	task body();
	bus_trans req;
	`uvm_do_with(req, {cmd==WRREG; addr==chnl*'h4;})
	`uvm_do_with(req, {cmd==RDREG; addr==chnl*'h4;})
	`uvm_do_with(req, {cmd==RDREG; addr==chnl*'h4 + 'h10;})
	endtask
endclass

class top_seq extends uvm_sequence;//顶层seq,对底层seq进行组合和随机化赋值
	...
	task body();//hs可以包含多个seq和item
		clk_rst_seq clkseq;
		reg_test_seq regseq0, regseq1, regseq2;
		`uvm_do_with(clkseq, {freq==150;})
		`uvm_do_with(regseq0, {chnl==0;})
		`uvm_do_with(regseq1, {chnl==1;})
		`uvm_do_with(regseq2, {chnl==2;})
	endtask
endclass

class reg_master_sequencer extends uvm_sequencer;
...endclass

class reg_master_driver extends uvm_driver;
...
	task run_phase(u p);
		REQ tmp;
		bus_trans req;
		forever begin
		seq_item_port.get_next_item(tmp);
		void'($cast(req, tmp));
		`uvm_info()
		seq_item_port.item_done();
		end
	endtask
endclass
  • 和virtual seq的异同
    • 同:对各个seq进行协调
    • 异:hs面对的对象时同一个sequencer,hs本身会挂载到sequencer上;vs内部不同的seq可以面向不同的sequencer种类

 

 

virtual sequence

  • 目的:更上层env的测试序列,面向多个sequencer
  • vs:各个模块环境的element seq和hs组成的容器
  • vser:作为routing sequencer。组织不同结构中的ser。连接所有底层sequencer句柄,是一个中心化的路由器,本身不会传递item数据对象(vser不需要和任何driver做tlm连接)
  • 需要在顶层的connect阶段,做好vser中各个sequencer句柄与底层sequencer对象的一一连接,避免句柄悬空
  • vs一般只会挂载在vser上

 

 

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()
function new(string name, uvm_component parent);
	super.new(name, parent);
endfunction
endclass

class mcdf_normal_seq extends uvm_sequence;
	`uvm_object_utils(mcdf_normal_seq)
	`uvm_declare_p_sequencer(mcdf_virtual_sequencer)
//新定义一个成员变量p_sequencer类型是p_sequencer,并$(p_seq, m_seq);
//m_sequencer的默认变量是uvm_sequencer_base类型
	...
	task body();
		clk_rst_seq clkreq;
		reg_cfg_seq cfgreq;
		data_trans_seq dataseq;
		fmt_slv_cfg_seq fmtseq;
//m_sequencer的类型是uvm_sequencer,p_sequencer的类型是子类mcdf_virtual_sequencer
		`uvm_do_on(fmtseq, p_sequencer.fmt_sqr)//挂载各个seq到各个ser
		`uvm_do_on(clkreq, p_sequencer.cr_sqr)
		`uvm_do_on(cfgreq, p_sequencer.reg_sqr)
		fork
			`uvm_do_on(dataseq, p_sequencer.chnl_sqr0)
			`uvm_do_on(dataseq, p_sequencer.chnl_sqr1)
			`uvm_do_on(dataseq, p_sequencer.chnl_sqr2)
		join
	endtask
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(u p);
		cr_master_agent=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_agt0", this);
		chnl_agt1=chnl_master_agent::type_id::create("chnl_agt1", this);
		chnl_agt2=chnl_master_agent::type_id::create("chnl_agt2", this);
		fmt_agt=fmt_slave_agent::type_id::create("fmt_agt", this);
		virt_sqr=mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
	endfunction
endclass

class test1 extends uvm_test;
	mcdf_env e;
	...
	task run_phase(u p);
	mcdf_normal_seq seq;
	phase.raise_objection(p);
	seq=new();
	seq.start(e.virt_sqr);//将vs挂载到vser
	phase.drop_objection(p);
	endtask
endclass

 

 

layering sequence

  • 目的:更复杂的协议总线传输,更深层次化的数据传输
  • 概念:通过层次化的seq可以分别构建transaction layer,transport layer, physical layer等从高抽象级到低抽象级的transaction转化,是一种层次化的seq构建方式
typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} phy_cmd_t;
typedef enum {FREQ_LOW_TRANS, FREQ_MED_TRANS, FREQ_HIGH_TRANS} layer_cmd_t;
class bus_trans extends uvm_sequence_item;//底层trans
	rand phy_cmd_t cmd;
	rand int addr;
	rand int data;
	constraint cstr { soft addr =='h0;
										soft data =='h0;}
...endclass

class layer_trans extends uvm_sequence_item;//抽象一点
	rand layer_cmd_t layer_cmd;
	rand int pkt_len;
	rand int pkt_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 packet_seq extends uvm_sequence;
	rand int len;
	rand int addr;
	rand int data[];
	ramd 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 adapter_seq extends uvm_sequence;//转化层
`uvm_objection_utils()
`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)//高抽象级len到低的pkt
		delay(trans.pkt_idle);
		end
	p_sequencer.up_sqr.item_done();//告诉上层,消化了item
	end
endtask

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(u p);
		REQ tmp;
		bus_trans req;
		forever begin
		seq_item_port.get_next_item(tmp);
		void'($cast(req, tmp));
		`uvm_info()
		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(u p);
		sqr=phy_master_sequencer::type_id::create("sqr", this);
		drv=phy_master_driver::type_id::create("drv", this);
	endfunction
	function void connect_phase(u p);
		drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass

virtual task delay(int delay); ...endtask
endclass

class test1 extends uvm_test;
	layering_sequencer layer_sqr;
	phy_master_agent phy_agt;
	...
	function void build_phase(u p);
		layer_sqr=layering_sequencer::type_id::create("layer_sqr", this);
		phy_agt  =phy_master_agent::type_id::create();
	endfunction
	function void connect_phase(u p);
		phy_agt.sqr.up_sqr=layer_sqr;
	endfunction
	task run_phase(u p);
		top_seq seq;
		adapter_seq adapter;
		//举手
		seq=new();
		adapter=new();
		fork
			adapter.start(phy_agt.sqr);//挂载到低层次的sqr
		join_none
		seq.start(layer_sqr);//顶层seq挂载到sqr上
		//落手
	endtask
endclass

 

 

  • 抽象层次的transaction类定义都要有对应的sequencer作为trans的路由通道
  • 抽象级sequencer中要有相应的转换方法,从高层次sequencer获取高层次trans转换成低层次trans,并通过低层次sequencer发送出去
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值