Feed on
Posts
Comments

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 

3 Responses to “Casting Strings to Enums in SystemVerilog”

  1. Avidan Efody Says:

    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

  2. JL Gray Says:

    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

  3. JL Gray Says:

    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

Work For Verilab