data_type
data_type_common_item ::=
integer_vector_type
[ signing ] { packed_dimension
} [ range ]
| integer_atom_type
[ signing ]
| type_declaration_identifier type_identifier { packed_dimension
}
| non_integer_type
| struct struct_union [ packed [ signing ]] { struct_union_member { struct_union_member } } { packed_dimension
}16
| union packed [ signing ] { { struct_union_member } } { packed_dimension
}
| struct [ signing ] {
{ struct_union_member } }
| union [ signing ] { { struct_union_member } }
| enum [ integer_type
[ signing ] { packed_dimension } ]
{ enum_identifier [ = constant_expression ] { , enum_identifier
[ = constant_expression ] } }
| enum [ enum_base_type
] { enum_name_declaration
{ , enum_name_declaration } }
| string
| event
| chandle
| class_scope_type_identifier
| virtual [interface] interface_identifier
data_type ::=
data_type_common_item
| event
| class_scope_type_identifier
| covergroup_identifier
class_scope_type_identifier::=
class_scope [ ::
type_identifier ]
class_identifier :: { class_identifier :: } type_declaration_identifier
| class_identifier
:: { class_identifier :: }
class_identifier
class_scope ::=
class_identifier [ parameter_value_assignment ]
{ :: class_identifier
[ parameter_value_assignment ] }
struct_union_member ::= { attribute_instance
} variable_declaration ;
struct_union_member ::=
{ attribute_instance } data_type { packed_dimension }
variable_identifier variable_dimension { ,
variable_identifier variable_dimension
} ;
struct_union ::= struct | union
variable_decl_assignment ::=
variable_identifier
variable_dimension [ =
constant_expression expression ]
| variable_identifier
[ ] = new [ constant_expression
expression ] [ ( variable_identifier
) ]
| class_variable_identifier [ parameter_value_assignment ] = new [ ( list_of_arguments
) ]
| [ covergroup_variable_identifier
] = new [ ( list_of_arguments ) ]19
type_declaration ::=
typedef [ data_type ] type_declaration_identifier ;
| typedef hierarchical_identifier . type_identifier
type_declaration_identifier ;
| typedef [ class ]
class_identifier ;
| typedef class_identifier [ parameter_value_assignment
] type_declaration_identifier ;
typedef data_type type_identifier variable_dimension ;
| typedef
interface_instance_identifier . type_identifier type_identifer ;
| typedef
[ enum | struct | union | class ] type_identifier ;
If the type is
defined within an interface, it must be re-defined locally before being used.
interface it;
typedef int intP;
endinterface
it it1 ();
typedef it1.intP intP;
User defined type
identifiers have the same scoping rules as data identifiers, except that hierarchical
reference to type identifiers shall not be allowed. References to type
identifiers defined within an interfaces through ports are allowed provided
they are locally re-defined before being used.
interface intf_i;
typedef int data_t;
endinterface
module sub(intf_i_i p)
typedef p.data_t my_data_t;
my_data_t data; //type of 'data'' will be int when
connected to interface above
endmodule
User-defined type names must
be used for complex data types in casting (see Section 3.14, below), which only
allows simple type names, and as parameters
type parameter values when unpacked array types are
used.
data_type
data_type_common_item ::=
...
| enum [ integer_type
[ signing ] { packed_dimension } ]
{ enum_identifier [ = constant_expression ] { , enum_identifier [ = constant_expression ] } }
| enum [ enum_base_type
] { enum_name_declaration
{ , enum_name_declaration } }
// Correct: IDLE=2’b00,
XX=2’b’x,
S1=2’b01, S2=2’b10
enum
integer {IDLE, XX=’x, S1=2’b01, S2=2’b10} state, next;
The values can be set for
some of the names and not set for other names. The
optional value of an enum label is an elaboration time constant expression (see
Section 5.3) and can include references to parameters, local parameters, genvars, other enum labels, and
constant functions of these. Hierarchical names and const variables are not
allowed. A name without a value is automatically assigned an increment
of the value of the previous name.
A sized
constant can be used to set the size of the type. All sizes must be the same.
// silver=4’h4, gold=4’h5 (all are 4
bits wide)
enum {bronze=4’h3, silver, gold} medal4;
// Syntax error: the width of the enum has been exceeded
// in both of these examples
enum {a=1'b0, b, c} alphabet;
enum [0:0] {a,b,c} alphabet;
Any
enumeration encoding value that is outside the representable
range of the enum shall be
an error.
Adding a constant range to
the enum declaration can be used to set the size of the type. If any of the enum members are
defined with a different sized constant, this shall be a syntax error. Any enumeration encoding value that is outside the representable range of the enum shall be an error. If any of the enum members are defined with a different sized
constant, this shall be a syntax error.
// Error in the bronze and gold member
declarations
enum bit [3:0] {bronze=5’h13, silver, gold=3’h5} medal4;
// Correct
declaration - bronze and gold sizes are redundant
enum bit [3:0] {bronze=4’h13, silver, gold=4’h5} medal4;
// Correct declaration - bronze and gold
are unsized
enum bit [3:0] {bronze=’h3, silver, gold=’h5} medal4;
// Correct declaration - bronze and gold
sizes are redundant
enum bit [3:0] {bronze=4’h3, silver, gold=4’h5} medal4;
// Error in the bronze and gold member declarations
enum [3:0]
{bronze=5’h13, silver, gold=3’h5} medal4;
// Error in c declaration, requires at least 2 bits
enum [0:0] {a,b,c} alphabet;
Type checking of enumerated
types used in assignments, as arguments and with operators is covered in Section
3.10.3. Like C, there is no overloading of literals, so medal and medal4 cannot
be defined in the same scope, since they contain the same names.
name |
Associates the next consecutive number with name. |
name
= |
|
name[N] |
Generates N labels in
the sequence: name0,
name1, ..., nameN-1N. Each generated label is associated the next
consecutive number. |
name[N] = C |
Optionally, a constant can be assigned to
the generated N must be an integral literal constant. |
name[N:M] |
Creates a sequence of |
name[N:M] = C |
Optionally, a constant can be assigned to the
generated labels to associate that constant to the first generated label;
subsequent generated labels are associated consecutive values. N and M must be integral literal constants. |
For example:
typedef enum
{ add=10, sub[5], jmp[6:8] } E1;
This example defines the enumerated type E1, which assigns the number 10 to the enumerated type label add. It also creates the enumerated types labels sub0,sub1,sub2,sub3,and sub4, and
assigns them the values 11..15, respectively. Finally, the example creates the
enumerated types labels jmp6,jmp7,
and jmp8, and assigns them the
values 16-18, respectively.
enum { register[1]
= 1, register[2:4] = 10 } vr;
The example above declares
enumerated variable vr, which creates the enumerated labels register0
and register1, which are assigned the values 1 and 2, respectively. Next, it
creates the enumerated labels register2, register3, and register4, and assigns them the values 10, 11, and 12.
data_type
data_type_common_item::=
...
| struct struct_union [ packed
[ signing ]] { struct_union_member { struct_union_member } } { packed_dimension
}16
| union packed [ signing ] { { struct_union_member } } { packed_dimension
}
| struct [ signing ] {
{ struct_union_member } }
| union [ signing ] { { struct_union_member } }
struct_union_member ::= { attribute_instance
} variable_declaration ;
struct_union_member ::=
{ attribute_instance } data_type { packed_dimension }
variable_identifier variable_dimension { ,
variable_identifier variable_dimension
} ;
struct_union ::= struct | union
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 ;
} sIllegalSignedUnpackedStructType; // illegal declaration
A class is a collection of data and a set of subroutines
that operate on that data. The data in a class is referred to as class properties, and its subroutines are called
methods. The class properties and methods, taken
together, define the contents and capabilities of a class instance or object.
The object-oriented class extension allows objects to be created
and destroyed dynamically. Class instances, or objects, can be passed around
via object handles, which add a safe-pointer capability to the language. An
object can be declared as an argument of type with direction input, output, inout, or, or ref. In each case,
the argument copied is the object handle, not the contents of the object.
3.13
Singular type and
Aggregate types
A singular type
includes packed arrays (and structures) and all other data types except
unpacked structures, unpacked arrays, and chandles.
Data types are categorized as either singular or aggregate. A
singular type shall be any data type except an unpacked structure, union, or
array (See section 4 Arrays). An aggregate type shall be any unpacked
structure, union, or array data type. A singular variable or expression
represents a single value, symbols, or handle. Aggregate expressions and
variables represent a set or collection of singular values. Integral types are
always singular even though they may be sliced into multiple singular values.
These categories are defined so that operators and functions may
simply refer to these data types as a collective group. For example, some
functions recursively descend into an aggregate variable until reaching a
singular value, and then perform an operation on each singular value.
Note that although a class is a type, there are no variables or
expressions of class type directly, only class object handles which are
singular. So classes need not be categorized in this manner (See section 11
Classes).
casting_type ::= simple_type
| number size
| signing // from
Annex A.2.2.1
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.
An explicit cast
between packed types is not required since they are treated as integral values,
but a cast can be used by tools to perform stronger type checking.
The following example demonstrates how
this conversion. In the example, the
$bits attribute gives is used to obtain the size of a
structure in bits (the $bits system function is discussed in Section 22.2), which facilitates conversion of the structure into a
packed array:.
3.16 Bit-stream casting
Type casting may 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, so that 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.
When a dynamic array, queue, or string is
converted to the packed representation, the item at index 0 occupies the most
significant bits. When an associative array is converted to the packed representation,
items are packed in index-sorted order with the first indexed element occupying
the most significant bits.
Both source_t and dest_t can include
one or more dynamically sized data in any position (for example, a structure
containing a dynamic array followed by a queue of bytes). If the source type, source_t,
includes dynamically-sized variables, they are all included in the
bit-stream. If the destination type, dest_t, includes
unbounded dynamically-sized types, the conversion process is greedy: compute
the size of the source_t,
subtract the size of the fixed-size data items in the destination, and then
adjust the size of the first dynamically sized item in the destination to the
remaining size; any remaining dynamically-sized items are left empty.
For the purposes of a bit-stream cast, a string is considered a
dynamic array of bytes.
Regardless of whether the destination type contains only
fixed-size items or dynamically-sized items, data is extracted into the
destination in left-to-right order. It is thus legal to fill a
dynamically-sized item with data extracted from the middle of the packed
representation.
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);
Bit-stream casting can be used to convert
between different aggregate types, such as two structure types, or a structure
and an array or queue type. This conversion can be useful to model packet data
transmission over serial communication streams. For example, the code below
uses bit-stream casting to model a control packet transfer over a data stream:
typedef struct
{
shortint address;
reg [3:0] code;
byte command [2];
} Control;
typedef bit Bits [36:1];
Control p;
Bits stream[$];
p = ... //
initialize control packet
stream = {stream, Bits’(p)} //
append packet to unpacked queue of bits
Control q;
q = Control’(stream[0]); // convert stream back to a
Control packet
stream = stream[1:$]; // remove packet from
stream
The following example uses bit-stream
casting to model a data packet transfer over a byte stream:
typedef struct {
byte length;
shortint address;
byte payload[];
byte chksum;
} Packet;
The above type defines a generic data packet
in which the size of the payload field is stored in the length field. Below is a function that randomly initializes
the packet and computes the checksum.
function Packet genPkt();
Packet p;
void’( randomize( p.address, p.length, p.payload )
with { p.length
> 1 && p.payload.size == p.length } );
p.chksum = p.payload.xor();
return p;
endfunction
The byte stream is modeled using a queue, and a bit-stream cast is
used to send the packet over the stream.
typedef byte channel_type[$];
channel_type channel;
channel = {channel, channel_type'(genPkt())};
And the code to receive the packet:
Packet p;
int size;
size = channel[0] + 4;
p = Packet’( channel[0 : size - 1] ); // convert stream to Packet
channel = channel[ size, $ ]; // remove packet data from
stream