UVM practice volume I learning notes 9 - sequence in UVM

sequence related macro and its implementation

uvm_do series macro

uvm_do series macros mainly include the following 8:

`uvm_do(SEQ_OR_ITEM)
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR)
`uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)
`uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS)
`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)

Where uvm_do,uvm_do_with,uvm_do_pri,uvm_do_pri_with has been mentioned earlier. UVM practice volume I learning notes 9 - sequence in UVM (1)

Introduce the other 4:
uvm_do_on is used to explicitly specify which sequencer to use to send this transaction. It has two parameters: a pointer to the transaction and a pointer to the sequencer. When using UVM in sequence_ For macros such as do, the default sequencer is the sequencer specified for this sequence when it is started. Sequence places the pointer of this sequencer in its member variable M_ In the sequencer. In fact, uvm_do is equivalent to: ` uvm_do_on(tr, this.m_sequencer)

It seems useless to specify which sequencer to use here. Its real role should be reflected in the virtual sequence (see later).
uvm_do_on_pri, which has three parameters: transaction pointer, sequencer pointer and priority;
uvm_do_on_with has three parameters: transaction pointer, sequencer pointer and constraint;
uvm_do_on_pri_with, four parameters: transaction pointer, sequencer pointer, priority and constraint;
For example: ` uvm_do_on_pri_with(tr, this, 100, {tr.pload.size == 100;}) / / note that curly braces are required for constraints

uvm_ The other seven macros in the do series actually use uvm_do_on_pri_with macro. Such as uvm_do macro:

`define uvm_do(SEQ_OR_ITEM) \
	`uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -1, {})

*uvm_create and uvm_send

In addition to using uvm_do macro generates transaction, and UVM can also be used_ Create macro and uvm_send macro to generate:

class case0_sequence extends uvm_sequence #(my_transaction);
	...
	virtual task body();
		int num = 0;
		int p_sz;
		...
		repeat (10) begin
			num++;
			`uvm_create(m_trans)
			assert(m_trans.randomize());
			p_sz = m_trans.pload.size();
			{m_trans.pload[p_sz - 4],
		 	 m_trans.pload[p_sz - 3],
			 m_trans.pload[p_sz - 2],
			 m_trans.pload[p_sz - 1]}
			 = num;
			`uvm_send(m_trans)
		end
		...
	endtask
	...
endclass

uvm_ The create macro is used to instantiate a transaction. When a transaction is instantiated, you can do more processing on it. After processing, use uvm_send macro is sent out. This method is better than uvm_do series macros are more flexible. As in the above example, replace the last four byte s of pload with the sequence number of the transaction.

In fact, UVM is completely unnecessary in the above code_ Create macro and directly call new for instantiation:

virtual task body();
	...
	m_trans = new("m_trans");
	assert(m_trans.randomize());
	p_sz = m_trans.pload.size();
	{m_trans.pload[p_sz - 4],
	 m_trans.pload[p_sz - 3],
	 m_trans.pload[p_sz - 2],
	 m_trans.pload[p_sz - 1]}
	 = num;
	`uvm_send(m_trans)
	... 
endtask

Except UVM_ There is UVM besides send_ send_ The PRI macro is used to set the priority when handing the transaction to the sequencer:

virtual task body();
	...
	m_trans = new("m_trans");
	assert(m_trans.randomize());
	p_sz = m_trans.pload.size();
	{m_trans.pload[p_sz - 4],
	 m_trans.pload[p_sz - 3],
	 m_trans.pload[p_sz - 2],
	 m_trans.pload[p_sz - 1]}
	 = num;
	`uvm_send_pri(m_trans, 200)
	...
endtask

*uvm_rand_send series macros

uvm_ rand_ The send series macros are as follows:

`uvm_rand_send(SEQ_OR_ITEM)
`uvm_rand_send_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_rand_send_with(SEQ_OR_ITEM, CONSTRAINTS)
`uvm_rand_send_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)

uvm_rand_send macro and UVM_ The send macro is similar, except that it randomizes the transaction. The premise of using this macro is that the transaction has been allocated space, that is, it has been instantiated:

m_trans = new("m_trans");
`uvm_rand_send(m_trans)

uvm_ rand_ send_ The PRI macro is used to specify the priority of the transaction. It has two parameters: transaction pointer and priority;
uvm_ rand_ send_ The with macro is used to specify the constraint when randomization is used. It has two parameters: the pointer of transaction and the constraint;
uvm_ rand_ send_ pri_ The with macro is used to specify priority and constraint. It has three parameters: transaction pointer, priority and constraint;
E.g.: m_trans = new(“m_trans”);
`uvm_rand_send_pri_with(m_trans, 100, {m_trans.pload.size == 100;}) / / note that curly braces should be added for constraints

uvm_rand_send series macros and UVM_ The significance of send series macros is that if a transaction occupies a large amount of memory, it is likely that the transactions sent before and after use the same block of memory, but the contents can be different, so as to save memory.

*start_item and finish_item

We have been using macros to generate transaction s. Macros hide details and facilitate users' use, but they also bring trouble to users: what did macros do?

The method of generating transaction without macro depends on start_item and finish_item. Before using these two tasks, you must instantiate the transaction before calling these two tasks:

tr = new("tr");
start_item(tr);
finish_item(tr);

A sequence built completely using the above two tasks is as follows:

virtual task body();
	repeat(10) begin
		tr = new("tr");
		start_item(tr);
		finish_item(tr);
	end
endtask

The code does not randomize tr. You can finish after the transaction is instantiated_ Randomize item before calling it:

class case0_sequence extends uvm_sequence #(my_transaction);
	...
	virtual task body();
		...
		repeat (10) begin
			tr = new("tr");
			assert(tr.randomize() with {tr.pload.size == 200;});
			start_item(tr);
			finish_item(tr);
		end
		...
	endtask
	...
endclass

The above assert statement can also be placed in start_ After item, finish_ Before item. uvm_ The do series macro actually encapsulates the following actions in a macro:

virtual task body();
	...
	tr = new("tr");
	start_item(tr);
	assert(tr.randomize() with {tr.pload.size() == 200;});
	finish_item(tr);
	...
endtask

If you want to specify the priority of transaction, you need to call start_item and finish_ Priority parameters should be added when item:

virtual task body();
	...
	start_item(tr, 100);
	finish_item(tr, 100);
	...
endtask

If the priority parameter is not specified, the default priority is - 1.

*pre_do, mid_do and post_do

uvm_do macro encapsulates a series of operations from transaction instantiation to sending. The more encapsulated, the less flexible it is.

To increase UVM_ For the functions of do series macros, UVM provides three interfaces:

  • pre_do is at start_ The task called in item is at start_item returns the last line of code executed before it is executed. After it is executed, the transaction is randomized.
  • mid_do is located in finish_ The initial function of item. Finish after executing this function_ Item to perform other operations.
  • post_do is also in finish_ The function in item, which is finish_ The last line of code executed before item returns.

Their execution order is roughly as follows:

wait_for_grant,send_request and wait_for_item_done are all interfaces inside the UVM. Examples of the use of these three interface functions / tasks are as follows:

class case0_sequence extends uvm_sequence #(my_transaction);
	my_transaction m_trans;
	int num;
	...
	virtual task pre_do(bit is_item);
		#100;
		`uvm_info("sequence0", "this is pre_do", UVM_MEDIUM)
	endtask
	virtual function void mid_do(uvm_sequence_item this_item);
		my_transaction tr;
		int p_sz;
		`uvm_info("sequence0", "this is mid_do", UVM_MEDIUM)
		void'($cast(tr, this_item));
		p_sz = tr.pload.size();
		{tr.pload[p_sz - 4],
		 tr.pload[p_sz - 3],
		 tr.pload[p_sz - 2],
		 tr.pload[p_sz - 1]} = num;
		tr.crc = tr.calc_crc();
		tr.print();
	endfunction
	virtual function void post_do(uvm_sequence_item this_item);
		`uvm_info("sequence0", "this is post_do", UVM_MEDIUM)
	endfunction
	virtual task body();
		...
		repeat (10) begin
			num++;
			`uvm_do(m_trans)
		end
		...
	endtask
	...
endclass

pre_ Parameter of do: used to indicate UVM_ Is the do macro operating on a transaction or a sequence.

mid_do and post_ The two parameters of do are pointers to the sequence or item being operated on, but their type is uvm_sequence_item type. cast can be used to convert to the target type (my_transaction in the example).

Posted by Jene200 on Mon, 25 Oct 2021 07:37:41 -0700