Casting into an enum

Hi, I’ve got a situation where I need to convert a bit into an enum. I’m looking at a code example from a book.

In class command_monitor, there is this line that tries to take op (bit[2:0]) and pass it’s value to an enumerated type (cmd.op):

cmd.op = op2enum(op);

VCS simulator has no idea what op2enum() is, so I’ve tried other things:

cmd.op = operation_t’(op);
$cast(cmd.op, op);

So far nothing works, those casting attempts get me a message:

Error-[IATC] Illegal argument to $cast
/apps/vcsmx/etc/uvm-1.2/src/tlm1/uvm_analysis_port.svh, 74
Illegal or unsupported arguments to $cast.
Source info: $cast(obj, t)

Does anybody know to get the value of op into the enumerated type? Thanks!


package tinyalu_pkg;
   import uvm_pkg::*;
`include "uvm_macros.svh"
   
      typedef enum bit[2:0] {no_op  = 3'b000,
                          add_op = 3'b001, 
                          and_op = 3'b010,
                          xor_op = 3'b011,
                          mul_op = 3'b100,
                          rst_op = 3'b111} operation_t;
   

   typedef struct {
      byte unsigned        A;
      byte unsigned        B;
      operation_t op;
   } command_s;

endpackage : tinyalu_pkg
class command_monitor extends uvm_component;
  `uvm_component_utils(command_monitor);
  
**uvm_analysis_port #(command_s) ap;**
  
  virtual tinyalu_bfm bfm;
  
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
  
  function void build_phase(uvm_phase phase);
    if(!uvm_config_db #(virtual tinyalu_bfm)::get(null, "*","bfm", bfm)) $fatal("Failed to get BFM");
    
    bfm.command_monitor_h = this;
    
    ap = new("ap", this);
  endfunction : build_phase
  
  function void write_to_monitor(byte A, byte B, bit[2:0] op);
    command_s cmd;
    cmd.A = A;
    cmd.B = B;
    cmd.op = op2enum(op); <- CASTING HAPPENS HERE
    
    `uvm_info("blah", $psprintf("COMMAND MONITOR: A:0x%2h B:0x%2h op: %s", A, B, cmd.op.name()), UVM_NONE);
    
    ap.write(cmd);
  endfunction : write_to_monitor
endclass : command_monitor

In reply to silverace99:

Seems like a type mismatch issue. Are you sure that the port types (initiator/target) are correct everywhere? What error does “cmd.op = operation_t’(op);” give?

In reply to silverace99:

Hi,

It appears that part of the example code is missing. The code on the github repository for the examples looks like this:


    $display("COMMAND MONITOR: A:0x%2h B:0x%2h op: %s", A, B, cmd.op.name());
    ap.write(cmd);
  endfunction : write_to_monitor

/// The function below is missing in your example above

   function operation_t op2enum(bit[2:0] op);
      case(op)
        3'b000 : return no_op;
        3'b001 : return add_op;
        3'b010 : return and_op;
        3'b011 : return xor_op;
        3'b100 : return mul_op;
        3'b111 : return rst_op;
        default : $fatal($sformatf("Illegal operation on op bus: %3b",op));
      endcase // case (op)
   endfunction : op2enum

   function new (string name, uvm_component parent);
      super.new(name,parent);
   endfunction

endclass : command_monitor

Best,
Ray

In reply to raysalemi:

Thanks Ray. I assume by that code that it means you can’t directly cast or assign the 3-bit op to enum even though it is also a 3-bit variable?

Also, I recompiled and am still getting this niggling uvm_analysis_port $cast error, so there is evidently something else going on:

Error-[IATC] Illegal argument to $cast
/apps/vcsmx/etc/uvm-1.2/src/tlm1/uvm_analysis_port.svh, 74
  Illegal or unsupported arguments to $cast.
  Source info: $cast(__obj__, t)

I googled uvm_analysis_port.svh and if I’m right the error line references the analysis port write() function:

8   // Method: write
   69   // Send specified value to all connected interface
   70   function void write (input T t);
   71     uvm_tlm_if_base # (T, T) tif;
   72     for (int i = 0; i < this.size(); i++) begin
   73       tif = this.get_if (i);
   74       if ( tif == null )
   75         uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE);
   76       tif.write (t);
   77     end 
   78   endfunction

However I can’t tell where the $cast error comes into play.

For reference I’m doing all this on EDA Playground so the code is all visible: (2) - EDA Playground

In reply to silverace99:

One can cast numbers to enums as I do here:


module cast;
	typedef bit[2:0] three_bits_t;
	typedef enum three_bits_t {
		ZERO = 0,
		ONE = 1,
		TWO = 2
	} four_e;


	four_e fe;

	initial
		for (three_bits_t ii = 0; ii <= 3; ii++) begin
			$cast(fe, ii);
			$display (fe.name());
		end
endmodule

I’ve never once looked at the UVM source code to debug a problem, so I’d assume that code is working properly.

In reply to raysalemi:

In reply to silverace99:
One can cast numbers to enums as I do here:


module cast;
typedef bit[2:0] three_bits_t;
typedef enum three_bits_t {
ZERO = 0,
ONE = 1,
TWO = 2
} four_e;
four_e fe;
initial
for (three_bits_t ii = 0; ii <= 3; ii++) begin
$cast(fe, ii);
$display (fe.name());
end
endmodule

I’ve never once looked at the UVM source code to debug a problem, so I’d assume that code is working properly.

Oh for sure. I was just hoping that the uvm_analysis_port source code would be able to point me to the source the problem. Unfortunately the error is cryptic…I don’t see anything in write() that could cause the $cast error :/

Also thanks for the example code.

I would assume the error appears because VCS doesn’t allow $cast(…) to anything other than class objects. I don’t mean any casts in your code, I mean casts in the UVM code. You’re defining an analysis port parameterized with a struct. Try changing to:


class command_s;
  byte unsigned A;
  byte unsigned B;
  operation_t op;
endclass

and using new(…) where required. The error might go away. Moreover, it might be that UVM requires classes to extend from uvm_object. If that’s the case, just add extends uvm_object to the class declaration.

In reply to Tudor Timi:

That would imply that VCS couldn’t run the module “cast” that I wrote above. Is that true?

In reply to raysalemi:

In your code you cast to an enum variable. It might be the case that I am partly wrong and that they allow casting to class variables and enums. This situation is explicitly listed in the 2012 LRM in section 6.24.2 $cast dynamic casting, on page 99.

In reply to Tudor Timi:

Actually, upon reading a bit further, notice that the syntax for $cast(…) is:


function int $cast( singular dest_var, singular source_exp );

Section 6.4 Singular and aggregate types states that unpacked structs (that the OP was using) aren’t singular types, so the compile error, though a bit lacking on the details, is correct.

In reply to Tudor Timi:

I would assume the error appears because VCS doesn’t allow $cast(…) to anything other than class objects. I don’t mean any casts in your code, I mean casts in the UVM code. You’re defining an analysis port parameterized with a struct. Try changing to:


class command_s;
byte unsigned A;
byte unsigned B;
operation_t op;
endclass

and using new(…) where required. The error might go away. Moreover, it might be that UVM requires classes to extend from uvm_object. If that’s the case, just add extends uvm_object to the class declaration.

This did indeed solve the problem, no extension needed.

Thanks guys for your help!