How to write a UVM Sequence

Hi,

I have a doubt in uvm_sequence creation. In the body of a uvm_sequence do I need to write 6 steps for generating a sequence or
create req
start_item(req)
req.randomize()
finish_item(req) is these steps enough?
Basically my question is whats is the difference between the codes below(one is with start_item and finish_item other without that)
Code1:

class my_sequence extends uvm_sequence#(transaction);
  `uvm_object_utils(my_sequence)
 
  transaction t;
  int LIMIT;
  ...
  task body();
    for (int i = 0; i < LIMIT; i++) begin
      t = new(“t”);
      start_item(t);
      t.data = i+1;
      if (!t.randomize())
        `uvm_fatal(get_type_name(), "Randomize FAILED")
      finish_item(t);
    end
  endtask
endclass

Code 2:

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

(1) What is the difference between start_item method in code 1 and the 6 step method in code 2?

(2) One more question I have is that if I am not using rand fields in my sequence item do I need to randomize the fields/ randomize the transactions in uvm_sequence_item(is sequence_item.randomize() mandatory step in body of sequence even if the fields are not rand)

Hi,
I am responding to your queries in a Q/A format below, please have a look.

Q1) What is the difference between start_item method in code 1 and the 6 step method in code 2?
A. Basically both the things are valid i.e. invoking a sequence item using a `uvm_do macro(6 steps mentioned) or the start_item()/finish_item() methods.

Code 1 won’t call any internal methods and send the sequence item to the driver connected with the sequencer(Note the sequencer was already set when you started your sequence). All in all this will result in less simulation time.

Code 2 the 6 steps is nothing else than what a uvm_do macro houses. What this will do is, it will call some extra methods as well which eats up extra sim time. The use of uvm_do it calls pre_do and post_do methods and internally completes all the process from create_item to till item_done().

Usage of any of the above mentioned completely depends upon the user. You can refer below links for further details:
https://www.chipverify.com/blog/tags/uvm-sequence-macros

Q2) One more question I have is that if I am not using rand fields in my sequence item do I need to randomize the fields/ randomize the transactions in uvm_sequence_item(is sequence_item.randomize() mandatory step in body of sequence even if the fields are not rand)?
A. It is not mandatory to use .randomize(). But both the things are legit even if you randomize it or not.
It is better that you randomize it because, may happen that going forward you add some rand fields to your code and if .randomize() is not called it won’t randomize that particular field (Sometimes we miss these small things and invest time in debugging at other places)

Thank You

In reply to rr2007:

1.) method used in code (1) is when sequence is not waiting for any response from driver end. while in code (2), wait_for_item_done() waits for req.item_done() of driver and after that get_response(rsp) is blocking task used to get response from driver end.

2.) if you are not using randomize, in code(1) before calling start_item(t), fill the data and remove randomization part. In code (2) before send_request(req),fill data in transaction and remove assert() statement too.

In reply to juhi_p:

@juhi_p in code 1 why do I need to fill the data before calling start_item(t) I can do it in between start_item and finish_item right?
Even if you look the code 1 there also it is filling t.data=i+1 after start_item
Can you please help on this