Typedef
In complex testbenches some variable declarations might have a longer data-type specification or require to be used in multiple places in the testbench.
In such cases we can use a typedef
to give a user-defined name to an existing data type. The new data-type can then be used throughout the code and hence avoids the need to edit in multiple places if required.
// Normal declaration may turn out to be quite long
unsigned shortint my_data;
enum {RED, YELLOW, GREEN} e_light;
bit [7:0] my_byte;
// Declare an alias for this long definition
typedef unsigned shortint u_shorti;
typedef enum {RED, YELLOW, GREEN} e_light;
typedef bit [7:0] ubyte;
// Use these new data-types to create variables
u_shorti my_data;
e_light light1;
ubyte my_byte;
Syntax
typedef data_type type_name [range];
Example
module tb;
typedef shortint unsigned u_shorti;
typedef enum {RED, YELLOW, GREEN} e_light;
typedef bit [7:0] ubyte;
initial begin
u_shorti data = 32'hface_cafe;
e_light light = GREEN;
ubyte cnt = 8'hFF;
$display ("light=%s data=0x%0h cnt=%0d", light.name(), data, cnt);
end
endmodule
ncsim> run light=GREEN data=0xcafe cnt=255 ncsim: *W,RNQUIE: Simulation is complete.
Alias
In SystemVerilog, an alias is a named reference to a variable, signal, or instance. It provides a way to refer to a variable using a different name. Aliases can be useful in many situations, including reducing code complexity, enhancing readability, and improving simulation performance. It is also used to model a bi-directional short-circuit and can be used inside modules, interfaces and generate blocks.
Here's an example of how to create an alias in SystemVerilog:
logic [7:0] data;
alias mydata = data; // alias "mydata" for signal "data"
initial begin
mydata = 8'hFF; // assign the value to "data" using the alias "mydata"
end
In this example, the signal data is assigned the value 8'hFF using the alias mydata . The advantage of using an alias is that it allows you to refer to the same signal using different names, which can make the code more readable and easier to understand.
An event
is a static object handle to synchronize between two or more concurrently active processes. One process will trigger the event, and another process waits for the event.
- Can be assigned or compared to other event variables
- Can be assigned to
null
- When assigned to another event, both variables point to same synchronization object
- Can be passed to queues, functions and tasks
An enumerated type defines a set of named values. In the following example, light_* is an enumerated variable that can store one of the three possible values (0, 1, 2). By default, the first name in the enumerated list gets the value 0 and the following names get incremental values like 1 and 2.
enum {RED, YELLOW, GREEN} light_1; // int type; RED = 0, YELLOW = 1, GREEN = 2
enum bit[1:0] {RED, YELLOW, GREEN} light_2; // bit type; RED = 0, YELLOW = 1, GREEN = 2
The user can assign any integer value for any of the enumerated names. If any name does not have an assigned value, then it automatically takes the incremented value of the previous name.
enum {RED=3, YELLOW, GREEN} light_3; // RED = 3, YELLOW = 4, GREEN = 5
enum {RED = 4, YELLOW = 9, GREEN} light_4; // RED = 4, YELLOW = 9, GREEN = 10 (automatically assigned)
enum {RED = 2, YELLOW, GREEN = 3} light_5; // Error : YELLOW and GREEN are both assigned 3
enum bit[0:0] {RED, YELLOW, GREEN} light_6; // Error: minimum 2 bits are required
What is a SystemVerilog string ?
The string
data-type is an ordered collection of characters. The length of a string
variable is the number of characters in the collection which can have dynamic length and vary during the course of a simulation. A string variable does not represent a string in the same way as a string literal. No truncation occurs when using the string
variable.
Syntax
string variable_name [= initial_value];
variable_name is a valid identifier and the optional initial_value can be a string literal, the value "" for an empty string, or a string data type expression. If an initial value is not specified at the time of declaration, then the variable defaults to "", an empty string literal.
In the previous article, an overview of the major data types were given. In this session, we'll look at 4-state and 2-state variables and two new data types called logic
and bit
.
4-state data types
Types that can have unknown (X) and high-impedance (Z) value in addition to zero (0) and one (1) are called 4-state types. Note that reg
can only be driven in procedural blocks like always
and initial
while wire
data types can only be driven in assign
statements. SystemVerilog introduces a new 4-state data type called logic
that can be driven in both procedural blocks and continuous assign
statements. But, a signal with more than one driver needs to be declared a net-type such as wire
so that SystemVerilog can resolve the final value.
logic
module tb;
logic [3:0] my_data; // Declare a 4-bit logic type variable
logic en; // Declare a 1-bit logic type variable
initial begin
$display ("my_data=0x%0h en=%0b", my_data, en); // Default value of logic type is X
my_data = 4'hB; // logic datatype can be driven in initial/always blocks
$display ("my_data=0x%0h en=%0b", my_data, en);
#1;
$display ("my_data=0x%0h en=%0b", my_data, en);
end
assign en = my_data[0]; // logic datatype can also be driven via assign statements
endmodule
ncsim> run my_data=0xx en=x my_data=0xb en=x my_data=0xb en=1 ncsim: *W,RNQUIE: Simulation is complete.
2-state data types
In a typical verification testbench, there are many cases where we don't really need all the four values (0, 1, x, z) like for example when modeling a network packet with a header that specifies the length of the packet.Length is usually a number, but not X and Z. SystemVerilog adds many new 2-state data types that can only store and have a value of either 0 or 1. This will aid in faster simulation, take less memory and are preferred in some design styles.
When a 4-state value is converted to a 2-state value, any unknown or high-impedance bits shall be converted to zeros.
The most important 2-state data type is bit
which is used most often in testbenches. A variable of type bit
can be either 0 or 1 which represents a single bit. A range from MSB to LSB should be provided to make it represent and store multiple bits
bit
module tb;
bit var_a; // Declare a 1 bit variable of type "bit"
bit [3:0] var_b; // Declare a 4 bit variable of type "bit"
logic [3:0] x_val; // Declare a 4 bit variable of type "logic"
initial begin
// Initial value of "bit" data type is 0
$display ("Initial value var_a=%0b var_b=0x%0h", var_a, var_b);
// Assign new values and display the variable to see that it gets the new values
var_a = 1;
var_b = 4'hF;
$display ("New values var_a=%0b var_b=0x%0h", var_a, var_b);
// If a "bit" type variable is assigned with a value greater than it can hold
// the left most bits are truncated. In this case, var_b can hold only 4 bits
// and hence 'h481 gets truncated leaving var_b with only 'ha;
var_b = 16'h481a;
$display ("Truncated value: var_b=0x%0h", var_b);
// If a logic type or any 4-state variable assigns its value to a "bit" type
// variable, then X and Z get converted to zero
var_b = 4'b01zx;
$display ("var_b = %b", var_b);
end
endmodule
ncsim> run Initial value var_a=0 var_b=0x0 New values var_a=1 var_b=0xf Truncated value: var_b=0xa var_b = 0100 ncsim: *W,RNQUIE: Simulation is complete.