<Previous
Page Next>
5.1 Introduction
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 = 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, 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 doesn�t 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[ 2�b3 ] = 1;
item[ 16�hffff ] = 2;
item[ 4b�1000 ] = 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
<Previous
Page Next>
|