HOME

    Electronics Directory Articles/ Tutorials eBooks

About Us

FORUM Links Contact Us
   

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} = 3’b111;

{log1, log2, log3} = {1’b1, 1’b1, 1’b1}; // same effect as 3’b111

 

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;

 

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;

 

 

 

 

 

 

 

 

 

 

 

 


 

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 (don’t 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 = 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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Home   |    About Us   |   Articles/ Tutorials   |   Downloads   |   Feedback   |   Links   |   eBooks   |   Privacy Policy
Copyright © 2005-2007 electroSofts.com.
webmaster@electroSofts.com