Error-[NOA] Null object access

Hi

Am getting following error in following tb scenario.
I have instantiated axi uvc in my tb and it is compile clean
Following that, am trying to send some random traffic on axi interface but getting run time error as below

Error-[NOA] Null object access
tb/sequences/tb_v_seq.sv, 117
The object at dereference depth 1 is being used before it was
constructed/allocated.
Please make sure that the object is allocated before using it.

Few questions:

  1. How do I know which object is the error referring to? When I look at the line number mentioned in the error, it is referring to the line in bold and underlined. So it could be either sequence or sequencer. I suspect p_sequencer because when I use uvm_do instead of uvm_do_on it again stops where p_sequencer is called.
  2. What am I missing here in my code. I have created the seqr and also connected.

Any help/pointers is really appreciated.

Here is the required code

class tb_env extends uvm_env; // {
   `uvm_component_utils(tb_env)

   tb_vseqr vseqr;

    //AXI switch Master agent
    uvc_mst_env axi_switch_mst;

    uvc_vif_mem_proxy vif_switch_m_proxy;
   
    function new(string name = "TB_ENV", uvm_component parent);
        super.new(name, parent);
    endfunction:new

    virtual function void build_phase(uvm_phase phase);
        
      super.build_phase(phase);
      axi_switch_mst = uvc_mst_env::type_id::create("axi_switch_mst", this);
      vif_switch_m_proxy = uvc_vif_mem_proxy::type_id::create("vif_switch_m_proxy",this);

      vif_switch_m_proxy.assign_vi(tb_verif_top.axi_switch_mst_if);
    
      uvm_config_db#(uvm_object)::set(this, "axi_switch_mst.agent", "vif_proxy", vif_switch_m_proxy);

      vseqr = tb_vseqr::type_id::create("vseqr",this);

    endfunction : build_phase

   
   // Function: connect_phase 
   //
    virtual function void connect_phase (uvm_phase phase); // {
        super.connect_phase(phase);
        vseqr.axi_switch_mst_wr_seqr = axi_switch_mst.agent.wr_agent.sequencer;

    endfunction : connect_phase // }

endclass: tb_env // }

class tb_vseqr extends uvm_sequencer; // {
   `uvm_component_utils(tb_vseqr)

   uvc_mst_wr_sequencer axi_switch_mst_wr_seqr;

   // Function: new 
   //
   // This is an constructor, which creates with given ~name~ 
   function new (string name = "tb_vseqr", uvm_component parent = null); // {
      super.new(name,parent);
   endfunction : new // }

   // Function: build_phase 
   //
   // In this phase the cfg interface is get using config_db, which is used in the <tb_v_seq> to get the clk, rst information.
   virtual function void build_phase (uvm_phase phase); // {
      super.build_phase(phase);
      axi_switch_mst_wr_seqr = uvc_mst_wr_sequencer::type_id::create("axi_switch_mst_wr_seqr", this);
   endfunction : build_phase // }

endclass : tb_vseqr // }

class tb_v_seq extends uvm_sequence ; // {
   `uvm_object_utils(tb_v_seq)
   `uvm_declare_p_sequencer(tb_vseqr)

   function new (string name = "tb_v_seq"); // {
      super.new(name);
   endfunction : new // }

   // Driving the Reset
   
   virtual task tb_reset (); 
     .......
     `uvm_info(get_type_name(),"Resetting DUT done",UVM_NONE)
   endtask : tb_reset 
endclass : tb_v_seq // }

class tb_random_axi_switch_seq extends tb_v_seq; // {
   `uvm_object_utils(tb_random_axi_switch_seq)
   `uvm_declare_p_sequencer(tb_vseqr)
   seq_mst_rand_alltypes_incr axi4_wr_seq_incr;

   function new(string name = "tb_random_axi_switch_seq"); // {
      super.new(name);
   endfunction : new // }
   
   // Task: body 
   //
   virtual task body(); // {

     **_`uvm_do_on(axi4_wr_seq_incr,p_sequencer.axi_switch_mst_wr_seqr);_**
     `uvm_info(get_type_name(),"AXI transaction sent",UVM_NONE)
   endtask: body // }

endclass : tb_random_axi_switch_seq // }

class seq_mst_rand_alltypes_incr extends uvc_mst_wr_seq_base#(uvc_axi4_transaction);
  `uvm_object_utils(seq_mst_rand_alltypes_incr)

    uvc_axi4_transaction transfer;
  function new (string name = "seq_mst_rand_alltypes_incr");
    super.new(name);
  endfunction // new

  virtual task body();

    
    uvm_report_info(get_type_name(), "Starting....");

    for (int i= 0; i < 16;i++) begin
      for (int j = 0; j <= 10;j++) begin
        repeat(8) begin
          `uvm_create(transfer)
          initialize_axi4_transaction(transfer);
          `uvm_rand_send_with(transfer, {addr <= 32'h10000; len == i; size == j;burst == AXI_BURST_TYPE_INCR;})
        end
      end
    end
    uvm_report_info(get_type_name(), "Completed....");
  endtask

endclass : seq_mst_rand_alltypes_incr

Thank you for your time

In reply to mpandejee:

The error message is very clear and points you directly to the cause:

Error-[NOA] Null object access
tb/sequences/tb_v_seq.sv, 117
The object at dereference depth 1 is being used before it was
constructed/allocated.
Please make sure that the object is constructed before using it.

Could you please show what line 117 of tb_v_seq.sv is?

In reply to mpandejee:

The issue most likely has to do with the way p_sequencer is assigned when the sequence is run, but you will need to trace into this call to see what exactly is going wrong.

Debugging a macro call is very difficult, as you are finding out. This is why we recommend the following:

  • Never use p_sequencer. It is a deprecated construct and should not be used. Instead, put the required information in the sequence itself.
  • Never use the `uvm_do_* macros. Use start()/start_item()/finish_item() directly. This gives you finer control over your sequences.

In reply to cgales:

Thank you.
I tried few experiments and observed 2 things.

  1. If I call same sequence from base test and pass tb.vseqr as the seqr argument, somehow there is no issue and the test passes. (Reality: I cannot implement all tests from base test)

  2. If I pass only p_sequencer instead of p_sequencer.axi_switch_mst_wr_seqr, it doesn’t give me null object access error for that particular start() call. But it stops later in axi seq with the same error. Since axi uvc sequence is using p_sequencer, I cannot avoid p_seqr even if I want to.
    As you can see in the env.sv file, axi uvc is created and seqr connections are made. I am not sure what could cause null object error.

In reply to chr_sue:

I am seeing null object error in following call.
As cgales suggested, I have also tried with start()and still face the same issue

`uvm_do_on(axi4_wr_seq_incr,p_sequencer.axi_switch_mst_wr_seqr);

In reply to mpandejee:

I had a closer look to your code. You are mixing 2 things together, the p_sequencer and the virtual sequencer. You should use one of these approaches, either p_sequencer(which is not recommended) or the virtual sequencer.

My recommendation is to remove all lines with

`uvm_declare_p_sequencer(tb_vseqr)

After doing this you should investigate your constructed testbench topology.
You can do this in your test in the start_of_simulation_phase like this:

function void your_test::start_of_simulation_phase(uvm_phase phase);
  super.start_of_simulation_phase(phase);
  uvm_top.print_topology();
endfunction : start_of_simulation_phase

This helps you to debug your environment.

In reply to chr_sue:

Thanks chr_sue for looking into it.
Test topology seemed ok as I can see axi seqr instantiated under vseqr.
Even after removing p_sequencer I was still facing the same issue.

However I was able to root cause the issue. The issue lied in the class where I was instantiating the test sequence in test lib for the first time. In there as an argument to sequencer, “null” was being passed.
That is why the test passed when I called sequence in base test and not child sequences.

Thank you for your help.