Casting

A data type can be changed by using a cast ( ) operation. The expression to be cast must be enclosed in parentheses or within concatenation or replication braces and is self-determined.

int’(2.0 * 3.0)
shortint’{8’hFA,8’hCE}

A positive decimal number as a data type means a number of bits to change the size.

17’(x - 2)

The signedness can also be changed.

signed’(x)

A user-defined type can be used.

mytype’(x)

The expression inside the cast must be an integral value when changing the size or sign. When changing the size, the sign passes through unchanged. When changing the sign, the size passes through unchanged. When casting to a predefined type, the prefix of the cast must be the predefined type keyword. When casting to a user-defined type, the prefix of the cast must be the user-defined type identifier.

When a shortreal is converted to an int or to 32 bits, its value is rounded, as in Verilog. Therefore, the conversion can lose information. To convert a shortreal to its underlying bit representation without a loss of information, use $shortrealtobits. To convert from the bit representation of a shortreal value into a shortreal, use $bitstoshortreal.

Structures can be converted to bits preserving the bit pattern, which means they can be converted back to the same value without any loss of information. When unpacked data is converted to the packed representation, the order of the data in the packed representation is such that the first field in the structure occupies the most significant bits. The effect is the same as a concatenation of the data items (struct fields or array elements) in order. The type of the elements in an unpacked structure or array must be valid for a packed representation in order to be cast to any other type, whether packed or unpacked.

The following example demonstrates how the $bits attribute is used to obtain the size of a structure in bits which facilitates the conversion of the structure into a packed array:

typedef struct {
bit isfloat;
union { int i; shortreal f; } n;
// anonymous type
} tagged_st; // named structure
typedef bit [$bits(tagged_st) - 1 : 0] tagbits; // tagged_st defined above
tagged_st a [7:0]; // unpacked array of structures
tagbits t = tagbits’(a[3]); // convert structure to array of bits
a[4] = tagged_st’(t); // convert array of bits back to structure

Note that the bit data type loses X values. If these are to be preserved, the logic type should be used instead.

The size of a union in bits is the size of its largest member. The size of a logic in bits is 1.

For compatibility, the Verilog functions $itor, $rtoi, $bitstoreal, $realtobits, $signed, $unsigned can also be used.

$cast dynamic casting

SystemVerilog provides the $cast system task to assign values to variables that might not ordinarily be valid because of differing data type. $cast can be called as either a task or a function.

The syntax for $cast is:

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

The dest_var is the variable to which the assignment is made.
The source_exp is the expression that is to be assigned to the destination variable.

Use of $cast as either a task or a function determines how invalid assignments are handled.

When called as a task, $cast attempts to assign the source expression to the destination variable. If the assignment is invalid, a runtime error occurs and the destination variable is left unchanged.

When called as a function, $cast attempts to assign the source expression to the destination variable, and returns 1 if the cast is legal. If the cast fails, the function does not make the assignment and returns 0. When called as a function, no runtime error occurs, and the destination variable is left unchanged.

It’s important to note that $cast performs a run-time check. No type checking is done by the compiler, except to check that the destination variable and source expression are singulars.

Example:

typedef enum { red, green, blue, yellow, white, black } Colors;
Colors col;
$cast( col, 2 + 3 );

This example assigns the expression (5 => black) to the enumerated type. Without $cast, or the static compile-time cast described below, this type of assignment is illegal.

The following example shows how to use the $cast to check if an assignment will succeed:

if ( ! $cast( col, 2 + 8 ) ) // 10: invalid cast

$display( "Error in cast" );

Alternatively, the preceding examples can be cast using a static SystemVerilog cast operation:
Example:

col = Colors’(2 + 3);

However, this is a compile-time cast, i.e, a coercion that always succeeds at run-time, and does not provide for error checking or warn if the expression lies outside the enumeration values.

Allowing both types of casts gives full control to the user. If users know that it is safe to assign certain expressions to an enumerated variable, the faster static compile-time cast can be used. If users need to check if the expression lies within the enumeration values, it is not necessary to write a lengthy switch statement manually, the compiler automatically provides that functionality via the $cast function. By allowing both types of casts, users can control the time/safety trade-offs.

Bit-stream casting

Type casting can also be applied to unpacked arrays and structs. It is thus possible to convert freely between bit-stream types using explicit casts. Types that can be packed into a stream of bits are called bit-stream types.
A bit-stream type is a type consisting of the following:

  • Any integral, packed, or string type
  • Unpacked arrays, structures, or classes of the above types
  • Dynamically-sized arrays (dynamic, associative, or queues) of any of the above types

This definition is recursive, for example, a structure containing a queue of int is a bit-stream type.
Assuming A is of bit-stream type source_t and B is of bit-stream type dest_t, it is legal to convert A into B by an explicit cast:

B = dest_t’(A);

The conversion from A of type source_t to B of type dest_t proceeds in two steps:

1) Conversion from source_t to a generic packed value containing the same number of bits as source_t. If source_t contains any 4-state data, the entire packed value is 4-state; otherwise, it is 2-state.

2) Conversion from the generic packed value to dest_t. If the generic packed value is a 4-state type and parts of dest_t designate 2-state types then those parts in dest_t are assigned as if cast to a 2-state.

If both source_t and dest_t are fixed-sized unpacked types of different sizes then a cast generates a compile-time error. If source_t or dest_t contain dynamically-sized types then a difference in their sizes will generate an error either at compile time or run time, as soon as it is possible to determine the size mismatch.

For example:

// Illegal conversion from 24-bit struct to int (32 bits) – compile time error
struct {bit[7:0] a; shortint b;} a;
int b = int’(a);

// Illegal conversion from 20-bit struct to int (32 bits) – run time error
struct {bit a[$]; shortint b;} a = {{1,2,3,4}, 67};
int b = int’(a);

// Illegal conversion from int (32 bits) to struct dest_t (25 or 33 bits),
// compile time error
typedef struct {byte a[$]; bit b;} dest_t;
int a;
dest_t b = dest_t’(a);

<< Previous | Next >>