When size of a collection is unknown or the data space is sparse, an associative array is a better option. Associative arrays do not have any storage allocated until it is used, and the index expression is not restricted to integral expressions, but can be of any type.

An associative array implements a look-up table of the elements of its declared type. The data type to be used as an index serves as the lookup key and imposes an ordering.

Syntax

  
  
	// Value     Array_Name          [ key ];
	data_type    array_identifier    [ index_type ];

  

Initialization Example

  
  
module tb;
  	
	int   	array1 [int]; 			// An integer array with integer index
	int   	array2 [string]; 		// An integer array with string index
	string  array3 [string]; 		// A string array with string index
  
  	initial begin
      	// Initialize each dynamic array with some values
    	array1 = '{ 1 : 22,
	            	6 : 34 };
	            
		array2 = '{ "Ross" : 100,
	            	"Joey" : 60 };
	            
		array3 = '{ "Apples" : "Oranges",
	            	"Pears" : "44" };
      
      	// Print each array
      $display ("array1 = %p", array1);
      $display ("array2 = %p", array2);
      $display ("array3 = %p", array3);
    end
endmodule

  
Simulation Log

ncsim> run
array1 = '{1:22, 6:34}
array2 = '{"Joey":60, "Ross":100}
array3 = '{"Apples":"Oranges", "Pears":"44"}
ncsim: *W,RNQUIE: Simulation is complete.

A dynamic array is an unpacked array whose size can be set or changed at run time, and hence is quite different from a static array where the size is pre-determined during declaration of the array. The default size of a dynamic array is zero until it is set by the new() constructor.

Syntax

A dynamic array dimensions are specified by the empty square brackets [ ].

  
  
	[data_type] [identifier_name]  [];

	bit [7:0] 	stack []; 		// A dynamic array of 8-bit vector
	string 		names []; 		// A dynamic array that can contain strings 

  

The new() function is used to allocate a size for the array and initialize its elements if required.

Dynamic Array Example

  
  
module tb;
	// Create a dynamic array that can hold elements of type int
	int 	array []; 			
	
	initial begin
		// Create a size for the dynamic array -> size here is 5
		// so that it can hold 5 values
		array = new [5]; 			
      
		// Initialize the array with five values
		array = '{31, 67, 10, 4, 99};
      
		// Loop through the array and print their values
		foreach (array[i]) 
			$display ("array[%0d] = %0d", i, array[i]);
	end
endmodule

  
Simulation Log

ncsim> run
array[0] = 31
array[1] = 67
array[2] = 10
array[3] = 4
array[4] = 99
ncsim: *W,RNQUIE: Simulation is complete.

A SystemVerilog queue is a First In First Out scheme which can have a variable size to store elements of the same data type.

It is similar to a one-dimensional unpacked array that grows and shrinks automatically. They can also be manipulated by indexing, concatenation and slicing operators. Queues can be passed to tasks/functions as ref or non-ref arguments.

Syntax and Usage

A queue is distinguished by it's specification of the size using $ operator.

  
  
	[data_type]  [name_of_queue] [$];
    
	string       name_list [$];        // A queue of string elements
	bit [3:0]    data [$];             // A queue of 4-bit elements
    
	logic [7:0]  elements [$:127];     // A bounded queue of 8-bits with maximum size of 128 slots
    
	int  q1 [$] =  { 1, 2, 3, 4, 5 };  // Integer queue, initialize elements
	int  q2 [$];                       // Integer queue, empty	
	int  tmp;                          // Temporary variable to store values
	
	tmp = q1 [0];            // Get first item of q1 (index 0) and store in tmp
	tmp = q1 [$];            // Get last item of q1 (index 4) and store in tmp
	q2  = q1;                // Copy all elements in q1 into q2
	q1  = {};                // Empty the queue (delete all items)
	
	q2[2] = 15;              // Replace element at index 2 with 15
	q2.insert (2, 15);       // Inserts value 15 to index# 2
	q2 = { q2, 22 };         // Append 22 to q2
	q2 = { 99, q2 };         // Put 99 as the first element of q2
	q2 = q2 [1:$];           // Delete first item
	q2 = q2 [0:$-1];         // Delete last item
	q2 = q2 [1:$-1];         // Delete first and last item

  

SystemVerilog Queue Example

  
  
module tb;
  	// Create a queue that can store "string" values
  	string   fruits[$] =  { "orange", "apple", "kiwi" };
  
	initial begin
   		// Iterate and access each queue element
  		foreach (fruits[i]) 
    		$display ("fruits[%0d] = %s", i, fruits[i]);
  
  		// Display elements in a queue
  		$display ("fruits = %p", fruits);
      
      	// Delete all elements in the queue
      	fruits = {};
      	$display ("After deletion, fruits = %p", fruits);
	end
endmodule

  
Simulation Log

ncsim> run
fruits[0] = orange
fruits[1] = apple
fruits[2] = kiwi
fruits = '{"orange", "apple", "kiwi"}
After deletion, fruits = '{}
ncsim: *W,RNQUIE: Simulation is complete.

What are queue slice expressions ?

A slice expression selects a subset of the existing variable. Queue elements can be selected using slice expressions as shown in the example below.

Some simulators provide different results, hence using queue methods is recommended.

  
  
module tb;
	// Create a queue that can store "string" values
	string   fruits[$] =  { "orange", "apple", "lemon", "kiwi" };
  
	initial begin
		// Select a subset of the queue
		$display ("citrus fruits = %p", fruits[1:2]);
      
		// Get elements from index 1 to end of queue
		$display ("fruits = %p", fruits[1:$]);
      
		// Add element to the end of queue
		fruits[$+1] = "pineapple";
		$display ("fruits = %p", fruits);
      
		// Delete first element
		$display ("Remove orange, fruits = %p", fruits[1:$]);
	end
endmodule

  
Simulation Log

Compiler version J-2014.12-SP1-1; Runtime version J-2014.12-SP1-1;  May 15 16:21 2018
citrus fruits = '{"apple", "lemon"} 
fruits = '{"apple", "lemon", "kiwi"} 
fruits = '{"orange", "apple", "lemon", "kiwi", "pineapple"} 
Remove orange, fruits = '{"apple", "lemon", "kiwi", "pineapple"} 
           V C S   S i m u l a t i o n   R e p o r t 

queue-methods

A SystemVerilog case statement checks whether an expression matches one of a number of expressions and branches appropriately. The behavior is the same as in Verilog.

Click here to learn about Verilog case statements !

unique,unique0 case

All case statements can be qualified by unique or unique0 keywords to perform violation checks like we saw in if-else-if construct.

unique and unique0 ensure that there is no overlapping case items and hence can be evaluated in parallel. If there are overlapping case items, then a violation is reported.

  • If more than one case item is found to match the given expression, then a violation is reported and the first matching expression is executed
  • If no case item is found to match the given expression, then a violation is reported only for unqiue

unique0 does not report a violation if no items match the expression

unique : No items match for given expression

  
  
module tb;
  bit [1:0] 	abc;
  
  initial begin
    abc = 1;
    
    // None of the case items match the value in "abc"
    // A violation is reported here
    unique case (abc)
      0 : $display ("Found to be 0");
      2 : $display ("Found to be 2");
    endcase
  end
endmodule

  
Simulation Log

ncsim> run
ncsim: *W,NOCOND: Unique case violation:  Every case item expression was false.
            File: ./testbench.sv, line = 9, pos = 14
           Scope: tb
            Time: 0 FS + 1

ncsim: *W,RNQUIE: Simulation is complete.

unique : More than one case item matches

  
  
module tb;
  bit [1:0] 	abc;
  
  initial begin
    abc = 0;
    
    // Multiple case items match the value in "abc"
    // A violation is reported here
    unique case (abc)
      0 : $display ("Found to be 0");
      0 : $display ("Again found to be 0");
      2 : $display ("Found to be 2");
    endcase
  end
endmodule

  
Simulation Log

ncsim> run
Found to be 0
ncsim: *W,MCONDE: Unique case violation:  Multiple matching case item expressions at {line=10:pos=6 and line=11:pos=6}.
            File: ./testbench.sv, line = 9, pos = 14
           Scope: tb
            Time: 0 FS + 1

ncsim: *W,RNQUIE: Simulation is complete.

priority case

  
  
module tb;
  bit [1:0] 	abc;
  
  initial begin
    abc = 0;
    
    // First match is executed
    priority case (abc)
      0 : $display ("Found to be 0");
      0 : $display ("Again found to be 0");
      2 : $display ("Found to be 2");
    endcase
  end
endmodule

  
Simulation Log

ncsim> run
Found to be 0
ncsim: *W,RNQUIE: Simulation is complete.

Till the previous stage we had defined and created everything required within the register environment. However which agent is responsible for driving these register transactions hadn't been defined.

  
  
class my_env extends uvm_env;
   `uvm_component_utils (my_env)
   
   my_agent       m_agent;   
   reg_env        m_reg_env;
   
   function new (string name = "my_env", uvm_component parent);
      super.new (name, parent);
   endfunction
   
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      m_agent = my_agent::type_id::create ("m_agent", this);
      m_reg_env = reg_env::type_id::create ("m_reg_env", this);
   endfunction

   virtual function void connect_phase (uvm_phase phase);
      super.connect_phase (phase);
      m_agent.m_mon.mon_ap.connect (m_reg_env.m_apb2reg_predictor.bus_in);
      m_reg_env.m_ral_model.default_map.set_sequencer (m_agent.m_seqr, m_reg_env.m_reg2apb);
   endfunction
   
endclass