Casting Strings to Enums in SystemVerilog
Every once and awhile, I want to convert a string to an enumeration in SystemVerilog. Casting from strings to enums is not supported in SystemVerilog, but luckily, it is possible to implement a function to do the appropriate conversion using built in methods designed for iterating over the enum values:
/////////// // enum.sv /////////// class cmd; // My enumerated type typedef enum {UNKNOWN, ADD, SUB, MULT} cmd_e; // Store the string -> enumerated type mappings. static cmd_e enum_map[string]; // Configure the mapping from string to enum the first // time this data structure is created. virtual function void config_enum_map(); cmd_e e; string str; e = e.first(); str = e.name(); enum_map[str] = e; // Note - we've already processed the first element above. This loop // starts at the *second* element. for (int i = 1; i < e.num(); i++) begin e = e.next(); str = e.name(); enum_map[str] = e; end foreach (enum_map[m]) begin $display("enum_map[%5s] = %5s (%1d)", m, enum_map[m].name(), enum_map[m]); end endfunction: config_enum_map function cmd_e get_enum(string s); get_enum = enum_map[s]; endfunction function new(); if (enum_map.num() == 0) begin config_enum_map(); end endfunction: new endclass: cmd program test; initial begin cmd c = new; cmd::cmd_e ce; string s = "ADD"; ce = c.get_enum(s); $display("Enum = %s (%1d) for string %s", ce.name, ce, s); end endprogram
In VCS, run the above code using ‘vcsi -sverilog -ntb_opts dtm -R enum.sv’ to see the following output:
Compiler version VCSi Y-2006.06-SP1; Runtime version VCSi Y-2006.06-SP1; Oct 21 14:43 2007 enum_map[ADD] = ADD (1) enum_map[MULT] = MULT (3) enum_map[SUB] = SUB (2) enum_map[UNKNOWN] = UNKNOWN (0) Enum = ADD (1) for string ADD V C S S i m u l a t i o n R e p o r t
October 22nd, 2007 at 3:22 am
Hi JL,
Your entry touched a raw SV nerve :-). I guess your intention was to demonstrate the use of hashes and to provide everyone with a useful function, but on the way you also demonstrated one of SV’s enums main shortcomings - although all enums have a similar behavior and share a basic set of functions, there is no such thing as “enum base class”, that is common to all of them. So, in the case above, although your function might be useful for every enum, you would have to rewrite it for each different enum type…
I have come across this problem in the past as well…One way of working around it, which is not perfect, is to define a class that wrapps around enums. Here’s your example rewritten (without the hash, just using brute force method):
virtual class enum_wrapper;
// functions defined by the standard go here.
// these are implemented by the specification
virtual function int first();endfunction
virtual function int last();endfunction
virtual function int next(int current);endfunction
virtual function int prev(int current);endfunction
virtual function int num();endfunction
virtual function string name(int value);endfunction
// more user defined functions go here
// here’s a brute force method for searching…
// could be made more efficient by adding the hash…
function int string_to_enum(string enum_name);
for (int i=first(); i!=last(); i=next(i))
if (enum_name == name(i)) return i;
endfunction // int
endclass // enum_wrapper
// just a garbage enum for default
typedef enum {false, true} bool;
class specific_enum#(type enum_type = bool) extends enum_wrapper;
enum_type m_enum;
function int first();
first = m_enum.first();
endfunction; // int
function int last();
last = m_enum.last();
endfunction; // int
function int next(int current);
m_enum = enum_type’(current);
next = m_enum.next();
endfunction; // int
function int prev(int current);
m_enum = enum_type’(current);
prev = m_enum.prev();
endfunction; // int
function int num();
num = m_enum.num();
endfunction; // int
function string name(int value);
m_enum = enum_type’(value);
name = m_enum.name();
endfunction; // int
endclass // specific_enum
typedef enum {UNKNOWN, ADD, SUB, MULT} cmd_e;
module test;
initial begin
string cmd_name = “ADD”;
specific_enum#(cmd_e) temp = new();
$display(”The int value for string %s is %d”, cmd_name, temp.string_to_enum(cmd_name));
end
endmodule
The disadvantage is that you have to define a class instance for the enum wrapper. The advantage is you could have a full library of such enum utilities written only once…
Avidan
October 22nd, 2007 at 8:52 am
Avidan,
You’re right, there are some significant issues with enums in SV. However, though I haven’t tried writing the code, I believe you could simplify things slightly in your example above by using parameterizable classes.
JL
November 28th, 2007 at 1:25 pm
Avidan,
I just looked again at your example… it actually *requires* parameterizable classes (I missed that the first time I read through the code). For that reason, the code won’t work with VCS, though it should work just fine with Modelsim.
JL