Null object reference - Mod 12 Counter design Verification

Hello all,
I am a beginner in UVM and I am trying to implement the verification for a mod 12 counter. But I am facing an error called null object reference in my environement connect phase. I have check all the lowler level components, if I have missed creating an object for them. I could not find any object not created. I have also checked if proper arguments to the function new construct are mentioned properly, againg could not find any fault. I have also check the configuration data base paramenters if they are set or not, still no luck.

Access the entire code by my git hub link: GitHub - MVS-Abhiram/Mod--12-Counter-Verification: This project deals with the verification of MOD 12 Counter

The code which I have developed is given below

/************************************************************************************************

---------------------------- MOD 12 COUNTER PROJECT UVM VERIFICATION-----------------------------

AUTHOR: MVS ABHIRAM

************************************************************************************************/

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

/***********************************************************************************************
---------------------------------------RTL CODE-------------------------------------------------
************************************************************************************************/

module Mod_12_loadable_up_down_counter(clk,rst,load,mode,data_in,data_out);
input clk,rst,load,mode;
input [3:0]data_in;
output reg [3:0]data_out;
always @(posedge clk) begin
        if (rst) begin
            data_out <= 4'b0000; // Reset to 0.
        end
        else if (load) begin
            data_out <= data_in; // Load new value.
        end
        else if (mode) begin
            // Increment (Up) mode, with mod-12 check
            if (data_out == 4'b1011) begin // If data_out is 11, next value should be 0.
                data_out <= 4'b0000;
            end else begin
                data_out <= data_out + 1;
            end
        end
        else begin
            // Decrement (Down) mode, with mod-12 check
            if (data_out == 4'b0000) begin // If data_out is 0, next value should be 11.
                data_out <= 4'b1011;
            end else begin
                data_out <= data_out - 1;
            end
        end
    end
endmodule


/***********************************************************************************************
---------------------------------------INTERFACE BLOCK------------------------------------------
************************************************************************************************/

interface counter_if(input bit clk);

	// Ports decleration
	bit       mode;
	bit       load;
	bit       rst;
	bit [3:0] data_in;
	bit [3:0] data_out;

	// Write Driver Clocking block
	clocking wr_drv_cb @(posedge clk);
		default input #1 output #0;
		output mode;
		output load;
		output rst;
		output data_in;
		//output data_out;
	endclocking : wr_drv_cb;

	// Write Monitor clocking block
	clocking wr_mon_cb @(posedge clk);
		default input #1 output #0;
		input mode;
		input load;
		input rst;
		input data_in;
		//output data_out;
	endclocking : wr_mon_cb

	// Read Monitor Clocking Block
	clocking rd_mon_cb @(posedge clk);
		default input #1 output #0;
		input data_out;
	endclocking: rd_mon_cb

	//Write Driver Modport decleration
	modport WR_DRV_MP (clocking wr_drv_cb);

	//Write Monitor Modport decleration
	modport WR_MON_MP (clocking wr_mon_cb);

	//Read Monnitor Modport delceration
	modport RD_MON_MP (clocking rd_mon_cb);

	modport DUV_MP (input clk,rst,load,mode,data_in, output data_out);
		
endinterface : counter_if



module counter_chip (counter_if.DUV_MP c_if);

	Mod_12_loadable_up_down_counter UUT (.clk(c_if.clk),
						.rst(c_if.rst),
						.load(c_if.load),
						.mode(c_if.mode),
						.data_out(c_if.data_out),
						.data_in(c_if.data_out));
endmodule



/***********************************************************************************************
--------------------------------------READ AGENT CONFIGURATION CLASS CODE---------------------
************************************************************************************************/

class rd_agent_config extends uvm_object;

	`uvm_object_utils(rd_agent_config)

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

	uvm_active_passive_enum is_active = UVM_PASSIVE;
	virtual counter_if vif;

endclass: rd_agent_config



/***********************************************************************************************
--------------------------------------WRITE AGENT CONFIGURATION CLASS CODE---------------------
************************************************************************************************/

class wr_agent_config extends uvm_object;

	`uvm_object_utils(wr_agent_config)

	virtual counter_if vif;

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

	uvm_active_passive_enum is_active = UVM_ACTIVE;

endclass: wr_agent_config



/***********************************************************************************************
---------------------------------------ENVIRONMENT CONFIGURATION CLASS CODE---------------------
************************************************************************************************/

class env_config extends uvm_object;

	`uvm_object_utils(env_config)

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

	virtual counter_if vif;

	int has_read_agent = 1;
	int has_write_agent = 1;
	int has_score_board = 1;
	int has_virtual_sequencer = 1;

	rd_agent_config rd_agent_configh;
	wr_agent_config wr_agent_configh;

endclass : env_config

/***********************************************************************************************
--------------------------------------WRITE TRANSCTIONS CLASS CODE------------------------------
************************************************************************************************/

class write_xtn extends uvm_sequence_item;

	`uvm_object_utils(write_xtn)

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

	rand bit rst;
	rand bit load;
	rand bit mode;
	rand bit [3:0] data_in;

	constraint valid_rst {rst dist {0:= 80, 1:= 20};}	
	constraint valid_load {load dist{0:= 80, 1:=20};}
	constraint valid_mode {mode dist{0:= 60, 1:=40};}
	constraint valid_data_in {data_in inside {[0:11]};}

endclass : write_xtn


/***********************************************************************************************
---------------------------------------READ TRANSCATIONS CODE-----------------------------------
************************************************************************************************/

class read_xtn extends uvm_sequence_item;

	`uvm_object_utils(read_xtn)

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

	bit [3:0] data_out;

endclass : read_xtn


/***********************************************************************************************
--------------------------------------SEQUENCE CLASS CODE---------------------------------------
************************************************************************************************/

class my_seq extends uvm_sequence #(write_xtn);

	`uvm_object_utils(my_seq)

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

	task body();
		repeat(10) begin
			req = write_xtn::type_id::create("req");
			start_item(req);
			assert(req.randomize());
			finish_item(req);
		end
			
	endtask
endclass: my_seq


/***********************************************************************************************
--------------------------------------TOP MODULE CODE-------------------------------------------
************************************************************************************************/

module top();

	bit clock = 0;
	always #5 clock = ~clock;

	counter_if in0(clock);

	counter_chip ch(in0);

	initial begin
		uvm_config_db#(virtual counter_if)::set(null,"*","in0",in0);
		run_test("my_test");
	end

endmodule: top




/***********************************************************************************************
--------------------------------------WRITE DRIVER CLASS CODE-----------------------------------
************************************************************************************************/

class wr_driver extends uvm_driver #(write_xtn);

	`uvm_component_utils(wr_driver);

	wr_agent_config wr_cfg;

	virtual counter_if.WR_DRV_MP vif;
	
	function new(string name = "wr_driver", uvm_component parent);
		super.new(name, parent);
	endfunction

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);

		uvm_config_db#(wr_agent_config)::get(this,"","wr_agent_config",wr_cfg);

	endfunction

	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);

		vif = wr_cfg.vif;
	endfunction

	task run_phase (uvm_phase phase);
		super.run_phase(phase);

		forever begin
			seq_item_port.get_next_item(req);
			send_to_dut(req);
			seq_item_port.item_done();
		end
	endtask

	task send_to_dut(write_xtn xtn);
		`uvm_info("WR_DRIVER",$sformatf("printing from driver \n %s", xtn.sprint()),UVM_LOW) 
	
		// Driving the data to DUV on the posedge of the clock
		@(vif.wr_drv_cb)

		vif.wr_drv_cb.rst <= xtn.rst;
		vif.wr_drv_cb.load <= xtn.load;
		vif.wr_drv_cb.mode <= xtn.mode;
		vif.wr_drv_cb.data_in <= xtn.data_in;
	endtask

	function void end_of_elaboration_phase(uvm_phase phase);
		uvm_top.print_topology();
	endfunction

endclass: wr_driver



/***********************************************************************************************
--------------------------------------WRITE MONITOR CLASS CODE----------------------------------
************************************************************************************************/

class wr_mon extends uvm_monitor;

	`uvm_component_utils(wr_mon)

	virtual counter_if.WR_MON_MP vif;
	wr_agent_config wr_cfg;

	uvm_analysis_port #(write_xtn) monitor_port;

	function new(string name ="wr_mon", uvm_component parent);
		super.new(name,parent);
		monitor_port = new("monitor_port",this);
	endfunction

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		uvm_config_db#(wr_agent_config)::get(this,"","wr_agent_config",wr_cfg);
	endfunction

	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);

		vif = wr_cfg.vif;
	endfunction

	task run_phase (uvm_phase phase);
		super.run_phase(phase);
		forever 
			monitor();
	endtask

	task monitor();
		write_xtn xtn;
		xtn = write_xtn::type_id::create("xtn");

		//Sampling the singnal for the dut interface
		xtn.rst <= vif.wr_mon_cb.rst;
		xtn.load <= vif.wr_mon_cb.load;
		xtn.mode <= vif.wr_mon_cb.mode;
		xtn.data_in <= vif.wr_mon_cb.data_in;
		`uvm_info("WR_MONITOR",$sformatf("printing from write monitor \n %s", xtn.sprint()),UVM_LOW)

		// Sending data to score Board
		monitor_port.write(xtn);
		
	endtask
endclass: wr_mon


/***********************************************************************************************
--------------------------------------WRITE SEQUENCER CLASS CODE--------------------------------
************************************************************************************************/

class wr_seqr extends uvm_sequencer #(write_xtn);

	`uvm_component_utils(wr_seqr)

	function new(string name ="wr_seqr",uvm_component parent);
		super.new(name,parent);
	endfunction
endclass : wr_seqr




/***********************************************************************************************
--------------------------------------READ MONITOR CLASS CODE----------------------------------
************************************************************************************************/

class rd_mon extends uvm_monitor;

	`uvm_component_utils(rd_mon)

	virtual counter_if.RD_MON_MP vif;
	rd_agent_config rd_cfg;

	uvm_analysis_port #(read_xtn) monitor_port1;

	function new(string name ="rd_mon", uvm_component parent);
		super.new(name,parent);
		monitor_port1 = new("monitor_port1",this);
	endfunction

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		uvm_config_db#(rd_agent_config)::get(this,"","rd_agent_config",rd_cfg);
	endfunction


	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);

		vif = rd_cfg.vif;
	endfunction

	task run_phase (uvm_phase phase);
		super.run_phase(phase);
		forever 
			monitor();
	endtask

	task monitor();
		read_xtn xtn; 
		xtn = read_xtn::type_id::create("xtn");

		//Sampling the singnal for the dut interface
		xtn.data_out <= vif.rd_mon_cb.data_out;
		//`uvm_info("RD_MONITOR",$sformatf("printing from read monitor \n %s", xtn.sprint()),UVM_LOW)
		monitor_port1.write(xtn);
	endtask
endclass: rd_mon


/***********************************************************************************************
--------------------------------------READ AGENT CLASS CODE-------------------------------------
************************************************************************************************/

class rd_agent extends uvm_agent;
	
	`uvm_component_utils(rd_agent)

	rd_agent_config rd_cfg;
	rd_mon rd_monh;

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

	function void build_phase(uvm_phase phase);
		phase.raise_objection(this);

		uvm_config_db#(rd_agent_config)::get(this,"","rd_agent_config",rd_cfg);

		if(rd_cfg.is_active == UVM_PASSIVE)
			rd_monh = rd_mon::type_id::create("rd_monh",this);

		phase.drop_objection(this);
	endfunction
endclass: rd_agent


/***********************************************************************************************
--------------------------------------WRITE AGENT CLASS CODE-------------------------------------
************************************************************************************************/
class wr_agent extends uvm_agent;
	
	`uvm_component_utils(wr_agent)

	wr_driver wr_drvh;
	wr_mon wr_monh;
	wr_seqr wr_seqrh;
	wr_agent_config wr_cfg;

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

	function void build_phase (uvm_phase phase);

		phase.raise_objection(this);

		uvm_config_db#(wr_agent_config)::get(this,"","wr_agent_config",wr_cfg);

		wr_monh = wr_mon::type_id::create("wr_monh",this);

		if(wr_cfg.is_active == UVM_ACTIVE) begin
			wr_drvh = wr_driver::type_id::create("wr_cfg",this);
			wr_seqrh = wr_seqr::type_id::create("wr_seqrh",this);
		end

		phase.drop_objection(this);
	endfunction

	function void connect_phasse(uvm_phase phase);
		super.connect_phase(phase);

		wr_drvh.seq_item_port.connect(wr_seqrh.seq_item_export);
	endfunction

endclass: wr_agent



/***********************************************************************************************
--------------------------------------AGENT TOP CLASS CODE--------------------------------------
************************************************************************************************/

class agent_top extends uvm_component;
	
	`uvm_component_utils(agent_top)

	env_config m_cfg;

	rd_agent rd_agenth;
	wr_agent wr_agenth;

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

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);

		phase.raise_objection(this);

		uvm_config_db#(env_config)::get(this,"","env_config",m_cfg);

		if(m_cfg.has_read_agent) begin
			rd_agenth = rd_agent::type_id::create("rd_agenth",this); end

		if(m_cfg.has_write_agent) begin
			wr_agenth = wr_agent::type_id::create("wr_agenth",this); end

		phase.drop_objection(this);
	endfunction

	
endclass: agent_top




/***********************************************************************************************
--------------------------------------VIRTUAL SEQUENCER CLASS CODE------------------------------
************************************************************************************************/

class v_sequencer extends uvm_sequencer;

	`uvm_component_utils(v_sequencer)

	wr_seqr wr_seqrh;

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

	

	
endclass : v_sequencer

/***********************************************************************************************
--------------------------------------VIRTUAL SEQUENCE CLASS CODE-------------------------------
************************************************************************************************/

class virtual_seq_base extends uvm_sequence #(uvm_sequence_item);

	`uvm_object_utils(virtual_seq_base)

	wr_seqr wr_seqrh;
	v_sequencer vseqrh;

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

	task body();
		if(!$cast(vseqrh,m_sequencer))
			`uvm_info("VIRTUAL_SEQUENCE","Casting not Successful",UVM_HIGH)
		wr_seqrh = vseqrh.wr_seqrh;
	endtask

endclass

class rand_seq extends virtual_seq_base;
	
	`uvm_object_utils(rand_seq)

	my_seq my_seqrh;

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

	task body();
		super.body();
		my_seqrh.start(wr_seqrh);
	endtask

endclass : rand_seq

/***********************************************************************************************
--------------------------------------SCOREBOARD CLASS CODE-------------------------------------
************************************************************************************************/

class sb extends uvm_scoreboard;
	
	`uvm_component_utils(sb)

	uvm_tlm_analysis_fifo #(write_xtn) fifo_wr;
	uvm_tlm_analysis_fifo #(read_xtn) fifo_rd;

	write_xtn wr_data;
	read_xtn rd_data;

	static bit [3:0] data_out_sb;

	function new(string name ="sb", uvm_component parent);
		super.new(name,parent);

		fifo_wr = new("fifo_wr",this);
		fifo_rd = new("fifo_rd",this);
	endfunction

	task run_phase(uvm_phase phase);
		fork
			forever begin
				fifo_wr.get(wr_data);
				counter(wr_data);
			end
			forever begin
				fifo_rd.get(rd_data);
				check_data(rd_data);
			end
		join
	endtask

	function void counter (write_xtn wr_data);
		if (wr_data.rst) begin
            		data_out_sb <= 4'b0000; // Reset to 0.
        	end
        	else if (wr_data.load) begin
            		data_out_sb <= wr_data.data_in; // Load new value.
        	end
        	else if (wr_data.mode) begin
            	// Increment (Up) mode, with mod-12 check
            		if (data_out_sb == 4'b1011) begin // If data_out is 11, next value should be 0.
                		data_out_sb <= 4'b0000;
            		end else begin
                		data_out_sb <= data_out_sb + 1;
            		end
        	end
        	else begin
            		// Decrement (Down) mode, with mod-12 check
            		if (data_out_sb == 4'b0000) begin // If data_out is 0, next value should be 11.
                		data_out_sb <= 4'b1011;
            		end else begin
                		data_out_sb <= data_out_sb - 1;
            		end
        	end

	endfunction

	function void check_data(read_xtn rd_data);
		
		if(rd_data.data_out == data_out_sb) begin
			`uvm_info("SB","Data Matched Successful",UVM_HIGH)
			$display("Read Monitor data out %0d",rd_data.data_out);
			$display("Reference Model data out %0d",data_out_sb);
		end
		else begin
			`uvm_info("SB","Data Not Matched UN-Successful",UVM_HIGH)
			$display("Read Monitor data out %0d",rd_data.data_out);
			$display("Reference Model data out %0d",data_out_sb);		
		end	 		
	endfunction
endclass: sb


/***********************************************************************************************
--------------------------------------ENVIRONMENT CLASS CODE------------------------------------
************************************************************************************************/

class my_env extends uvm_env;

	`uvm_component_utils(my_env)

	v_sequencer v_seqrh;

	env_config m_cfg;

	agent_top agent_toph;
	rd_agent rd_agenth;
	wr_agent wr_agenth;
	sb sbh;

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

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);

		phase.raise_objection(this);

		uvm_config_db#(env_config)::get(this,"","env_config",m_cfg);

		agent_toph = agent_top::type_id::create("agent_toph",this);

		if(m_cfg.has_read_agent) begin
			//rd_agenth = rd_agent::type_id::create("rd_agenth",this);
			uvm_config_db#(rd_agent_config)::set(this,"*","rd_agent_config",m_cfg.rd_agent_configh);
		end

		if(m_cfg.has_write_agent) begin
			//wr_agenth = wr_agent::type_id::create("wr_agenth",this);
			uvm_config_db#(wr_agent_config)::set(this,"*","wr_agent_config",m_cfg.wr_agent_configh);
		end

		if(m_cfg.has_score_board)
			sbh = sb::type_id::create("sbh",this);

		if(m_cfg.has_virtual_sequencer)
			v_seqrh = v_sequencer::type_id::create("v_seqrh",this);

	endfunction

	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		
		// COnnect monitor to sb (Monitor is initiator)
		wr_agenth.wr_monh.monitor_port.connect(sbh.fifo_wr.analysis_export);
		rd_agenth.rd_monh.monitor_port1.connect(sbh.fifo_rd.analysis_export);

		// COnnect virtual sequencer handels to physical sequencers
		v_seqrh.wr_seqrh =agent_toph.wr_agenth.wr_seqrh;
	endfunction

endclass: my_env

/***********************************************************************************************
--------------------------------------TEST CLASS CODE-------------------------------------------
************************************************************************************************/
class my_test extends uvm_test;

	`uvm_component_utils(my_test)
	
	rand_seq rand_seqh;
	
	my_env envh;
	env_config m_cfg;
	rd_agent_config rd_cfg;
	wr_agent_config wr_cfg;

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

	function void build_phase(uvm_phase phase);
		super.build_phase(phase);

		m_cfg = env_config::type_id::create("m_cfg");

		uvm_config_db#(virtual counter_if)::get(this,"","in0",m_cfg.vif);

		
		if(m_cfg.has_read_agent) begin
			rd_cfg = rd_agent_config::type_id::create("rd_cfg");
			if(!uvm_config_db#(virtual counter_if)::get(this,"","in0",rd_cfg.vif))
				`uvm_fatal("TEST","Getting virtual interface failed in test class for read config");
			m_cfg.rd_agent_configh =rd_cfg;
		end


		if (m_cfg.has_write_agent) begin
			wr_cfg = wr_agent_config::type_id::create("wr_cfg");
			if(!uvm_config_db#(virtual counter_if)::get(this,"","in0",wr_cfg.vif))
				`uvm_fatal("TEST","Getting virtual interface faild in test class for write config")
			m_cfg.wr_agent_configh = wr_cfg;
		end
		

		uvm_config_db#(env_config)::set(this,"*","env_config",m_cfg);

		envh = my_env::type_id::create("envh",this);
					
	endfunction

	task run_phase(uvm_phase phase);
		phase.raise_objection(this);
			rand_seqh = rand_seq::type_id::create("rand_seqh");
			rand_seqh.start(envh.v_seqrh);
		phase.drop_objection(this);
	endtask
endclass: my_test

The error I am getting

" UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_WARNING @ 0: build_objection [OBJTN_CLEAR] Object 'uvm_top' cleared objection counts for build_objection

Error-[NOA] Null object access
counter.sv, 740
  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.

  #0 in \my_env::connect_phase  at counter.sv:740
  #1 in \uvm_connect_phase::exec_func  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_common_phases.svh:96
  #2 in \uvm_bottomup_phase::execute  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_bottomup_phase.svh:108
  #3 in \uvm_bottomup_phase::traverse  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_bottomup_phase.svh:81
  #4 in \uvm_bottomup_phase::traverse  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_bottomup_phase.svh:61
  #5 in \uvm_bottomup_phase::traverse  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_bottomup_phase.svh:61
  #6 in \uvm_phase::execute_phase  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_phase.svh:1162
  #7 in \uvm_phase::m_run_phases  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_phase.svh:1858
  #8 in \uvm_root::run_test  at
  /home/cad/eda/SYNOPSYS/VCS/vcs/T-2022.06-SP1/etc/uvm/base/uvm_root.svh:424


Kindly help me unterstand where I have made a mistake in my design.

Thanks in Advance

In my_env class rd_agenth and wr_agenth are not created

Hi Jayant,

Appreciate for the reply,
I have an angent top class , so in my environment I am creating the object for agent_toph. Which in turn creates the rd_agent and wr_agent.