(19) Summary of the strongest sequence related macro operations in the history of UVM

Posted by the_ut_tick on Fri, 19 Nov 2021 02:04:16 +0100

Summary of the strongest sequence related macro operations in history

1, Sequence macro

The following code is a natural code description of the execution process of the start() method. You can see the sequence relationship and conditions of their execution:

sub_seq.pre_start()       (task)
sub_seq.pre_body()        (task) if call_pre_post==1
	parent_seq.pre_do(0)  (task) if parent_sequence!=null
	parent_seq.mid_do(this) (func) if parent_sequence!=null
sub_seq.body               (task) YPUR STIMULUS CODE
	parent_seq.post_do(this) (func) if parent_sequence!=null
sub_seq.post_body()        (task) if_call_pre_post==1
sub_seq.post_start()       (task)

Here is start_ item()/finish_ The natural code description of item () indicates the execution sequence of relevant methods when sending item:

sequencer.wait_for_grant(prior) (task)
parent_seq.pre_do(1)            (task)
parent_seq.mid_do(item)         (func)
sequencer.send_request(item)    (func)
sequencer.wait_for_item_done()  (task)
parent_seq.post_do(item)        (func)

  • sync is wait_for_grant
  • sync and post_sync actually needs to get priority, which is obtained in the body of seq. Every time seq sends an item, it will get the priority every time.
  • Only sequence can call these macros
  • If there is no on, its mounted sqr is the same as that of the top-level seq

It is the way to win the world through several sequence/item macros. Users can

`uvm_do/`uvm_do_with

To send either sequence or item. This method of not distinguishing whether the object is sequence or item brings a lot of convenience, but it is also easy to cause the inertia of verifier s. Therefore, before using them, you need to understand the sequence and item sending methods behind them.

Different macros may contain the process of creating objects or may not create agile objects. for example

`uvm_do/`uvm_do_with

Object will be created instead of ` uvm_send will not create objects and will not randomly process objects. Therefore, it is necessary to understand their execution contents and order.

There are also other macros, such as those that pass priority as a parameter

`uvm_do_pri/`uvm_do_on_prio

And so on, there are special for sequence

`uvm_create_seq/`uvm_do_seq/`uvm_do_seq_with

Wait for macro.
The on function indicates that we want to specifically mount the current seq to an sqr

2, Examples of sequence macros

class child_seq extends uvm_sequence;
	...
	task body();
		bus_trans req;
		`uvm_create(req)
		`uvm_rand_send_with(req,{data==10;})
	endtask
endclass

class top_seq extends uvm_sequence;
	...
	task body();
		child_seq cseq;
		bus_trans req;
		`uvm_do(cseq)
		`uvm_do_with(req,{data==20;})
	endtask
endclass

Finally, some suggestions on sending sequence/item are given:

  • No matter what level the sequence is at, the sequence should be executed before the end of the test. However, this is not a sufficient condition. Generally speaking, a part of the time should be reserved for the DUT to process all the transmitted incentives and enter the idle state before the test can be ended.
  • Try to avoid using for join_ Any or fork join_ None to control the sequence sending order. Because the hidden risk behind this is that if the user wants to terminate the sequence thread running in the background and simply use the disable mode, the sequencer may be locked at an inappropriate time point.
  • Once the sequencer is locked and cannot be released, no other sequences can be sent. So if the user wants to implement a fork join like_ Any or fork join_ For the sending order of none, you should also pay attention to the background operation of each sequence thread before using disable, and try to terminate the sequence after sending the item and completing the handshake, so as to avoid the deadlock of the sequencer.
  • If users want to use fork join mode, they should ensure that there is a method to make the sequence thread stop sending item s after some conditions are met. Otherwise, as long as one sequence thread cannot be stopped, the whole fork join cannot exit. In this case, users still need to consider monitoring appropriate events or time points before they can use disable to close threads.

3, Why is it locked sqr?

Because start_ When item, it will wait_for_grant, once you get the permission and don't return, disable the whole seq violently in the middle, it may be too late to release the permission to sqr, and sqr may be deadlocked.

4, The arbitration mechanism of sequencer

  • uvm_ The sequencer class has built its own arbitration mechanism to ensure that when multiple sequences are mounted to the sequencer at the same time, item s in a specific sequence can be allowed to pass first according to the arbitration rules.

  • In practice, we can use uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val) function to set the arbitration mode. The arbitration mode here is UVM_ SEQ_ ARB_ Type has the following values to choose from.
    1.UVM_SEQ_ARB_FIFO: default mode. The sending requests from sequences are authorized in order according to FIFO first in first out, which has nothing to do with the priority.
    2.UVM_SEQ_ARB_WEIGHTED: the sending requests of different sequence s will be authorized randomly according to their priority weight.
    3.UVM_SEQ_ARB_RANDOM: different requests are randomly authorized regardless of their arrival order and priority.
    4.UVM_SEQ_ARB_STRICT_FIFO: different requests will be authorized according to their priority and arrival order, so it is related to priority and arrival time.
    5.UVM_SEQ_ARB_STRICT_RANDOM: different requests will be granted randomly according to their highest priority, regardless of the arrival time.
    6.UVM_SEQ_ARB_USER: you can customize the arbitration method user_priority_arbitration() to determine that the request of that sequence is authorized first.

  • In the above arbitration mode, the priority related mode is UVM_SEQ_ARB_WEIGHTED,UVM_SEQ_ARB_STRICT_FIFO and UVM_SEQ_ARB_STRICT_RANDOM.

  • The difference between the three modes is that UVM_ SEQ_ ARB_ The authorization of weighted may fall on the request of each priority sequence, while the UVM_SEQ_ARB_STRICT_RANDOM will only randomly arrange the authorization to the request with the highest priority, UVM_SEQ_ARB_STRICT_FIFO will not authorize randomly, but in strict accordance with priority and arrival order.

  • There are no special requirements. Users do not need to customize the authorization mechanism, so they use UVM_SEQ_ARB_USER is the first mock exam in this area. Other modes can satisfy the overwhelming majority of arbitration requirements.

  • Since the priority of sequence transmission can affect the arbitration authorization of the sequencer, it is necessary to give an example code combined with the arbitration mode of the sequencer and the priority of the sequence.

class bus_trans extends uvm_sequence_item;
	rand bit data;
	...
endclass

class child_seq extends uvm_sequence;
	rand int base;
	...
	task body();
		bus_trans req;
		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);
	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(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 %0d from parent sequence %s",req.data,req.get_parent_sequence().get_name()),UVM_LOW)
			seq_item_port.item_done();
		end
	endtask
endclass

class env extends uvm_env;
	sequencer sqr;
	driver drv;
	...
	function void build_phase(uvm_phase phase);
		sqr=sequencer::type_id::create("sqr",this);
		drv=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;
	env e;
	...
	task run_phase(uvm_phase phase);
	top_seq seq;
	phase.raise_objection(phase);
	seq=new();
	seq.start(e.sqr);
	phase.drop_objection(phase);
	endtask
endclass

5, Locking mechanism of sequencer

uvm_sequencer provides two locking mechanisms, which are implemented by lock() and grab() methods respectively. The differences between the two methods are as follows:

  • The pair of lock() and unlock() methods can provide exclusive access to the sequence, but the precondition is that the sequence must first be authorized according to the sequencer's arbitration mechanism. Once the sequence is authorized, there is no need to worry about the permission being revoked. Only when the sequence actively unlocks its sequencer can the locked permission be released. lock() is a blocking task that returns only after obtaining permission.
  • Grab and ungrab() can also provide exclusive access to the sequence, and it only needs to be authorized unconditionally at the next authorization cycle of the sequencer. Compared with the lock method, the grab method ignores other sequences that initiate transmission requests at the same time, and the only ones that can block it are other locks or grab sequences that have been authorized in advance.
  • What we need to note here is that since sequence is used for lock, or grab(), we must call unlock() or ungrab() before sequence ends. Otherwise, sequencer will enter the deadlock state without continuing to authorize the rest sequence.

6, Locking example for sequencer

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);
		`uvm_info("LOCK",get exclusive access by lock()",UVM_LOW)
		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("GRAB","get exclusive access by grab()",UVM_LOW)
	repeat(3) #10ns `uvm_do_with(req,{data inside {[200:210]};})
	m_sequencer.ungrab(this);
	endtask
endclass

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)
			`uvm_do(grabs)
		join
	endtask
endclass


Child here_ In SEQ, although two items are sent as above, there is an interval of 10ns between each item. Sending the first item is also delayed by 10ns

7, Lock sample resolution for sequencer

Combined with the example code and output results, we can find the following points:
1. For sequence locks, a request is sent to the sequencer together with several other sequences at 10ns. According to the arbitration mode, the sequencer is authorized to seq1,seq2,seq3, and finally to locks.
2. After locks is authorized, it can always enjoy the permission without worrying about the permission being revoked by the sequencer. Before locks ends, the user needs to return the permission through the unlock() method.
3. For sequence grabs, although it initiates permission requests at 20ns (in fact, seq1, seq2 and seq3 also initiate permission requests at the same time), it has no right to withdraw permissions because the permissions have been occupied by locks.
4. Therefore, only when the locks end in 40ns can grabs obtain permission when the sequencer is not locked, and grabs obtains permission under this condition regardless of other sequences that initiate requests at the same time.
5. Similarly, before the end of grabs, the permission should also be released through the ungrab() method to prevent the deadlock behavior of the 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.

Topics: Verilog microchip systemverilog uvm