When the size of a collection is unknown up front, or the data space is sparse, an associative array is a better fit than a fixed-size or dynamic array. Associative arrays don't allocate any storage until you actually use an index, and that index isn't restricted to integers — it can be of any type.

An associative array works like a look-up table: the type used as the index becomes the lookup key, and that key type also determines the ordering used when you iterate the array.

9 min read | Intermediate Level

What You'll Learn

  • How to declare an associative array with any key type, not just integers
  • The built-in methods for checking, counting, and deleting entries
  • How first(), last(), next(), and prev() traverse the array in sorted key order
  • How to nest associative arrays with dynamic arrays in either direction

Syntax


// Value     Array_Name          [ key ];
data_type    array_identifier    [ index_type ];
  • data_type – the type of value stored at each key
  • array_identifier – the variable name
  • index_type – the key's data type; commonly int or string, but any type is allowed

An associative array is recognized by a data type sitting inside the square brackets, e.g. int m_data [string];. Compare that to a dynamic array's empty [ ] or a queue's [$] — all three are unpacked arrays, but each is written differently.

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

Output

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

Notice that array2 prints "Joey" before "Ross" even though "Ross" was assigned first in the source — string keys are displayed in alphabetical order, not insertion order. array1's integer keys likewise print numerically ascending (1 before 6), regardless of assignment order.

Quick Check

Q: If you assign array1[6] before array1[1], does $display("%p", array1) print 6 first?

Show Answer

No. Associative arrays with integer keys always print in ascending numeric order regardless of the order the entries were assigned in.

Associative Array Methods

MethodDescription
function int num ();Returns the number of entries in the associative array
function int size ();Also returns the number of entries; 0 if empty
function void delete ( [input index] );index, when specified, deletes the entry at that index; otherwise the whole array is deleted
function int exists (input index);Checks whether an element exists at the specified index; returns 1 if it does, else 0
function int first (ref index);Assigns the value of the first index to the given variable; returns 0 for an empty array
function int last (ref index);Assigns the value of the last index to the given variable; returns 0 for an empty array
function int next (ref index);Finds the smallest index whose value is greater than the given index
function int prev (ref index);Finds the largest index whose value is smaller than the given index
Associative array iteration order

Associative arrays can have non-consecutive or arbitrary index values, and next()/prev() always walk through them in sorted key order.


module tb;
  int aa_array [int];
  
  initial begin
    int idx;
  
    // Initialized indices in a mixed order, not 1,2,5,8
    aa_array[5] = 20;
    aa_array[8] = 10;
    aa_array[1] = 50;
    aa_array[2] = 100;
  
    // Finds the smallest index whose value is greater than the given index
    // Current index is 0, the next smallest value out of 1,2,5,8 is 1
    aa_array.next(idx);
    $display("aa_array[%0d]=%0d", idx, aa_array[idx]);
  
    // Current index is 1, the next smallest value out of 2,5,8 is 2
    aa_array.next(idx);
    $display("aa_array[%0d]=%0d", idx, aa_array[idx]);
  
    // Finds the largest index whose value is smaller than the given index
    // Current index is 5, the next largest value out of 1,2 is 2
    idx = 5;
    aa_array.prev(idx);
    $display("aa_array[%0d]=%0d", idx, aa_array[idx]);
  end
endmodule

Output

Output
xcelium> run
aa_array[1]=50
aa_array[2]=100
aa_array[2]=100
xmsim: *W,RNQUIE: Simulation is complete.

idx starts at its default value of 0, and each call to next() updates idx in place, so the second call continues from wherever the first one left off. That's why the two next() calls step 0→1 and then 1→2, walking the sorted keys one at a time.

This sorted-order guarantee is exactly why associative arrays are convenient for building a sorted report from sparse data — iterating with first()/next() visits every populated address, ID, or name in order, without you having to sort anything yourself.

Associative Array Methods Example


module tb;
    int      fruits_l0 [string];

    initial begin
      fruits_l0 = '{ "apple"  : 4,
                     "orange" : 10,
                     "plum"   : 9,
                     "guava"  : 1 };
  
  
      // size() : Print the number of items in the given associative array
      $display ("fruits_l0.size() = %0d", fruits_l0.size());
  
  
      // num() : Another function to print number of items in given array
      $display ("fruits_l0.num() = %0d", fruits_l0.num());
  
  
      // exists() : Check if a particular key exists in this dynamic array
      if (fruits_l0.exists ("orange"))
        $display ("Found %0d orange !", fruits_l0["orange"]);
  
      if (!fruits_l0.exists ("apricots"))
        $display ("Sorry, season for apricots is over ...");
  
      // Note: String indices are taken in alphabetical order
      // Correct order: apple, guava, orange, plum
      // first() : Get the first element in the array
      begin
      	string f;
        // This function returns true if it succeeded and first key is stored
        // in the provided string "f"
        if (fruits_l0.first (f))
          $display ("fruits_l0.first [%s] = %0d", f, fruits_l0[f]);
      end
  
      // last() : Get the last element in the array
      begin
        string f;
        if (fruits_l0.last (f))
          $display ("fruits_l0.last [%s] = %0d", f, fruits_l0[f]);
      end
  
      // prev() : Get the previous element in the array
      begin
        string f = "orange";
        if (fruits_l0.prev (f))
          $display ("fruits_l0.prev [%s] = %0d", f, fruits_l0[f]);
      end
  
      // next() : Get the next item in the array
      begin
        string f = "orange";
        if (fruits_l0.next (f))
          $display ("fruits_l0.next [%s] = %0d", f, fruits_l0[f]);
      end
    end
endmodule

Output

Output
ncsim> run
fruits_l0.size() = 4
fruits_l0.num() = 4
Found 10 orange !
Sorry, season for apricots is over ...
fruits_l0.first [apple] = 4
fruits_l0.last [plum] = 9
fruits_l0.prev [guava] = 1
fruits_l0.next [plum] = 9
ncsim: *W,RNQUIE: Simulation is complete.

With keys apple, guava, orange, plum in alphabetical order, prev("orange") lands on guava (the key right before it alphabetically) and next("orange") lands on plum (the key right after it) — each begin...end block resets f to "orange" independently, so the two calls don't interfere with each other.

Quick Check

Q: first() and last() both return an int. What does that return value mean?

Show Answer

Whether the call succeeded. It returns 0 if the array is empty (so there's no first/last element to find) and a non-zero value otherwise — which is why the example wraps each call in an if statement before using the result.

Dynamic Array of Associative Arrays

You can nest these unpacked array types inside one another. Here, each index of a dynamic array holds its own associative array.


module tb;
  // Create an associative array with key of type string and value of type int
  // for each index in a dynamic array
  int fruits [] [string];
  
  initial begin
    // Create a dynamic array with size 2
    fruits = new [2];
  
    // Initialize the associative array inside each dynamic array index
    fruits [0] = '{ "apple" : 1, "grape" : 2 };
    fruits [1] = '{ "melon" : 3, "cherry" : 4 };
  
    // Iterate through each index of dynamic array
    foreach (fruits[i])
      // Iterate through each key of the current index in dynamic array
      foreach (fruits[i][fruit])
        $display ("fruits[%0d][%s] = %0d", i, fruit, fruits[i][fruit]);
  
  end
endmodule

Output

Output
ncsim> run
fruits[0][apple] = 1
fruits[0][grape] = 2
fruits[1][cherry] = 4
fruits[1][melon] = 3
ncsim: *W,RNQUIE: Simulation is complete.

The outer foreach walks the dynamic array's numeric indices in order (0, then 1), while each inner foreach walks that entry's string keys alphabetically — which is why cherry prints before melon even though melon was assigned first.

Dynamic Array Within Each Index of an Associative Array

The nesting also works the other way around: an associative array whose values are dynamic arrays.


// Create a new typedef that represents a dynamic array
typedef int int_da [];

module tb;
  // Create an associative array where key is a string
  // and value is a dynamic array
  int_da fruits [string];

  initial begin
    // For key "apple", create a dynamic array that can hold 2 items
    fruits ["apple"] = new [2];
  
    // Initialize the dynamic array with some values
    fruits ["apple"] = '{ 4, 5};

    // Iterate through each key, where key represented by str1
    foreach (fruits[str1])
      // Iterate through each item inside the current dynamic array ie.fruits[str1]
      foreach (fruits[str1][i])
        $display ("fruits[%s][%0d] = %0d", str1, i, fruits[str1][i]);

  end
endmodule

Output

Output
ncsim> run
fruits[apple][0] = 4
fruits[apple][1] = 5
ncsim: *W,RNQUIE: Simulation is complete.

The typedef int int_da []; line is what makes this declaration possible — a dynamic array's dimension has to be given a name via typedef before it can be used as the value type of another array.

An associative array of dynamic arrays is a natural model for something like per-address memory content in a sparse memory model, where each populated address holds a variable-length burst of data.

Common Mistakes

Mistake #1: Assuming iteration follows insertion order

As shown throughout this article, foreach, first()/next(), and direct %p printing all visit associative array entries in sorted key order — numeric ascending for integer keys, alphabetical for string keys — never in the order the entries were assigned.

Mistake #2: Indexing a key that doesn't exist without checking first

Reading fruits_l0["kiwi"] when "kiwi" was never assigned returns the type's default value and issues a warning — but a plain read does not add a new entry to the array; only a write (or passing the key by reference) actually allocates one. Use exists() first if you need to distinguish "not present" from "present with a default value," and don't assume a read alone grows the array.

Mistake #3: Forgetting that first()/last()/next()/prev() return success, not the key

The key or index is written into the ref argument, not the return value. if (fruits_l0.first(f)) checks whether the call succeeded; f itself holds the actual first key afterward.

Mistake #4: Using an associative array where a queue would fit better

If you need strict insertion order preserved, or need to push/pop from either end, an associative array is the wrong tool even though it can technically store the same data — reach for a queue instead.

Practice Exercise

Challenge: Build a Register Name Lookup

Declare an associative array named reg_addr that maps register names (strings) to their addresses (int). Add entries for "CTRL" (0x10), "STATUS" (0x14), and "DATA" (0x18). Check whether "CTRL" exists before printing its address, then print every entry using first()/next().

Hint

Use string as the key type: int reg_addr [string];. Remember that first()/next() return 0 when there's nothing left to visit, which makes them a natural fit for a while loop.

Solution

module tb;
  int reg_addr [string];

  initial begin
    reg_addr["CTRL"]   = 'h10;
    reg_addr["STATUS"] = 'h14;
    reg_addr["DATA"]   = 'h18;

    if (reg_addr.exists("CTRL"))
      $display("CTRL is at 0x%0h", reg_addr["CTRL"]);

    begin
      string name;
      if (reg_addr.first(name)) begin
        $display("%s = 0x%0h", name, reg_addr[name]);
        while (reg_addr.next(name))
          $display("%s = 0x%0h", name, reg_addr[name]);
      end
    end
  end
endmodule

Summary

In this tutorial, you learned:

  • An associative array is recognized by a data type inside the square brackets, and allocates no storage until an index is actually used
  • size()/num() count entries, exists() checks for a key, and delete() removes one entry or the whole array
  • first(), last(), next(), and prev() traverse the array in sorted key order — numeric ascending for integer keys, alphabetical for string keys — not insertion order
  • first()/last()/next()/prev() return success/failure; the actual key comes back through the ref argument
  • Associative arrays can nest with dynamic arrays in either direction, useful for sparse, variable-length data
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5