Use of sequence macros give the added advantage of inline constraints, however you lose the ability to control the invocation of pre_body and post_body methods in the executed sequence. It reduces the number of lines in our code by creating the item, randomizing it and automatically calling the required tasks to start the given sequence or sequence item.

In a previous article, we learned that all `uvm_do macros ultimately call the code defined in `uvm_do_on_pri_with. So, let's see how that is structured within UVM to get better clarity behind the process.

In How to create and use a sequence, we saw that a sequence calls on the tasks start_item() and finish_item(). You can avoid putting all these statements in your code by simply calling UVM sequence macros `uvm_do or `uvm_do_with. At compile time, these macros will be substituted with calls to start_item() and finish_item(). There are primarily four types of UVM macros that can be executed on the default sequencer.

Sequences are made up of several data items, which may form an interesting scenario. For example, you can have a sequence that performs register read/writes to all the registers within the design, a sequence to perform reset, or another one to apply some stimulus to the DUT. So, you'll end up having a number of different sequences that perform different tasks to verify different aspects of the design. Remember that a sequence item refers to a packet of data, while a sequence is just a container for an arrangement of items/sub-sequences. sequence_library Now, you have a few options :

  • Use existing sequences to drive stimulus to the DUT individually
  • Combine existing sequences to create new ones - perform reset sequence followed by register read/writes followed by FSM state change sequence
  • Pull random sequences from the sequence library and execute them on the DUT
arrange sequences in multiple ways


module tff ( 	input clk,
            	input rstn,
            	input t,
            output reg q);
  always @ (posedge clk) begin
    if (!rstn) 
      q <= 0;
    	if (t)
      		q <= ~q;
      		q <= q;



module tb;
  reg clk;
  reg rstn;
  reg t;
  tff u0 (	.clk(clk),
  always #5 clk = ~clk;
  initial begin  
    {rstn, clk, t} <= 0;
    $monitor ("T=%0t rstn=%0b t=%0d q=%0d", $time, rstn, t, q);
    repeat(2) @(posedge clk);
    rstn <= 1;
    for (integer i = 0; i < 20; i = i+1) begin
      reg [4:0] dly = $random;
      #(dly) t <= $random;
	#20 $finish;

Simulation Log

ncsim> run
T=0 rstn=0 t=0 q=x
T=5 rstn=0 t=0 q=0
T=15 rstn=1 t=0 q=0
T=19 rstn=1 t=1 q=0
T=25 rstn=1 t=1 q=1
T=35 rstn=1 t=1 q=0
T=43 rstn=1 t=0 q=0
T=47 rstn=1 t=1 q=0
T=55 rstn=1 t=0 q=1
T=59 rstn=1 t=1 q=1
T=65 rstn=1 t=1 q=0
T=67 rstn=1 t=0 q=0
T=71 rstn=1 t=1 q=0
T=75 rstn=1 t=0 q=1
T=79 rstn=1 t=1 q=1
T=83 rstn=1 t=0 q=1
T=87 rstn=1 t=1 q=1
T=95 rstn=1 t=0 q=0
Simulation complete via $finish(1) at time 115 NS + 0