How to synchronize between task sequence and uvm end of test?

When I ran a sequence from a task through the UVM test, the UVM objection mechanism propagation was broken. UVM simulation was terminated abnormally. Especially the driver does not finished correctly after my_test.my_run(32’h1234, 32’h12341234);

class my_test extends uvm_test;
...
rnd_seq_c  rnd_seq;

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    rnd_seq = rnd_seq_c::type_id::create("rnd_seq", this);
endfunction

task run_phase(uvm_phase phase);
 phase.raise_objection(this);
 fork
     my_test.my_run(32'h1234, 32'h12341234);
 join
 phase.drop_objection(this);
endclass

This is my sequence.

class rnd_seq_c  extends vseq_c;
`uvm_objection_utils(rnd_seq_c)

function new(string name="rnd_seq_c ");
    super.new(name);
endfucntion


virtual task my_run( bit [31:0] addr, bit [31:0] data);
    rnd_item= rnd_seq_item::type_id::create("rnd_item");
    start_item(rnd_item,,rnd_seqr);
    rnd_item.data = data;
    rnd_item.addr = addr;
    finish_item(item);
endtask
endclass

pipelined driver used.

class my_pipelined_driver extends uvm_driver #(rnd_seq_c  );
  `uvm_component_utils(my_pipelined_driver)
  
  /// Virtual Interface
  virtual my_interface my_if;
  
  /// Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction: new
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db #(virtual my_interface)::get(this, "", "vif", my_if))begin
      `uvm_fatal(get_type_name(), "Virtual Interface not set in my_driver")
    end
    else
      `uvm_info(get_type_name(), "Virtual Interface set in my_driver", UVM_LOW)
  endfunction

  /// Semaphore Declaration
  semaphore pipeline_lock = new(1);
  
  /// Run Phase Task
  task run_phase (uvm_phase phase);
  
  @(posedge my_if.RESETn);
  @(posedge my_if.HCLK);
  
  fork
    do_pipelined_transfer;
    do_pipelined_transfer;
  join
  
  endtask: run_phase
  
  /// do_pipelined_transfer task
  task automatic do_pipelined_transfer;
  
//  rnd_seq_c   req;
  
  forever begin
    pipeline_lock.get();
    seq_item_port.get_next_item(req);
    accept_tr(req, $time);
    void'(begin_tr(req, "pipelined_driver"));
    my_if.HADDR <= req.HADDR;
    my_if.HWRITE <= req.HWRITE;
    my_if.HBURST <= req.HBURST;
    @(posedge my_if.HCLK);
    while(!my_if.HREADY == 1) begin
    @(posedge my_if.HCLK);
  end
  // Command phase ends here
  // Unlock semaphore
  pipeline_lock.put();
  // Data phase starts here
  if (req.HWRITE == 0) begin
    @(posedge my_if.HCLK);
  while(my_if.HREADY != 1) begin
    @(posedge my_if.HCLK);
  end
    req.HRDATA = my_if.HRDATA;
    $display("!!Driver:read_data: %0h", req.HRDATA);
    req.HRESP = my_if.HRESP;
  end
  else begin
    my_if.HWDATA <= req.HWDATA;
    @(posedge my_if.HCLK);
      while(my_if.HREADY != 1) begin
    @(posedge my_if.HCLK);
    end
    req.HRESP = my_if.HRESP;
  end
  // Return the Request as Response
    seq_item_port.item_done(req);
    end_tr(req);
  end
  endtask: do_pipelined_transfer
  
endclass: my_pipelined_driver

How do I run until the end of simulation from an abnormal termination?

fork
my_test.my_run(32’h1234, 32’h12341234);
join

If I use objection into the sequence,

class rnd_seq_c  extends vseq_c;
`uvm_objection_utils(rnd_seq_c)

function new(string name="rnd_seq_c ");
    super.new(name);
endfucntion


virtual task my_run( bit [31:0] addr, bit [31:0] data);
    uvm_phase phase;
    phase.raise_objection(this);
    rnd_item= rnd_seq_item::type_id::create("rnd_item");
    start_item(rnd_item,,rnd_seqr);
    rnd_item.data = data;
    rnd_item.addr = addr;
    finish_item(item);
    phase.drop_objection(this);
endtask
endclass

I get the NULL pointer dereference. Error. What if we start the sequence through task then how do I correctly start the sequence until end of test?

In reply to UVM_LOVE:

You can’t use custom task calls and expect that UVM will function correctly. You need to execute sequences with the seq.start() call and use body() in your sequence.

1 Like

In reply to cgales:

So I implemented as your recommend.

This is my test

class my_test extends uvm_test;
...
rnd_seq_c    rnd_seq;
write_seq_c  write_seq;

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    rnd_seq    = rnd_seq_c::type_id::create("rnd_seq", this);
    write_seq  = write_seq_c::type_id::create("write_seq", this);
endfunction
 
task run_phase(uvm_phase phase);
 phase.raise_objection(this);
 write_seq.start(rnd_env.rnd_vseqr); 
 phase.drop_objection(this);
endclass

I move the task in base sequence,

class vseq_c  extends uvm_sequence;
`uvm_objection_utils(vseq_c  )
 
function new(string name="vseq_c");
    super.new(name);
endfucntion
 
 
virtual task my_run( bit [31:0] addr, bit [31:0] data);
    rnd_item= rnd_seq_item::type_id::create("rnd_item");
    start_item(rnd_item,,rnd_seqr);
    rnd_item.data = data;
    rnd_item.addr = addr;
    finish_item(item);
endtask
endclass

and I extended it into the write_seq.

class write_seq extends vseq_c;
...
task body();
    my_run('h4, 'h1111_0000);
endtask
endclass

endclass

//////////////////////////

When I ran " write_seq.start(rnd_env.rnd_vseqr); " result is the same as before. this style also need extra drain time.

Could you guide me with example code?

In reply to UVM_LOVE:

Without seeing the entire testbench, it’s difficult to provide an accurate assessment.

Your pipelined driver seems strange, with two of the same task running in parallel. Have you looked at the UVM Cookbook section on pipelined drivers?

In reply to cgales:

I’ve just updated with the new code as the below,
The “isr_seq” sequence works in the background while bseq[0] works.
Every 200ns, ISR sequence starts from monitor trigger.

But there is one problem which is “ISR finish” does not finish after “ISR start”.
So I implemented raise/drop objection in the sequence. but this also does not work.
I thought that the objection mechanism would have controlled in sequence but even objection in sequence would does not work.

UVM_INFO testbench.sv(33) @ 1500: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR start
UVM_INFO testbench.sv(41) @ 1500: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f
UVM_INFO testbench.sv(41) @ 1550: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f
UVM_INFO testbench.sv(41) @ 1600: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f
UVM_INFO testbench.sv(47) @ 1650: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR finish
UVM_INFO testbench.sv(93) @ 1650: uvm_test_top.env_o.agt.seqr@@bseq          0 [base_seq] data = 0x000d
UVM_INFO testbench.sv(33) @ 1700: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR start


How do I correctly finish the sequence in this case?

`include "uvm_macros.svh"
import uvm_pkg::*;
 
`include "seq_item.sv"
`include "sequencer.sv"
`include "monitor.sv"
`include "driver.sv"
`include "agent.sv"
`include "env.sv"
 
class my_isr_sequence extends uvm_sequence #(seq_item);
  seq_item req;
  seq_item rsp;
  uvm_event e;
  
`uvm_object_utils(my_isr_sequence)
 
  function new(string name = "my_isr_sequence");
    super.new(name);
  endfunction
  
 virtual task pre_start();
       if(starting_phase != null)
      starting_phase.raise_objection(this);                                           
  endtask: pre_start
  
task body();
  e = uvm_event_pool::get_global("INT");
  forever begin
    e.wait_trigger();
    `uvm_info(get_type_name(), "ISR start", UVM_MEDIUM)                               
    grab();
    repeat(3) begin
      req = seq_item::type_id::create("req");                                         
      start_item(req);
      if(!req.randomize() with {req.data == 4'hf;}) begin
        `uvm_fatal(get_type_name(), "randomize fail");
      end
      `uvm_info(get_type_name(), $sformatf("data = 0x%h", req.data), UVM_MEDIUM)
      finish_item(req);
      get_response(req);
    end
    ungrab();
    e.reset();                                                                        
    `uvm_info(get_type_name(), "ISR finish", UVM_MEDIUM)                              
  end
endtask
 
  task post_body();
    // drop objection if started as a root sequence
    if(starting_phase != null)
      starting_phase.drop_objection(this);
    endtask
    
endclass
 
class my_seq_item_c extends uvm_sequence_item;
rand bit [7:0] data;                        
                                            
`uvm_object_utils(my_seq_item_c)            
                                            
  function new(string name = "my_seq_item_c");
    super.new(name);                        
  endfunction                               
                                            
endclass                                    
                                            
                                            
class base_seq extends uvm_sequence #(seq_item);
  process p[$];                             
  process pstate;                           
  seq_item req;                             
  seq_item rsp;                             
  std::process p1,p2,p3;                    
                                            
  `uvm_object_utils(base_seq)               
                                            
  function new (string name = "base_seq");  
    super.new(name);                        
  endfunction                               
                                            
  task body();                              
    for(int i=0; i<10; i++) begin           
//    repeat(10) begin                      
//    `uvm_info(get_type_name(), $sformatf("Base seq: Inside Body:%0d",i), UVM_LOW);
    req = seq_item::type_id::create("req"); 
    start_item(req);                        
     if (!req.randomize() with { req.data < 4'hF; }) begin
      `uvm_fatal(get_name(), "randomization fail");
    end                                     
      `uvm_info(get_type_name(), $sformatf("data = 0x%h", req.data), UVM_LOW)
                                            
    finish_item(req);                       
    get_response(rsp);                      
    // or                                   
    //$cast(req, create_item(seq_item::get_type(), m_sequencer, "req"));
    end                                     
//////////////////////////////////////////////////////////////////////////////////////////////////////////
  endtask                                   
                                            
endclass                                    
                                            
                                            
class base_test extends uvm_test;           
  env         env_o;                        
  base_seq    bseq[3];                      
  my_isr_sequence isr_seq;                  
                                            
  `uvm_component_utils(base_test)           
                                            
  function new(string name = "base_test", uvm_component parent = null);
   super.new(name, parent);                                  
  endfunction                                                 
                                                              
  function void build_phase(uvm_phase phase);                 
    super.build_phase(phase);                                 
    env_o = env::type_id::create("env_o", this);              
    //foreach(bseq[i]) begin                                  
      bseq[0] = base_seq::type_id::create( $sformatf("bseq%d", 0), this);
      isr_seq = my_isr_sequence::type_id::create("isr_seq", this);
    //end                                                     
  endfunction                                                 
                                                              
  task run_phase(uvm_phase phase);                            
    phase.raise_objection(this);                              
                                                              
    fork                                                      
      isr_seq.start(env_o.agt.seqr);                          
    join_none                                                 
                                                              
    bseq[0].start(env_o.agt.seqr);                            
                                                              
    //#1000;                                                  
    phase.drop_objection(this);                               
  endtask                                                     
endclass                                                      
                                                              
module tb_top;                                                
  initial begin                                               
    run_test("base_test");                                    
  end                                                         
endmodule

this is monitor to trigger to events

class monitor extends uvm_monitor;
  `uvm_component_utils(monitor)                               
    
  uvm_analysis_port #(seq_item)  mon_analysis_port;           
    
    
  function new(string name = "monitor", uvm_component parent = null);
    super.new(name ,parent);
  endfunction                                                 
                                                              
  virtual function void build_phase(uvm_phase phase);         
    super.build_phase(phase);                                 
    mon_analysis_port = new("mon_analysis_port", this);       
  endfunction
   
  virtual task run_phase(uvm_phase phase);                    
    uvm_event e;
    super.run_phase(phase);                                   
   
    e = uvm_event_pool::get_global("INT");                    
    forever begin
      #100;
      e.trigger();                                            
                                                              
    end
    
  endtask
endclass

In reply to UVM_LOVE:

If you want your ISR sequence to always block phase completion, you should raise/drop the objection within the body() and don’t use pre_start()/post_body().

In reply to cgales:

Even if I implement raise/drop objection in body() but that’s not finished at the “ISR finish”

UVM_INFO testbench.sv(48) @ 1450: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR finish
UVM_INFO testbench.sv(98) @ 1450: uvm_test_top.env_o.agt.seqr@@bseq          0 [base_seq] data = 0x0007
UVM_INFO testbench.sv(35) @ 1500: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR start
UVM_INFO testbench.sv(43) @ 1500: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f
UVM_INFO testbench.sv(43) @ 1550: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f
UVM_INFO testbench.sv(43) @ 1600: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f
UVM_INFO testbench.sv(48) @ 1650: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR finish
UVM_INFO testbench.sv(98) @ 1650: uvm_test_top.env_o.agt.seqr@@bseq          0 [base_seq] data = 0x000d
UVM_INFO testbench.sv(35) @ 1700: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] ISR start
UVM_INFO testbench.sv(43) @ 1700: uvm_test_top.env_o.agt.seqr@@isr_seq [my_isr_sequence] data = 0x000f

This is what I implemented with objection.

task body();              
       if(starting_phase != null)
      starting_phase.raise_objection(this);
  e = uvm_event_pool::get_global("INT");
  forever begin
    e.wait_trigger();
    `uvm_info(get_type_name(), "ISR start", UVM_MEDIUM)                               
    grab();
    repeat(3) begin
      req = seq_item::type_id::create("req");
      start_item(req);
      if(!req.randomize() with {req.data == 4'hf;}) begin                             
        `uvm_fatal(get_type_name(), "randomize fail");                                
      end
      `uvm_info(get_type_name(), $sformatf("data = 0x%h", req.data), UVM_MEDIUM)      
      finish_item(req);
      get_response(req);
    end
    ungrab();
    e.reset();
    `uvm_info(get_type_name(), "ISR finish", UVM_MEDIUM)
  end
    if(starting_phase != null) 
      starting_phase.drop_objection(this);
endtask