Runtime checks with the $cast() method

Introduction

Verilog was always known for its lack of type checking, treating everything as just bits strung together into vectors and arrays. “Compile it and find the problems at run-time.” SystemVerilog introduced new types that require more discipline. If you are new to SystemVerilog, the $cast() method can be mysterious as it checks values at runtime, not types at compile time.

This is the third post in a series on OOP and UVM. Here is the previous post on Verification Class Categories.

Enumerated Type

Traffic light: red, yellow, green
Traffic light: green, yellow, red

An enumerated variable creates a new type that has a limited set of values, specified by named constants. That sounds boring – how can it help you? If you are modeling a traffic light, you could create an enumerated type for the three states. Make it one-hot so you can connect this type to a port that drives the three bulbs.

typedef enum bit[2:0] {GREEN=3’b001, YELLOW=3’b010, RED=3b100} traffic_t;

Now your code has the abstract names GREEN, YELLOW, and RED instead of the magic numbers 3’b001, 3’b010, 3’b100. Enumerated variables are strongly typed which means you can only assign an enum variable from a value of the same type. On the right side of the assignments of light and next_light are constants or variables of the traffic_t type. Here is a simple state machine with assignments.

traffic_t light, next_light;

always_ff @(posedge clk or negedge reset_n) begin
  if (! reset_n) 
    light = RED;                    // Reset to RED
  else begin
    case (light)                    // Specify the order of the light values
      RED:     next_light = GREEN;
      YELLOW:  next_light = RED;
      GREEN:   next_light = YELLOW;
      default: $error("Illegal light value %b", light);
    endcase
    light <= next_light;
  end
end

Injecting Values

What if you have a 3-bit vector, v3, that you need to assign to the traffic_t enum called light? SystemVerilog won’t let you directly assign it as that could put light in an unknown state such as 0, or 3’b111. This type checking is done at compile time, so the following code won’t compile. Try it on your favorite simulator.

traffic_t light;
bit [2:0] v3 = 3'b010; // One-hot value, not traffic_t type
initial
  light = v3;          // Gets compile error

You need a way to check that the value of v3 is one of the legal values for light, ‘b001 for GREEN, ‘b010 for YELLOW, and ‘b100 for RED. The SystemVerilog $cast() method performs this check for you. Here you are calling it like a task.

initial
  $cast(light, v3); // Check value of v3 at run time: compatible with traffic_t?

The order of the arguments is the same as the assignment: destination = source;

The problem with this call is that if v3 has a bad value, the simulator prints an cryptic error. Instead, call $cast() like a function and check its return value so you can print your own message.

if (! $cast(light, v3))
  $error("v3 value %b out of bounds for traffic_t", v3);

Remember, $cast() checks the value on the right side, not the variable’s type. This can only be done at runtime. The following code has two identical calls to $cast(), yet they produce different results.

v3 = YELLOW;      // Legal as enum values are a subset of bit[2:0]: 'b000-'b111
$cast(light, v3); // Success, light = YELLOW
v3++;             // v3 now is 'b011
$cast(light, v3); // Run-time error:3’b011 is not a legal value

Venn Time

Look at a Venn diagram of the possible values. The variable v3 is 3 bits so it can hold ‘b000 – ‘b111, all the values shown below. The light variable can only hold ‘b001, ‘b010, or ‘b100, which are the inner box. So v3 holds a wider range of values than light, and $cast() makes sure that the current value of v3 is inside the smaller set.

Venn diagram of v3 and light values

Summary

When you need to assign between two variables of different types, and the source might have a value incompatible with the destination, use $cast() to check the value. The check happens at runtime. If you want to give a helpful message, call $cast() as a function.

Wait – this series is supposed to be on OOP and this post has no class. What gives? Next week I’ll show the next concept, and all will be revealed. Thank you for your patience!

Leave a Reply