UVM Sequence

How to write uvm sequence

A sequence generates a series of sequence_item’s and sends it to the driver via sequencer, Sequence is written by extending the uvm_sequence.

UVM Sequence
UVM Sequence
  • A uvm_sequence is derived from an uvm_sequence_item
  • a sequence is parameterized with the type of sequence_item, this defines the type of the item sequence that will send/receive to/from the driver.

sequence base class

 virtual class uvm_sequence #( type REQ = uvm_sequence_item,
                               type RSP = REQ ) extends uvm_sequence_base

example:

class write_sequence extends uvm_sequence #(mem_seq_item);
....
....
endclass

the sequence has handle req and rsp of mem_seq_item.

 

request/req:

A transaction that provides information to initiate the processing of a particular operation.

response/rsp:

A transaction that provides information about the completion or status of a particular operation.

Sequence Execution

 

Most important properties of a sequence are,

  • body method
  • m_sequencer handle

body Method:

body method defines, what the sequence does.

m_sequencer Handle:

The m_sequencer handle contains the reference to the sequencer on which the sequence is running.

The sequence will get executed upon calling the start of the sequence from the test.

sequence_name.start(sequencer_name);

sequencer_name specifies on which sequencer sequence has to run.

  • There are Methods, macros and pre-defined callbacks associated with uvm_sequence.
  • Users can define the methods(task or function) to pre-defined callbacks. these methods will get executed automatically upon calling the start of the sequence.
  • These methods should not be called directly by the user.

Below block diagram shows the order in which the methods will get called on calling the start of a sequence.

uvm sequence phases
uvm sequence phases

* mid_do and post_do are functions, All other are tasks

Starting The Sequence:

Logic to generate and send the sequence_item will be written inside the body() method of the sequence.
The handshake between the sequence, sequencer and driver to send the sequence_item is given below.

sequence driver communication
sequence driver communication

Communication between the Sequence and driver involves below steps,
1.create_item() / create req.
2.wait_for_grant().
3.randomize the req.
4.send the req.
5.wait for item done.
6.get response.

* Step 5 and 6 are optional.

seq driver communication without response stage
seq driver communication without response stage
Method Call Description
create_item()
req = **_seq_item::type_id::create(“req”);
Create and initialize* a sequence_item or sequence
*initialize – initialized to communicate with the specified sequencer
wait_for_grant() This method call is
blocking, Execution will be blocked until the method returns.
1.This method issues a request to the current sequencer
2.The sequencer grants on getting get_next_item() request
from driver
req.randomize() This method is to randomize the sequence_item
send_request(req,re-randomize)
re-randomize = 0 or
re-randomize = 1;
Send the request item to the sequencer, which will forward it to the driver.
If the re-randomize the bit is set, the item will be randomized before being sent to the driver.
wait_for_item_done() This call is optional.
This task will block until the driver calls item_done or put.
get_current_item() Returns the request item currently being executed by the sequencer.
If the sequencer is not currently executing an item, this method will return null.
get_response(rsp) receives the response from driver.

Writing UVM Sequence

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();

    req = mem_seq_item::type_id::create("req");  //create the req (seq item)
    wait_for_grant();                            //wait for grant
    assert(req.randomize());                     //randomize the req                    
    send_request(req);                           //send req to driver
    wait_for_item_done();                        //wait for item done from driver
    get_response(rsp);                           //get response from driver

  endtask
endclass

Note: assert(req.randomize());, will return the assertion error on randomization failure.

UVM Sequence macros

These macros are used to start sequences and sequence items on default sequencer, m_sequencer.

Macro Description
`uvm_do(Item/Seq) This macro takes seq_item or sequence as argument.
On calling `uvm_do() the above-defined 6 steps will be executed.
`uvm_create(Item/Seq) This macro creates the item or sequence.
`uvm_send(Item/Seq) create() and randomize() are skipped, rest all other steps are executed.
`uvm_rand_send(Item/Seq) Only create() is skipped, rest all other steps are executed.
`uvm_do_with(Item/Seq,Constraints) This macro performs above 6 steps along with constraints defined in second argument.
`uvm_rand_send_with(Item/Seq,Constraints) create() is skipped, rest all other steps are executed along with constraints defined in second argument.
`uvm_do_pri(Item/Seq,Priority ) Performs `uvm_do() with priority mentioned.
`uvm_do_pri_with(Item/Seq,Constraints,Priority) Performs `uvm_do() along with constraints defined and priority mentioned.
`uvm_send_pri(Item/Seq,Priority) create() and randomize() are skipped, rest all other steps are executed with priority mentioned.
`uvm_rand_send_pri(Item/Seq,Priority) Only create() is skipped, rest all other steps are executed with priority mentioned.
`uvm_rand_send_pri_with(Item/Seq,Priority, Constraints) create() is skipped, rest all other steps are executed along with constraints defined with priority mentioned.
`uvm_declare_p_sequencer(SEQUENCER) This macro is used to declare a variable p_sequencer whose type is specified by SEQUENCER. by using p_sequencer handle, properties of sequencer can be accessed.

Writing the sequence using Macro’s

`uvm_do()

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do(req)
  endtask
  
endclass

`uvm_create() and `uvm_send()

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_create(req)
    assert(req.randomize());
    `uvm_send(req);
  endtask
  
endclass

`uvm_rand_send()

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_create(req)
    `uvm_rand_send(req)
  endtask
  
endclass

`uvm_do_with()

class write_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(write_sequence)
   
  //Constructor
  function new(string name = "write_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do_with(req,{req.wr_en == 1;})
  endtask
  
endclass

`uvm_rand_send_with()

class read_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(read_sequence)
   
  //Constructor
  function new(string name = "read_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_create(req)
    `uvm_rand_send_with(req,{req.rd_en == 1;})
  endtask
  
endclass

Calling sequence’s inside the sequence

class wr_rd_seq extends uvm_sequence#(mem_seq_item);
  
  write_sequence wr_seq;
  read_sequence  rd_seq;
  
  `uvm_object_utils(wr_rd_seq)
   
  //Constructor
  function new(string name = "wr_rd_seq");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do(wr_seq)
    `uvm_do(rd_seq)
  endtask
  
endclass

difference between m_sequencer and p_sequencer:

m_sequencer,

The m_sequencer handle contains the reference to the sequencer(default sequencer) on which the sequence is running.
This is determined by,

  • the sequencer handle provided in the start method
  • the sequencer used by the parent sequence
  • the sequencer that was set using the set_sequencer method

p_sequencer,

The p_sequencer is a variable, used as a handle to access the sequencer properties.
p_sequencer is defined using the macro `uvm_declare_p_sequencer(SEQUENCER_NAME)
❮ Previous Next ❯