(21)UVM virtual sequence

UVM virtual sequence


In the previous section, we talked about hierarchical sequence. The next step is virtual sequence. How to distinguish between the virtual sequence and the hierarchical sequence?

What they have in common is the coordination of each sequence. The difference between them is that the objects facing the hierarchical sequence are the same sequencer, that is, the hierarchical sequence itself will also be mounted on the sequencer. For the virtual sequence, different sequences in it can be oriented to different sequencer types.

Introduction to virtual sequence

The virtual sequencer acts as a simple route

  • With the end of the verification cycle of the underlying modules, in the process of MCDF subsystem verification environment integration, the early vertical reuse of the structure is completed, so it is necessary to consider how to reuse the element sequence and hierarchical sequence of each module.
  • For the higher-level environment, it can be imagined that the top-level test sequence needs to coordinate not only the sequence group facing one sequencer, but the sequence group facing multiple sequencers. Then, how can sequence communities facing different sequencers be connected to different sequencers after being organized?
  • The sequences we introduced earlier are all for a single sequencer, so mounting is also very simple, that is, through uvm_sequence::start() to mount the root sequence, while the internal child sequence can be accessed through the macro ` uvm_do.
  • If the element sequence and hierarchical sequence in each module environment are regarded as reusable sequence resources, a container that can hold each sequence is needed to carry them, and an appropriate routing sequencer is also needed to organize sequencers in different structures, Such a sequence and sequencer are called virtual sequence and virtual sequencer respectively.

virtual has changes to sequence and sequencer

As for the previous sequence and sequencer, the difference between them is:

  • Virtual sequences can carry the sequence communities of different target sequencer s, and the way of organizing and coordinating these sequences is similar to high-level hierarchical sequence s. The virtual sequence is usually only attached to the virtual sequence.
  • Virtual sequencer is very different from ordinary sequencer. They play the role of bridging to other sequencers, that is, virtual sequencer is a place that links all the underlying sequencer handles. It is a centralized router.
  • At the same time, the virtual sequencer itself does not transfer the item data object, so the virtual sequencer does not need to make TLM connection with any driver. Therefore, in the connect phase of the top layer, the UVM user needs to connect each sequencer handle in the virtual Sequencer with the underlying sequencer entity object one by one to avoid the handle hanging.

virtual sequence example

The following examples are used to show the relationship between element sequence/hierarchical sequence and virtual sequence, as well as the relationship between the underlying sequencer and virtual sequencer. At the same time, they also illustrate the mounting relationship between virtual sequence and 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;
		// Configure formatter slave agent
		`uvm_do_on(fmt_seq,p_sequencer.fmt_sqr)
		// Turn on the clock and complete multiplexing
		`uvm_do_on(clk_seq,p_sequencer.cr_sqr)
		// Configure MCDF register
		`uvm_do_on(cfg_seq,p_sequencer.reg_sqr)
		// Transfer channel packets
		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

m_sequencer is a parent class handle, which is uvm_seq predefined
p_sequencer is a subclass handle. In this instance, its type is mcdf_virtual_sequencer, and M_ The sequencer is different. It is not predefined, but newly defined. The macro content that defines it has completed two parts.

  1. Defines the type of the member variable mcdf_virtual_sequencer p_sequencer;
  2. Handle conversion $cast(p_sequencer,m_sequencer); Put m_sqr parent class handle converted to child class handle p_sqr. Whether it's m_sqr or p_sqr points to virtual_sqr, of course, virtual_sqr is the type of a subclass
//Definition of sequencer and agent at the child level
//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_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;
	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);
		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

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

virtual sequence sample parsing

  • For virtual sequence MCDF_ normal_ For SEQ, it can host the element sequence of each sub module environment, and through the last mounted virtual sequencer MCDF_ virtual_ Each underlying sequencer handle in the sequencer, and each element sequence can be mounted to the corresponding underlying sequencer.
  • Although the virtual sequence is mounted on the virtual sequencer in the last test1, the fundamental purpose of this mounting is to provide a centralized sequencer route for the virtual sequence, with the help of the virtual sequence MCDF_ normal_ Macro used in SEQ ` uvm_declare_p_sequencer, so that the declared member variable p can be used by the virtual sequence_ Sequencer (type mcdf_virtual_sequencer). To further backtrack the various sequencer handles inside the virtual sequencer.
  • Use here ` uvm_declare_p_sequencer is more convenient, because this macro is in the background and a new P can be created_ Sequencer variable, and M_ The default variable of sequencer (uv m_sequencer_base type) is changed to type MCDF through dynamic conversion_ virtual_ P of sequencer_ sequencer.
  • As long as the declared mounted sequencer type is correct, users can complete convenient type conversion through this macro, so they can pass p_sequencer index to MCDF_ virtual_ Each sequencer handle declared in the sequencer.
  • Beginners need to understand the coordination role of the virtual sequence, the routing role of the virtual sequencer, and the connection between the virtual sequencer and the underlying sequencer in the top layer, and finally mount the virtual sequence to the virtual sequencer in the test layer.
  • This centralized coordination method makes the top-level environment more handy in scenario creation and incentive control, and the readability of the test scenario is also improved in the post code maintenance.

virtual sequence recommendation

  1. It is necessary to distinguish the virtual sequence from other ordinary sequences (element sequence, hierarchical sequence).
  2. It is necessary to distinguish the virtual sequencer from other low-level sequencers responsible for transmitting data objects.
  3. Remember to use macro ` UVM in virtual sequence_ declare_ p_sequencer to create the correct type of P_ The sequencer variable is used to facilitate the index of each target sequencer.
  4. In the top-level environment, remember to create a virtual sequencer and complete the cross-level connection between each sequencer handle in the virtual sequencer and the bottom sequencer.

Focus on the author

  • Readme
    The author is a graduate student majoring in digital design at China University of science and technology. His level is limited. If there are mistakes, please correct them and want to make progress with you.
  • experience
    He has won the national scholarship, "Higher Education Society Cup" mathematical modeling national second prize
  • Update in succession:
    1. Follow up content of system verilog related to UVM verification;
    2. Some basic module designs related to verilog digital design, such as FIFO, UART, I2C, etc.
    3. Research guarantee and competition experience, etc
  • WeChat official account
    Welcome to the official account of "the daily practice of digital IC Xiao Bai". We look forward to fighting with you to travel around the digital IC world.

Tags: Verilog microchip systemverilog uvm

Posted on Sat, 20 Nov 2021 11:51:57 -0500 by robvan75