UVM learning and sorting - UVM communication (sequence)


5, sequence

5.1 execution process of sequence

5.2 start mode of sequence -- start()/default_sequence

5.3 sequence production data - body()

Series macros ` uvm_do():

5.4 arbitration mechanism of sequence

5.4.1 priority setting

5.4.2 special operation

5, sequence

         The biggest function of the sequence mechanism of UVM is to separate test case from testbench. For a project, Testbench is a relatively stable framework, and there are different test contents for each module, so the specific test cases are very different. In UVM, test and sequence classes always appear in pairs, which realizes the combination of testbench and specific test case. In the test class, you can make some differential configurations for testbench according to the specific test content, and in the sequence class, you can implement the specific details of the test case.

5.1 execution process of sequence

         uvm_sequence_item (wrapped data): only data can be encapsulated, and there are no automatically executed functions;

         uvm_sequence (production data): it has an automatically executable function, which can perform executable operations through the body() function to generate data incentives;

         uvm_sequencer: send data to driver;

         sequence item is the minimum granularity content of each interaction between driver and DUT. The sequencer acts as a bridge between sequence and driver. Both sequencer and driver are component components, and the communication between them is also realized through TLM port. The connection transmission of UVM sequence is shown in the following figure:

         1. The sequence object itself will generate a target number of sequence item objects. With the randomization of SV and the support of sequence item for randomization, the data content in each sequence item object is different.

         2. The generated sequence item will pass through the sequencer and then flow to the driver.

         3. The driver obtains each sequence item, analyzes the data, and then writes the data to the interface according to the physical interface protocol with the DUT, forming an effective incentive for the DUT.

         4. If necessary, after parsing and digesting a sequence item each time, the driver will return the last status information to the sequencer together with the sequence item object itself, and finally reach the side of the sequence object. The purpose of this is that sometimes the sequence needs to know the state of the interaction between the driver and the DUT, which requires the driver to still have a loop, and then write the processed sequence item object and state information back to the sequence side.

5.2 start mode of sequence -- start()/default_sequence

         sequence startup in UVM can be divided into display startup and implicit startup.

  • Explicit start (direct start) - call the start() method to start;
  • Implicit startup - using uvm_config_db mechanism configuration default_sequence starts.
//Explicit start of sequence
//This method lifts and drops the object through phase.raise_objection(this)/phase.drop_objection(this)
task my_case0::main_phase(uvm_phase phase);
    my_sequence  seq;
    seq = my_sequence::type_id::create("seq");

//Implicit start of sequence
//This method can use starting in the sequence_ Phase lift and undo object
//In my_ body task in sequence
virtual task body;
  if(starting_phase != null)
  if(starting_phase != null)

5.3 sequence production data - body()

         When a sequence is started, the body() function will be automatically executed to produce data, and the sequencer will send the data to the driver to complete the data transmission. The communication between the sequencer and the driver is also realized through the TLM port. The TLM port needs to specify the communication parameters in the instantiation. The communication parameters here are the type of sequence item.

class tr_sequence extends uvm_sequence#(transaction);
   virtual task body();
      if(starting_phase != null)
         starting_phase.raise_objection(this,"starting");   //1. Start simulation and production data
         `uvm_do(req);                                      //2. Through macro ` uvm_do automatic randomization to generate data
      if(starting_phase != null)
         starting_phase.drop_objection(this,"done");        //3. End the simulation

class driver extends uvm_driver#(transaction);
   virtual task run_phase(uvm_phase phase);
      forever begin
         seq_item_port.get_next_item(req);                 //4.driver application data
         send(req);                                        //5. Process the received data according to the physical timing
         seq_item_port.item_done();                        //6. Data transmission completed

  • In the sequence, the data production during simulation is controlled through the object mechanism;
  • Run in driver_ Phase phase, using TLM port seq_ item_ Get of port_ next_ Item () and item_ The done () method controls the transmission of packets.

Series macros ` uvm_do():

         When a sequence is started, the body task in the sequence will be automatically executed. In the body task, ` UVM can be called_ Do series macros to produce data.

`uvm_do(SEQ_OR_ITEM)                       //1. According to sequence_item instance, randomize to generate data
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS)     //2. Add constraints on the basis of randomized data
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_on(SEQ_OR_ITEM, SEQR)               //3. At the same time of randomization, explicitly specify which sequencer to use to send this transaction
`uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)

        ` uvm_ The do series macros actually encapsulate the following actions in a macro (start_item and finish_item). In actual code writing, engineers can not use macros uvm_do() processes the data, but manually executes these embedded programs according to the actual situation.

 req = my_sequence::type_id::create("req");  \       1. establish item Object instance;
 start_item(req);      \                   2.obtain sequencer Authorization and license of;
 assert(req.randomzie() with {req.data == 100;}); //assert(req.ranomzie()); 3. * * randomize item s * *;
 finish_item(req);     \                   4.take item Send to sequencer,Then complete and driver Interaction between

5.4 arbitration mechanism of sequence

         UVM supports starting multiple sequences on the same sequencer at the same time. Priority can be set for multiple sequences on the same sequencer, and the sequence with higher priority will send transaction first.

`uvm_do_pri(m_trans, 100)
`uvm_do_pri_with(m_trans, 200, {m_trans.pload.size < 500;})

5.4.1 priority setting

         Common uvm_do and uvm_do_ The priority of the transaction generated by the with macro is the default priority, which is - 1;

         uvm_do_pri and uvm_do_pre_with can change the priority of the generated transaction;

      After changing the priority, you need to select the sequencer's arbitration algorithm to make the set priority effective; UVM utilization   set_arbitration sets the arbitration algorithm. The existing priority algorithms are:

         SEQ_ARB_FIFO, / / the default arbitration algorithm is SEQ_ARB_FIFO, first in first out, regardless of priority

         SEQ_ARB_WEIGHTED, / / weighted arbitration

         SEQ_ARB_RANDOM, / / is a completely random selection

         SEQ_ARB_STRICT_FIFO, / / is selected strictly according to priority and in the order of first in first out

         SEQ_ARB_STRICT_RANDOM, / / is random according to the highest priority

         SEQ_ARB_USER / / user can customize

5.4.2 special operation

1. lock and unlock

         Lock and unlock operations. After the lock operation, the sequence can always send the transaction until the unlock operation, and then send it according to the normal priority; The lock operation does not take effect until all previous requests are completed;

2. grab and ungrab

         The result of the grab operation is similar to that of lock, but the grab request is placed directly in front of the arbitration queue, and the sequencer's permission is obtained almost after it has been issued;


         When the sequencer arbitrates, it will view the is of the sequence_ The return value of relevant. When it is 1, the sequence is valid, otherwise it is invalid. Can overload is_relevant to control whether the sequence is valid;

         is_relevant and wait_for_relevant is usually overloaded in pairs, and one of them cannot be overloaded;

Posted by salhzmzm on Sun, 28 Nov 2021 00:56:07 -0800