UVM-使用start发送item,sequence

当sequence得知自己挂载的sequencer时,他就会调用sequencer自带的TLM端口与driver(的TLM端口)进行通信
而sequencer在这里就像一个傀儡

I sequence中拥有item

package pack1; //pack1头
	import uvm_pkg::*; //+UVM
  	`include "uvm_macros.svh"//+工厂
	
	class item extends uvm_sequence_item;
		rand int data_auto;
		rand int data_noauto;
					//声明两个data,一个加入自动化域,一个
					//不加入
		`uvm_object_utils_begin(item)
			`uvm_field_int(data_auto,UVM_ALL_ON)
		`uvm_object_utils_end
		function new(string name = "item");
			super.new(name);
		endfunction
	endclass
	
	class seq extends uvm_sequence;
		`uvm_object_utils(seq)
		function new(string name = "seq");
			super.new(name);
		endfunction
		task body();
			uvm_sequence_item temp;
			item req,rsp;
			temp = create_item(item::get_type(),m_sequencer,"req");
				//create_item:能够实例化一个继承于uvm_sequence_item类的类
				//返回值:uvm_sequence_item句柄
				//参数1:指明要例化的继承于uvm_sequence_item类的类
				//参数2:指明这个对象即将挂载到哪个sequencer上
				//       (m_sequencer是uvm_sequence类的一个属
				//       性,当m_sequencer被挂载到某个
				//       sequencer上时,m_sequencer会自动指向
				//       这个sequencer)
				//参数3:这个对象的名字
			void'($cast(req,temp));
				//在上一句话中由于使用create_item方法,导致
				//父类句柄指向子类对象
				//(uvm_sequence_item句柄) --> (item对象)
				//做个转化使子类对象重新被子类句柄指向
			start_item(req);
				void'(req.randomize with{data_auto == 50;
							 data_noauto == 50;});
				`uvm_info("sequence","sequence request to send item", UVM_LOW)
				`uvm_info("data_auto",$sformatf("%d",req.data_auto), UVM_LOW)
				`uvm_info("data_noauto",$sformatf("%d",req.data_noauto), UVM_LOW)
				req.print();
			finish_item(req);
				//
				//seq发起start告知seqr,我要向driver发送item
				//(start会立即返回,然后执行下面的语句)
				//seqr判断此时的driver是否已经get_next_item,
				//若否,则继续等待。若是,那么driver收到完item
				//后会执行item_done,收到item_done后,
				//finish_item的阻塞结束
				//

			get_response(temp);  //get_response返回的uvm_sequence_item是句柄,
					     //需要做个中间转化
			void'($cast(rsp,temp));
			`uvm_info("sequence","sequence already recive item", UVM_LOW)
			`uvm_info("data_auto",$sformatf("%d",rsp.data_auto), UVM_LOW)
			`uvm_info("data_noauto",$sformatf("%d",rsp.data_noauto), UVM_LOW)
			req.print();
		endtask
	endclass

			
	class seqr extends uvm_sequencer;
		`uvm_component_utils(seqr)
		function new(string name = "seqr", uvm_component parent = null);
			super.new(name, parent);
		endfunction
	endclass

	class dri extends uvm_driver;
		`uvm_component_utils(dri)
		function new(string name = "dri", uvm_component parent = null);
			super.new(name, parent);
		endfunction
		
		task run_phase(uvm_phase phase);
			uvm_sequence_item temp ;
			uvm_object temp1;
			item req,rsp;
			phase.raise_objection(this);//进入run_phase需要先举手

			seq_item_port.get_next_item(temp);
			void'($cast(req,temp));
			`uvm_info("driver","driver already recive item", UVM_LOW)
			`uvm_info("data_auto",$sformatf("%d",req.data_auto), UVM_LOW)
			`uvm_info("data_noauto",$sformatf("%d",req.data_noauto), UVM_LOW)
			req.print();
			//driver使用自带的TLM端口,向seqr的TLM端口使用get_next_item
			//来获取一个对象,(get_next_item返回的是uvm_sequence_item
			//句柄需要类型转换)

			#1us;
			//---------------------------------------------
			//--此处省略driver解析item并向interface进行驱动
			//---------------------------------------------
			
		
			temp1 = req.clone();
			void'($cast(rsp,temp1));
			`uvm_info("clone:data_auto",$sformatf("%d",rsp.data_auto), UVM_LOW)
			`uvm_info("clone:data_noauto",$sformatf("%d",rsp.data_noauto), UVM_LOW)
			//克隆一个上一步接收到的对象
			//(clone返回的居然是uvm_object的句柄,需要类型转换)
			//!!clone只会克隆已经加入自动化域的属性的值,
			//data_noauto不在自动化域内,在克隆时候,类声明时候的
			//默认值0,而不是req的对象值50
			//同样‘req’的sequence_id也不会被克隆,克隆时候得到的也
			//是类中的声明初始值


			rsp.set_sequence_id(req.get_sequence_id());
			rsp.data_auto = rsp.data_auto + 100;
			rsp.data_noauto = rsp.data_noauto + 100;
			seq_item_port.item_done(rsp);
			//get_sequence_id用于获取‘req’这个item所在sequence的id好
			//然后使用set_sequence_id把id号交给‘rsp’这个item
			//这样item_done这个方法就知道要把‘rsp’这个item发送给谁
			//了
			//细节来说,item_done这个方法的作用有两个
			//1是:告知seq的finish_item,你别在那阻塞了,我都消化
			//     掉了
			//2是:向seqr的rspfifo中传递rsp这个对象
			//     这样sequence里的get_response才能得到对象
			//     要不然是得不到对象的
			`uvm_info("driver","driver already send item", UVM_LOW)
			`uvm_info("data_auto",$sformatf("%d",rsp.data_auto), UVM_LOW)
			`uvm_info("data_noauto",$sformatf("%d",rsp.data_noauto), UVM_LOW)

			phase.drop_objection(this);//退出run_phase需要先落手
		endtask

	endclass

	class env extends uvm_env;
		seqr seqr0;
		dri dri0;
		`uvm_component_utils(env)
		function new(string name="env" ,uvm_component parent = null);
			super.new(name,parent);
		endfunction
		//buildphase中例化sequencer 和 driver
		function void build_phase(uvm_phase phase);
			seqr0 = seqr::type_id::create("seqr0",this);		
			dri0 = dri::type_id::create("dri0",this);		
		endfunction
		//connect_phase中连接sequencer和driver自带的一组TLM端口
		function void connect_phase(uvm_phase phase);
			dri0.seq_item_port.connect(seqr0.seq_item_export);
		endfunction
		
	endclass


	class test1 extends uvm_test;
		env env0;
		`uvm_component_utils(test1)
		function new(string name = "test1", uvm_component parent = null);
			super.new(name, parent);
		endfunction

		function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			env0 = env::type_id::create("env0",this);
			`uvm_info("test1",$sformatf("build"), UVM_LOW)
		endfunction

		task run_phase(uvm_phase phase);
			seq seq0;
			phase.raise_objection(this);//进入run_phase需要先举手
			
			`uvm_info("test1",$sformatf("run"), UVM_LOW)
			seq0 = new();
			seq0.start(env0.seqr0);
			//将seq0挂载到 env0的seqr0上
			//一旦seq被挂载到了seqr上,那么这个seq就知道了他的m_seqencer是谁
			//他的body任务也会自动执行
			
			phase.drop_objection(this);//退出run_phase需要先落手
		endtask
	endclass

endpackage

//--------------------------------------module---------------------------------
module hardware1;
	import pack1::*;
	import uvm_pkg::*; //+UVM

	
	initial begin
		run_test("test1"); 	
	end
		
endmodule

II sequence中拥有item和sequence

package pack1; //pack1头
	import uvm_pkg::*; //+UVM
  	`include "uvm_macros.svh"//+工厂
	
	class item extends uvm_sequence_item;
		rand int data_auto;
		`uvm_object_utils_begin(item)
			`uvm_field_int(data_auto,UVM_ALL_ON)
		`uvm_object_utils_end
		function new(string name = "item");
			super.new(name);
		endfunction
	endclass
	
	//底层sequence
	class child_seq extends uvm_sequence;
		`uvm_object_utils(child_seq)
		function new(string name = "child_seq");
			super.new(name);
		endfunction
		task body();
			uvm_sequence_item temp;
			item req;
			temp = create_item(item::get_type(),m_sequencer,"req");
			void'($cast(req,temp));
			start_item(req);
				void'(req.randomize with{data_auto == 99;});
				`uvm_info("child_seq","i want to send item", UVM_LOW)
				`uvm_info("data_auto",$sformatf("%d",req.data_auto), UVM_LOW)
			finish_item(req);

			//不get response
		endtask
	endclass

	//顶层sequence
	class top_seq extends uvm_sequence;
		`uvm_object_utils(top_seq)
		function new(string name = "top_seq");
			super.new(name);
		endfunction
		task body();

			uvm_sequence_item temp;
			item req;
			child_seq cseq;

			//创建一个sequcence和一个item对象
			cseq = child_seq::type_id::create("cseq");
			temp = create_item(item::get_type(),m_sequencer,"req");
			void'($cast(req,temp));

			//发送sequence
			cseq.start(m_sequencer,this);
					//start任务的入口参数有4个(这里使用两个):
					//参数1指定了挂载的是哪个sequencer,
					//(m_sequencer是什么请看第一节的代码)
					//参数2是如果你start这个sequence不是最顶层的sequence,那么请你为他指定上级

			//发送item
			start_item(req);
				void'(req.randomize with{data_auto == 66;});
				`uvm_info("top_seq","i want to send item", UVM_LOW)
				`uvm_info("data_auto",$sformatf("%d",req.data_auto), UVM_LOW)
			finish_item(req);
			
			//不get responce
		endtask
	endclass

			
	class seqr extends uvm_sequencer;
		`uvm_component_utils(seqr)
		function new(string name = "seqr", uvm_component parent = null);
			super.new(name, parent);
		endfunction
	endclass

	class dri extends uvm_driver;
		`uvm_component_utils(dri)
		function new(string name = "dri", uvm_component parent = null);
			super.new(name, parent);
		endfunction
		
		task run_phase(uvm_phase phase);
			uvm_sequence_item temp ;
			item req;
			
			forever begin
				seq_item_port.get_next_item(temp);
				void'($cast(req,temp));
				`uvm_info("driver","driver already recive item", UVM_LOW)
				`uvm_info("data_auto",$sformatf("%d",req.data_auto), UVM_LOW)

				//只告诉完成,不发送响应(response)
				seq_item_port.item_done();

			end
		endtask

	endclass

	class env extends uvm_env;
		seqr seqr0;
		dri dri0;
		`uvm_component_utils(env)
		function new(string name="env" ,uvm_component parent = null);
			super.new(name,parent);
		endfunction
		function void build_phase(uvm_phase phase);
			seqr0 = seqr::type_id::create("seqr0",this);		
			dri0 = dri::type_id::create("dri0",this);		
		endfunction
		function void connect_phase(uvm_phase phase);
			dri0.seq_item_port.connect(seqr0.seq_item_export);
		endfunction
		
	endclass


	class test1 extends uvm_test;
		env env0;
		`uvm_component_utils(test1)
		function new(string name = "test1", uvm_component parent = null);
			super.new(name, parent);
		endfunction

		function void build_phase(uvm_phase phase);
			super.build_phase(phase);
			env0 = env::type_id::create("env0",this);
			`uvm_info("test1",$sformatf("build"), UVM_LOW)
		endfunction

		task run_phase(uvm_phase phase);
			top_seq seq0;
			phase.raise_objection(this);
			`uvm_info("test1",$sformatf("run"), UVM_LOW)
			
			seq0 = new();
			seq0.start(env0.seqr0);
			
			phase.drop_objection(this);//退出run_phase需要先落手
		endtask
	endclass

endpackage

//--------------------------------------module---------------------------------
module hardware1;
	import pack1::*;
	import uvm_pkg::*; //+UVM

	
	initial begin
		run_test("test1"); 	
	end
		
endmodule

使用start启动sequence

启动sequence的start可以在另一个sequence内部,如 II 中的topseq 和 childseq (sequence嵌套sequence)
也可以在别的地方使用,如I 和 II 中的test

函数原型:
virtual task start (uvm_sequencer_base sequencer,

uvm_sequence_base parent_sequence = null,

int this_priority = -1,

bit call_pre_post = 1);
sequencer:指定了当前sequence要挂载的是哪个sequencer
parent_sequence :如果要start的这个sequence是个底层sequence(sequence套sequence)
就可以来为他指定parent。指定后会在这个start的过程中,调用父类的pre_do、mid_do、post_do
this_priority : 指明产生transaction的优先级,sequencer在某些条件下会根据优先级来将transaction发送给sequence。
call_pre_post :如果为1, 要启动的这个sequence的 pre_do(), mid_do(), post_do() 将会被调用。
调用顺序如下:
(sub指此sequence,parent即参数2)
在这里插入图片描述

使用start启动item

启动item的start只能在sequence中使用,
在这里插入图片描述
通常只使用第一个参数(想发送的item句柄)
调用顺序如下:
(sequencer是该item挂载的sequencer,parent_seq是该item所在的sequence)
在这里插入图片描述

发送item和sequence的小知识总结

1:sequence和item都有自身的优先级,可以决定什么时刻可以获得sequencer的授权
2:在发送item 或者在发送底层sequence的过程中,会调用上层sequence的一些方法:pre_do,mid_do,post_do,但一般情况都是让上层的这些方法为空,不然验证环境的可读性会变差。
3:在发送sequence的过程中,在执行body任务的前后,还会执行pre_body()和post_body(),但这个机制可以通过将start函数的第四个参数call_pre_post置0来关闭掉。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
`start_item`函数是UVM中序列化对象的一种机制,用于将序列化对象插入到序列执行队列中。以下是UVM中`start_item`的源代码: ```systemverilog function bit uvm_sequence_base::start_item (uvm_sequence_item item, uvm_sequencer_base sequencer, bit set_priority = 0, string source_file = "", int source_line = 0); uvm_sequence_item item_copy; uvm_tlm_transaction_base t; uvm_component comp = get_parent(); uvm_phase phase; if (!item) `uvm_fatal("NOITEM","Attempting to start a NULL sequence_item") if (!sequencer) `uvm_fatal("NOSEQ","Attempting to start a sequence_item with a NULL sequencer") if (comp is uvm_root) begin `uvm_warning("SEQROOT",{"Attempt to start sequence '",get_type_name(), "' outside of a phase process. Ignored."}) return 0; end // Create a copy of the item if(item.try_clone(item_copy) == 0) begin `uvm_error("CLONE", {"Unable to clone sequence item '",item.get_type_name(),"'"}) return 0; end // Check for TLM analysis ports if(item_copy.get_type_name() == "uvm_tlm_analysis_port_base") begin t = item_copy; t.set_source_info(source_file, source_line); t.analysis_imp.connect(item_copy.analysis_export); t.write(t); return 1; end // Set the item's sequencer item_copy.set_sequencer(sequencer); // Set the item's source info item_copy.set_source_info(source_file, source_line); // Set the item's priority if (set_priority) item_copy.set_priority(m_priority); // If in a run phase, start the item phase = comp.get_phase(); if (phase != null && phase.get_name() == "run") begin if (!sequencer.start_item(item_copy)) begin `uvm_error("NOSEQITEM", {"Failed to start sequence item ", item_copy.get_type_name()," with sequencer ", sequencer.get_type_name()}) return 0; end end else m_req_q.push_back(item_copy); return 1; endfunction ``` 此函数接收四个参数: - `item`:要插入序列执行队列中的序列化对象。 - `sequencer`:将序列化对象插入到其执行队列中的UVM序列器。 - `set_priority`:指示是否应将`item`的优先级设置为该序列的优先级。 - `source_file`和`source_line`:指示从哪个源代码文件和行开始创建序列化对象。 该函数首先检查传递的参数是否有效。然后,它会复制序列化对象并将其设置在传递的`sequencer`中。如果序列化对象是一个TLM分析端口,则该函数会将其连接到分析导出,并通过`write`函数写入分析对象。如果在运行阶段,则该函数将使用传递的`sequencer`启动序列化对象。否则,它将序列化对象插入到要求队列中。函数返回1表示成功,返回0表示失败。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

搞IC的那些年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值