Each class instance would normally have a copy of each of its internal variables.


class Packet;
	bit [15:0] 	addr;
	bit [7:0] 	data;
	
	function new (bit [15:0] ad, bit [7:0] d);
		addr = ad;
		data = d;
		$display ("addr=0x%0h data=0x%0h", addr, data);
	endfunction
endclass

module tb;
	initial begin
		Packet 	p1, p2, p3;
		p1 = new (16'hdead, 8'h12);
		p2 = new (16'hface, 8'hab);
		p3 = new (16'hcafe, 8'hfc);
	end
endmodule

Each of the class objects p1, p2, p3 will have addr and data variables within it.

 Simulation Log
ncsim> run
addr=0xdead data=0x12
addr=0xface data=0xab
addr=0xcafe data=0xfc
ncsim: *W,RNQUIE: Simulation is complete.

Static Variables

When a variable inside a class is declared as static, that variable will be the only copy in all class instances. To demonstrate an example we'll compare a static counter vs a non-static counter. The static counter is declared with static keyword and named as static_ctr while the normal counter variable is named as ctr. Both counters will be incremented within the new() function so that they are updated everytime an object is created.


class Packet;
	bit [15:0] 	addr;
	bit [7:0] 	data;
	static int 	static_ctr = 0;
		   int 	ctr = 0;
	
	function new (bit [15:0] ad, bit [7:0] d);
		addr = ad;
		data = d;
		static_ctr++;
		ctr++;
		$display ("static_ctr=%0d ctr=%0d addr=0x%0h data=0x%0h", static_ctr, ctr, addr, data);
	endfunction
endclass

module tb;
	initial begin
		Packet 	p1, p2, p3;
		p1 = new (16'hdead, 8'h12);
		p2 = new (16'hface, 8'hab);
		p3 = new (16'hcafe, 8'hfc);
	end
endmodule

You'll see that the static counter is shared between all class objects p1, p2 and p3 and hence will increment to 3 when three packets are created. On the other hand, the normal counter variable ctr is not declared as static and hence every class object will have its own copy. This is the reason why ctr is still 1 after all three objects are created.

 Simulation Log
ncsim> run
static_ctr=1 ctr=1 addr=0xdead data=0x12
static_ctr=2 ctr=1 addr=0xface data=0xab
static_ctr=3 ctr=1 addr=0xcafe data=0xfc
ncsim: *W,RNQUIE: Simulation is complete.

Declaring a variable as static can be very useful in cases where you want to know the total number of packets generated until a particular time.


Static functions

A static method follows all class scoping and access rules, but the only difference being that it can be called outside the class even with no class instantiation. A static method has no access to non-static members but it can directly access static class properties or call static methods of the same class. Also static methods cannot be virtual. Static function calls using class names need to be made through the scope operator ::.


class Packet;
	static int ctr=0;

   function new ();
      ctr++;
   endfunction
	
	static function get_pkt_ctr ();
		$display ("ctr=%0d", ctr);
	endfunction

endclass

module tb;
	Packet pkt [6];
	initial begin
		for (int i = 0; i < $size(pkt); i++) begin
			pkt[i] = new;
		end
		Packet::get_pkt_ctr(); 	// Static call using :: operator
		pkt[5].get_pkt_ctr(); 	// Normal call using instance
	end
endmodule
 Simulation Log
ncsim> run
ctr=6
ctr=6
ncsim: *W,RNQUIE: Simulation is complete.

Let's add in a non-static member called mode and try to call that from our static function.


class Packet;
	static int ctr=0;
   bit [1:0] mode;

   function new ();
      ctr++;
   endfunction
	
	static function get_pkt_ctr ();
		$display ("ctr=%0d mode=%0d", ctr, mode);
	endfunction
endclass

It's not allowed and will result in a compilation error.

 Simulation Log
                $display ("ctr=%0d mode=%0d", ctr, mode);
                                                      |
ncvlog: *E,CLSNSU (static-function.sv,10|40): A static class method cannot access non static class members.