An enumerated type defines a set of named values. In the following example, light_* is an enumerated variable that can store one of the three possible values (0, 1, 2). By default, the first name in the enumerated list gets the value 0 and the following names get incremental values like 1 and 2.
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
The user can assign any integer value for any of the enumerated names. If any name does not have an assigned value, then it automatically takes the incremented value of the previous 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 (automatically assigned)
enum {RED = 2, YELLOW, GREEN = 3} light_5; // Error : YELLOW and GREEN are both assigned 3
enum bit[0:0] {RED, YELLOW, GREEN} light_6; // Error: minimum 2 bits are required
Note that an enumeration name cannot start with a number !
enum {1WAY, 2TIMES, SIXPACK=6} e_formula; // Compilation error on 1WAY, 2TIMES
enum {ONEWAY, TIMES2, SIXPACK=6} e_formula; // Correct way is to keep the first character non-numeric
How to define a new enumerated data type ?
A custom data-type can be created so that the same data-type may be used to declare other variables.
module tb;
// "e_true_false" is 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" that can store TRUE or FALSE
e_true_false answer;
// Assign TRUE/FALSE to the enumerated variable
answer = TRUE;
// Display string value of the variable
$display ("answer = %s", answer.name);
end
endmodule
ncsim> run
answer = TRUE
ncsim: *W,RNQUIE: Simulation is complete.
Why do we need enumeration ?
To make the code more simple and readable.
Consider the following example without enumeration.
bit [1:0] light;
light = 2'b00; // Assume 00 stands for RED
// After many lines of code we have to correlate what
// 00 stands for - is it RED, YELLOW or GREEN ?
if (light == 2'b00)
// Do something
The following code is more readable because of the enumerated names RED, YELLOW and GREEN.
typedef enum {RED, YELLOW, GREEN} e_light;
e_light light;
light = RED; // Initialize light to RED
// Even after many lines of code it's easier to understand
if (light == RED)
// Do something
Enumerated-type ranges
name | The next number will be associated with name |
name = C | Associates the constant C to name |
name[N] | Generates N named constants : name0, name1, ..., nameN-1 |
name[N] = C | First named constant gets value C and subsequent ones are associated to consecutive values |
name[N:M] | First named constant will be nameN and last named constant nameM, where N and M are integers |
name[N:M] = C | First named constant, nameN will get C and subsequent ones are associated to consecutive values until nameM |
Example
In the following example, we'll try out each of the different styles shown in the table above.
module tb;
// name : The next number will be associated with name starting from 0
// GREEN = 0, YELLOW = 1, RED = 2, BLUE = 3
typedef enum {GREEN, YELLOW, RED, BLUE} color_set_1;
// name = C : Associates the constant C to name
// MAGENTA = 2, VIOLET = 7, PURPLE = 8, PINK = 9
typedef enum {MAGENTA=2, VIOLET=7, PURPLE, PINK} color_set_2;
// name[N] : Generates N named constants : name0, name1, ..., nameN-1
// BLACK0 = 0, BLACK1 = 1, BLACK2 = 2, BLACK3 = 3
typedef enum {BLACK[4]} color_set_3;
// name[N] = C : First named constant gets value C and subsequent ones
// are associated to consecutive values
// RED0 = 5, RED1 = 6, RED2 = 7
typedef enum {RED[3] = 5} color_set_4;
// name[N:M] : First named constant will be nameN and last named
// constant nameM, where N and M are integers
// YELLOW3 = 0, YELLOW4 = 1, YELLOW5 = 2
typedef enum {YELLOW[3:5]} color_set_5;
// name[N:M] = C : First named constant, nameN will get C and
// subsequent ones are associated to consecutive values until nameM
// WHITE3 = 4, WHITE4 = 5, WHITE5 = 6
typedef enum {WHITE[3:5] = 4} color_set_6;
initial begin
// Create new variables for each enumeration style
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
ncsim> run color1 = 1, name = YELLOW color2 = 8, name = PURPLE color3 = 3, name = BLACK3 color4 = 6, name = RED1 color5 = 0, name = YELLOW3 color6 = 5, name = WHITE4 ncsim: *W,RNQUIE: Simulation is complete.
Enumerated-Type Methods
SystemVerilog includes a set of specialized methods to enable iterating over the values of enumerated types.
first() | function enum first(); | Returns the value of the first member of the enumeration |
last() | function enum last(); | Returns the value of the last member of the enumeration |
next() | function enum next (int unsigned N = 1); | Returns the Nth next enumeration value starting from the current value of the given variable |
prev() | function enum prev (int unsigned N = 1); | Returns the Nth previous enumeration value starting from the current value of the given variable |
num() | function int num(); | Returns the number of elements in the given enumeration |
name() | function string name(); | Returns the string representation of the given enumeration value |
Enumeration Methods Example
// GREEN = 0, YELLOW = 1, RED = 2, BLUE = 3
typedef enum {GREEN, YELLOW, RED, BLUE} colors;
module tb;
initial begin
colors color;
// Assign current value of color to YELLOW
color = YELLOW;
$display ("color.first() = %0d", color.first()); // First value is GREEN = 0
$display ("color.last() = %0d", color.last()); // Last value is BLUE = 3
$display ("color.next() = %0d", color.next()); // Next value is RED = 2
$display ("color.prev() = %0d", color.prev()); // Previous value is GREEN = 0
$display ("color.num() = %0d", color.num()); // Total number of enum = 4
$display ("color.name() = %s" , color.name()); // Name of the current enum
end
endmodule
ncsim> run color.first() = 0 color.last() = 3 color.next() = 2 color.prev() = 0 color.num() = 4 color.name() = YELLOW ncsim: *W,RNQUIE: Simulation is complete.
Type Checking
Enumerated types are strongly typed and hence a variable of type enum
cannot be assigned an integer value that lie outside the enumeration set unless an explicit cast is used.
typedef enum bit [1:0] {RED, YELLOW, GREEN} e_light;
module tb;
e_light light;
initial begin
light = GREEN;
$display ("light = %s", light.name());
// Invalid because of strict typing rules
light = 0;
$display ("light = %s", light.name());
// OK when explicitly cast
light = e_light'(1);
$display ("light = %s", light.name());
// OK. light is auto-cast to integer
if (light == RED | light == 2)
$display ("light is now %s", light.name());
end
endmodule
Some simulators provide a compilation error for going against SystemVerilog strict typing rules, like Aldec Riviera Pr which may take a commandline argument to avoid these errors.
ERROR VCP2694 "Assignment to enum variable from expression of different type." "testbench.sv" 11 1
FAILURE "Compile failure 1 Errors 0 Warnings Analysis time: 0[s]."
Some other simulators simply provide a warning and allow simulation to run, like Cadence ncsim.
light = 0;
|
ncvlog: *W,ENUMERR (testbench.sv,11|11): This assignment is a violation of SystemVerilog strong typing rules for enumeration datatypes.
Loading snapshot worklib.tb:sv .................... Done
ncsim> run
light = GREEN
light = RED
light = YELLOW
ncsim: *W,RNQUIE: Simulation is complete.