Trying layering sequences, but facing some issues

Hi,

I have a basic testbench architecture where I have a driver, sequencer, sequence, seq_item. Now I want to layer the current sequence, what i exactly want to do is to use the current sequence’s generated data, modify it and drive it using the same driver.

The basic idea behind is somewhat like this:
consider one protocol that generates data packets, now there is another protocol that takes the data packet from prev protocol as input and then modifies it.

I tried creating an example of what I am trying to do which is as follows (There might be some basic thing that I am lacking in my env please let me know if you know any solution):


// CODE START //

  `include "uvm_macros.svh"

interface dut_if;

  logic clock, reset;
  logic [7:0] data;

endinterface


module dut(dut_if dif);

  import uvm_pkg::*;

  initial begin
    forever begin
      @(posedge dif.clock);
        `uvm_info("", $sformatf("Driven Data seen on interface data=%d", dif.data), UVM_MEDIUM)
    end
  end

endmodule

package my_pkg;

  import uvm_pkg::*;
  `include "uvm_macros.svh"

  class seq_item_base extends uvm_sequence_item;
    `uvm_object_utils(seq_item_base)
    rand int data;
    constraint c_data { data == 5; }
    
    function new (string name = "");
      super.new(name);
    endfunction
    
  endclass: seq_item_base

  class seq_item_1 extends seq_item_base;
    `uvm_object_utils(seq_item_1)
    rand int data1;
    constraint c_data1 { data1 == 30; }
    
    function new (string name = "");
      super.new(name);
    endfunction
    
  endclass: seq_item_1

  class seq_item_2 extends seq_item_base;
    `uvm_object_utils(seq_item_2)
    rand int data2;
    
    function new (string name = "");
      super.new(name);
    endfunction
    
  endclass: seq_item_2
  
  
  class my_sequencer extends uvm_sequencer #(seq_item_base);
    `uvm_component_utils(my_sequencer)

    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
  endclass

  class my_l1_seqr extends uvm_sequencer #(seq_item_1);
    `uvm_component_utils(my_l1_seqr)

    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
  endclass

  class sequence1 extends uvm_sequence #(seq_item_1);
  
    `uvm_object_utils(sequence1)
    
    rand int m_data;
    
    function new (string name = "");
      super.new(name);
    endfunction

    task body;
      repeat(4)
      begin
        // 1. Create a sequence item of the given type
        req = seq_item_1::type_id::create("req");
        `uvm_info ("", $sformatf("About to call start_item"), UVM_MEDIUM)
 
        // 2. Start the item on the sequencer which will send this to the driver
        start_item(req);
        `uvm_info ("", $sformatf("start_item() fn call done"), UVM_MEDIUM)
 
        // 3. Do some late randomization to create a different content in this transaction object
        assert(req.randomize());
        `uvm_info ("", $sformatf("randomized with data=0x%0d", req.data), UVM_MEDIUM)

        req.data = req.data1 + req.data;
 
        // 4. Call finish_item to let driver continue driving the transaction object or sequence item
        finish_item(req);
        `uvm_info ("", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
      end
    endtask: body
   
  endclass: sequence1
  
  
  class sequence2 extends uvm_sequence #(seq_item_2);

    `uvm_object_utils(sequence2)
    uvm_sequencer #(seq_item_1) up_sequencer;
    
    function new (string name = "");
      super.new(name);
    endfunction
    
    task body;
      seq_item_1 si1;
      seq_item_2 si2;
      forever begin
        up_sequencer.get_next_item(si1);
        si2 = seq_item_2::type_id::create();
        start_item(si2);
        si2.data = si1.data + 300;
        finish_item(si2);
      end
      up_sequencer.item_done();
    endtask
    
  endclass: sequence2
  

  class my_driver extends uvm_driver #(seq_item_base);
  
    `uvm_component_utils(my_driver)

    virtual dut_if dut_vi;

    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
      // Get interface reference from config database
      if( !uvm_config_db #(virtual dut_if)::get(this, "", "dut_if", dut_vi) )
        `uvm_error("", "uvm_config_db::get failed")
    endfunction 

    task run_phase(uvm_phase phase);
      forever
      begin
        seq_item_port.get_next_item(req);

        // Wiggle pins of DUT
        @(posedge dut_vi.clock);
        dut_vi.data = req.data;
        `uvm_info("", $sformatf("Data recieved in the driver : data = %d", req.data), UVM_MEDIUM)

        seq_item_port.item_done();
      end
    endtask

  endclass: my_driver
  
  
  class my_agent extends uvm_agent;

    `uvm_component_utils(my_agent)
    
    my_sequencer m_seqr;
    my_driver    m_driv;
    
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
 
    function void build_phase(uvm_phase phase);
      m_seqr = my_sequencer::type_id::create("m_seqr", this);
      m_driv = my_driver   ::type_id::create("m_driv", this);
    endfunction
    
    function void connect_phase(uvm_phase phase);
      m_driv.seq_item_port.connect(m_seqr.seq_item_export );
    endfunction
    
  endclass: my_agent

  class my_env extends uvm_env;

    `uvm_component_utils(my_env)
    
    my_agent  m_agent;
    
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
 
    function void build_phase(uvm_phase phase);
      m_agent = my_agent::type_id::create("m_agent", this);
    endfunction
    
  endclass: my_env
  
  
  class my_test extends uvm_test;
  
    `uvm_component_utils(my_test)
    
    //sequence1 seq1;
    my_l1_seqr l1_seqr;
    sequence2 seq2;
    my_env m_env;
    
    function new(string name, uvm_component parent);
      super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
      m_env = my_env::type_id::create("m_env", this);
      l1_seqr = my_l1_seqr::type_id::create("l1_seqr", this);
      //seq1 = sequence1::type_id::create("seq1", this);
      seq2 = sequence2::type_id::create("seq2", this);
    endfunction

    task run_phase(uvm_phase phase);
      super.run_phase(phase);
      phase.raise_objection(this);
      //seq1.start(m_env.m_agent.m_seqr);
      seq2.start(l1_seqr);
      phase.drop_objection(this);
    endtask
  endclass: my_test
  
  
endpackage: my_pkg


module top;

  import uvm_pkg::*;
  import my_pkg::*;
  
  dut_if dut_if1 ();
  
  dut    dut1 ( .dif(dut_if1) );

  // Clock generator
  initial
  begin
    dut_if1.clock = 0;
    forever #5 dut_if1.clock = ~dut_if1.clock;
  end

  initial
  begin
    uvm_config_db #(virtual dut_if)::set(null, "*", "dut_if", dut_if1);
    
    uvm_top.finish_on_completion = 1;
    
    run_test("my_test");
  end

endmodule: top

// CODE END //

In reply to verif_newbie:

It would help others understand your code more quickly if you explained what specific issues you are having, i.e. what output you expected from this code versus what you are actually seeing. Also, you have several lines of code commented out, but no comments about why they were there in the first place.

Hi Dave,

Thanks for quick reply, the commented code is when there is no sequence2. In that case the driver gets item from sequence1 and drives it. Earlier there was no sequence2 and any code related to it. I commented these lines now considering i have another layer over the sequence1 which appends some data to the existing sequence1’s data.

Using up_sequencer the sequence2 gets next item as the driver was getting then adds 'd300 to it and I expect output as below :

UVM_INFO: … Data recieved in the driver : data = 335

I know that I am missing some basic understanding in above code. and because of which I am getting below error:

UVM_INFO @ 0: reporter [RNTST] Running test my_test…
***E,TRNULLID: NULL pointer dereference.
File: ./top.sv, line = 129, pos = 19
Scope: worklib.my_pkg::sequence2@3247_4.body
Time: 0 FS + 36
**Verilog Stack Trace:
0: task worklib.my_pkg::sequence2@3247_4.body at ./top.sv:129
1: process in worklib.uvm_pkg::uvm_sequence_base@3247_4.start at /proj/asic/predev/tools/uvm_ml/UVM_ML-1.9-XLM18.03.004/ml/frameworks/uvm/sv/1.1d-ml/src/seq/uvm_sequence_base.svh:314

./top.sv:129 up_sequencer.get_next_item(si1);

In reply to verif_newbie:

Your problem is located in this line

up_sequencer.get_next_item(si1);

You cannot call

get_next_item

on the sequencer.

In reply to chr_sue:

Hi,

Actually above code you mentioned is correct and we can call get_next_item like this. The issue was in the connections, I figured out finally after few experiments. Below code works now:

// BEGIN
`include “uvm_macros.svh”

interface dut_if;

logic clock, reset;
logic [7:0] data;

endinterface

module dut(dut_if dif);

import uvm_pkg::*;

initial begin
forever begin
@(dif.data);
`uvm_info(“”, $sformatf(“Driven Data seen on interface data=%d”, dif.data), UVM_MEDIUM)
end
end

endmodule

package my_pkg;

import uvm_pkg::*;
`include “uvm_macros.svh”

class seq_item_base extends uvm_sequence_item;
`uvm_object_utils(seq_item_base)
rand int data;
constraint c_data { data == 5; }

function new (string name = "");
  super.new(name);
endfunction

endclass: seq_item_base

class seq_item_1 extends seq_item_base;
`uvm_object_utils(seq_item_1)
rand int data1;
constraint c_data1 { data1 == 30; }

function new (string name = "");
  super.new(name);
endfunction

endclass: seq_item_1

class seq_item_2 extends seq_item_base;
`uvm_object_utils(seq_item_2)
rand int data2;

function new (string name = "");
  super.new(name);
endfunction

endclass: seq_item_2

class my_sequencer extends uvm_sequencer #(seq_item_base);
`uvm_component_utils(my_sequencer)

function new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

endclass

class my_l1_seqr extends uvm_sequencer #(seq_item_1);
`uvm_component_utils(my_l1_seqr)

function new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

endclass

class sequence1 extends uvm_sequence #(seq_item_1);

`uvm_object_utils(sequence1)

rand int m_data;

function new (string name = "");
  super.new(name);
endfunction

task body;
  repeat(10)
  begin
    // 1. Create a sequence item of the given type
    req = seq_item_1::type_id::create("req");
    `uvm_info ("", $sformatf("About to call start_item"), UVM_MEDIUM)

    // 2. Start the item on the sequencer which will send this to the driver
    start_item(req);
    `uvm_info ("", $sformatf("start_item() fn call done"), UVM_MEDIUM)

    // 3. Do some late randomization to create a different content in this transaction object
    assert(req.randomize());
    `uvm_info ("", $sformatf("randomized with data=0x%0d", req.data), UVM_MEDIUM)

    req.data = req.data1 + req.data;

    // 4. Call finish_item to let driver continue driving the transaction object or sequence item
    finish_item(req);
    `uvm_info ("", $sformatf("finish_item() fn call done"), UVM_MEDIUM)
  end
endtask: body

endclass: sequence1

class sequence2 extends uvm_sequence #(seq_item_2);

`uvm_object_utils(sequence2)
my_l1_seqr up_sequencer;

function new (string name = "");
  super.new(name);
endfunction

task body;
  seq_item_1 si1;
  seq_item_2 si2;
  int pkt_no;
  repeat(10) begin
    up_sequencer.get_next_item(si1);
    `uvm_info ("", $sformatf("got item from up_sqr"), UVM_MEDIUM)
    si2 = seq_item_2::type_id::create();
    start_item(si2);
    si2.data = si1.data + 100 + pkt_no;
    `uvm_info ("", $sformatf("sending item further"), UVM_MEDIUM)
    finish_item(si2);
    up_sequencer.item_done();
    pkt_no++;
  end
endtask

endclass: sequence2

class my_driver extends uvm_driver #(seq_item_base);

`uvm_component_utils(my_driver)

virtual dut_if dut_vi;

function new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
  // Get interface reference from config database
  if( !uvm_config_db #(virtual dut_if)::get(this, "", "dut_if", dut_vi) )
    `uvm_error("", "uvm_config_db::get failed")
endfunction 

task run_phase(uvm_phase phase);
  forever
  begin
    seq_item_port.get_next_item(req);

    // Wiggle pins of DUT
    @(posedge dut_vi.clock);
    dut_vi.data = req.data;
    `uvm_info("", $sformatf("Data recieved in the driver : data = %d", req.data), UVM_MEDIUM)

    seq_item_port.item_done();
  end
endtask

endclass: my_driver

class my_agent extends uvm_agent;

`uvm_component_utils(my_agent)

my_sequencer m_seqr;
my_driver    m_driv;

function new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
  m_seqr = my_sequencer::type_id::create("m_seqr", this);
  m_driv = my_driver   ::type_id::create("m_driv", this);
endfunction

function void connect_phase(uvm_phase phase);
  m_driv.seq_item_port.connect(m_seqr.seq_item_export );
endfunction

endclass: my_agent

class my_env extends uvm_env;

`uvm_component_utils(my_env)

my_agent  m_agent;

function new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
  m_agent = my_agent::type_id::create("m_agent", this);
endfunction

endclass: my_env

class my_test extends uvm_test;

`uvm_component_utils(my_test)

sequence1 seq1;
sequence2 seq2;
my_env m_env;
my_sequencer m_seqr;
function new(string name, uvm_component parent);
  super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);
  m_env = my_env::type_id::create("m_env", this);
  seq1 = sequence1::type_id::create("seq1", this);
  seq2 = sequence2::type_id::create("seq2", this);
  seq2.up_sequencer = my_l1_seqr::type_id::create("up_sequencer", this);
endfunction

task run_phase(uvm_phase phase);
  super.run_phase(phase);
  m_seqr = m_env.m_agent.m_seqr;
  phase.raise_objection(this);
  fork
    seq1.start(seq2.up_sequencer);
    seq2.start(m_seqr);
  join
  phase.drop_objection(this);
endtask

endclass: my_test

endpackage: my_pkg

module top;

import uvm_pkg::;
import my_pkg::
;

dut_if dut_if1 ();

dut dut1 ( .dif(dut_if1) );

// Clock generator
initial
begin
dut_if1.clock = 0;
forever #5 dut_if1.clock = ~dut_if1.clock;
end

initial
begin
uvm_config_db #(virtual dut_if)::set(null, “*”, “dut_if”, dut_if1);

uvm_top.finish_on_completion = 1;

run_test("my_test");

end

endmodule: top
// END