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:
- Basic Array Style
typedef enum {GREEN, YELLOW, RED, BLUE} color_set_1; // GREEN = 0, YELLOW = 1, RED = 2, BLUE = 3
- Assigning Specific Values
typedef enum {MAGENTA = 2, VIOLET = 7, PURPLE, PINK} color_set_2; // MAGENTA = 2, VIOLET = 7, PURPLE = 8, PINK = 9
- Generating Named Constants with Arrays
typedef enum {BLACK[4]} color_set_3; // BLACK0 = 0, BLACK1 = 1, BLACK2 = 2, BLACK3 = 3
- Using Ranges in Arrays
typedef enum {YELLOW[3:5]} color_set_5; // YELLOW3 = 0, YELLOW4 = 1, YELLOW5 = 2
- 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.