UVM introduction and advanced learning notes 14 - sequence and item

  • Sequence refers to uvm_sequence class, and item refers to uvm_sequence_item class.
  • For incentive generation and scene control, it is woven by sequence, while the specific data and control requirements for incentive are obtained from the member data of item.

Sequence Item

  • item is based on uvm_object class, which indicates that it has the necessary data operation methods of UVM core base class, such as copy(), clone(), compare(), record().
  • Items are divided into:
    • Control class. For example, the read-write type, data length, transmission mode, etc. on the bus protocol.
    • Load class. Generally refers to data packets on the data bus.
    • Configuration class. It is used to control the driving behavior of the driver, such as the sending interval of the command driver or whether there is error insertion.
    • Debug class. It is used to mark some additional information for debugging, such as the instance serial number of the object, the creation time, the beginning and end of the time parsed by the driver, etc.

Sequence Item example

class bus_trans extends uvm_sequence_item;
	rand bit write;
	rand int data;
	rand int addr;
	rand int delay;
	static int id_num;
	`uvm_object_utils_begin(bus_trans)
		`uvm_field_int ...
	`uvm_object_utils_end
	...
endclass
class test1 extends uvm_test;
	`uvm_component_utils(test1)
	...
	task run_phase(uvm_phase phase);
		bus_trans t1, t2;
		phase.raise_objection(phase);
		#100ns;
		t1 = new("t1");
		t1.print();
		#200ns;
		t2 = new("t2");
		void'(t2.randomize());
		t2.print();
		phase.drop_objection(phase);
	endtask
endclass

Output result:

  • Features of item:
    • If the data domain needs to be used as a driver, it should be defined as rand type, and appropriate constraint s should be given according to the driver protocol.
    • Due to the data attribute of item itself, in order to make full use of the characteristics declared by UVM domain, all necessary data members are passed through 'UVM'_ field_ XXX macro to declare, easy to use the basic data method to realize automatically.
    • t1 is not randomized, but t2 is randomized. This difference is obvious before item leads to sequencer. UVM requires that the creation and randomization of items should occur in the body() task of the sequence, not in the sequencer or driver.
    • According to the life cycle of item object, its life should start from the body() method of sequence, then go through randomization and cross the sequencer, and finally reach the driver. Its life will generally not end until it is digested. The reason why this point should be highlighted is that some users will inappropriately operate the item object directly, modify its data directly, or send its handle to other components for use, which virtually modifies the data gene of the item or prolongs the life of an item object. The alternative is to make rational use of data methods such as copy() and clone().

Relationship between Item and Sequence

  • A sequence can contain some orderly organized item instances. Considering that the item needs to be randomized after creation, the sequence also needs to reserve some variables for external randomization when declaring. Some of these random variables are used to finally control the item object through hierarchical transfer constraints, One part is used to organize and control the timing between item objects.
  • In order to distinguish several common sequence definition methods, they are classified as:
    • Flat class. This category is often only used to organize finer granularity, that is, the organization composed of item instances.
    • Hierarchy class. In this category, higher-level sequences are used to organize the lower-level sequences, and then these sequences are mounted to the same sequencer in a sequential / parallel manner.
    • Virtual class. This type is the way to finally control the whole test scenario. Since there are often different kinds of sequencers and their corresponding sequences in the whole environment, a virtual sequence is needed to coordinate the top-level test scenario. The reason why it is called a virtual class is that the sequence will not be fixedly mounted on a certain sequencer type, but will eventually mount its internal different types of sequences to different target sequencers (this is the biggest point different from hierarchical sequence s).

Flat Sequence

  • A flat sequence is often composed of a small sequence item community. On this basis, the sequence has more information to complete the incentive scenarios it needs to implement.
  • Generally, for flat sequence, it contains the following information:
    • Sequence items and related constraint s are used to correlate the relationship between the generated items, so as to improve the timing form of a flat sequence.
    • In addition to limiting the contents of sequence item s, the timing information between items also needs to be given by flat sequence. For example, when to generate the next item and send it to the driver.
    • When the driver handshake is required (for example, read operation), or wait for the monitor event to respond, the sequence needs to decide the next operation after receiving the status of the component on the other side, that is, respond to the specific event to create the corresponding item and send it.

Flat Sequence example 1

class bus_trans extends uvm_sequence_item;
	rand bit write;
	rand int data;
	rand int length;
	rand int addr;
	rand int delay;
	static int id_num;
	`uvm_object_utils_begin(bus_trans)
		`uvm_field_int ...
	`uvm_object_utils_end
	...
endclass
class flat_seq extends uvm_sequence;
	rand int length;
	rand int addr;
	rand int data[];
	rand bit write;
	rand int delay;
	constraint cstr{
		data.size() == length;
		foreach(data[i])  soft data[i] == i;
		soft addr == 'h100;
		soft write == 1;
		delay inside {[1:5]};
	};
	`uvm_object_utils(flat_seq)
	...
	task body();  //Analogous to the run of a component
		bus_trans tmp;
		foreach(data[i]) begin
			tmp = new();
			tmp.randomize() with {
				data == local::data[i];
				addr == local::addr + i << 2;
				write == local::write;
				delay == local::delay;
			};
			tmp.print();
		end
	endtask
endclass
class test1 extends uvm_test;
	`uvm_component_utils(test1)
	...
	task run_phase(uvm_phase phase);	
		flat_seq seq;
		phase.raise_objection(phase);
		seq = new();
		seq.randomize() with {addr == 'h200; length == 100};
		seq.body();
		phase.drop_objection(phase);
	endtask
endclass

Output result:

  • At present, the macro of sequence or other macros that send item are not used to realize the transmission between sequence/item and sequencer, but to describe this hierarchical relationship in a more straightforward way.
  • flat_seq class can be regarded as a longer data packet, in which the specific content, length, address and other information of the data packet are contained. In the process of generating item, the random variable of item is limited by taking its own random variable as the constraint content, which is the approximate processing method of flat sequence.
  • Example code is not given, such as UVM_ do/uvm_ do_ with/uvm_ Macros such as create are used to first recognize the relationship between sequence and item. Therefore, this example is only given in flat_ Create and randomize items in the SEQ:: body() task, and omit sending items.
  • Actually bus_trans should accommodate more timing content, not just as a data transmission. As the minimum granularity of data transmission, users have the right to expand them to a larger data and time range, so as to indirectly reduce the cost of data communication and processing and improve the overall operation efficiency.

Flat Sequence example 2

class bus_trans extends uvm_sequence_item;
	rand bit write;
	rand int data[];	//The particle size becomes larger and more data can be transmitted
	rand int length;
	rand int addr;
	rand int delay;
	static int id_num;
	constraint cstr{
		data.size() == length;
		foreach(data[i])  soft data[i] == i;
		soft addr == 'h100;
		soft write == 1;
		delay inside {[1:5]};
	};
	`uvm_object_utils_begin(bus_trans)
		`uvm_field_int ...
	`uvm_object_utils_end
	...
endclass
class flat_seq extends uvm_sequence;
	rand int addr;
	rand int length;
	`uvm_object_utils(flat_seq)
	...
	task body();
		bus_trans tmp;
		tmp.new();
		tmp.randomize() with {length == local::length;
							  addr == local::addr;};
		tmp.print();
	endtask
endclass
class test1 extends uvm_test;
	`uvm_component_utils(test1)
	...
	task run_phase(uvm_phase phase);	
		flat_seq seq;
		phase.raise_objection(phase);
		seq = new();
		seq.randomize() with {addr == 'h200; length == 3};
		seq.body();
		phase.drop_objection(phase);
	endtask
endclass

Output result:

  • You can "incorporate" a complete piece of data that occurs in data transmission and longer data. In the bus_trans class, improve the abstraction level of the item granularity and make it more "temperament". Once you have a more mature and more suitable cut item, the flat sequence on the upper layer will be easier to use.
  • flat_ The SEQ class should no longer consider the data content, but only the length, address and other information of the data packet, because the responsibility of expanding random data is generally borne by item. Use flat_ Users of SEQ do not need to consider redundant data constraints.

Hierarchical Sequence

  • The difference between hierarchical sequence and flat sequence is that it can use other sequences and item s to create richer incentive scenarios.
  • Through the hierarchical nesting relationship, the hierarchical sequence can use other hierarchical sequences, flat sequences and sequence items, which means that if the granularity of the underlying sequence items and flat sequences is appropriate, these flat sequences and sequences can be fully reused to form more hierarchical sequences.

Hierarchical Sequence example

class hier_seq extends uvm_sequence;
	`uvm_object_utils(hier_seq)
	function new(string name = "hier_seq");
		super.new(name);
	endfunction
	task body();
		bus_trans t1, t2;
		flat_seq s1, s2;
		`uvm_do_with(t1, {length == 2;})
		fork
			`uvm_do_with(s1, {length == 5;})
			`uvm_do_with(s2, {length == 8;})
		join
		`uvm_do_with(t2, {length == 3;})
	endtask
endclass
  • From hier_seq::body() to see if it contains bus_trans t1, t2 and flat_seq s1, s2, and its hierarchical relationship is reflected in the coordination of each sequence/item. The example code uses uvm_do_with macro, which completes three steps:
    • Creation of sequence or item;
    • Randomization of sequence or item;
    • Transmission of sequence or item.
  • Different from the previous example code, this example code passes uvm_do_with helps us understand that the so-called sequence reuse is to nest the low-level sequence / item through the high-level sequence, and finally create the desired scene.
  • In the example, there are both serial and parallel incentive relationships. In more complex scenarios, users can also consider adding event synchronization or a certain delay relationship to form the timing relationship between sequence/item.

Added by jmr3460 on Tue, 25 Jan 2022 18:49:25 +0200