Type casting in SystemVerilog
SystemVerilog adds a cast operator ( ' , forward tick) that supports the ability to cast a value to a different type. The expression to be cast should be enclosed in parentheses or within concatenation or replication braces and is self-determined. The syntax is
<casting_type> '(<expression>)
shortint'(2 * 4) // cast result of 2 *4 to shortint
In addition to this, SV also offers support to cast a unsigned value to signed (or vice versa) and to cast a vector to a different size.
<size>'(<expression>)
logic [7:0] x;
x = 8'(5) // cast literal value 5 to 8-bits wide
<sign>'(<expression>)
y = signed'(x)
Static casting does not include run-time checking i.e. if the cast results in a illegal value during run time, SV does not report any error. For more robust checking, SV offers a dynamic cast function $cast that performs dynamic run time checking. The syntax of $cast is
$cast (dest_var, source_exp) where
dest_var is the variable to which assignment is made and
source_exp is expression that is assigned
-
int x, y;
-
always @(posedge clk)
-
$cast(y, 2.5 * x);
$cast can also be defined as a task and reports a error if the cast value is illegal during runtime. An example would be assigning a cast value to an enumerated type that is not in the set. When called as a function, $cast returns a '1' if the cast was successful or a '0' if it fails. When called as a function, $cast does not report any runtime error and leaves the destination variable unchanged.
-
typedef enum { ADD, MUL, DIVI, SUB, MOD } Opcode;
-
Opcode operat_e;
-
$cast( operat_e, 2 + 1 ); // Dynamic cast : assigns 3 => DIVI to operat_e
-
operat_e = Opcode'(2+1) // Static cast
Type casting can also applied to unpacked arrays and structs known as bit-stream casting. We will visit this when we cover arrays and structs.
Sphere: Related Content
Inertial and Transport Delays & the Event Queue in Verilog
Simulation cycle consists of two phases - a signal update phase where the simulation time is moved to the earliest scheduled transaction and values in all transactions scheduled for this time are applied to their corresponding signals and a process evaluation phase where signal assignments trigger events and all processes responding to these events are executed.
Scheduling and assigning signal values largely depends on the delay mechanism used. Transport Delay models are ideal and any change in the input is propagated to the output, no matter how small the duration of the change. Any pending transactions on a driver that are scheduled for a time late than or equal to the new transaction are deleted.
Transport Delay Illustration
Inertial Delay models depict real hardware and any change in input value is propagated to the output only if the change is stable for a duration greater than the propagation delay of the model. An inertially delayed signal assignment involves looking at pending transactions when adding a new transaction.
All transactions scheduled for a time equal to or later than the current transaction (t1) are deleted as in transport delay model. If the pulse rejection time is tr, any pending transactions between t1-tr and tr driving the current transaction value are retained and all other transactions are removed.
Inertial Delay Illustration
Verilog Stratified Event Queue (from Verilog LRM)
The Verilog event queue is logically segmented into five different regions. Events are added to any of the five regions but are only removed from the active region.
- Events that occur at the current simulation time and can be processed in any order. These are the active events. Blocking assignments, evaluation of RHS of nonblocking assignments, conitnuous assignments, $display commads are executed in this queue.
- Events that occur at the current simulation time, but that shall be processed after all the active events are processed. These are the inactive events. Blocking assignments with #0 delays fall in this category, they are not recommended as they add unnecessary events in the queue and make simulations run slower. For more details, please refer to Cliff Cummings paper on NonBlocking Assignments.
- Events that have been evaluated during some previous simulation time, but that shall be assigned at this simulation time after all the active and inactive events are processed. These are the non blocking assign LHS update events.
- Events that shall be processed after all the active, inactive, and non blocking assign update events are processed. These are the monitor events. $monitor and $strobe are executed in this queue.
- Events that occur at some future simulation time. These are the future events. Future events are divided into future inactive events, and future non blocking assignment update events.
The processing of all the active events is called a simulation cycle.
Sphere: Related ContentData Types in SystemVerilog
Verilog supports variable and net types that are identical to each other and drive four-state values.
- reg, integer, time variables can have '0', '1', 'Z' and 'X' values
- wand , wor , wire net types can have '0', '1', 'Z' and 'X' values with 7 strengths giving 120 values
SystemVerilog (SV) extends Verilog variable types that can be either 2-state ('0' or '1') or 4-state ('0', '1', 'X', 'Z') data types while net types can be only 4-state data types. Data declarations in SystemVerilog have a type (that indicates if the signal is a net or a variable) and a data type (that indicates if it is 2-state or 4-state values).
SV Four state logic type
To replace the confusing reg type in Verilog, SystemVerilog defines a 4-state logic data type that can be associated with variables or nets. For example,
var logic [31:0] data; // a 32-bit variable supporting 4-state values
wire logic [31:0] data; // a 32-bit net capable of driving 4-state values.
Note that Verilog reg type cannot be associated with net types while SV logic type can be. Also note that the variable is implied if var keyword is absent in a declaration i.e.
logic [31:0] data // is same as var logic [31:0] data
Similarly, if the var is explicitly defined but the datatype is absent, it is assumed to be logic data type by default.
var [31:0] data // is same as var logic [31:0] data
wire [31:0] data; // a 32-bit net type, 4-state logic datatype.
SV Two state types
SV adds new 2-state types that can aid faster simulations and also consume less memory while modeling hardware at higher levels. These include
- bit - a single bit 2-state integer, user-defined vector size
var bit flag; // -bit wide 2-state variable
var bit [31:0] count; // a 32-bit 2-state variable
- byte - a single byte 2-state integer
- shortint - a 16-bit 2-state integer
- int - a 32-bit 2-state integer, similar to C
- longint - a 64-bit 2-state integer
The byte, int, longint, shortint types are signed by default, SV includes unsigned keyword to override this default.
int unsigned data; // Unsigned 32-bit variable
The 4-state variables if uninitialized take a value of 'X' until the first assignment - it is the recommended choice for synthesizable RTL. 2-state variables if uninitialized default to '0'. When a 4-state variable is assigned to a 2-state variable, the 'X' and 'Z' are translated to '0'. 2-state variables are synthesized similar to the 4-state variables by tools that ignore the default value of zero.
Abstract Data Types (not synthesizable) such as real (similar to Cdouble), shortreal (C float), void (used to define functions that do not return any value or in tagged unions) are also supported in SV.