Monday, October 13, 2014

SYSTEM VERILOG PART-1

1.  Introduction to System Verilog

1.1.       System Verilog origins

System Verilog is a standard set of extensions to the IEEE 1364- 2005 Verilog Standard (commonly referred to as “Verilog-2005”).These extensions integrate many of the features of the SUPERLOG and C languages. System Verilog also contains many extensions for the verification of large designs, integrating features from the SUPERLOG, VERA C, C++, and VHDL languages, along with OVA and PSL assertions. This integrated whole created by System Verilog greatly exceeds the sum of its individual components, creating a new type of engineering language, a Hardware Description and Verification Language or HDVL. Using a single, unified language enables engineers to model large, complex designs, and verify that these designs are functionally correct.

1.2.        Key System Verilog enhancements for hardware design

The following list highlights some of the more significant enhancements System Verilog adds to the Verilog HDL for the design and verification of hardware: This list is not intended to be all inclusive of every enhancement to Verilog that is in System Verilog. This list just highlights a few key features that aid in writing synthesizable hardware models.

·         Interfaces to encapsulate communication and protocol checking within a design
·         C like data types, such as int
·         User-defined types, using typedef
·         Enumerated types
·         Type casting
·         Structures and unions
·         Packages for definitions shared by multiple design blocks
·         External compilation-unit scope declarations
·         ++, --, += and other assignment operators
·         Explicit procedural blocks
·         Priority and unique decision modifiers
·         Programming statement enhancements
·         Pass by reference to tasks, functions and modules



2.  Data types


A data type is a set of values and a set of operations that can be performed on those values. Data types can be used to declare data objects or to define user-defined data types that are constructed from other data types. A data object is a named entity that has a data value and a data type associated with it, such as a parameter, a variable, or a net.

The System Verilog value set consists of the following four basic values:

Ø  0—represents a logic zero, or a false condition
Ø  1—represents a logic one, or a true condition
Ø  x—represents an unknown logic value
Ø  z—represents a high-impedance state

The values 0 and 1 are logical complements of one another. When the z value is present at the input of a gate or when it is encountered in an expression, the effect is usually the same as an x value.

Several System Verilog data types are 4-state types, which can store all four logic values. All bits of 4-state vectors can be independently set to one of the four basic values. Some System Verilog data types are 2-state, and only store 0 or 1 values in each bit of a vector.  System Verilog 2-state data types can simulate faster, take less memory, and are preferred in some design styles. Then a 4-state value is automatically converted to a 2-state value, X and Z will be converted to zeros.

            Table 1: Different system verilog data types

A singular variable or expression represents a single value, symbol, or handle. Aggregate expressions and variables represent a set or collection of singular values. An aggregate type shall be any unpacked structure, unpacked union, or unpacked array data type.

2.1.          Nets and Variables:

There are two main groups of data objects: variables and nets. These two groups differ in the way in which they are assigned and hold values.

2.1.1.  Nets:

            The net types can represent physical connections between structural entities, such as gates. A net shall not store a value. Instead, its value shall be determined by the values of its drivers, such as a continuous assignment or a gate. If no driver is connected to a net, its value shall be high-impedance (z).

A net declaration begins with a net type that determines how the values of the nets in the declaration are resolved. The declaration can include optional information such as delay values, drive or charge strength, and a data type.

Example1: Declaration of nets

typedef logic [31:0] addressT;
wireaddressT w1;
wire struct packed { logic ecc; logic [7:0] data; } memsig;

If a data type is not specified in the net declaration or if only a range and/or signing isspecified, then the data type of the net is implicitly declared as logic.

Example2: Declaration of nets

wirew; // equivalent to "wire logic w;"
wire[15:0] ww; // equivalent to "wire logic [15:0] ww;"

A net can be written by one or more continuous assignments, by primitive outputs, or through module ports. A net cannot be procedurally assigned. If a net on one side of a port is driven by a variable on the other side, a continuous assignment is implied.

2.1.2.  Variables:

A variable is an abstraction of a data storage element. A variable shall store a value from one assignment to the next. An assignment statement in a procedure acts as a trigger that changes the value in the data storage element.
One form of variable declaration consists of a data type followed by one or more instances.

shortints1, s2[0:9];

   Another form of variable declaration begins with the keyword var. The data type is optional in this case. If a data type is not specified or if only a range and/or signing is specified, then the data type is implicitly declared as logic.

Example3: Declaration of variables

var byte my_byte; // equivalent to "byte my_byte;"
varv; // equivalent to "var logic v;"
var[15:0] vw; // equivalent to "var logic [15:0] vw;"
var enum bit { clear, error } status;
input var logic data_in;
var reg r;

   Variables can be written by one or more procedural statements, including procedural continuous assignments. The last write determines the value. Alternatively, variables can be written by one continuous assignment or one port.
   Variables can be packed or unpacked aggregates of different types Multiple assignments made to independent elements of a variable are examined individually. Independent elements include different members of a structure, or different elements of an array. Each bit in a packed type is also an independent element. Thus, in an aggregate of packed types, each bit in the aggregate is an independent element.
   An assignment where the left-hand side contains a slice is treated as a single assignment to the entire slice. Thus, a structure or array can have one element assigned procedurally and another element assigned continuously.

Example4: assignment to nets and variables
struct{
bit[7:0] A;
bit[7:0] B;
byteC;
} abc;

The following statements are legal assignments to struct abc:

assignabc.C = sel ?8'hBE : 8'hEF;
not(abc.A[0],abc.B[0]),
(abc.A[1],abc.B[1]),
(abc.A[2],abc.B[2]),
(abc.A[3],abc.B[3]);
always@(posedge clk) abc.B <= abc.B + 1;

The following additional statements are illegal assignments to struct abc:

// Multiple continuous assignments to abc.C
assignabc.C = sel ?8'hDE : 8'hED;       

// Mixing continuous and procedural assignments to abc.A[3]
always@(posedge clk) abc.A[7:3] <= !abc.B[7:3];

   Variable cannot be connected to inout port. Variables can be shared across ports with the ref port type. Nets and variables can be assigned negative values, but only signed types shall retain the significance of the sign. The byte, shortint, int, integer, and longint types are signed types by default. Other net and variable types can be explicitly declared as signed.

2.1.3.  Vector declarations:

A data object declared as reg, logic, or bit (or as a matching user-defined type or implicitly as logic) without a range specification shall be considered 1 bit wide and is known as a scalar. A multibit data object of one of these types shall be declared by specifying a range, and is known as a vector.
The range specification gives addresses to the individual bits in a multibit reg, logic, or bit vector. The most significant bit specified by the msb constant expression is the left-hand value in the range, and the least significant bit specified by the lsb constant expression is the right-hand value in the range.
Both the msb constant expression and the lsb constant expression shall be constant integer expressions. The msb and lsb constant expressions may be any integer value—positive, negative, or zero. It shall be illegal for them to contain any unknown (x) or high-impedance bits. The lsb value may be greater than, equal to, or less than the msb value.
Vectors shall obey laws of arithmetic modulo-2 to the power n (2n), where n is the number of bits in the vector. Vectors of reg, logic, and bit types shall be treated as unsigned quantities, unless declared to be signed or connected to a port that is declared to be signed

Example5: Declaration of vectors

logica; // a scalar variable
logic[3:0] v; // a 4-bit vector made up of (from MSB to LSB)v[3], v[2], v[1], and v[0]
logic signed [3:0] signed_reg; // a 4-bit vector in range -8 to 7
logic[-1:4] b; // a 6-bit vector
wirew1, w2; // declares two nets
logic[4:0] x, y, z; // declares three 5-bit variables

In the absence of an explicit declaration, an implicit net of default net type shall be assumed in the following circumstances:
Ø If an identifier is used in a port expression declaration, then an implicit net of default net type shall be assumed, with the vector width of the port expression declaration.
Ø If an identifier is used in the terminal list of a primitive instance or a module instance, and that identifier has not been declared previously in the scope where the instantiation appears or in any scope whose declarations can be directly referenced from the scope where the instantiation appears, then an implicit scalar net of default net type shall be assumed.
Ø If an identifier appears on the left-hand side of a continuous assignment statement, and that identifier has not been declared previously in the scope where the continuous assignment statement appears or in any scope whose declarations can be directly referenced from the scope where the continuous assignment statement appears, then an implicit scalar net of default net type shall be assumed.

2.2.             Integer and real data types:

The term integral is used throughout this standard to refer to the data types that can represent a single basic integer data type, packed array, packed structure, packed union, enum variable, or time variable.
The term simple bit vector type is used throughout this standard to refer to the data types that can directly represent a one-dimensional packed array of bits.
The real data type is the same as a C double. The shortreal data type is the same as a C float. The realtime declarations shall be treated synonymously with real declarations and can be used interchangeably.

2.2.1.     2-state (two-value) and 4-state (four-value) data types:

Types that can have unknown and high-impedance values are called 4-state types. These are logic, reg, integer, and time. The other types do not have unknown values and are called 2-state types, for example, bit and int.
The difference between int and integer is that int is a 2-state type and integer is a 4-state type. The 4- state values have additional bits, which encode the X and Z states. The 2-state data types can simulate faster, take less memory, and are preferred in some design styles. logicandreg denote the same type.
Automatic type conversions from a smaller number of bits to a larger number of bits involve zero extensions if unsigned or sign extensions if signed. Automatic type conversions from a larger number of bits to a smaller number of bits involve truncations of the most significant bits (MSBs). When a 4-state value is automatically converted to a 2-state value, any unknown or high-impedance bits shall be converted to zeros.
Example6: Declaration of  2-state bit vectors
bit [msb:lsb] varlable_name [=inltial_value] ;
• Sized as specified
• Defaults to unsigned
bitflag;
bit [15:0] sample, temp = 16' hdeed;
bit[7:0] a = 8'h1; // 8'b0000_0001
bit [7:0] b = 'h1; // 8'b0000_0001
bit[ 7: 0] c = ' 1; // 8'b1111_1111
bit[31:0] signed ref_data = -155;

System Verilog adds the ability to specify unsized literal single-bit values with a preceding apostrophe ( ' ), but without the base specifier. All bits of the unsized value are set to the value specified. Supported unsized literals are ' 0, ' 1, ' x, ' z.

2.2.2.     Sized 2-state data types:


2-state-type variable name [=initial value] ;

Where 2-state-type is one of
• byte - 8-bit signed data type
• shortint - 16-bit signed data type
• int - 32-bit signed data type
• longint - 64-bit signed data type

Example7: Declaration of 2-state sized data types

shortint temp = 256;
int sample, ref data = -9876;
longint a, b;
longint unsigned testdata;

2.2.3.  2-State Real Data Types


2-state-type variable_name [=initial_value] ;
Where 2-state-type is one of

• real- Equivalent to double in C
• shortreal- Equivalent to float in C
• realtime

♦ 64-bit real variable for use with $realtime
♦ Can be used interchangeably with real variables

Example8:Declaration of 2-state sized Real data types

realalha = 100 .3 , cov_result ;
realtimet64 ;
#100 t64 = $realtime;
cov_result = $get_coverage();
if (cov_result == 200.0) ... ;

2.3.       4-State (0|1|X|Z) Data Types:

Variable initialized to ’x if initial_value is not specified

2.3.1.  Bit vector:

reg [msb:lsb] variable_name [=initial_value] ;
logic[msb:lsb] variable_name [=initial_value] ;
• regandlogic are synonyms
• Can be used in continuous assignment (single driver only),unlike Verilog
• Can be used as outputs of modules
• Defaults to unsigned

Example9: Declaration of 4-state bit vector

logic [15:0] sample = '1, ref_data = ' x;
assign sample= rtr_io.cb.dout;

2.3.2.  Sized 4-state data types:

Integer variable name [=initial value];
• 32-bit signed data type

time variable name [=initial value] ;
• 64-bit unsigned data type

Example10: Declaration of 4-state sized data types

integer a = -100, b;
time current_time;
b = -a;
current_time = $time;
i f (current_time >= 100ms) . . . ;

A %t format specifier is available for displaying time in user-defined units and suffix strings.
$timeformat [ (units_number,precision number , suffix_string , minimum_field_width ) ] ;

e.g.
$timeformat (-9, 5, “ns", 5 ) ;
$display ("current time is = %t", $time ) ; / / o r $realtime
/ / displays for example current time is = 1650.00000ns
You may define the $timeformat in an initial block to format all future %t uses.
The result of using logical or relational operators on real numbers and real variables is a single-bit scalarvalue. Not all operators can be used with expressions involving real numbers and real variables.
Real number constants and real variables are also prohibited in the following cases:
Ø  Edge event controls (posedge, negedge, edge) applied to real variables
Ø  Bit-select or part-select references of variables declared as real
Ø  Real number index expressions of bit-select or part-select references of vectors

Real numbers shall be converted to integers by rounding the real number to the nearest integer, rather than by truncating it. Implicit conversion shall take place when a real number is assigned to an integer. If the fractional part of the real number is exactly 0.5, it shall be rounded away from zero. Implicit conversion shall also take place when an expression is assigned to a real. Individual bits that are x or z in the net or the variable shall be treated as zero upon conversion.

2.4.       String data type:

The string data type is an ordered collection of characters. The length of a string variable is the number of characters in the collection. Variables of type string are dynamic as their length may vary during simulation. A single character of a string variable may be selected for reading or writing by indexing the variable. A single character of a string variable is of type byte.
A string variable does not represent a string in the same way as a string literal. String literals behave like packed arrays of a width that is a multiple of 8 bits. A string literal assigned to a packed array of an integral variable of a different size is either truncated to the size of the variable or padded with zeros to the left as necessary. When using the string data type instead of an integral variable, strings can be of arbitrary length and no truncation occurs. String literals are implicitly converted to the string type when assigned to a string type or used in an expression involving string type operands.
The indices of string variables shall be numbered from 0 to N–1 (where N is the length of the string) so that index 0 corresponds to the first (leftmost) character of the string and index N–1 corresponds to the last (rightmost) character of the string. The string variables can take on the special value “”, which is the empty string. Indexing an empty string variable shall be an out-of-bounds access.A string variable shall not contain the special character "\0". Assigning the value 0 to a string character shall be ignored.

The syntax to declare a string variable is as follows:

String variable_name [= initial_value];

Where variable_name is a valid identifier and the optional initial_value can be a string literal, thevalue “” for an empty string, or a string data type expression. Anempty string has zero length. System Verilog provides a set of operators that can be used to manipulate combinations of string variables and string literals. The basic operators defined on the string data type are:
Ø  ==, ! =, compare () and icompare
Ø  (),itoa (), atoi (), atohex (), toupper (), tolower (), etc.
Ø  len (), getc (), putc (), substr ().
A string literal can be assigned to a variable of a string or an integral data type. When assigning to a variable f integral data type, if the number of bits of the data object is not equal to the number of characters in the string literal multiplied by 8, the literal is right justified and either truncated on the left or zero filled on the left, as necessary.

Example11: Declaration of strings

parameter string default_name = "John Smith";
stringmyName = default_name;

bytec = "A"; // assigns to c "A"
bit[10:0] b = "\x41"; // assigns to b ’b000_0100_0001
bit[1:4][7:0] h = "hello" ; // assigns to h "ello"

A string literal or an expression of string type can be assigned directly to a variable of string type (astring variable). Values of integral type can be assigned to a string variable, but require a cast. When casting an integral value to a string variable, that variable shall grow or shrink to accommodate the integral value. If the size of the integral value is not a multiple of 8 bits, then the value shall be zero-filled on the left so that its size is a multiple of 8 bits.

A string literal assigned to a string variable is converted according to the following steps:
Ø  All "\0" characters in the string literal are ignored (i.e., removed from the string).
Ø  If the result of the first step is an empty string literal, the string is assigned the empty string.
Ø  Otherwise, the string is assigned the remaining characters in the string literal.

Casting an integral value to a string variable proceeds in the following steps:
Ø  If the size (in bits) of the integral value is not a multiple of 8, the integral value is left extended and filled with zeros until its bit size is a multiple of 8.
Ø   The extended value is then treated the same as a string literal, where each successive 8 bits represent a character.
Ø  The steps described above for string literal conversion are then applied to the extended value.

Example12: String assignment

strings0 = "String literal assign";// sets s0 to "String literal assign"
strings1 = "hello\0world"; // sets s1 to "helloworld"
bit[11:0] b = 12’ha41;
strings2 = string’(b); // sets s2 to 16’h0a41

typedef logic [15:0] r_t;
r_t r;
integer i = 1;
string b = "";
string a = {"Hi", b};
r = r_t'(a); // OK
b = string’(r); // OK
b = "Hi"; // OK
b = {5{"Hi"}}; // OK
a = {i{"Hi"}}; // OK (non-constant replication)
r = {i{"Hi"}}; // invalid (non-constant replication)
a = {i{b}}; // OK
a = {a,b}; // OK
a = {"Hi",b}; // OK
r = {"H",""}; // yields "H\0". "" is converted to 8'b0
b = {"H",""}; // yields "H". "" is the empty string
a[0] = "h"; // OK, same as a[0] = "cough"
a[0] = b; // invalid, requires a cast
a[1] = "\0"; // ignored, a is unchanged

2.4.1.  String operators:

The String operators are used in conditional statements and looping statements:
a)      Str1 == Str2 Equality. Checks whether the two string operands are equal. Result is 1 if they are equal and 0 if they are not. Both operands can be expressions of string type, or one can be an expression of string type and the other can be a string literal, which shall be implicitly converted to string type for the comparison. If both operands are string literals, the operator is the same equality operator as for integral types.

b)      Str1 != Str2 Inequality. Logical negation of ==.


c)      Str1 < Str2, Str1 <= Str2,Str1> Str2, Str1 >= Str2 Comparison: Relational operators return 1 if the corresponding condition is true using the lexicographic ordering of the two strings Str1 and Str2. The comparison uses the compare string method. Both operands can be expressions of string type, or one can be an expression of string type and the other can be a string literal, which shall be implicitly converted to string type for the comparison. If both operands are string literals, the operator is the same comparison operator as for integral types.

d)     {Str1,Str2,...,Strn} Concatenation: Each operand can be a string literal or an expression of string type. If all the operands are string literals the expression shall behave as a concatenation of integral values; if the result of such a concatenation is used in an expression involving string types then it shall be implicitly converted to string type. If at least one operand is an expression of string type, then any operands that are string literals shall be converted to string type before the concatenation is performed, and the result of the concatenation shall be of string type.

e)      {multiplier{Str}} Replication: Str can be a string literal or an expression of string type. multiplier shall be an expression of integral type, and is not required to be a constant expression. If multiplier is non-constant or Str is an expression of string type, the result is a string containing N concatenated copies of Str, where N is specified by the multiplier. If Str is a literal and the multiplier is constant, the expression behaves like numeric replication.

f)       Str[index] Indexing. Returns a byte, the ASCII code at the given index. Indices range from0 to N–1, where N is the number of characters in the string. If given an index outof range, returns 0.

2.4.2.  String functions:

a)      Len()

function int len();
str.len() returns the length of the string, i.e., the number of characters in the string (excluding any terminating character). If str is "", then str.len() returns 0.

b)      Putc()

function void putc(int i, byte c);
str.putc(i, c) replaces the ith character in str with the given integral value.
putc does not change the size of str: If i < 0 or i >= str.len(), then str is unchanged. If the second argument to putc is zero, the string is unaffected. The putc method assignment str.putc(j, x) is semantically equivalent to str[j] = x.

c)       Getc()

function byte getc(int i);
str.getc(i) returns the ASCII code of the ith character in str.
If i < 0 or i >= str.len(), then str.getc(i) returns 0.
The getc method assignment x = str.getc(j) is semantically equivalent to x = str[j].

d)     Toupper()

function string toupper();
str.toupper() returns a string with characters in str converted to uppercase. str is unchanged.

e)       Tolower()

function string tolower();
str.tolower() returns a string with characters in str converted to lowercase. str is unchanged.

f)        Compare()

function int compare(string s);
str.compare(s) compares str and s, as in the ANSI C strcmp function with regard to lexical ordering and return value.

g)       Icompare()

function int icompare(string s);
str.icompare(s) compares str and s, like the ANSI C strcmp function with regard to lexical ordering and return value, but the comparison is case insensitive.

h)       Substr()

function string substr(int i, int j);
str.substr(i, j) returns a new string that is a substring formed by characters in position i through j of str. If i < 0, j < i, or j >= str.len(), substr() returns " " (the empty string).

i)         Atoi(), atohex(), atooct(), atobin()

function integer atoi();
function integer atohex();
function integer atooct();
function integer atobin();

str.atoi() returns the integer corresponding to the ASCII decimal representation in str(string).

 Forexample:

str = "123";
inti = str.atoi(); // assigns 123 to i.

The conversion scans all leading digits and underscore characters ( _ ) and stops as soon as it encounters any other character or the end of the string. It returns zero if no digits were encountered. It does not parse the full syntax for integer literals (sign, size, apostrophe, base).

atohex interprets the string as hexadecimal.
atooct interprets the string as octal.
atobin interprets the string as binary.

j)         Atoreal()

function real atoreal();
str.atoreal() returns the real number corresponding to the ASCII decimal representation in str. The conversion parses for real constants. The scan stops as soon as it encounters any character that does not conform to this syntax or the end of the string. It returns zero if no digits were encountered.

k)       Itoa()

function void itoa(integer i);
str.itoa(i) stores the ASCII decimal representation of i into str (inverse of atoi).

l)         Hextoa()

function void hextoa(integer i);
str.hextoa(i) stores the ASCII hexadecimal representation of i into str (inverse of atohex).

m)     Octtoa()

function void octtoa(integer i);
str.octtoa(i) stores the ASCII octal representation of i into str (inverse of atooct).

n)       Bintoa()

function void bintoa(integer i);
str.bintoa(i) stores the ASCII binary representation of i into str (inverse of atobin).

o)      Realtoa()

function void realtoa(real r);
 str.realtoa(r) stores the ASCII real representation of r into str (inverse of atoreal).




2.5. User-defined types:

System Verilog’s data types can be extended with user-defined types using typedef. A typedef may be used to give a user-defined name to an existing data type. For example:

typedef int intP;

The named data type can then be used as follows:

int P a, b;

User-defined data type names must be used for complex data types in casting, which only allows simple data type names, and as type parameter values when unpacked array types are used. A type parameter may also be used to declare a type_identifier. The declaration of a user-defined data type shall precede any reference to its type_identifier. User-defined data type identifiers have the same scoping rules as data identifiers, except that hierarchical references to type_identifier shall not be allowed.
References to type identifiers defined within an interface through ports are not considered hierarchical references and are allowed provided they are locally redefined before being used. Such a typedef is called an interface based typedef.

Example13: Interface based typedef

Interface intf_i;
typedef int data_t;
endinterface

module sub(intf_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

Sometimes a user-defined type needs to be declared before the contents of the type have been defined. Thisis of use with user-defined types derived from the basic data types: enum, struct, union, and class. Supportfor this is provided by the following forms for a forward typedef:

typedef enum type_identifier;
typedef struct type_identifier;
typedef union type_identifier;
typedef class type_identifier;
typedeftype_identifier;

The actual data type definition of a forward typedef declaration shall be resolved within the same local scope. It shall be an error if the type_identifier does not resolve to a data type. It shall be an error if a basic data type was specified by the forward type declaration and the actual type definition does not conform to the specified basic data type. It shall be legal to have a forward type declaration in the same scope, either before or after the final type definition. It shall be legal to have multiple forward type declarations for the same type identifier in the same scope. While incomplete forward types, type parameters, and types defined by an interface based typedef may resolve to class types, use of the class scope resolution operator to select a type with such a prefix shall be restricted to a typedef declaration. It shall be an error if the prefix does not resolve to a class.

2.6.                   Enumerations:

An enumerated type declares a set of integral named constants. Enumerated data types provide the capability to abstractly declare strongly typed variables without either a data type or data value(s) and later add the required data type and value(s) for designs that require more definition. Enumerated data types also can be easily referenced or displayed using the enumerated names as opposed to the enumerated values.
In the absence of a data type declaration, the default data type shall be int. Any other data type used with enumerated types shall require an explicit data type declaration.
An enumerated type defines a set of named values. In the following example, light1 and light2 are defined to be variables of the anonymous (unnamed) enumerated int type that includes the three members: red, yellow, and green.

enum{red, yellow, green} light1, light2; // anonymous int type

An enumerated name with x or z assignments assigned to an enum with no explicit data type or an explicit 2-state declaration shall be a syntax error.

// Syntax error: IDLE=2’b00, XX=2’bx <ERROR>, S1=2’b01, S2=2’b10
enum bit [1:0] {IDLE, XX=’x, S1=2’b01, S2=2’b10} state, next;

An enum declaration of a 4-state type, such as integer, that includes one or more names with x or z assignments shall be permitted.

// Correct: IDLE=0, XX=’x, S1=1, S2=2
enum integer {IDLE, XX=’x, S1=’b01, S2=’b10} state, next;

An unassigned enumerated name that follows an enum name with x or z assignments shall be a syntax error.

// Syntax error: IDLE=0, XX=’x, S1=??, S2=??
enum integer {IDLE, XX=’x, S1, S2} state, next;




The values can be cast to integer types and increment from an initial value of 0. This can be overridden.

enum{bronze=3, silver, gold} medal; // silver=4, gold=5

Both the enumeration names and their integer values shall be unique. It shall be an error to set two values to the same name or to set the same value to two names, regardless of whether the values are set explicitly or by automatic incrementing.

// Error: c and d are both assigned 8
enum{a=0, b=7, c, d=8} alphabet;

If the first name is not assigned a value, it is given the initial value of 0.
// a=0, b=7, c=8
enum{a, b=7, c} alphabet;

Any enumeration encoding value that is outside the representable range of the enum base type shall be an error. If the integer value expression is a sized literal constant, it shall be an error if the size is different from the enum base type, even if the value is within the represent able range.

// Correct declaration - bronze and gold are unsized
enum bit [3:0] {bronze='h3, silver, gold='h5} medal2;

// Correct declaration - bronze and gold sizes are redundant
enum bit [3:0] {bronze=4'h3, silver, gold=4'h5} medal3;

// Error in the bronze and gold member declarations
enum bit [3:0] {bronze=5'h13, silver, gold=3'h5} medal4;

// Error in c declaration, requires at least 2 bits
enum bit [0:0] {a,b,c} alphabet;

2.6.1.  Enumerated type ranges

a)      name = C Associates the constant C to name.
b)     name[N] : Generates N named constants in the sequence: name0, name1,..., nameN-1. N shall be a positive integral number. name[N] = C Optionally, a constant can be assigned to the generated named constants to associate that constant to the first generated named constant; subsequent generated named constants are associated consecutive values.
c)      name[N:M] Creates a sequence of named constants starting with name N and incrementing or decrementing until reaching named constant name M. N and M shall be nonnegative integral numbers. name[N:M] = C Optionally, a constant can be assigned to the generated named constants to associate that constant to the first generated named constants; subsequent generated named constants are associated consecutive values.

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 named constant add. It also creates the enumerated named constants sub0, sub1, sub2, sub3, and sub4 and assigns them the values 11...15, respectively. Finally, the example creates the enumerated named constants jmp6, jmp7, and jmp8 and assigns them the values 16 through 18, respectively.

enum{ register[2] = 1, register[2:4] = 10 } vr;

The example above declares enumerated variable vr, which creates the enumerated named constants register0 and register1, which are assigned the values 1 and 2, respectively. Next, it creates the enumerated named constants register2, register3, and register4 and assigns them the values 10, 11 and 12.

Enumerated types are strongly typed; thus, a variable of type enum cannot be directly assigned a value that lies outside the enumeration set unless an explicit cast is used or unless the enum variable is a member of a union. This is a powerful type-checking aid, which prevents users from accidentally assigning nonexistent values to variables of an enumerated type.

Enumerated variables are type-checked in assignments, arguments, and relational operators. Enumerated variables are auto-cast into integral values, but assignment of arbitrary expressions to an enumerated variable requires an explicit cast.

Example14: Casting for enumerations

typedef enum { red, green, blue, yellow, white, black } Colors;
Colors c;
c = green;
c = 1; // Invalid assignment

if( 1 == c ) // OK. c is auto-cast to integer

In the example above, the value green is assigned to the variable c of type Colors. The second assignment is invalid because of the strict typing rules enforced by enumerated types.

Elements of enumerated type variables can be used in numerical expressions. The value used in the expression is the numerical value associated with the enumerated value.

Example15: Automatic type casting

typedef enum { red, green, blue, yellow, white, black } Colors;
Colors col;
integera, b;
a = blue * 3;
col = yellow;
b = col + green;

From the previous declaration, blue has the numerical value 2. This example assigns a the value of 6 (2*3), and it assigns b a value of 4 (3+1).

An enum variable or identifier used as part of an expression is automatically cast to the base type of the enum declaration (either explicitly or using int as the default). A cast shall be required for an expression that is assigned to an enum variable where the type of the expression is not equivalent to the enumeration type of the variable.
Casting to an enum type shall cause a conversion of the expression to its base type without checking the validity of the value.

typedef enum {Red, Green, Blue} Colors;
typedef enum {Mo,Tu,We,Th,Fr,Sa,Su} Week;
Colors C;
Week W;
intI;
C = Colors'(C+1); // C is converted to an integer, then added toone, then converted back to a Colors type.

C = C + 1; C++; C+=2; C = I; // Illegal because they would all be assignments of expressions without a cast.

C = Colors'(Su); // Legal; puts an out of range value into C

I = C + W; // Legal; C and W are automatically cast to int one, then converted back to a Colors type.

2.6.2.  Enumerated type methods:


a)      First()
The prototype for the first() method is as follows:
function enum first();
The first() method returns the value of the first member of the enumeration.
b)      Last()
The prototype for the last() method is as follows:
function enum last();
The last() method returns the value of the last member of the enumeration.
c)       Next()
The prototype for the next() method is as follows:
function enum next( int unsigned N = 1 );
The next() method returns the Nth next enumeration value (default is the next one) starting from the current value of the given variable. A wrap to the start of the enumeration occurs when the end of the enumeration is reached. If the given value is not a member of the enumeration, the next() method returns the default initial value for the enumeration.
d)      Prev()
The prototype for the prev() method is as follows:
function enum prev( int unsigned N = 1 );
The prev() method returns the Nth previous enumeration value (default is the previous one) starting from the current value of the given variable. A wrap to the end of the enumeration occurs when the start of the enumeration is reached. If the given value is not a member of the enumeration, the prev() method returns the default initial value for the enumeration.
e)       Num()
The prototype for the num() method is as follows:
function int num();
The num() method returns the number of elements in the given enumeration.
f)        Name()
The prototype for the name() method is as follows:
function string name();
The name() method returns the string representation of the given enumeration value. If the given value is not a member of the enumeration, the name() method returns the empty string.

Example16: Usage of enumerated type functions

typedef enum { red, green, blue, yellow } Colors;
Colors c = c.first;
forever begin
$display( "%s : %d\n", c.name, c );
if( c == c.last ) break;
c = c.next;
end

2.7.       Constants:

Constants are named data objects that never change. System Verilog provides three elaboration-time constants: parameter, localparam, and specparam. System Verilog also provides a run-time constant, const.
The parameter, localparam, and specparam constants are collectively referred to as parameter constants. Parameter constants can be initialized with a literal.

Example17: Declaration of parameter

localparam byte colon1 = ":" ;
specparamdelay = 10 ; // specparams are used for specify blocks
parameter logic flag = 1 ;

System Verilog provides four methods for setting the value of parameter constants. Each parameter may be assigned a default value when declared.
 The value of a parameter of an instantiated module, interface or program can be overridden in each instance using one of the following:
Ø  Assignment by ordered list (e.g., m #(value, value) u1 (...); ).
Ø  Assignment by name (e.g., m #(.param1(value), .param2(value)) u1 (...); ).
Ø  Defparam statements, using hierarchical path names to redefine each parameter.

The list_of_param_assignments can appear in a module, interface, program, class, or package or in the parameter_port_list of a module, interface, program, or class. If the declaration of a design element uses a parameter_port_list (even an empty one), then in any parameter_declaration directly contained within the declaration, the parameter keyword shall be a synonym for the localparam keyword.

 All param_assignments appearing within a class body shall become localparam declarations regardless of the presence or absence of a parameter_port_list. All param_assignments appearing within apackage shall become localparam declarations.
The parameter keyword can be omitted in a parameter port list.

Example18: Parameterized class, interface and module

classvector #(size = 1); // size is a parameter in a parameter port list
logic[size-1:0] v;
endclass

interfacesimple_bus #(AWIDTH = 64, type T = word) // parameter port list
(input logic clk) ; // port list
...
endinterface

modulemc #(int N = 5, M = N*16, type T = int, T x = 0)
…..
endmodule

In a list of parameter constants, a parameter can depend on earlier parameters. In the following declaration, the default value of the second parameter depends on the value of the first parameter. The third parameter is a type, and the fourth parameter is a value of that type.

In the declaration of a parameter in a parameter port list, the specification for its default value may be omitted, in which case the parameter shall have no default value. If no default value is specified for a parameter of a design element, then an overriding parameter value shall be specified in every instantiation of that design element. Also, if no default value is specified for a parameter of a design element, then a tool shall not implicitly instantiate that design element. If no default value is specified for a parameter of a class, then an overriding parameter value shall be specified in every specialization of that class.

2.7.1.  Value parameters:

A parameter constant can have a type specification and a range specification. The type and range of parameters shall be in accordance with the following rules:
Ø  A parameter declaration with no type or range specification shall default to the type and range of the final value assigned to the parameter, after any value overrides have been applied. If the expression is real, the parameter is real. If the expression is integral, the parameter is a logic vector of the same size with range [size-1:0].
Ø  A parameter with a range specification, but with no type specification, shall have the range of the parameter declaration and shall be unsigned. The sign and range shall not be affected by value overrides.
Ø  A parameter with a type specification, but with no range specification, shall be of the type specified. A signed parameter shall default to the range of the final value assigned to the parameter, after any value overrides have been applied.
Ø  A parameter with a signed type specification and with a range specification shall be signed and shall have the range of its declaration. The sign and range shall not be affected by value overrides.
Ø  A parameter with no range specification and with either a signed type specification or no type specification shall have an implied range with an lsb equal to 0 and an msb equal to one less than the size of the final value assigned to the parameter.

In an assignment to, or override of, a parameter with an explicit type declaration, the type of the right-hand expression shall be assignment compatible with the declared type. The conversion rules between real and integer values apply to parameters as well. A specparam can also be set to an expression containing one or more specparams.

Example19:summary of declaration of parameter
parametermsb = 7; // defines msb as a constant value 7
parametere = 25, f = 9; // defines two constant numbers
parameterr = 5.7; // declares r as a real parameter
parameter byte_size = 8,
byte_mask = byte_size - 1;
parameter average_delay = (r + f) / 2;
parameter signed [3:0] mux_selector = 0;
parameter real r1 = 3.5e17;
parameter p1 = 13'h7e;
parameter [31:0] dec_const = 1'b1; // value converted to 32 bits
parameter newconst = 3'h4; // implied range of [2:0]
parameter newconst = 4; // implied range of at least [31:0]
parameter logic [31:0] P1 [3:0] = '{ 1, 2, 3, 4 } ; // unpacked array parameter declaration

A parameter can also be declared as an aggregate type, such as an unpacked array or an unpacked structure. An aggregate parameter must be assigned to or overridden as a whole; individual members of an aggregate parameter may not be assigned or overridden separately. However, an individual member of an aggregate parameter may be used in an expression.

Example20: Usage of defparm

moduletop;

logic lk;
logic [0:4] in1;
logic [0:9] in2;
wire [0:4] o1;
wire [0:9] o2;
vdff m1 (o1, in1, clk);
vdff m2 (o2, in2, clk);
endmodule
module vdff (out, in, clk);
parameter size = 1, delay = 1;
input [0:size-1] in;
input clk;
output [0:size-1] out;
logic[0:size-1] out;
always@(posedge clk)
# delay out = in;
endmodule
module annotate;
defparam
top.m1.size = 5,
top.m1.delay = 10,
top.m2.size = 10,
top.m2.delay = 20;
endmodule

The module annotate has the defparam statement, which overrides size and delay parameter values for instances m1 and m2 in the top-level module top. The modules top and annotate would both be considered top-level modules.

Local parameters are identical to parameters except that they cannot directly be modified by defparam Statements or instance parameter value assignments. Local parameters can be assigned constant expressions containing parameters, which in turn can be modified with defparam statements or instance parameter value assignments. Local parameters may be declared in a module’s parameter_port_list.

The keyword specparam declares a special type of parameter that is intended only for providing timing and delay values, but can appear in any expression that is not assigned to a parameter and is not part of the range specification of a declaration. Specify parameters (also called specparams) are permitted both within the specify block and in the main module body.

A specify parameter declared outside a specify block shall be declared before it is referenced. The value assigned to a specify parameter can be any constant expression. A specify parameter can be used as part of a constant expression for a subsequent specify parameter declaration. Unlike the parameter constant, a specify parameter cannot be modified from within the language, but it can be modified through SDF annotation

moduleRAM16GEN ( output[7:0] DOUT,
input [7:0] DIN,
input [5:0] ADR,
input WE, CE);
specparam dhold = 1.0;
specparam ddly = 1.0;
parameter width = 1;
parameter regsize = dhold + 1.0; // Illegal - cannot assign specparams to parameters
endmodule

2.8.       Const constants

A const form of constant differs from a localparam constant in that the localparam shall be set during elaboration, whereas a const can be set during simulation, such as in an automatic task.
A static constant declared with the const keyword can be set to an expression of literals, parameters, local parameters, genvars, enumerated names, a constant function of these, or other constants. Hierarchical names are allowed because constants declared with the const keyword are calculated after elaboration.

const logic option = a.b.c ;

An instance of a class (an object handle) can also be declared with the const keyword.
Const class_name object = new(5,3);




2.9.       Scope and lifetime of Variables

Variables declared outside a module, program, interface, checker, task or functions are local to the compilation unit and have a static lifetime (exist for the whole simulation). This is roughly equivalent to C static variables declared outside a function, which are local to a file.

Variables declared inside a module, interface, program, or checker, but outside a task, process, or function, are local in scope and have a static lifetime.

Variables declared inside a static task, function, or block are local in scope and default to a static life time. Specific variables within a static task, function, or block can be explicitly declared as automatic. Such variables have the lifetime of the call or block and are initialized on each entry to the call or block. This is roughly equivalent to a C automatic variable.

Tasks and functions may be declared as automatic. Variables declared in an automatic task, function, or block are local in scope, default to the lifetime of the call or block and are initialized on each entry to the call or block.

 An automatic block is one in which declarations are automatic by default. Specific variables within an automatic task, function, or block can be explicitly declared as static. Such variables have a static lifetime. This is roughly equivalent to C static variables declared within a function.

The lifetime of a fork-join block shall encompass the execution of all processes spawned by the block. The lifetime of a scope enclosing any fork-join block includes the lifetime of the fork-join block.

Example21: lifetime of variables in module

Module msl;
intst0; // static
initial begin
intst1; // static
static int st2; // static
automatic int auto1; // automatic
end
task automatic t1();
intauto2; // automatic
static int st3; // static
automatic int auto3; // automatic
endtask
endmodule

Variables declared in a static task, function, or procedural block default to a static lifetime and a local scope. However, an explicit static keyword shall be required when an initialization value is specified as part of a static variable’s declaration to indicate the user’s intent of executing that initialization only once at the beginning of simulation. The static keyword shall be optional where it would not be legal to declare the variables as automatic.
Example22: lifetime of variables in for loops
module top_legal;
int svar1 = 1; // static keyword optional
initial begin
for(int i=0; i<3; i++) begin
automatic int loop3 = 0; // executes every loop
for(int j=0; j<3; j++) begin
loop3++;
$display(loop3);
end
end// prints 1 2 3 1 2 3 1 2 3
for(int i=0; i<3; i++) begin
static int loop2 = 0; // executes once before time 0
for(int j=0; j<3; j++) begin
loop2++;
$display(loop2);
end
end// prints 1 2 3 4 5 6 7 8 9
end
endmodule : top_legal

module top_illegal; // should not compile
initial begin
int svar2 = 2; // static/automatic needed to show intent
for(int i=0; i<3; i++) begin
intloop3 = 0; // illegal statement
for(int i=0; i<3; i++) begin
loop3++;
$display(loop3);
end
end
end
endmodule : top_illegal

An optional qualifier can be used to specify the default lifetime of all variables declared in a task, function, or block defined within a module, interface, package, or program. The lifetime qualifier is automatic or static. The default lifetime is static.

Example23:lifetime of variables in program block
program automatic test ;
inti; // not within a procedural block - static
taskt ( int a ); // arguments and variables in t are automatic
... // unless explicitly declared static
endtask
endprogram

Class methods and declared for loop variables are by default automatic, regardless of the lifetime attribute of the scope in which they are declared.
Automatic variables and members or elements of dynamic variables—class properties and dynamically sized variables—shall not be written with nonblocking, continuous, or procedural continuous assignments. References to automatic variables and elements or members of dynamic variables shall be limited to procedural blocks.

2.10. Casting:

A data type can be changed by using a cast ( ) operation. In a static cast, the expression to be cast shall be enclosed in parentheses that are prefixed with the casting type and an apostrophe. If the expression is assignment compatible with the casting type, then the cast shall return the value that a variable of the casting type would hold after being assigned the expression.

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

Thus, in the following example, if expressions expr_1 and expr_2 are assignment compatible with data types cast_t1 and cast_t2, respectively, then

A = cast_t1'(expr_1) + cast_t2'(expr_2);

If the casting type is a constant expression with a positive integral value, the expression in parentheses shall be padded or truncated to the size specified. It shall be an error if the size specified is zero or negative.

Examples24:casting for parameters

17’(x - 2)

parameterP = 16;
(P+1)’(x – 2)

The signedness can also be changed.
signed’(x)





2.11. Structures

A structure represents a collection of data types that can be referenced as a whole, or the individual data types that make up the structure can be referenced by name. By default, structures are unpacked, meaning that there is an implementation-dependent packing of the data types. Unpacked structures can contain any data type.
Structure declarations follow the C syntax, but without the optional structure tags before the ‘{’.

Example25: Declaring of unpacked structures

struct {bit [7:0] opcode; bit [23:0] addr; }IR; // anonymous structure defines variable IR
IR.opcode = 1; // set field in IR.
typedef struct {
bit[7:0] opcode;
bit[23:0] addr;
} instruction; // named structure type
instruction IR; // define variable

2.11.1.        Packed structures

A packed structure is a mechanism for subdividing a vector into subfields, which can be conveniently accessed as members. Consequently, a packed structure consists of bit fields, which are packed together in memory without gaps. An unpacked structure has an implementation-dependent packing. A packed structure differs from an unpacked structure in that, when a packed structure appears as a primary, it shall be treated as a single vector.
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 keyword, according to the desired arithmetic behavior. The default is unsigned.

Example26: Declaring of packed structures
struct packed signed {
inta;
shortintb;
bytec;
bit[7:0] d;
} pack1; // signed, 2-state

struct packed unsigned {
timea;
integerb;
logic[31:0] c;
} pack2; // unsigned, 4-state

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

Example27: Declaring of unpacked structures (illegal)

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

If all data types within a packed structure are 2-state, the structure as a whole is treated as a 2-state vector. If any data type within a packed structure is 4-state, the structure as a whole is treated as a 4-state vector. If there are also 2-state members in the structure, there is an implicit conversion from 4-state to 2-state when reading those members and from 2-state to 4-state when writing them. Only packed data types and the integer data types shall be legal in packed structures. 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 structure can be assigned as a whole and passed to or from a subroutine as a whole. Members of a structure data type can be assigned individual default member values by using an initial assignment with the declaration of each member. The assigned expression shall be a constant expression. An example of initializing members of a structure type is as follows:

typedef struct {
intaddr = 1 + constant;
intcrc;
bytedata [4] = '{4{1}};
} packet1;

The structure can then be instantiated.
packet1 p1; // initialization defined by the typedef. p1.crc will use the default value for an int

If an explicit initial value expression is used with the declaration of a variable, the initial assignment expression within the structure data type shall be ignored.
packet1 pi = '{1,2,'{2,3,4,5}}; //suppresses the typedef initialization

2.12. Unions

A union is a data type that represents a single piece of storage which can be accessed using one of the named member data types. Only one of the data types in the union can be used at a time.

Example28: Declaration of union

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

typedef struct {
bitisfloat;
union{int i; shortreal f; } n; // anonymous union type
} tagged_st; // named structure

If no initial value is specified in the declaration of a variable of an unpacked union type, then the variable shall be initialized to the default initial value for variables of the type of the first member in declaration order of the union type.

2.12.1.                    Packed unions

Packed unions shall only contain members that are of integral data types. 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. One or more bits of a packed union can be selected as if it were a packed array with the range [n-1:0].Only packed data types and the integer data types shall be legal in packed unions.

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:

Example28: Declaring of packed unions

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;
byteb; 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;

With packed unions, writing one member and reading another is independent of the byte ordering of the machine, unlike an unpacked union of unpacked structures, which are C-compatible and have members in ascending address order.

2.12.2.                    Tagged unions

The qualifier tagged in a union declares it as a tagged union, which is a type-checked union. An ordinary (untagged) union can be updated using a value of one member type and read as a value of another member type, which is a potential type loophole. A tagged union stores both the member value and a tag, i.e., additional bits representing the current member name. The tag and value can only be updated together consistently using a statically type-checked tagged union expression. The member value can only be read with a type that is consistent with the current tag value (i.e., member name). Thus, it is impossible to store a value of one type and (mis)interpret the bits as another type.

Example29: Creation of tagged unions

typedef union tagged {
struct{
bit[4:0] reg1, reg2, regd;
} Add;
union tagged {
bit[9:0] JmpU;
struct{
bit[1:0] cc;
bit[9:0] addr;
} JmpC;
} Jmp;
} Instr;

A value of Instr type is either an Add instruction, in which case it contains three 5-bit register fields, or it is a Jmp instruction. In the latter case, it is either an unconditional jump, in which case it contains a 10-bit destination address, or it is a conditional jump, in which case it contains a 2-bit condition-code register field and a 10-bit destination address.



Ø  The size is always equal to the number of bits needed to represent the tag plus the maximum of thesizes of the members.
Ø  The size of the tag is the minimum number of bits needed to code for all the member names (e.g.,five to eight members would need 3 tag bits).
Ø  The tag bits are always left-justified (i.e., towards the MSBs).
Ø  For each member, the member bits are always right-justified [i.e., towards the least significant bits(LSBs)].
Ø  The bits between the tag bits and the member bits are undefined. In the extreme case of a void member,only the tag is significant and all the remaining bits are undefined.

2.13. Packed and unpacked arrays

System Verilog supports both packed arrays and unpacked arrays of data. The term packed array is used to refer to the dimensions declared before the data identifier name. The term unpacked array is used to refer to the dimensions declared after the data identifier name.

bit[7:0] c1; // packed array of scalar bit types
realu [7:0]; // unpacked array of real types

2.13.1.        Packed arrays

A packed array is a mechanism for subdividing a vector into subfields, which can be conveniently accessed as array elements. Consequently, a packed array is guaranteed to be represented as a contiguous set of bits. An unpacked array may or may not be so represented. A packed array differs from an unpacked array in that, when a packed array appears as a primary, it is treated as a single vector.

Packed arrays can be made of only the single bit data types (bit, logic, reg), enumerated types, and recursively other packed arrays and packed structures. Integer types with predefined widths shall not have packed array dimensions declared. These types are byte, shortint, int, longint, integer, and time. Although an integer type with a predefined width n is not a packed array, it matches, and can be selected from as if it were, a packed array type with a single [n-1:0] dimension.

bytec2; // same as bit signed [7:0] c2;
integeri1; // same as logic signed [31:0] i1;

2.13.2.        Unpacked arrays

Unpacked arrays can be made of any data type. Arrays whose elements are themselves arrays are declared as multidimensional arrays. Unpacked arrays shall be declared by specifying the element address range(s) after the declared identifier.
Elements of net arrays can be used in the same fashion as a scalar or vector net. Net arrays are useful for connecting to ports of module instances inside loop generate constructs.

Each fixed-size dimension shall be represented by an address range, such as [1:1024], or a single positive number to specify the size of a fixed-size unpacked array, as in C. In other words, [size] becomes the same as [0:size-1]. The following examples declare equivalent size two-dimensional fixed-size arrays of int variables:

Int Array[0:7][0:31]; // array declaration using ranges
Int Array[8][32]; // array declaration using sizes

The expressions that specify an address range shall be constant integer expressions. The value of the constant expression can be a positive integer, a negative integer, or zero. It shall be illegal for them to contain any unknown (x) or high-impedance bits.

2.13.3.        Operations on arrays

The following operations can be performed on all arrays, packed or unpacked. The examples provided with these rules assume that A and B are arrays of the same shape and type.

Ø  Reading and writing the array, e.g., A = B
Ø  Reading and writing a slice of the array, e.g., A[i:j] = B[i:j]
Ø  Reading and writing a variable slice of the array, e.g., A[x+:c] = B[y+:c]
Ø  Reading and writing an element of the array, e.g., A[i] = B[i]
Ø  Equality operations on the array or slice of the array, e.g., A==B, A[i:j] != B[i:j]

The following operations can be performed on packed arrays, but not on unpacked arrays. The examples provided with these rules assume that A is an array.

Ø  Assignment from an integer, e.g., A = 8’b11111111;
Ø  Treatment as an integer in an expression, e.g., (A + 3)

If an unpacked array is declared as signed, then this applies to the individual elements of the array because the whole array cannot be viewed as a single vector.

2.13.4.        Memories

A one-dimensional array with elements of typesreg, logic or bit is also called a memory. Memory arrays can be used to model read-only memories (ROMs), random access memories (RAMs), and register files. An element of the packed dimension in the array is known as a memory element or word.

logic[7:0] mema [0:255]; // declares a memory array of 256 8-bit elements. The array indices are 0 to 255
mema[5] = 0; // Write to word at address 5
data = mema[addr]; // Read word at address indexed by addr

2.13.5.        Multidimensional arrays

A multidimensional array is an array of arrays. Multidimensional arrays can be declared by including multiple dimensions in a single declaration. The dimensions preceding the identifier set the packed dimensions. The dimensions following the identifier set the unpacked dimensions.

bit[3:0] [7:0] joe [1:10]; // 10 elements of 4 8-bit bytes (each element packed into 32 bits) can be used as follows:
joe[9] = joe[8] + 1; // 4 byte add
joe[7][3:2] = joe[6][1:0]; // 2 byte copy



Multiple unpacked dimensions can also be defined in stages with typedef.

typedefbsix mem_type [0:3]; // array of four ’bsix’ elements
mem_type ba [0:7]; // array of eight ’mem_type’ elements

A subarray is an array that is an element of another array. Omitting indices for all the dimensions references the entire array.

intA[2][3][4], B[2][3][4], C[5][4];
...
A[0][2] = B[1][1]; // assign a subarray composed of four ints
A[1] = B[0]; // assign a subarray composed of three arrays of  four ints each
A = B; // assign an entire array
A[0][1] = C[4]; // assign compatible subarray of four ints

A comma-separated list of array declarations can be specified. All arrays in the list shall have the same data type and the same packed array dimensions.

bit[7:0] [31:0] v7 [1:5] [1:10], v8 [0:255]; // two arrays declared

2.13.6.        Indexing and slicing of arrays

An expression can select part of a packed array, or any integer type, which is assumed to be numbered down to 0.The term part-selectrefers to a selection of one or more contiguous bits of a single-dimension packed array.


logic[63:0] data;
logic[7:0] byte2;
byte2 = data[23:16]; // an 8-bit part-select from data

A single element of a packed or unpacked array can be selected using an indexed name.

bit[3:0] [7:0] j; // j is a packed array
bytek;
k = j[2]; // select a single 8-bit element from j





One or more contiguous elements can be selected using a slice name. A slice name of a packed array is a packed array. A slice name of an unpacked array is an unpacked array.

bit signed [31:0] busA [7:0] ; // unpacked array of 8 32-bit vectors
intbusB [1:0]; // unpacked array of 2 integers
busB = busA[7:6]; // select a 2-vector slice from busA
The size of the part-select or slice shall be constant, but the position can be variable.
inti = bitvec[j +: k]; // k must be constant.
inta[x:y], b[y:z], e;
a = {b[c -: d], e}; // d must be constant
Slices of an array can only apply to one dimension, but other dimensions can have single index values in anexpression.

2.13.7.        Dynamic arrays

A dynamic array is an unpacked array whose size can be set or changed at run time. The default size of an uninitialized dynamic array is zero. The size of a dynamic array is set by the new constructor or array assignmentrespectively. Dynamic arrays support all variable data types as element types, including arrays.
Dynamic array dimensions are denoted in the array declaration by [ ]. Any unpacked dimension in an array declaration may be a dynamic array dimension.

For example:
bit[3:0] nibble[]; // Dynamic array of 4-bit vectors
integer mem[2][]; // Fixed-size unpacked array composed of 2 dynamic subarrays of integers

Note that in order for an identifier to represent a dynamic array, it must be declared with a dynamic array dimension as the leftmost unpacked dimension.

The new constructor sets the size of a dynamic array and initializes its elements. It may appear in place of the right-hand side expression of variable declaration assignments and blocking procedural assignments when the left-hand side indicates a dynamic array.

The new constructor follows the System Verilog precedence rules. Because both the square brackets [] and the parenthesis () have the same precedence, the arguments to the new constructor are evaluated left to right: [ expression] first, and ( expression ) second.
Dynamic array declarations may include a declaration assignment with the new constructor as the right-hand side:

intarr1 [][2][3] = new [4]; // arr1 sized to length 4; elements are  fixed-size arrays and so do not require initializing
intarr2 [][] = new [4]; // arr2 sized to length 4; dynamic subarrays remain unsized and uninitialized
intarr3 [1][2][] = new [4]; // Error – arr3 is not a dynamic array, though it contains dynamic subarrays.

Dynamic arrays may be initialized in procedural contexts using the new constructor in blocking
assignments:

intarr[2][][];
arr[0] = new [4]; // dynamic subarray arr[0] sized to length 4
arr[0][0] = new [2]; // legal, arr[0][n] created above for n = 0..3
arr[1][0] = new [2]; // illegal, arr[1] not initialized so arr[1][0] does not exist
arr[0][] = new [2]; // illegal, syntax error - dimension without subscript on left hand side
arr[0][1][1] = new[2]; // illegal, arr[0][1][1] is an int, not a dynamic array



The optional initialization expression is used to initialize the dynamic array. When present, it shall be an array that is assignment-compatible with the left-hand-side dynamic array.

Int idest[], isrc[3] = '{5, 6, 7};
idest = new [3] (isrc); // set size and array element data values (5, 6, 7)

The size argument need not match the size of the initialization array. When the initialization array’s size is greater, it is truncated to match the size argument; when it is smaller, the initialized array is padded with default values to attain the specified size.

Int src[], dest1[], dest2[];
src = new [3] ('{2, 3, 4});
dest1 = new[2] (src); // dest1’s elements are {2, 3}.
dest2 = new[4] (src); // dest1’s elements are {2, 3, 4, 0}.

This behavior provides a mechanism for resizing a dynamic array while preserving its contents. An existing dynamic array can be resized by using it both as the left-hand side term and the initialization expression.

integeraddr[]; // Declare the dynamic array.
addr = new[100]; // Create a 100-element array.
...
// Double the array size, preserving previous values.
// Preexisting references to elements of addr are outdated.
addr = new[200](addr);

Resizing or reinitializing a previously-initialized dynamic array using new is destructive; no preexistingarray data is preserved, and all preexisting referencesto array elements become outdated.

2.13.8.        Array functions:


a)      Size()

The prototype for the size() method is as follows:

function int size();

The size() method returns the current size of a dynamic array or returns zero if the array has not beencreated.

intj = addr.size;
addr = new[ addr.size() * 4 ] (addr); // quadruple addr array


b)     Delete()

The prototype for the delete() method is as follows:

function void delete();

The delete() method empties the array, resulting in a zero-sized array.

intab [] = new[ N ]; // create a temporary array of size N

// use ab
ab.delete; // delete the array contents
$display( "%d", ab.size ); // prints 0

2.14. Associative arrays

Dynamic arrays are useful for dealing with contiguous collections of variables whose number changes dynamically. When the size of the collection is unknown or the data space is sparse, an associative array is a better option. Associative arrays do not have any storage allocated until it is used, and the index expression is not restricted to integral expressions, but can be of any type.
An associative array implements a lookup table of the elements of its declared type. The data type to be used as an index serves as the lookup key and imposes an ordering.
The syntax to declare an associative array is as follows:

data_type array_id [ index_type ];

Where data_type is the data type of the array elements. Can be any type allowed for fixed-size arrays.array_id is the name of the array being declared. index_type is the data-type to be used as an index or is *. If * is specified, then the array is indexed by any integral expression of arbitrary size. An index type restricts the indexing expressions to a particular type. It shall be illegal for index_type to declare a type.

Examples of associative array declarations are as follows:
integeri_array[*]; // associative array of integer (unspecified  index)
bit[20:0] array_b[string]; // associative array of 21-bit vector, indexed by string

Array elements in associative arrays are allocated dynamically; an entry is created the first time it is written. The associative array maintains the entries that have been assigned values and their relative order according to the index data type. Associative array elements are unpacked. In other words, other than for copying or comparing arrays, an individual element must be selected out of the array before it can be used in most expressions.



2.14.1.        Wildcard index type

For example:
intarray_name [*];

Associative arrays that specify a wildcard index type have the following properties:
Ø  The array may be indexed by any integral expression. Because the index expressions may be of different sizes, the same numerical value can have multiple representations, each of a different size. SystemVerilog resolves this ambiguity by removing the leading zeros and computing the minimal length and using that representation for the value.
Ø  Non integral index values are illegal and result in an error.

A 4-state index value containing X or Z is invalid. Indexing expressions are self-determined and treated as unsigned. A string literal index is automatically cast to a bit vector of equivalent size. The ordering is numerical (smallest to largest).
Associative arrays that specify a wildcard index type shall not be used in a foreach loop or with an array manipulation method that returns an index value or array of values.

2.14.2.        String index

For example:
intarray_name [ string];

Associative arrays that specify a string index have the following properties:
Ø  Indices can be strings or string literals of any length. Other types are illegal and shall result in a typecheck error.
Ø  An empty string “” index is valid.
Ø  The ordering is lexicographical (lesser to greater).

2.14.3.        Integral index

For example:
intarray_name1 [ integer];
typedef bit signed [4:1] SNibble;
intarray_name2 [ SNibble ];
typedef bit [4:1] UNibble;
intarray_name3 [ UNibble ];

Associative arrays that specify an index of integral data type shall have the following properties:
Ø  The index expression shall be evaluated in terms of a cast to the index type, except that an implicit cast from a real or shortreal data type shall be illegal.
Ø  A 4-state index expression containing X or Z is invalid.
Ø  The ordering is signed or unsigned numerical, depending on the signedness of the index type.

2.14.4.        Associative array methods

In addition to the indexing operators, several built-in methods are provided, which allow users to analyze and manipulate associative arrays, as well as iterate over its indices or keys.

a)      Num() and size()
The syntax for the num() and size() methods is as follows:
function int num();
function int size();
The num() and size() methods return the number of entries in the associative array. If the array is empty, they return 0.

Int imem[int];
imem[ 2’b3 ] = 1;
imem[ 16’hffff ] = 2;
imem[ 4b’1000 ] = 3;
$display( "%0d entries\n", imem.num ); // prints "3 entries"

b)     Delete()

The syntax for the delete() method is as follows:
function void delete( [input index] );
where index is an optional index of the appropriate type for the array in question.
If the index is specified, then the delete() method removes the entry at the specified index. If the entry to be deleted does not exist, the method issues no warning.
If the index is not specified, then the delete() method removes all the elements in the array.

intmap[string ];
map[ "hello" ] = 1;
map[ "sad" ] = 2;
map[ "world" ] = 3;
map.delete( "sad" ); // remove entry whose index is "sad" from "map"
map.delete; // remove all entries from the associative array "map"

c)      Exists()

The syntax for the exists() method is as follows:
function int exists( input index );
where index is an index of the appropriate type for the array in question.
The exists() function checks whether an element exists at the specified index within the given array. It returns 1 if the element exists; otherwise, it returns 0.

if( map.exists( "hello" ))
map[ "hello" ] += 1;
else
map[ "hello" ] = 0;

d)     First()

The syntax for the first() method is as follows:
function int first( ref index );
where index is an index of the appropriate type for the array in question. Associative arrays that specify awildcard index type shall not be allowed. The first() method assigns to the given index variable the value of the first (smallest) index in the associative array. It returns 0 if the array is empty; otherwise, it returns 1.

strings;
if( map.first( s ) )
$display( "First entry is : map[ %s ] = %0d\n", s, map[s] );

e)      Last()

The syntax for the last() method is as follows:
function int last( ref index );

where index is an index of the appropriate type for the array in question. Associative arrays that specify a wildcard index type shall not be allowed. The last() method assigns to the given index variable the value of the last (largest) index in the associative array. It returns 0 if the array is empty; otherwise, it returns 1.
strings;
if( map.last( s ) )
$display( "Last entry is : map[ %s ] = %0d\n", s, map[s] );


f)       Next()

The syntax for the next() method is as follows:
function int next( ref index );
where index is an index of the appropriate type for the array in question. Associative arrays that specify a wildcard index type shall not be allowed. The next() method finds the smallest index whose value is greater than the given index argument. If there is a next entry, the index variable is assigned the index of the next entry, and the function returns 1. Otherwise, the index is unchanged, and the function returns 0.

strings;
if( map.first( s ) )
do
$display( "%s : %d\n", s, map[ s ] );
while( map.next( s ) );

g)      Prev()

The syntax for the prev() method is as follows:

function int prev( ref index );
where index is an index of the appropriate type for the array in question. Associative arrays that specify a
wildcard index type shall not be allowed. The prev() function finds the largest index whose value is smaller than the given index argument. If there is a previous entry, the index variable is assigned the index of the previous entry, and the function returns 1. Otherwise, the index is unchanged, and the function returns 0.

strings;
if( map.last( s ) )
do
$display( "%s : %d\n", s, map[ s ] );
while( map.prev( s ) );

2.15. Queues:

A queue is a variable-size, ordered collection of homogeneous elements. A queue supports constant-time access to all its elements as well as constant-time insertion and removal at the beginning or the end of the queue. Each element in a queue is identified by an ordinal number that represents its position within the queue, with 0 representing the first, and $ representing the last. A queue is analogous to a one-dimensional unpacked array that grows and shrinks automatically. Thus, like arrays, queues can be manipulated using the indexing, concatenation, slicing operator syntax, and equality operators.
Queues are declared using the same syntax as unpacked arrays, but specifying $ as the array size.
The maximum size of a queue can be limited by specifying its optional right bound (last index).Queue values may be written using assignment patterns or unpacked array concatenations.




For example:
Byte q1[$]; // A queue of bytes
string names[$] = { "Bob" }; // A queue of strings with one element
integer Q[$] = { 3, 2, 7 }; // An initialized queue of integers
bitq2[$:255]; // A queue whose maximum size is 256 bits

The empty array literal {} is used to denote an empty queue. If an initial value is not provided in the declaration, the queue variable is initialized to the empty queue.

2.15.1.        Queue operators

Queues shall support the same operations that can be performed on unpacked arrays. In addition, queues shall support the following operations:

Ø  A queue shall resize itself to accommodate any queue value that is written to it, except that its maximum size may be bounded.
Ø  In a queue slice expression such as Q[a:b], the slice bounds may be arbitrary integral expressions and, in particular, are not required to be constant expressions.
Ø  Unlike arrays, the empty queue, {}, is a valid queue and the result of some queue operations. The following rules govern queue operators:
v  Q[ a : b ] yields a queue with b - a + 1 elements.
v  If a > b, then Q[a:b] yields the empty queue {}.
v  Q[ n : n ] yields a queue with one item, the one at position n. Thus, Q[ n : n ] === {Q[n] }.
v  If n lies outside Q’s range (n < 0 or n > $), then Q[n:n] yields the empty queue {}.
v  If either a or b are 4-state expressions containing X or Z values, it yields the empty queue {}.
v  Q[ a : b ] where a < 0 is the same as Q[ 0 : b ].
v  Q[ a : b ] where b > $ is the same as Q[ a : $ ].
v  An invalid index value (i.e., a 4-state expression with X’s or Z’s, or a value that lies outside 0...$)shall cause a read operation (e = Q[n]) to return the default initial value for the type of queue item
v  An invalid index (i.e., a 4-state expression with X’s or Z’s, or a value that lies outside 0...$+1) shallcause a write operation to be ignored and a run-time warning to be issued; however, writing toQ[$+1] is legal.

2.15.2.        Queue methods

In addition to the array operators, queues provide several built-in methods. Assume these declarations for the examples that follow:

Typedef mytype element_t; // mytype is any legal type for a queue
Typedef element_t queue_t[$];
element_t e;
queue_t Q;
inti;

a)      Size()
The prototype for the size() method is as follows:
function int size();

The size() method returns the number of items in the queue. If the queue is empty, it returns 0.
for(int j = 0; j < Q.size; j++ ) $display( Q[j] );

b)     Insert()

The prototype of the insert() method is as follows:
function void insert(input int index, input element_t item);

The insert() method inserts the given item at the specified index position.

c)      Delete()

The syntax for the delete() method is as follows:
function void delete( [int index] );

where index is an optional index.
If the index is specified, then the delete() method deletes the item at the specified index position.
If the index is not specified, then the delete() method deletes all the elements in the queue, leaving the queue empty.

d)     Pop_front()

The prototype of the pop_front() method is as follows:
Function element_t pop_front();
The pop_front() method removes and returns the first element of the queue.

e)      Pop_back()

The prototype of the pop_back() method is as follows:
Function element_t pop_back();
The pop_back() method removes and returns the last element of the queue.

f)       Push_front()

The prototype of the push_front() method is as follows:
function void push_front(input element_t item);
The push_front() method inserts the given element at the front of the queue.

g)      Push_back()

The prototype of the push_back() method is as follows:
function void push_back(input element_t item);
The push_back() method inserts the given element at the end of the queue.

Example illustrating the queue functions:

intq[$] = { 2, 4, 8 };
inte, pos, junk;
// assignment // method call yielding the
// // same value in variable q
// ----------------------------- // -------------------------
q = { q, 6 }; // q.push_back(6)
q = { e, q }; // q.push_front(e)
q = q[1:$]; // q.pop_front(junk) or q.delete(0)
q = q[0:$-1]; // q.pop_back(junk) or q.delete(q.size-1)
q = { q[0:pos-1], e, q[pos:$] }; // q.insert(pos, e)
q = { q[0:pos], e, q[pos+1:$] }; // q.insert(pos+1, e)
q = {}; // q.delete()

Some useful operations that cannot be implemented as a single queue method call are illustrated in the following examples. As in the examples above, assignment to the queue variable outdates any reference to its elements.

q = q[2:$]; // a new queue lacking the first two items
q = q[1:$-1]; // a new queue lacking the first and last items

2.16. Operators

Operators are single-, double-, or triple-character sequences and are used in expressions. Unary operators shall appear to the left of their operand. Binary operators shall appear between their operands.
A conditional operator shall have two operator characters that separate three operands.
List of all the operators supported in System Verilog has been given in the table

Table 2: Overall operators

In addition to the simple assignment operator, =, SystemVerilog includes the C assignment operators and special bitwise assignment operators: 
+=,
 -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, <<<=,>>>=. 

An assignment operator is semantically equivalent to a blocking assignment, with the exception that any left-hand side index expression is only evaluated once. 

For example: a
[i]+=2; // same as a[i] = a[i] +2; 

Following are the new SystemVerilog assignment operators and its equivalent in Verilog


Assignments in expressions:

In SystemVerilog, an expression can include a blocking assignment. such an assignment must be enclosed in parentheses to avoid common mistakes such as using a=b for a==b, or a|=b for a!=b.
if(a=b) // error in systemverilog
(a=b) statement assigns ‘b’ value to ‘a’ and then returns ‘a’ value. 

if((a=b))           // isequivalentto
a=b; 
if(a) 

2.16.2.        Concatenation


{} concatenation right of assignment. 
´{} concatenation left of assignment. 

A concatenation is the result of the joining together of bits resulting from one or more expressions. The concatenation shall be expressed using the brace characters ‘{’ and ‘}’, with commas separating the expressions within.
Unsized constant numbers shall not be allowed in concatenations. This is because the size of each operand inthe concatenation is needed to calculate the complete size of the concatenation.
The concatenation is treated as a packed vector of bits. It can be used on the left-hand side of an assignmentor in an expression.
Example:
logiclog1, log2, log3;
{log1, log2, log3} = 3’b111;
{log1, log2, log3} = {1’b1, 1’b1, 1’b1}; // same effect as 3’b111



# >>= <<= relational






The different types of equality (and inequality) operators in SystemVerilog behave differently when their operands contain unknown values (X or Z). The == and != operators may result in X if any of their operands contains an X or Z. The === and !== check the 4-state explicitly, therefore, X and Z values shall either match or mismatch, never resulting in X. The ==? and !=? operators may result in X if the left operand contains an X or Z that is not being comparedwith a wildcardin the right operand.           




SystemVerilog added two new logical operators logical implication (->), and logical equivalence (<->). The logical implication expression1 -> expression2 is logically equivalent to (!expression1 || expression2), and the logical equivalence expression1 <-> expression2 is logically equivalent to ((expression1 -> expression2) && (expression2 -> expression1)). 





 

In System Verilog, bitwise exclusive nor has two notations (~^ and ^~). 
The bitwise operators shall perform bitwise manipulations on the operands; that is, the operator shall combinea bit in one operand with its corresponding bit in the other operand to calculate 1 bit for the result.






The unary reduction operators shall perform a bitwise operation on a single operand to produce a single-bit result.

2.16.9.        Shift Operators:




The left shift operators, << and <<<, shall shift their left operand to the left by the number by the number of bit positions given by the right operand. In both cases, the vacated bit positions shall be filled with zeros. The right shift operators, >> and >>>, shall shift their left operand to the right by the number of bit positions given by the right operand. The logical right shift shall fill the vacated bit positions with zeros. The arithmetic right shift shall fill the vacated bit positions with zeros if the result type is unsigned. It shall fill the vacated bit positions with the value of the most significant (i.e., sign) bit of the left operand if the result type is signed. If the right operand has an x or z value, then the result shall be unknown. The right operand is always treated.
 ++ increment
 -- decrement
SystemVerilog includes the C increment and decrement assignment operators ++i, --i, i++, and i--. These do not need parentheses when used in expressions. These increment and decrement assignment operators behave as blocking assignments.

2.16.11.   Set

# inside !inside dist 

SystemVerilog supports singular value sets and set membership operators. 

The syntax for the set membership operator is: 
inside_expression ::= expression inside { open_range_list } 

The expression on the left-hand side of the inside operator is any singular expression. The set-membership open_range_list on the right-hand side of the inside operator is a comma-separated list of expressions or ranges. Values can be repeated, so values and value ranges can overlap. The order of evaluation of the expressions and ranges is non-deterministic. 

2.16.12.   Operator presidency

o   () Highest precedence 
o   ++ -- 
o   & ~& | ~| ^ ~^ ~ >< - 
o   (unary) 
o   * / % 
o   + - 
o   <<>> 
o   <<= >>= in !in dist 
o   =?= !?= == != === !== 
o   &&~ 
o   ^ ^~ 
o   | |~ 
o   && 
o   || 
o   ?: 
o   = += -= *= /= %= 

o   <<= >>= &= |= ^= ~&= ~|= ~^= Lowest precedence