1.
Introduction
Verilog 1995 version
has been in market for a very long time. IEEE extended the features of
Verilog 1995 and released it as Verilog 2001. But this was no good for
verification engineers, so verification engineers had to use languages
like "e", VERA, Testbuider. It was rather painfull to have two languages,
one for design and other for verification. SystemVerilog combines the
Verification capabilties of HVL (Hardware Verification Language) with ease
of Verilog to provide a single platform for both design and verification.
Some of the new
features in SystemVerilog are as listed below.
-
C
type data types like int, typedef, struct, union, enum.
-
Dynamic data types: struct, classes, dynamic queues, dynamic arrays.
-
New
operators and built in methods.
-
Enhanced flow control like, foreach, return, break and continue.
-
Semaphores, mailboxes, event extensions.
-
Classes for object oriented programming.
-
Assertions.
-
Coverage.
-
VPI
extensions.
Now IEEE has accepted
the SystemVerilog and it will be official intergrated into Verilog 2005,
which is suppose to be released in year 2005.

Anyone with background
of C++, or OO programming language will feel at home with SystemVerilog.
But on other hand if you have been thinking C or C++ is not required, then
you may be shocked to know that SystemVerilog is very much like C++.
This document
specifies the Accellera extensions for a higher level of abstraction for
modeling and verification with the Verilog Hardware Description Language.
These additions extend Verilog into the systems space and the verification
space. SystemVerilog is built on top of the work of the IEEE Verilog 2001
committee.
Throughout this
document:
Verilog or
Verilog-2001 refers to the IEEE Std. 1364-2001 standard for the Verilog
Hardware Description Language
SystemVerilog
refers to the Accellera extensions to the Verilog-2001 standard.
This document numbers
the generations of Verilog as follows:
Verilog 1.0
is the IEEE Std. 1364-1995 Verilog standard, which is also called
Verilog-1995
Verilog 2.0
is the IEEE Std. 1364-2001 Verilog standard, commonly called Verilog-2001;
this generation of Verilog contains the first significant enhancements to
Verilog since its release to the public in 1990
SystemVerilog
3.x is Verilog-2001 plus an extensive set of high-level abstraction
extensions, as defined in this document
SystemVerilog 3.0,
approved as an Accellera standard in June 2002, includes enhancements
primarily directed at high-level architectural modeling
SystemVerilog 3.1,
approved as an Accellera standard in May 2003, includes enhancements
primarily directed at advanced verification and C language integration
SystemVerilog 3.1a,
approved as an Accellera standard in April 2004, includes corrections and
clarifications to the SystemVerilog 3.1 manual, as well as some additional
enhancements to Verilog such as VCD and PLI specifications for
SystemVerilog construct.
SystemVerilog is built
on top of Verilog 2001. SystemVerilog improves the productivity,
readability, and reusability of Verilog based code. The language
enhancements in SystemVerilog provide more concise hardware Descriptions,
while still providing an easy route with existing tools into current
hardware implementation Flows. The enhancements also provide extensive
support for directed and constrained-random testbench development,
coverage driven verification, and assertion based verification.
SystemVerilog adds
extended and new constructs to Verilog-2001, including:
Extensions to
data types for better encapsulation and compactness of code and for
tighter specification
C data types:
int, typedef, struct, union, enum
Other data
types: bounded queues, logic (0, 1, X, Z) and bit (0, 1), tagged unions
for safety
Dynamic data
types: string, classes, dynamic queues, dynamic arrays, associative arrays
including automatic memory management freeing users from de-allocation
issues
Dynamic casting
and bit-stream casting
Automatic/static specification on a per variable instance basis
Extended
operators for concise description
Wild equality
and inequality
Built-in
methods to extend the language
Operator
overloading
streaming
operators
set membership
Extended
procedural statements
Pattern
matching on selection statements for use with tagged unions
enhanced loop
statements plus the foreach statement
C like jump
statements: return, break, continue
Final blocks
that executes at the end of simulation (inverse of initial)
extended event
control and sequence events
Enhanced
process control
Extensions to
always blocks to include synthesis consistent simulation semantics
Extensions to
fork
join to model pipelines and for enhanced process control
Fine-grain
process control
Enhanced tasks
and functions
C like void
functions
pass by
reference
default
arguments
pass by name
Optional
arguments
import/export
functions for DPI (Direct Programming Interface)
Classes:
Object-Oriented mechanism that provides abstraction, encapsulation, and
safe pointer capabilities
Automated
testbench support with random constraints
Interprocess
communication synchronization
semaphores
Mailboxes
Event extensions,
event variables, and event sequencing
Clarification
and extension of the scheduling semantics
Cycle-Based
Functionality: Clocking blocks and cycle-based attributes that help reduce
development ease maintainability, and promote reusability:
cycle-based
signal drives and samples
Synchronous
samples
race-free
program context
Assertion
mechanism for verifying design intent and functional coverage intent.
Property and
sequence declarations
Assertions and
Coverage statements with action blocks
Extended
hierarchy support
Packages for
declaration encapsulation with import for controlled access
compilation-unit scope nested modules and extern modules for separate
compilation support
Extension of
port declarations to support interfaces, events, and variables.
$root to
provide unambiguous access using hierarchical references
Interfaces to
encapsulate communication and facilitate Communication Oriented design
Functional
coverage
Direct
Programming Interface (DPI) for clean, efficient interoperation with other
languages (C provided)
Assertion API
Coverage API
Data Read API
VPI extensions
for SystemVerilog constructs
Concurrent
assertion formal semantics
2. Operators
System
verilog adds the following operators ++ and increment and decrement
operators similar to C
Loop
variables can be declared inside a loop. In verilog, the variable has to
be declared and then used within a loop
|
Operator Type |
Operator Symbol |
Operation Performed |
|
Arithmetic |
* |
Multiply |
|
|
/ |
Division |
|
|
+ |
Add |
|
|
- |
Subtract |
|
|
% |
Modulus |
|
|
+ |
Unary plus |
|
|
- |
Unary minus |
|
Logical |
! |
Logical negation |
|
|
&& |
Logical and |
|
|
|| |
Logical or |
|
Relational |
> |
Greater than |
|
|
< |
Less than |
|
|
>= |
Greater than or equal |
|
|
<= |
Less than or equal |
|
Equality |
== |
Equality |
|
|
!= |
inequality |
|
Reduction |
~ |
Bitwise negation |
|
|
~& |
nand |
|
|
| |
or |
|
|
~| |
nor |
|
|
^ |
xor |
|
|
^~ |
xnor |
|
|
~^ |
xnor |
|
Shift |
>> |
Right shift |
|
|
<< |
Left shift |
|
Concatenation |
{ } |
Concatenation |
|
Conditional |
? |
conditional |
|
Assignment operator |
=,
+=, -=,
*=
, /=,
%=,
&=,
|=,
^=,
<<=,
>>=,
<<<=,
>>>=
|
|
Conditional_Expression |
cond_predicate
?
{ attribute_instance } expression
:
expression |
|
Unary_operator |
+,
-, !, ~, &, ~&, |, ~|, ^, ~^, ^~ |
|
Binary_operator |
+,-, *, /, %, ==, !=, ===,!==, =?=, !?=, &&, ||, **
<,
>, <=, >=, &, |, ^, ~^, ^~, >>, <<, <<<, >>> |
|
Increment, decrement operators |
++,
-- |
|
Unary_module_path_operator |
!,
~, &, ~&, |, ~|, ^, ~^, ^~ |
|
Binary_module_path_operator |
==,
!=, &&, ||, &, |, ^, ~^, ^~ |
Concatenation
Braces ( { } ) are
used to show concatenation, as in Verilog. The concatenation is treated as
a packed vector of bits. It can be used on the left hand side of an
assignment or in an expression.
logic
log1, log2, log3;
{log1, log2, log3} =
3b111;
{log1, log2, log3} =
{1b1, 1b1, 1b1}; // same effect as 3b111
SystemVerilog enhances
the concatenation operation to allow concatenation of variables of type
string. In general, if any of the operands is of type
string,
the concatenation is treated as a string, and all other arguments are
implicitly converted to the
string
type. String
concatenation is not allowed on the left hand side of an assignment, only
as an expression.
string
sv = "SystemVerilog";
string
s;
s = {sv, " ", "is
easy};
$display (%s\n", s);
// displays 'SystemVerilog is easy
s = {s, , enjoy};
$display (%s\n", s);
// displays 'SystemVerilog is easy, enjoy
3. Structures and unions
Structures:
User can create a
logical collection of objects using struct
Not restricted
to elements of same size and type as with arrays
Can be
referenced as a whole or by individual element

Unions:
Unions also allow the
user to create a collection of objects
However, unions
only store a single element
![Text Box: typedef struct packed {
opc_t opcode;
reg_t ra, rb, rc;
logic [11:0] c3;
} instr_format_3;
typedef struct packed {
opc_t opcode;
reg_t ra, rb;
logic [16:0] c2;
} instr_format_2;
typedef struct packed {
opc_t opcode;
reg_t ra;
logic [21:0] c1;
} instr_format_1;](datatypes_files/image003.gif)
Advantage: single
element stored with different representations
![Text Box: typedef union packed {
instr_format_1 IW1;
instr_format_2 IW2;
instr_format_3 IW3;
logic [31:0] BITS;
} InstrType;
InstrType IR;
always_comb
if (c1o)
q = {{10{IR.IW1.c1[21]}}, IR.IW1.c1};
else if (c2o)
q = {{15{IR.IW2.c2[16]}}, IR.IW2.c2};
else
q = IR.BITS;](datatypes_files/image004.gif)
4. Control Statements
Wait, what's this? if,
else, repeat, while, for, case - it's Verilog that looks exactly like C
(and probably whatever other language you're used to programming in)! Even
though the functionality appears to be the same as C, Verilog is an HDL,
so the descriptions should translate to hardware. This means you've got to
be careful when using control statements (otherwise your designs might not
be implementable in hardware).
if-else
if-else statements
check a condition to decide whether or not to execute a portion of code.
If a condition is satisfied, the code is executed. Else, it runs this
other portion of code.
// begin and end act like curly braces in C/C++.
if (enable == 1'b1)
begin
data = 10; // Decimal assigned
address = 16'hDEAD; // Hexadecimal
enable = 1'b1; // Binary
end
else
begin
data = 32'b0;
enable = 1'b0;
address = address + 1;
end
One could use any
operators in the condition checking as in the case of C language. If
needed we can have nested if else statements, statements without else is
also ok, but then it has its own problem when modeling combinational
logic, if statement without else results in a Latch (this is not always
true).
case
Case statements are
used where we have one variable which needs to be checked for multiple
values. Like an address decoder, where the input is an address and it
needs to check for all the values that it can take. Instead of using
multiple nested if-else statements, one for each value we're looking for,
we use a single case statement, and this is similar to switch statements
in languages like C++.
Case statements begin
with the reserved word case and end with the reserved word endcase
(Verilog does not use brackets to delimit blocks of code). The cases,
followed with a colon and the statements you wish executed, are listed
within these two delimiters. It's also a good idea to have a default case.
Just like with a finite state machine (FSM), if the Verilog machine enters
into a non-covered statement, the machine hangs. Defaulting the statement
with a return to idle keeps us safe.
case (address)
0: $display ("It is 11:40PM");
1: $display ("I am feeling sleepy");
2: $display ("Let me skip this tutorial");
default : $display ("Need to complete");
endcase
Looks like address
value was 3 and so I am still writing this tutorial. Note: One thing that
is common to if-else and case statement is that, if you don't cover all
the cases (dont have else in if-else or default in case), and you are
trying to write a combination statement, the synthesis tool will infer
Latch.
While
A while statement
executes the code within it repeatedly if the condition it is assigned to
check returns true. While loops are not normally used for models in real
life, but they are used in test benches. As with other statement blocks,
they are delimited by begin and end.
while(free_time) begin
$display ("Continue with webpage development");
end
As long as free_time
variable is set, code within the begin and end will be executed. i.e.
print "Continue with web development". Lets look at a stranger example,
which uses most of the constructs of Verilog. Well you heard it right.
Verilog has very few reserve words then VHDL, and in this few, we use even
lesser few for actual coding.
module counter (clk,rst,enable,count);
input clk, rst, enable;
output [3:0] count;
reg [3:0] count;
always @ (posedge clk or posedge rst)
if (rst) begin
count <= 0;
end else begin : COUNT
while (enable) begin
count <= count + 1;
disable COUNT;
end
end
endmodule
The example above uses
most of the constructs of Verilog. You'll notice a new block called always
- this illustrates one of the key features of Verilog. Most software
languages, as we mentioned before, execute sequentially - that is,
statement by statement. Verilog programs, on the other hand, often have
many statements executing in parallel. All blocks marked always will run -
simultaneously - when one or more of the conditions listed within it is
fulfilled.
In the example above,
the always block will run when either rst or clk reaches a positive edge -
that is, when their value has risen from 0 to 1. You can have two or more
always blocks in a program going at the same time (not shown here, but
commonly used).
We can disable a block
of code, by using the reserve word disable. In the above example, after
each incrementation of the counter, the COUNT block of code (not shown
here) is disabled.
for loop
For loops in Verilog
are almost exactly like for loops in C or C++. The only difference is that
the ++ and -- operators are not supported in Verilog. Instead of writing i++
as you would in C, you need to write out its full operational equivalent,
i = i + 1.
for (i = 0; i < 16; i = i +1)
begin
$display ("Current value of i is %d", i);
end
This code will print
the numbers from 0 to 15 in order. Be careful when using for loops for
register transfer logic (RTL) and make sure your code is actually sanely
implementable in hardware.. and that your loop is not infinite.
repeat
Repeat is similar to
the for loop we just covered. Instead of explicitly specifying a variable
and incrementing it when we declare the for loop, we tell the program how
many times to run through the code, and no variables are incremented
(unless we want them to be, like in this example).
repeat (16)
begin
$display ("Current value of i is %d", i);
i = i + 1;
end
The output is exactly
the same as the previous for-loop program example. It is relatively rare
to use a repeat (or for-loop) in actual hardware implementation.
Summary
-
while, if-else, case(switch) statements are same as C language.
-
An
if-else and case statement requires all the cases to covered for
combinational logic.
-
for-loop same as C, but no ++ and -- operators.
-
repeat is the same as for-loop but without the incrementing variable.
Variable
Assignment
In digital there are
two types of elements, combinational and sequential. Of course we know
this. But the question is "how do we model this in Verilog". Well Verilog
provides two ways to model the combinational logic and only one way to
model sequential logic.
-
Combination elements can be modeled using assign and always statements.
-
Sequential elements can be modeled using only always statement.
-
There
is third type, which is used in test benches only, it is called initial
statement.
Initial Blocks
Initial block as name
suggests, is executed only once and that too, when simulation starts. This
is useful in writing test bench. If we have multiple initial blocks, then
all of them are executed at beginning of simulation.
Example
initial begin
clk = 0;
reset = 0;
req_0 = 0;
req_1 = 0;
end

In the above example
at the beginning of simulation, (i.e when time = 0), all the variables
inside the begin and end are driven zero.
Always Blocks
As name suggest,
always block executes always. Unlike initial block, which executes only
once, at the beginning of simulation? Second difference is always block
should have sensitive list or delay associated with it.
Sensitive list is the
one which tells the always block when to execute the block of code, as
shown in figure below. @ Symbol after the always reserved word indicates
that always block will be triggers "at" condition in parenthesis after
symbol @.
One important note
about always block is, it can not drive a wire data type, but can drive
reg and integer data type.
always @ (a or b or sel)
begin
y = 0;
if (sel == 0) begin
y = a;
end else begin
y = b;
end
end
Above example is a 2:1
mux, with input a and b, sel is the select input and y is mux output. In
any combination logic output is changes, whenever the input changes. This
theory when applied to always blocks means that, the code inside always
block needs to be executed when ever the input variables (or output
controlling variables) change. This variables are the one which are
included in the sensitive list, namely a, b and sel.
There are two types of
sensitive list, the one which are level sensitive ( like combinational
circuits) and the one which are edge sensitive (like flip-flops). Below
the code is same 2:1 Mux but the output y now is output of a flip-flop.
always @ (posedge clk)
if (reset == 0) begin
y <= 0;
end else if (sel == 0) begin
y <= a;
end else begin
y <= b;
end
We normally have reset
to flip-flops, thus every time clock makes transition from 0 to 1 (posedge),
we check if reset is asserted (synchronous reset), and followed by normal
logic. If we look closely we see that in the case of combinational logic
we had "=" for assignment, and for the sequential block we had "<="
operator. Well "=" is blocking assignment and "<=" is nonblocking
assignment. "=" executes code sequentially inside a begin and end, where
as nonblocking "<=" executes in parallel. We can have always block without
sensitive list, in that case we need to have delay as shown in code below.
always
begin
#5 clk = ~clk;
end
#5 in front of the
statement delays the execution of the statement by 5 time units.
Assign Statement
Assign statement is
used for modeling only combinational logic and it is executed
continuously. So assign statement called continuous assignment statement
as there is no sensitive list.
assign out = (enable) ? data : 1'bz;
Above example is a
tri-state buffer. When enable is 1, data is driven to out, else out is
pulled to high-impedance. We can have nested conditional operator to
construct mux, decoders and encoders.
assign out = data;
Above example is a
simple buffer.
5. Arrays
5.1 Introduction
(informative)
An array is a
collection of variables, all of the same type, and accessed using the same
name plus one or more indices.
In C, arrays are
indexed from 0 by integers, or converted to pointers. Although the whole
array can be initialized, each element must be read or written separately
in procedural statements.
In Verilog-2001,
arrays are indexed from left-bound to right-bound. If they are vectors,
they can be assigned as a single unit, but not if they are arrays.
Verilog-2001 allows multiple dimensions.
In Verilog-2001, all
data types can be declared as arrays. The
reg,
wire
and all other net
types can also have a vector width declared. A dimension declared before
the object name is referred to as the vector width dimension.
The dimensions
declared after the object name are referred to as the array dimensions.
reg [7:0] r1 [1:256];
// [7:0] is the vector width, [1:256] is the array size
SystemVerilog uses the
term packed array to refer to the dimensions declared
before the object name (what Verilog-2001 refers to as the vector width).
The term unpacked array is used to refer to the dimensions
declared after the object name.
bit
[7:0] c1; // packed
array
real
u [7:0]; // unpacked
array
SystemVerilog enhances
packed arrays by allowing multiple dimensions. SystemVerilog adds the
ability to procedurally change the size of one of the dimensions of an
unpacked array. Fixed-size unpacked arrays can be multi-dimensional and
have fixed storage allocated for all the elements of the array. Each
dimension of an unpacked array can be declared as having a fixed or
un-fixed size. A dynamic array allocates storage for elements at runtime
along with option of changing the size of one of its dimensions. An
associative array allocates storage for elements individually as they are
written. Associative arrays can be indexed using arbitrary data types. A
queue type of array grows or shrinks to accommodate the number elements
written to the array at runtime.
5.2 Packed and
unpacked 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.
If a packed array is
declared as signed, then the array viewed as a single vector shall be
signed. The individual elements of the array are unsigned unless they are
of a named type declared as signed. A part-select of a packed array shall
be unsigned.
Packed arrays allow
arbitrary length integer types, so a 48 bit integer can be made up of 48
bits. These integers can then be used for 48 bit arithmetic. The maximum
size of a packed array can be limited, but shall be at least 65536 (216)
bits.
Packed arrays can only
be made of the single bit types (bit,
logic,
reg,
wire,
and the other net types) and recursively other packed arrays and packed
structures.
Integer types with
predefined widths cannot have packed array dimensions declared. These
types are:
byte,
shortint,
int,
longint,
and integer.
An integer type with a predefined width can be treated as a single
dimension packed array. The packed dimensions of these integer types shall
be numbered down to 0, such that the right-most index is 0.
byte
c2; // same as
bit
[7:0] c2;
integer
i1; // same as
logic signed
[31:0] i1;
Unpacked arrays can be
made of any type. SystemVerilog enhances fixed-size unpacked arrays in
that in addition to all other variable types, unpacked arrays can also be
made of object handles (see Section 11.4) and events (see Section 13.5).
SystemVerilog accepts
a single number, as an alternative to a range, to specify the size of an
unpacked array, like C. That is, [size] becomes the same as [0:size-1].
example:
int
Array[8][32]; is the
same as: int
Array[0:7][0:31];
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 = 8b11111111;
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, since the whole array cannot be viewed as a single vector.
When assigning to an
unpacked array, the source and target must be arrays with the same number
of unpacked dimensions, and the length of each dimension must be the same.
Assignment to an unpacked array is done by assigning each element of the
source unpacked array to the corresponding element of the target unpacked
array. Note that an
element of an unpacked array can be a packed array.
For the purposes of
assignment, a packed array is treated as a vector. Any vector expression
can be assigned to any packed array. The packed array bounds of the target
packed array do not affect the assignment. A packed array cannot be
directly assigned to an unpacked array without an explicit cast.
5.3 Multiple
dimensions
Like Verilog memories,
the dimensions following the type set the packed size. The dimensions
following the
instance set the
unpacked size.
bit
[3:0] [7:0] test
[1:10]; // 10 entries of 4 bytes (packed into 32 bits)
can be used as
follows:
test [9] = test[8] +
1; // 4 byte add
test [7][3:2] = test
[6][1:0]; // 2 byte copy
Note that the
dimensions declared following the type and before the name ([3:0][7:0] in
the preceding declaration) vary more rapidly than the dimensions following
the name ([1:10] in the preceding declaration).
When used, the first
dimensions ([3:0]) follow the second dimensions ([1:10]).
5.4 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.
SystemVerilog uses the
term part select to refer to a selection of one or more
contiguous bits of a single dimension packed array. This is consistent
with the usage of the term part select in Verilog.
reg
[63:0] data;
reg
[7:0] byte2;
byte2 = data [23:16];
// an 8-bit part select from data
SystemVerilog uses the
term slice to refer to a selection of one or more contiguous
elements of an array. Verilog only permits a single element of an array to
be selected, and does not have a term for this selection.
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
byte
k;
k = j [2]; // select a
single 8-bit element from j
5.5 Array querying
functions
SystemVerilog provides
new system functions to return information about an array. These are:
$left,
$right, $low, $high, $increment, $size, and $dimensions.
5.6 Dynamic arrays
A dynamic array is one
dimension of an unpacked array whose size can be set or changed at
runtime. The space for a dynamic array doesnt exist until the array is
explicitly created at runtime.
The syntax to declare
a dynamic array is:
data_type array_name
[];
where data_type is the
data type of the array elements. Dynamic arrays support the same types as
fixed-size arrays.
For example:
bit
[3:0] nibble[]; //
Dynamic array of 4-bit vectors
integer
mem[]; // Dynamic
array of integers
The
new[]
operator is used to set or change the size of the array.
The
size()
built-in method returns the current size of the array.
The
delete()
built-in method clears all the elements yielding an empty array (zero
size).
5.6.1 new[]
The built-in function
new
allocates the
storage and initializes the newly allocated array elements either to their
default initial value or to the values provided by the optional argument.
For example:
integer
addr[]; // Declare the
dynamic array.
addr =
new[100];
// Create a 100-element array.
...
// Double the array
size, preserving previous values.
addr =
new[200](addr);
The
new
operator follows the
SystemVerilog precedence rules. Since both the square brackets [] and the
parenthesis () have the same precedence, the arguments to this operator
are evaluated left to right:
[
expression ]
first, and ( expression ) second.
In the above example
[200] indicates the number of elements in the array. Must be a
non-negative integral expression and (addr) is Optional. An
array with which to initialize the new array. If it is not specified, the
elements of the newly allocated array are initialized to their default
value. This array identifier must be a dynamic array of the same data type
as the array on the left-hand side, but it need not have the same size. If
the size of this array is less than the size of the new array, the extra
elements shall be initialized to their default value. If the size of this
array is greater than the size of the new array, the additional elements
shall be ignored.
5.6.2 size ()
The prototype for the
size () method is:
function int
size();
The size() method
returns the current size of a dynamic array, or zero if the array has not
been created.
int
j = addr.size;
addr =
new[
addr.size() * 4 ] (addr); // quadruple addr array
Note:
The size method is equivalent to $length(addr, 1 ).
5.6.3 delete()
The prototype for the
delete() method is:
function void
delete();
The delete() method
empties the array, resulting in a zero-sized array.
int
ab [] =
new[
N ]; // create a temporary array of size N
// use ab
ab.delete; //
delete the array contents
$display (%d",
ab.size); // prints 0
4.9 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:
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
*.
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.
5.10 Associative
array methods
In addition to the
indexing operators, several built-in methods are provided that allow users
to analyze and manipulate associative arrays, as well as iterate over its
indices or keys.
5.10.1 num()
The syntax for the
num() method is:
function int
num();
The num() method
returns the number of entries in the associative array. If the array is
empty, it returns 0.
int
item[*];
item[ 2b3 ] = 1;
item[ 16hffff ] = 2;
item[ 4b1000 ] = 3;
$display( "%0d
entries\n", imem.num ); // prints "3 entries"
5.10.2 delete()
The syntax for the
delete() method is:
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.
int
map[
string
];
map[ "systemverilog" ]
= 1;
map[ "is" ] = 2;
map[ "not easy" ] = 3;
map.delete( "sad" );
// remove entry whose index is "sad" from "map"
map.delete; // remove
all entries from the associative array "map"
5.10.3 exists()
The syntax for the
exists() method is:
function int
exists(
input
index );
Where index is
an index of the appropriate type for the array in question.
The exists() function
checks if 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(
"SystemVerilog" ))
map[ "SystemVerilog" ]
+= 1;
else
map[ "SystemVerilog" ]
= 0;
5.10.4 first()
The syntax for the
first() method is:
function int
first(
ref
index );
Where index is
an index of the appropriate type for the array in question.
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, and 1
otherwise.
string
s;
if
( map.first( s ) )
$display( "First entry
is : map[ %s ] = %0d\n", s, map[s] );
5.10.5 last()
The syntax for the
last() method is:
function int
last(
ref
index );
Where index is
an index of the appropriate type for the array in question.
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, and 1
otherwise.
string
s;
if
( map.last( s ) )
$display( "Last entry
is : map[ %s ] = %0d\n", s, map[s] );
5.10.6 next()
The syntax for the
next() method is:
function int
next(
ref
index );
Where index is
an index of the appropriate type for the array in question.
The next() method
finds the entry whose index is greater than the given index. If there is a
next entry, the index variable is assigned the index of the next entry,
and the function returns 1. Otherwise, index is unchanged, and the
function returns 0.
string
s;
if
( map.first( s ) )
do
$display( "%s : %d\n",
s, map[ s ] );
while
( map.next( s ) );
5.10.7 prev()
The syntax for the
prev() method is:
function int
prev(
ref
index );
Where index is
an index of the appropriate type for the array in question.
The prev() function
finds the entry whose index is smaller than the given index. 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.
string
s;
if
( map.last( s ) )
do
$display( "%s : %d\n",
s, map[ s ] );
while
( map.prev( s ) );
If the argument passed
to any of the four associative array traversal methods first, last, next,
and prev is smaller than the size of the corresponding index, then the
function returns 1 and shall copy only as much data as can fit into the
argument. For example:
string
aa[*];
byte
ix;
int
status;
aa[ 1000 ] = "a";
status = aa.first( ix
);
// status is 1
// ix is 232 (least
significant 8 bits of 1000)
5.11 Queues
SystemVerilog adds
dynamic queues to Verilog
A dynamic array
can grow and shrink in size during simulation
Can represent
FIFO, LIFO or other types of queues
A queue is declared
like an array, but using
$
for the range
Optionally, a
maximum size for the queue can be specified
A queue can only
hold one data type, which is specified when the queue is declared
int q1 [$];
//an empty queue,
with an unbounded size
int q2 [$] =
{1,2,3,5,8};
//unbounded queue,
initialized with 5 locations
typedef struct {int
a, b; bit flag} packet_t;
packet_t q3 [$:16];
//a bounded
queue, with a maximum size of 16
5.11.1 Queue methods
SystemVerilog queues
have several built-in methods
insert(value)
The
method inserts the given item at the specified index position.
delete(value)
The method deletes the item at the specified index position.
push_front(<value>)
adds a
new location at the beginning of the queue with the value.
push_back(<value>)
adds a
new location at the end of the queue with the value.
variable =
pop_front()
removes the first
element of the queue and returns its value.
variable =
pop_back()
removes the last element of the queue and returns its value.
insert(<index>,<value>)
changes
the value of a queue location without changing the queue size
variable =
<queue_name>[<index>]
retrieves
the value of a queue location without changing the queue size
variable =
size()
returns the current number of elements in the queue.
It is a
run-time error to write to a full queue or to read from an empty queue
|