In SystemVerilog, an enumeration type (or enum) defines a set of named values. These named values allow you to represent different states or options in a clear and manageable way, making your code more readable and maintainable.

Basics of SystemVerilog Enumeration

In the example below, the variable light is an enumerated type, which can store one of three values: RED, YELLOW, or GREEN.

enum {RED, YELLOW, GREEN} light_1;   // int type; RED = 0, YELLOW = 1, GREEN = 2
enum bit[1:0] {RED, YELLOW, GREEN} light_2;  // bit type; RED = 0, YELLOW = 1, GREEN = 2

By default, the first name in the list (e.g., RED) gets the value 0, and the following names are assigned incremental values like 1, 2, etc. The user can assign any integer value to any enumerated name.

Assigning Custom Values to Enumerated Types

You can also assign specific values to the enumeration names. If no value is assigned, SystemVerilog will automatically assign incremental values starting from the first name.

enum {RED=3, YELLOW, GREEN} light_3;  // RED = 3, YELLOW = 4, GREEN = 5
enum {RED = 4, YELLOW = 9, GREEN} light_4; // RED = 4, YELLOW = 9, GREEN = 10
enum {RED = 2, YELLOW, GREEN = 3} light_5; // Error: YELLOW and GREEN both have value 3

Restrictions in Naming Enumerated Types

In SystemVerilog, the names of enumeration types cannot start with a number. The following example would result in a compilation error:

enum {1WAY, 2TIMES, SIXPACK=6} e_formula; // Compilation error

However, if the names are modified to start with a letter, it will compile correctly:

enum {ONEWAY, TIMES2, SIXPACK=6} e_formula; // Correct way

Creating Custom Data Types Using Enumeration

In SystemVerilog, you can define custom data types using the typedef keyword. These types can then be used to declare variables with a limited set of possible values.

module tb;
	// Create a new data type with two valid values: TRUE and FALSE
	typedef enum {TRUE, FALSE} e_true_false;

	initial begin
		// Declare a variable of type e_true_false
		e_true_false answer;

		// Assign TRUE to the enumerated variable
		answer = TRUE;

		// Display the value of the variable
		$display("answer = %s", answer.name);
	end
endmodule

Simplifying Code with Enumerations

Without enumerations, you might use a bit type and manually track what each value represents. For example:

bit [1:0] light;

light = 2'b00;  // 00 represents RED
if (light == 2'b00)
	// Do something

However, this can become unclear as the code grows. Using enumerations makes it much clearer:

typedef enum {RED, YELLOW, GREEN} e_light;
e_light light;

light = RED;  // Initialize light to RED

if (light == RED)
	// Do something

Working with Arrays of Named Constants

You can create arrays of named constants within an enumeration. Below are different styles you can use in your code:

  1. Basic Array Style
typedef enum {GREEN, YELLOW, RED, BLUE} color_set_1;  // GREEN = 0, YELLOW = 1, RED = 2, BLUE = 3
  1. Assigning Specific Values
typedef enum {MAGENTA = 2, VIOLET = 7, PURPLE, PINK} color_set_2;  // MAGENTA = 2, VIOLET = 7, PURPLE = 8, PINK = 9
  1. Generating Named Constants with Arrays
typedef enum {BLACK[4]} color_set_3;  // BLACK0 = 0, BLACK1 = 1, BLACK2 = 2, BLACK3 = 3
  1. Using Ranges in Arrays
typedef enum {YELLOW[3:5]} color_set_5;  // YELLOW3 = 0, YELLOW4 = 1, YELLOW5 = 2
  1. Using Starting Values in Arrays
typedef enum {WHITE[3:5] = 4} color_set_6;  // WHITE3 = 4, WHITE4 = 5, WHITE5 = 6

Example: Using Arrays of Enumerated Values

module tb;
  typedef enum {GREEN, YELLOW, RED, BLUE} color_set_1;
  typedef enum {MAGENTA = 2, VIOLET = 7, PURPLE, PINK} color_set_2;
  typedef enum {BLACK[4]} color_set_3;
  typedef enum {RED[3] = 5} color_set_4;
  typedef enum {YELLOW[3:5]} color_set_5;
  typedef enum {WHITE[3:5] = 4} color_set_6;

  initial begin
    color_set_1 color1;
    color_set_2 color2;
    color_set_3 color3;
    color_set_4 color4;
    color_set_5 color5;
    color_set_6 color6;

    color1 = YELLOW; $display ("color1 = %0d, name = %s", color1, color1.name());
    color2 = PURPLE; $display ("color2 = %0d, name = %s", color2, color2.name());
    color3 = BLACK3; $display ("color3 = %0d, name = %s", color3, color3.name());
    color4 = RED1; $display ("color4 = %0d, name = %s", color4, color4.name());
    color5 = YELLOW3; $display ("color5 = %0d, name = %s", color5, color5.name());
    color6 = WHITE4; $display ("color6 = %0d, name = %s", color6, color6.name());
  end
endmodule

SystemVerilog Enum Functions

SystemVerilog offers several useful methods for working with enumerations:

  • first(): Returns the first member of the enum.
  • last(): Returns the last member of the enum.
  • next(): Returns the next member of the enum.
  • prev(): Returns the previous member of the enum.
  • num(): Returns the total number of elements in the enum.
  • name(): Returns the string name of the current enum value.

Here’s an example demonstrating these functions:

typedef enum {GREEN, YELLOW, RED, BLUE} colors;

module tb;
  initial begin
    colors color;

    color = YELLOW;

    $display ("color.first() = %0d", color.first());  // GREEN = 0
    $display ("color.last()  = %0d", color.last());   // BLUE = 3
    $display ("color.next()  = %0d", color.next());   // RED = 2
    $display ("color.prev()  = %0d", color.prev());   // GREEN = 0
    $display ("color.num()   = %0d", color.num());    // 4
    $display ("color.name()  = %s", color.name());     // YELLOW
  end
endmodule

Conclusion

Using SystemVerilog Enumerations makes your code more readable, easier to maintain, and less error-prone. It allows you to represent a set of named values clearly, and you can even customize the value assignments. By taking advantage of enumeration methods like first(), last(), and next(), you can easily iterate over these values in your simulation.

By using the practices described above, you can write cleaner and more understandable SystemVerilog code for any project involving enumerated values.

Scroll to Top