Structures and unions

Structure and union declarations follow the C syntax but without the optional structure tags before the ‘{‘.

struct { bit [7:0] opcode; bit [23:0] addr; } REG; // anonymous structure defines variable REG

REG.opcode = 1; // set field opcode in REG.

Some additional examples of declaring structure and unions are:

typedef struct {
bit [7:0] opcode;
bit [23:0] addr;
} REG ; // named structure type
REG REG1; // define variable

typedef union { int i; shortreal f; } num; // named union type
num n;
n.f = 0.0; // set n in floating point format

typedef struct {
bit isfloat;
union { int i; shortreal f; } n; // anonymous type
} tagged_st; // named structure
tagged_st a[9:0]; // array of structures

A structure can be assigned as a whole and passed to or from a function or task as a whole. A packed structure consists of bit fields, which are packed together in memory without gaps. This means that they are easily converted to and from bit vectors. An unpacked structure has an implementation-dependent packing, normally matching the C compiler.

Like a packed array, a packed structure can be used as a whole with arithmetic and logical operators. The first member specified is the most significant and subsequent members follow in decreasing significance. The structures are declared using the packed keyword, which can be followed by the signed or unsigned keywords, according to the desired arithmetic behavior. The default is unsigned:

struct packed signed {
int a;
shortint b;
byte c;
bit [7:0] d;
} pack1; // signed, 2-state

struct packed unsigned {
time a;
integer b;
logic [31:0] c;
} pack2; // unsigned, 4-state

If any data type within a packed structure is 4-state, the whole structure is treated as 4-state. Any 2-state members are converted as if cast. One or more bits of a packed structure can be selected as if it were a packed array, assuming an [n-1:0] numbering.

Non-integer data types, such as real and shortreal, are not allowed in packed structures or unions nor are in unpacked arrays.
A packed structure can be used with a typedef.

typedef struct packed { // default unsigned
bit [3:0] GFC;
bit [7:0] VPI;
bit [11:0] VCI;
bit CLP;
bit [3:0] PT ;
bit [7:0] HEC;
bit [47:0] [7:0] Payload;
bit [2:0] filler;
} s_atmcell;

A packed union shall contain members that must be packed structures or packed arrays or integer data types all of the same size (in contrast to an unpacked union, where the members can be of different sizes). This ensures that you can read back a union member that was written as another member. A packed union can also be used as a whole with arithmetic and logical operators, and its behavior is determined by the signed or unsigned keyword, the latter being the default. If a packed union contains a 2-state member and a 4-state member, the entire union is 4-state. There is an implicit conversion from 4-state to 2-state when reading and from 2-state to 4-state when writing the 2-state member.

For example, a union can be accessible with different access widths:

typedef union packed { // default unsigned
s_atmcell acell;
bit [423:0] bit_slice;
bit [52:0][7:0] byte_slice;
} u_atmcell;
u_atmcell u1;
byte b; bit [3:0] nib;
b = u1.bit_slice[415:408]; // same as b = u1.byte_slice[51];
nib = u1.bit_slice [423:420]; // same as nib = u1.acell.GFC;

Note that writing one member and reading another is independent of the byte ordering of the machine, unlike a normal union of normal structures, which are C-compatible and have members in ascending address order.

The signing of unpacked structures is not allowed. The following declaration would be considered illegal:

typedef struct signed {
int f1 ;
logic f2 ;
} IllegalSignedUnpackedStructType; // illegal declaration

<< Previous | Next >>

Event data types

The event data type is an enhancement over Verilog named events. SystemVerilog events provide a handle to a synchronization object. Like Verilog, event variables can be explicitly triggered and waited for. Furthermore, SystemVerilog events have a persistent triggered state that lasts for the duration of the entire time step. In addition, an event variable can be assigned another event variable or the special value null. When assigned another event variable, both event variables refer to the same synchronization object. When assigned null, the association between the synchronization object and the event variable is broken. Events can be passed as arguments to tasks.

The syntax to declare an event is:

event variable_name [= initial_value];

Where variable_name is a valid identifier and the optional initial_value can be another event variable or the special value null.

If an initial value is not specified then the variable is initialized to a new synchronization object.

If the event is assigned null, the event becomes nonblocking, as if it were permanently triggered.


event E1;               // declare a new event called E1

event E2 = E1;  // declare E2 as alias to E1

event empty = null    // event variable with no synchronization object

<< Previous | Next >>