Saturday, September 2, 2017

system verilog for digital design

                     SYSTEM VERILOG
Content:
phần 1: lý thuyết
1.Basic Constructs
2.Interface
3.OOPS
4.Randomization
5.Functional Converage
6.Assertion
7.DPI
8.VMM Ethernet Example
9.Verification Concepts
10.UVM Tutorial
11.OVM Tutorial 
12.Easy Labs: UVM
13.Easy Labs: OVM
14.Easy Labs: VMM
15.Easy Labs: AVM
phần 2: xây dựng các mô hình test cho các IP core


sau đây ta sẽ đi tìm hiểu chi tiết về system verilog và các vấn đề liên quan đến digital system design:

I/phần 1:

1. basic constructs
*introduction:
SystemVerilog is a combined Hardware Description Language and Hardware Verification Language based on extensions to Verilog. SystemVerilog was created by the donation of the Superlog language to Accellera in 2002. The bulk of the verification functionality is based on the OpenVera language donated by Synopsys. In 2005, SystemVerilog was adopted as IEEE Standard 1800-2005 . 

Few of SystemVerilog's capabilities are unique, but it is significant that these capabilities are combined and offered within a single HDL. There is great value in a common HDL which handles all aspects of the design and verification flow: design description, functional simulation, property specification, and formal verification.
*DATA TYPES:
SystemVerilog adds extended and new data types to Verilog for better encapsulation and compactness. SystemVerilog extends Verilog by introducing C like data types. SystemVerilog adds a new 2-state data types that can only have bits with 0 or 1 values unlike verilog 4-state data types which can have 0, 1, X and Z. SystemVerilog also allows user to define new data types. 

SystemVerilog offers several data types, representing a hybrid of both Verilog and C data types. SystemVerilog 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. 



chú ý:  If you don't need the x and z values then use the SystemVerilog int and bit types which make execution faster. 

Integer types use integer arithmetic and can be signed or unsigned.The data types byte, shortint, int, integer, and longint default to signed. The data types bit, reg, and logic default to unsigned, as do arrays of these types. 

To use these types as unsigned, user has to explicitly declare it as unsigned. 

signed and unsigned:

int unsigned ui; 
int signed si 
byte unsigned ubyte; 


User can cast using signed and unsigned casting. 


if (signed'(ubyte)< 150) // ubyte is unsigned 

void:

The void data type represents nonexistent data. This type can be specified as the return type of functions to indicate no return value. 


void = function_call(); 

*LITERALS:

Integer And Logic Literals
iIn verilog , to assign a value to all the bits of vector, user has to specify them explicitly. 


reg[31:0] a = 32'hffffffff; 


Systemverilog Adds the ability to specify unsized literal single bit values with a preceding (').'0, '1, 'X, 'x, 'Z, 'z // sets all bits to this value. 


reg[31:0] a = '1; 

'x is equivalent to Verilog-2001 'bx 
'z is equivalent to Verilog-2001 'bz 
'1 is equivalent to making an assignment of all 1's 
'0 is equivalent to making an assignment of 0 

Time Literals:


Time is written in integer or fixed-point format, followed without a space by a time unit (fs ps ns us ms s step). 


EXAMPLE 
0.1ns 
40ps 


The time literal is interpreted as a realtime value scaled to the current time unit and rounded to the current time precision. 


Array Literals 



Array literals are syntactically similar to C initializers, but with the replicate operator ( {{}} ) allowed. 


EXAMPLE 
int n[1:2][1:3] = '{'{0,1,2},'{3{4}}}; 


The nesting of braces must follow the number of dimensions, unlike in C. However, replicate operators can be nested. The inner pair of braces in a replication is removed. A replication expression only operates within one dimension. 


EXAMPLE: 
int n[1:2][1:6] = '{2{'{3{4, 5}}}}; // same as '{'{4,5,4,5,4,5},'{4,5,4,5,4,5}} 

Structure Literals 



Structure literals are structure assignment patterns or pattern expressions with constant member expressions A structure literal must have a type, which may be either explicitly indicated with a prefix or implicitly indicated by an assignment-like context. 


EXAMPLE 
typedef struct {int a; shortreal b;} ab; 
ab c; 
= '{0, 0.0}; // structure literal type determined from 
// the left-hand context (c) 


Nested braces should reflect the structure. 
EXAMPLE 
ab abarr[1:0] = '{'{1, 1.0}, '{2, 2.0}}; 



The C-like alternative '{1, 1.0, 2, 2.0} for the preceding example is not allowed. 



EXAMPLE: default values 
= '{a:0, b:0.0}; 
= '{default:0}; 
= ab'{int:1, shortreal:1.0}; 

*STRINGS:
In Verilog, string literals are packed arrays of a width that is a multiple of 8 bits which hold ASCII values. In Verilog, if a string is larger than the destination string variable, the string is truncated to the left, and the leftmost characters will be lost. SystemVerilog adds new keyword "string" which is used to declare string data types unlike verilog. String data types can be of arbitrary length and no truncation occurs. 

string myName = "TEST BENCH"; 


String Methods : 



SystemVerilog also includes a number of special methods to work with strings. These methods use the built-in method notation. These methods are: 
1. str.len() returns the length of the string, i.e., the number of characters in the string. 
2. str.putc(i, c) replaces the ith character in str with the given integral value. 
3. str.getc(i) returns the ASCII code of the ith character in str. 
4. str.toupper() returns a string with characters in str converted to uppercase. 
5. str.tolower() returns a string with characters in str converted to lowercase. 
6. str.compare(s) compares str and s, and return value. This comparison is case sensitive. 
7. str.icompare(s) compares str and s, and return value .This comparison is case insensitive. 
8. str.substr(i, j) returns a new string that is a substring formed by index i through j of str. 
9. str.atoi() returns the integer corresponding to the ASCII decimal representation in str. 
10. str.atoreal() returns the real number corresponding to the ASCII decimal representation in str. 
11. str.itoa(i) stores the ASCII decimal representation of i into str (inverse of atoi). 
12. str.hextoa(i) stores the ASCII hexadecimal representation of i into str (inverse of atohex). 
13. str.bintoa(i) stores the ASCII binary representation of i into str (inverse of atobin). 
14. str.realtoa(r) stores the ASCII real representation of r into str (inverse of atoreal)




EXAMPLE : String methods 
module str; 
string A; 
string B; 
initial 
begin 
= "TEST "; 
= "Bench"; 
$display(" %d ",A.len() ); 
$display(" %s ",A.getc(5) ); 
$display(" %s ",A.tolower); 
$display(" %s ",B.toupper); 
$display(" %d ",B.compare(A) ); 
$display(" %d ",A.compare("test") ); 
$display(" %s ",A.substr(2,3) ); A = "111"; 
$display(" %d ",A.atoi() ); 
end 
endmodule 

RESULTS : 

5 

test 
BENCH 
-18 
-32 
ST 
111 

String Pattren Match 



Use the following method for pattern matching in SystemVerilog. Match method which is in OpenVera or C , is not available in SystemVerilog . For using match method which is in C , use the DPI calls . For native SystemVerilog string match method, hear is the example. 



CODE: 
function match(string s1,s2); 
int l1,l2; 
l1 = s1.len(); 
l2 = s2.len(); 
match = 0 ; 
if( l2 > l1 ) 
return 0; 
for(int i = 0;< l1 - l2 + 1; i ++) 
if( s1.substr(i,i+l2 -1) == s2) 
return 1; 
endfunction 

EXAMPLE: 
program main; 

string str1,str2; 
int i; 


initial 
begin 
str1 = "this is first string"; 
str2 = "this"; 
if(match(str1,str2)) 
$display(" str2 : %s : found in :%s:",str2,str1); 

str1 = "this is first string"; 
str2 = "first"; 
if(match(str1,str2)) 
$display(" str2 : %s : found in :%s:",str2,str1); 

str1 = "this is first string"; 
str2 = "string"; 
if(match(str1,str2)) 
$display(" str2 : %s : found in :%s:",str2,str1); 

str1 = "this is first string"; 
str2 = "this is "; 
if(match(str1,str2)) 
$display(" str2 : %s : found in :%s:",str2,str1); 

str1 = "this is first string"; 
str2 = "first string"; 
if(match(str1,str2)) 
$display(" str2 : %s : found in :%s:",str2,str1); 

str1 = "this is first string"; 
str2 = "first string ";// one space at end 
if(match(str1,str2)) 
$display(" str2 : %s : found in :%s:",str2,str1); 

end 

endprogram 


RESULTS: 

str2 : this : found in :this is first string: 
str2 : first : found in :this is first string: 
str2 : string : found in :this is first string: 
str2 : this is : found in :this is first string: 
str2 : first string : found in :this is first string: 


String Operators :



SystemVerilog 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 

Equality 




Syntax : Str1 == Str2 

Checks whether the two strings are equal. Result is 1 if they are equal and 0 if they are not. Both strings can be of type string. Or one of them can be a string literal. If both operands are string literals, the operator is the same Verilog equality operator as for integer types. 



EXAMPLE 
program main; 
initial 
begin 
string str1,str2,str3; 
str1 = "TEST BENCH"; 
str2 = "TEST BENCH"; 
str3 = "test bench"; 
if(str1 == str2) 
$display(" Str1 and str2 are equal"); 
else 
$display(" Str1 and str2 are not equal"); 
if(str1 == str3) 
$display(" Str1 and str3 are equal"); 
else 
$display(" Str1 and str3 are not equal"); 

end 
endprogram 

RESULT 

Str1 and str2 are equal 
Str1 and str3 are not equal 


Inequality. 



Syntax: Str1 != Str2 

Logical negation of Equality operator. Result is 0 if they are equal and 1 if they are not. Both strings can be of type string. Or one of them can be a string literal. If both operands are string literals, the operator is the same Verilog equality operator as for integer types. 



EXAMPLE 
program main; 
initial 
begin 
string str1,str2,str3; 
str1 = "TEST BENCH"; 
str2 = "TEST BENCH"; 
str3 = "test bench"; 
if(str1 != str2) 
$display(" Str1 and str2 are not equal"); 
else 
$display(" Str1 and str2 are equal"); 
if(str1 != str3) 
$display(" Str1 and str3 are not equal"); 
else 
$display(" Str1 and str3 are equal"); 

end 
endprogram 
RESULT 

Str1 and str2 are equal 
Str1 and str3 are not equal 


Comparison. 


Syntax: 
Str1 < Str2 
Str1 <= Str2 
Str1 > Str2 
Str1 >= Str2 



Relational operators return 1 if the corresponding condition is true using the lexicographical ordering of the two strings Str1 and Str2. The comparison uses the compare string method. Both operands can be of type string, or one of them can be a string literal. 


EXAMPLE 
program main; 
initial 
begin 
string Str1,Str2,Str3; 
Str1 = "c"; 
Str2 = "d"; 
Str3 = "e"; 

if(Str1 < Str2) 
$display(" Str1 < Str2 "); 
if(Str1 <= Str2) 
$display(" Str1 <= Str2 "); 
if(Str3 > Str2) 
$display(" Str3 > Str2"); 
if(Str3 >= Str2) 
$display(" Str3 >= Str2"); 
end 
endprogram 

RESULT 

Str1 < Str2 
Str1 <= Str2 
Str3 > Str2 
Str3 >= Str2 


Concatenation. 

Syntax: {Str1,Str2,...,Strn} 


Each operand can be of type string or a string literal (it shall be implicitly converted to type string). If at least one operand is of type string, then the expression evaluates to the concatenated string and is of type string. If all the operands are string literals, then the expression behaves like a Verilog concatenation of integral types; if the result is then used in an expression involving string types, it is implicitly converted to the string type. 


EXAMPLE 
program main; 
initial 
begin 
string Str1,Str2,Str3,Str4,Str5; 
Str1 = "WWW."; 
Str2 = "TEST"; 
Str3 = ""; 
Str4 = "BENCH"; 
Str5 = ".IN"; 
$display(" %s ",{Str1,Str2,Str3,Str4,Str5}); 
end 
endprogram 

RESULT 

WWW.TESTBENCH.IN 


Replication. 


Syntax : {multiplier{Str}} 


Str can be of type string or a string literal. Multiplier must be of integral type and can be nonconstant. If multiplier is nonconstant or Str is of type string, 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 in Verilog (if the result is used in another expression involving string types, it is implicitly converted to the string type). 


EXAMPLE 
program main; 
initial 
begin 
string Str1,Str2; 
Str1 = "W"; 
Str2 = ".TESTBENCH.IN"; 
$display(" %s ",{{3{Str1}},Str2}); 
end 
endprogram 

RESULT 

WWW.TESTBENCH.IN 


Indexing. 

Syntax: Str[index] 


Returns a byte, the ASCII code at the given index. Indexes range from 0 to N-1, where N is the number of characters in the string. If given an index out of range, returns 0. Semantically equivalent to Str.getc(index) 


EXAMPLE 
program main; 
initial 
begin 
string Str1; 
Str1 = "WWW.TESTBENCH.IN"; 
for(int i =0 ;< 16 ; i++) 
$write("%s ",Str1[i]); 
end 
endprogram 

RESULT 
W W W . T E S T B E N C H . I N 

*userdefined Datatypes
Systemverilog allos the user to define datatypes. There are different ways to define user defined datatypes. They are 
1. Class. 
2. Enumarations. 
3. Struct. 
4. Union. 
5. Typedef. 


*enumarations:
You'll sometimes be faced with the need for variables that have a limited set of possible values that can be usally referred to by name. For example, the state variable like IDLE,READY,BUZY etx of state machine can only have the all the states defined and Refraining or displaying these states using the state name will be more comfortable. There's a specific facility, called an enumeration in SystemVerilog . Enumerated data types assign a symbolic name to each legal value taken by the data type. Let's create an example using one of the ideas I just mentioned-a state machine . 

You can define this as follows: 


enum {IDLE,READY,BUZY} states; 


This declares an enumerated data type called states, and variables of this type can only have values from the set that appears between the braces, IDLE,READY and BUZY. If you try to set a variable of type states to a value that isn't one of the values specified, it will cause an error. Enumerated data type are strongly typed. 

One more advantage of enumerated datatypes is that if you don't initialize then , each one would have a unique value. By defaule they are int types. In the previous examples, IDLE is 0, READY is 1 and BUZY is 2. These values can be printed as values or strings. 
The values can be set for some of the names and not set for other names. A name without a value is automatically assigned an increment of the value of the previous name. The value of first name by default is 0. 



// c is automatically assigned the increment-value of 8 
enum {a=3, b=7, c} alphabet; 

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

// a=0, b=7, c=8 
enum {a, b=7, c} alphabet; 

Enumarated Methods: 




SystemVerilog includes a set of specialized methods to enable iterating over the values of enumerated. 

The first() method returns the value of the first member of the enumeration. 

The last() method returns the value of the last member of the enumeration. 

The next() method returns the Nth next enumeration value (default is the next one) starting from the current value of the given variable. 

The prev() method returns the Nth previous enumeration value (default is the previous one) starting from the current value of the given variable. 

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. 

EXAMPLE : ENUM methods 
module enum_method; 
typedef enum {red,blue,green} colour; 
colour c; 
initial 
begin 
= c.first(); 
$display(" %s ",c.name); 
= c.next(); 
$display(" %s ",c.name); 
= c.last(); 
$display(" %s ",c.name); 
= c.prev(); 
$display(" %s ",c.name); 
end 
endmodule 

RESULTS : 

red 
blue 
green 
blue 

Enum Numerical Expressions 

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. 

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.


EXAMPLE: 
module enum_method; 
typedef enum {red,blue,green} colour; 
colour c,d; 
int i; 
initial 
begin 
$display("%s",c.name()); 
= c; 
$display("%s",d.name()); 
= colour'(+ 1); // use casting 
$display("%s",d.name()); 
= d; // automatic casting 
$display("%0d",i); 
= colour'(i); 
$display("%s",c.name()); 
end 
endmodule 
RESULT 

red 
red 
blue 
1 
blue 
TIP: If you want to use X or Z as enum values, then define it using 4-state data type explicitly. 
enum integer {IDLE, XX='x, S1='b01, S2='b10} state, next; 


*structures and uniouns:
Structure: 



The disadvantage of arrays is that all the elements stored in then are to be of the same data type. If we need to use a collection of different data types, it is not possible using an array. When we require using a collection of different data items of different data types we can use a structure. Structure is a method of packing data of different types. A structure is a convenient method of handling a group of related data items of different data types. 


struct { 
int a; 
byte b; 
bit [7:0] c; 
} my_data_struct; 


The keyword "struct" declares a structure to holds the details of four fields namely a,b and c. These are members of the structures. Each member may belong to different or same data type. The structured variables can be accessed using the variable name "my_data_struct". 


my_data_struct.= 123; 
$display(" a value is %d ",my_data_struct.a); 


Assignments To Struct Members: 



A structure literal must have a type, which may be either explicitly indicated with a prefix or implicitly indicated by an assignment-like context. 


my_data_struct = `{1234,8'b10,8'h20}; 


Structure literals can also use member name and value, or data type and default value. 


my_data_struct = `{a:1234,default:8'h20}; 

Union 



Unions like structure contain members whose individual data types may differ from one another. However the members that compose a union all share the same storage area. A union allows us to treat the same space in memory as a number of different variables. That is a Union offers a way for a section of memory to be treated as a variable of one type on one occasion and as a different variable of a different type on another occasion. 


union { 
int a; 
byte b; 
bit [7:0] c; 
} my_data; 


memory allocation for the above defined struct "my_data_struct". 
 

Memory allocation for the above defined union "my_data_union". 
 




Packed Structures: 



In verilog , it is not convenient for subdividing a vector into subfield. Accessing subfield requires the index ranges. 

For example 



reg [0:47] my_data; 
`define a_indx 16:47 
`define b_indx 8:15 
`define c_indx 0:7 

my_data[`b_indx] = 8'b10; // writing to subfield b 
$display(" %d ",my_data[`a_indx]); // reading subfield a 


A packed structure is a mechanism for subdividing a vector into subfields that can be conveniently accessed as members. Consequently, a packed structure consists of bit fields, which are packed together in memory without gaps. A packed struct or union type must be declared explicitly using keyword "packed". 


struct packed { 
integer a; 
byte b; 
bit [0:7] c; 
} my_data; 

my_data.= 8'b10; 
$display("%d", my_data.a); 



Memory allocation for the above defined packed struct "my_data". 
 

One or more bits of a packed structure can be selected as if it were a packed array, assuming an [n-1:0] numbering: 


My_data [15:8] // b 



If all members of packed structure are 2-state, the structure as a whole is treated as a 2-state vector. 
If all members of packed structure is 4-state, the structure as a whole is treated as a 4-state vector. 
If there are also 2-state members, 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. 


*Typedef:
A typedef declaration lets you define your own identifiers that can be used in place of type specifiers such as int, byte, real. Let us see an example of creating data type "nibble". 


typedef bit[3:0] nibble; // Defining nibble data type.

nibble a, b; // a and b are variables with nibble data types.

Advantages Of Using Typedef : 



Shorter names are easier to type and reduce typing errors.
Improves readability by shortening complex declarations. 
Improves understanding by clarifying the meaning of data.
Changing a data type in one place is easier than changing all of its uses throughout the code.
Allows defining new data types using structs, unions and Enumerations also.
Increases reusability. 
Useful is type casting.

Example of typedef using struct, union and enum data types.


typedef enum {NO, YES} boolean;
typedef union { int i; shortreal f; } num; // named union type
typedef struct {
bit isfloat;
union { int i; shortreal f; } n; // anonymous type
} tagged_st; // named structure

boolean myvar; // Enum type variable
num n; // Union type variable
tagged_st a[9:0]; // array of structures 
*arrays
Arrays hold a fixed number of equally-sized data elements. Individual elements are accessed by index using a consecutive range of integers. Some type of arrays allows to access individual elements using non consecutive values of any data types. Arrays can be classified as fixed-sized arrays (sometimes known as static arrays) whose size cannot change once their declaration is done, or dynamic arrays, which can be resized. 


Fixed Arrays: 



"Packed array" to refer to the dimensions declared before the object name and "unpacked array" refers to the dimensions declared after the object name. 
SystemVerilog accepts a single number, as an alternative to a range, to specify the size of an unpacked array. That is, [size] becomes the same as [0:size-1]. 


int Array[8][32]; is the same as: int Array[0:7][0:31]; 



 



// Packed Arrays 
reg [0:10] vari; // packed array of 4-bits 
wire [31:0] [1:0] vari; // 2-dimensional packed array 

// Unpacked Arrays 
wire status [31:0]; // 1 dimensional unpacked array 
wire status [32]; // 1 dimensional unpacked array 

integer matrix[7:0][0:31][15:0]; // 3-dimensional unpacked array of integers 
integer matrix[8][32][16]; // 3-dimensional unpacked array of integers 

reg [31:0] registers1 [0:255]; // unpacked array of 256 registers; each 
reg [31:0] registers2 [256]; // register is packed 32 bit wide 








Operations On Arrays 



The following operations can be performed on all arrays, packed or unpacked: 



register1 [6][7:0] = `1; // Packed indexes can be sliced 
register1 = ~register1 ; // Can operate on entire memory 
register1 = register2 ; // Reading and writing the entire array 
register1[7:4] = register2[3:0] // Reading and writing a slice of the array 
register1[4+:i]= register2[4+;i] // Reading and writing a variable slice 
if(register1 == register2) //Equality operations on the entire array 
int n[1:2][1:3] = `{`{0,1,2},`{4,4,3}};// multidimensional assignment 
int triple [1:3] = `{1:1, default:0}; // indexes 2 and 3 assigned 0 

Accessing Individual Elements Of Multidimensional Arrays: 



In a list of multi dimensions, the rightmost one varies most rapidly than the left most one. Packed dimension varies more rapidly than an unpacked. 


In the following example, each dimension is having unique range and reading and writing to a element shows exactly which index corresponds to which dimension. 


module index(); 
bit [1:5][10:16] foo [21:27][31:38]; 
initial 
begin 
foo[24][34][4][14] = 1; 
$display(" foo[24][34][4][14] is %d ",foo[24][34][4][14] ); 
end 
endmodule 


The result of reading from an array with an out of the address bounds or if any bit in the address is X or Z shall return the default uninitialized value for the array element type. 

As in Verilog, a comma-separated list of array declarations can be made. All arrays in the list shall have the same data type and the same packed array dimensions. 


module array(); 
bit [1:5][10:16] foo1 [21:27][31:38],foo2 [31:27][33:38]; 
initial 
begin 
$display(" dimensions of foo1 is %d foo2 is %d",$dimensions(foo1),$dimensions(foo2)); 
$display(" reading with out of bound resulted %d",foo1[100][100][100][100]); 
$display(" reading with index x resulted %d",foo1[33][1'bx]); 
end 
endmodule 
RESULT: 

dimensions of foo1 is 4 foo2 is 4 
reading with out of bound resulted x 
reading with index x resulted x 


bit [3:4][5:6]Array [0:2]; 


Accessing "Array[2]" will access 4 elements Array[2][3][5],Array[2][3][6],Array[2][4][5] and Array[2][4][6]. 
Accessing "Array[1][3]" will access 2 elements Array[1][3][5] and Array[1][3][6]. 
Accessing "Array[0][3][6]" will access one element. 

*array methods

Array Methods: 



Systemverilog provides various kinds of methods that can be used on arrays. They are 

 Array querying functions 
 Array Locator Methods 
 Array ordering methods 
 Array reduction methods 
 Iterator index querying 



Array Querying Functions: 



SystemVerilog provides new system functions to return information about an array. They are 


(S)$left 


$left shall return the left bound (MSB) of the dimension. 


(S)$right 


$right shall return the right bound (LSB) of the dimension. 


(S)$low 


$low shall return the minimum of $left and $right of the dimension. 


(S)$high 


$high shall return the maximum of $left and $right of the dimension. 


(S)$increment 


$increment shall return 1 if $left is greater than or equal to $right and -1 if $left is less than $right. 


(S)$size 


$size shall return the number of elements in the dimension, which is equivalent to $high - $low +1. 


(S)$dimensions 


$dimensions shall return the total number of dimensions in the array. 




EXAMPLE : arrays 
module arr; 
bit [2:0][3:0] arr [4:0][5:0]; 

initial 
begin 
$display(" $left %0d $right %0d $low %0d $high %0d $increment %0d $size %0d $dimensions %0d",$left(arr),$right(arr),$low(arr),$high(arr),$increment(arr),$size(arr),$dimensions(arr)); 
end 
endmodule 

RESULTS : 

$left 4 $right 0 $low 0 $high 4 $increment 1 $size 5 $dimensions 4 


Array Locator Methods: 



Array locator methods operate on any unpacked array, including queues, but their return type is a queue. These locator methods allow searching an array for elements (or their indexes) that satisfies a given expression. Array locator methods traverse the array in an unspecified order. The optional "with" expression should not include any side effects; if it does, the results are unpredictable. 

The following locator methods are supported (the "with" clause is mandatory) : 



(S)find() 


find() returns all the elements satisfying the given expression 


(S)find_index() 


find_index() returns the indexes of all the elements satisfying the given expression 


(S)find_first() 


find_first() returns the first element satisfying the given expression 


(S)find_first_index() 


find_first_index() returns the index of the first element satisfying the given expression 


(S)find_last() 


find_last() returns the last element satisfying the given expression 


(S)find_last_index() 


find_last_index() returns the index of the last element satisfying the given expression 

For the following locator methods the "with" clause (and its expression) can be omitted if the relational operators (<, >, ==) are defined for the element type of the given array. If a "with" clause is specified, the relational operators (<, >, ==) must be defined for the type of the expression. 



(S)min() 


min() returns the element with the minimum value or whose expression evaluates to a minimum 


(S)max() 


max() returns the element with the maximum value or whose expression evaluates to a maximum 


(S)unique() 


unique() returns all elements with unique values or whose expression is unique 


(S)unique_index() 


unique_index() returns the indexes of all elements with unique values or whose expression is unique 



EXAMPLE : 
module arr_me; 
string SA[10], qs[$]; 
int IA[*], qi[$]; 
initial 
begin 
SA[1:5] ={"Bob","Abc","Bob","Henry","John"}; 
IA[2]=3; 
IA[3]=13; 
IA[5]=43; 
IA[8]=36; 
IA[55]=237; 
IA[28]=39; 
// Find all items greater than 5 
qi = IA.find( x ) with ( x > 5 ); 
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] ); 
$display(""); 
// Find indexes of all items equal to 3 
qi = IA.find_index with ( item == 3 ); 
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] ); 
$display(""); 
// Find first item equal to Bob 
qs = SA.find_first with ( item == "Bob" ); 
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] ); 
$display(""); 
// Find last item equal to Henry 
qs = SA.find_last( y ) with ( y == "Henry" ); 
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] ); 
$display(""); 
// Find index of last item greater than Z 
qi = SA.find_last_index( s ) with ( s > "Z" ); 
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] ); 
$display(""); 
// Find smallest item 
qi = IA.min; 
for ( int j = 0; j < qi.size; j++ ) $write("%0d_",qi[j] ); 
$display(""); 
// Find string with largest numerical value 
qs = SA.max with ( item.atoi ); 
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] ); 
$display(""); 
// Find all unique strings elements 
qs = SA.unique; 
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] ); 
$display(""); 
// Find all unique strings in lowercase 
qs = SA.unique( s ) with ( s.tolower ); 
for ( int j = 0; j < qs.size; j++ ) $write("%s_",qs[j] ); 
end 
endmodule 

RESULTS : 

13_43_36_39_237_ 
2_ 
Bob_ 
Henry_ 

3_ 
_ 
_Bob_Abc_Henry_John_ 
_Bob_Abc_Henry_John_ 


Array Ordering Methods: 



Array ordering methods can reorder the elements of one-dimensional arrays or queues. The following ordering methods are supported: 



(S)reverse() 


reverse() reverses all the elements of the packed or unpacked arrays. 


(S)sort() 


sort() sorts the unpacked array in ascending order, optionally using the expression in the with clause. 


(S)rsort() 


rsort() sorts the unpacked array in descending order, optionally using the with clause expression. 


(S)shuffle() 


shuffle() randomizes the order of the elements in the array. 


EXAMPLE: 
module arr_order; string s[] = '{ "one", "two", "three" }; 
initial 
begin 
s.reverse; 
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] ); 
s.sort; 
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] ); 
s.rsort; 
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] ); 
s.shuffle; 
for ( int j = 0; j < 3;j++ ) $write("%s",s[j] ); 
end 
endmodule 
RESULT: 

three two one 
one three two 
two three one 
three one two 


Array Reduction Methods : 



Array reduction methods can be applied to any unpacked array to reduce the array to a single value. The expression within the optional "with" clause can be used to specify the item to use in the reduction. The following reduction methods are supported: 



(S)sum() 


sum() returns the sum of all the array elements. 


(S)product() 


product() returns the product of all the array elements 


(S)and() 


and() returns the bit-wise AND ( & ) of all the array elements. 


(S)or() 


or() returns the bit-wise OR ( | ) of all the array elements 


(S)xor() 


xor() returns the logical XOR ( ^ ) of all the array elements. 


EXAMPLE: 
module array_redu(); 
byte b[] = { 1, 2, 3, 4 }; 
int sum,product,b_xor; 
initial 
begin 
sum = b.sum ; // y becomes 10 => 1 + 2 + 3 + 4 
product = b.product ; // y becomes 24 => 1 * 2 * 3 * 4 
b_xor = b.xor with ( item + 4 ); // y becomes 12 => 5 ^ 6 ^ 7 ^ 8 
$display(" Sum is %0d, product is %0d, xor is %0b ",sum,product,b_xor); 
end 
endmodule 
RESULT 

Sum is 10, product is 24, xor is 1100 


Iterator Index Querying: 



The expressions used by array manipulation methods sometimes need the actual array indexes at each iteration, not just the array element. The index method of an iterator returns the index value of the specified dimension. 


// find all items equal to their position (index) 
= arr.find with ( item == item.index ); 
// find all items in mem that are greater than corresponding item in mem2 
= mem.find( x ) with ( x > mem2[x.index(1)][x.index(2)] ); 

*DYNAMIC ARRAYS
Verilog does not allow changing the dimensions of the array once it is declared. Most of the time in verification, we need arrays whose size varies based on the some behavior. For example Ethernet packet varies length from one packet to other packet. In verilog, for creating Ethernet packet, array with Maximum packet size is declared and only the number of elements which are require for small packets are used and unused elements are waste of memory. 

To overcome this deficiency, System Verilog provides Dynamic Array. A dynamic array is unpacked array whose size can be set or changed at runtime unlike verilog which needs size at compile time. Dynamic arrays allocate storage for elements at run time along with the option of changing the size. 


Declaration Of Dynmic Array: 


integer dyna_arr_1[],dyn_arr_2[],multi_dime_dyn_arr[][]; 

Allocating Elements: 



New[]:The built-in function new allocates the storage and initializes the newly allocated array elements either to their default initial value. 


dyna_arr_1 = new[10] ;// Allocating 10 elements 
multi_dime_dyn_arr = new[4];// subarrays remain unsized and uninitialized 

Initializing Dynamic Arrays: 



The size argument need not match the size of the initialization array. When the initialization array~Rs 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. 


dyna_arr_2 = new[4]('{4,5,6}); // elements are {4,5,6,0} 

Resizing Dynamic Arrays: 



Using new[] constructor and its argument, we can increase the array size without losing the data content. 


Dyna_arr_1 = new[100] (dyna_arr_1); // Previous 10 data preserved 

Copying Elements: 



Copy constructor of dynamic arrays is an easy and faster way of creating duplicate copies of data. 


Dyna_arr_2 = new[100](dyna_arr_1);// allocating and copying 100 elements. 
Dyna_arr_1 = [1000]; // Previous data lost. 1000 elements are allocated. 



 



RESULT 

4 
8 
0 

The information about the size of the dynamic array is with the array itself. It can be obtained using .size() method. This will be very helpful when you are playing with array. You don't need to pass the size information explicitly. We can also use system task $size() method instead of .size() method. SystemVerilog also provides delete() method clears all the elements yielding an empty array (zero size).
*associative arrays
Dynamic arrays are useful for dealing with contiguous collections of variables whose number changes dynamically. Associative arrays give you another way to store information. When the size of the collection is unknown or the data space is sparse, an associative array is a better option. In Associative arrays Elements Not Allocated until Used. Index Can Be of Any Packed Type, String or Class. Associative elements are stored in an order that ensures fastest access. 

In an associative array a key is associated with a value. If you wanted to store the information of various transactions in an array, a numerically indexed array would not be the best choice. Instead, we could use the transaction names as the keys in associative array, and the value would be their respective information. Using associative arrays, you can call the array element you need using a string rather than a number, which is often easier to remember. 
The syntax to declare an associative array is: 


data_type array_id [ key _type]; 


data_type is the data type of the array elements. 
array_id is the name of the array being declared. 
key_type is the data-type to be used as an key. 

Examples of associative array declarations are: 


int array_name[*];//Wildcard index. can be indexed by any integral datatype. 
int array_name [ string ];// String index 
int array_name [ some_Class ];// Class index 
int array_name [ integer ];// Integer index 
typedef bit signed [4:1] Nibble; 
int array_name [ Nibble ]; // Signed packed array 



Elements in associative array elements can be accessed like those of one dimensional arrays. Associative array literals use the '{index:value} syntax with an optional default index. 


//associative array of 4-state integers indexed by strings, default is '1. 
integer tab [string] = '{"Peter":20, "Paul":22, "Mary":23, default:-1 }; 

Associative Array Methods 



SystemVerilog provides several methods which allow analyzing and manipulating associative arrays. They are: 

The num() or size() method returns the number of entries in the associative array. 
The delete() method removes the entry at the specified index. 
The exists() function checks whether an element exists at the specified index within the given array. 
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. 
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. 
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, the index is unchanged, and the function returns 0. 
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. 



EXAMPLE 
module assoc_arr; 
int temp,imem[*]; 
initial 
begin 
imem[ 2'd3 ] = 1; 
imem[ 16'hffff ] = 2; 
imem[ 4'b1000 ] = 3; 
$display( "%0d entries", imem.num ); 
if(imem.exists( 4'b1000) ) 
$display("imem.exists( 4b'1000) "); 
imem.delete(4'b1000); 
if(imem.exists( 4'b1000) ) 
$display(" imem.exists( 4b'1000) "); 
else 
$display(" ( 4b'1000) not existing"); 
if(imem.first(temp)) 
$display(" First entry is at index %0db ",temp); 
if(imem.next(temp)) 
$display(" Next entry is at index %0h after the index 3",temp); 
// To print all the elements alone with its indexs 
if (imem.first(temp) ) 
do 
$display( "%d : %d", temp, imem[temp] ); 
while ( imem.next(temp) ); 
end 
endmodule 

RESULT 

3 entries 
imem.exists( 4b'1000) 
( 4b'1000) not existing 
First entry is at index 3b 
Next entry is at index ffff after the index 3 
3 : 1 
65535 : 2 
*QUEUES
A queue is a variable-size, ordered collection of homogeneous elements. A Queue is analogous to one dimensional unpacked array that grows and shrinks automatically. Queues can be used to model a last in, first out buffer or first in, first out buffer. Queues support insertion and deletion of elements from random locations using an index. Queues Can be passed to tasks / functions as ref or non-ref arguments. Type checking is also done. 



Queue Operators: 



Queues and dynamic arrays have the same assignment and argument passing semantics. Also, queues support the same operations that can be performed on unpacked arrays and use the same operators and rules except as defined below: 


int q[$] = { 2, 4, 8 }; 
int p[$]; 
int e, pos; 
= q[0]; // read the first (leftmost) item 
= q[$]; // read the last (rightmost) item 
q[0] = e; // write the first item 
= q; // read and write entire queue (copy) 
= { q, 6 }; // insert '6' at the end (append 6) 
= { e, q }; // insert 'e' at the beginning (prepend e) 
= q[1:$]; // delete the first (leftmost) item 
= q[0:$-1]; // delete the last (rightmost) item 
= q[1:$-1]; // delete the first and last items 
= {}; // clear the queue (delete all items) 
= { q[0:pos-1], e, q[pos,$] }; // insert 'e' at position pos 
= { q[0:pos], e, q[pos+1,$] }; // insert 'e' after position pos 

Queue Methods: 



In addition to the array operators, queues provide several built-in methods. They are: 

The size() method returns the number of items in the queue. If the queue is empty, it returns 0. 
The insert() method inserts the given item at the specified index position. 
The delete() method deletes the item at the specified index. 
The pop_front() method removes and returns the first element of the queue. 
The pop_back() method removes and returns the last element of the queue. 
The push_front() method inserts the given element at the front of the queue. 
The push_back() method inserts the given element at the end of the queue. 




EXAMPLE 
module queues; 
byte qu [$] ; 

initial 
begin 
qu.push_front(2); 
qu.push_front(12); 
qu.push_front(22); 
qu.push_back(11); 
qu.push_back(99); 
$display(" %d ",qu.size() ); 
$display(" %d ",qu.pop_front() ); 
$display(" %d ",qu.pop_back() ); 
qu.delete(3); 
$display(" %d ",qu.size() ); 
end 
endmodule 
RESULTS : 
5 
22 
99 


Dynamic Array Of Queues Queues Of Queues 


EXAMPLE: 
module top; 
typedef int qint_t[$]; 
// dynamic array of queues 
qint_t DAq[]; // same as int DAq[][$]; 
// queue of queues 
qint_t Qq[$]; // same as int Qq[$][$]; 
// associative array of queues 
qint_t AAq[string]; // same as int AAq[string][$]; 
initial begin 
// Dynamic array of 4 queues 
DAq = new[4]; 
// Push something onto one of the queues 
DAq[2].push_back(1); 
// initialize another queue with three entries 
DAq[0] = {1,2,3}; 
$display("%p",DAq); 
// Queue of queues -two 
Qq= {{1,2},{3,4,5}}; 
Qq.push_back(qint_t'{6,7}); 
Qq[2].push_back(1); 
$display("%p",Qq); 
// Associative array of queues 
AAq["one"] = {}; 
AAq["two"] = {1,2,3,4}; 
AAq["one"].push_back(5); 
$display("%p",AAq); 
end 

endmodule : top 

RESULTS: 

'{'{1, 2, 3}, '{}, '{1}, '{}} 
'{'{1, 2}, '{3, 4, 5}, '{6, 7, 1}} 
'{one:'{5}, two:'{1, 2, 3, 4} } 
*COMPARISON ARRAYS

Static Array 



Size should be known at compilation time. 
Time require to access any element is less. 
if not all elements used by the application, then memory is wasted. 
Not good for sparse memory or when the size changes. 
Good for contagious data. 



Associative Array 



No need of size information at compile time. 
Time require to access an element increases with size of the array. 
Compact memory usage for sparse arrays. 
User don't need to keep track of size. It is automatically resized. 
Good inbuilt methods for Manipulating and analyzing the content. 



Dynamic Array 



No need of size information at compile time. 
To set the size or resize, the size should be provided at runtime. 
Performance to access elements is same as Static arrays. 
Good for contagious data. 
Memory usage is very good, as the size can be changed dynamically. 



Queues 



No need of size information at compile time. 
Performance to access elements is same as Static arrays. 
User doesn't need to provide size information to change the size. It is automatically resized. 
Rich set of inbuilt methods for Manipulating and analyzing the content. 
Useful in self-checking modules. Very easy to work with out of order transactions. 
Inbuilt methods for sum of elements, sorting all the elements. 
Searching for elements is very easy even with complex expressions. 
Useful to model FIFO or LIFO. 


*LINKED LIST
The List package implements a classic list data-structure, and is analogous to the STL (Standard Template Library) List container that is popular with C++ programmers. The container is defined as a parameterized class, meaning that it can be customized to hold data of any type. The List package supports lists of any arbitrary predefined type, such as integer, string, or class object. First declare the Linked list type and then take instances of it. SystemVerilog has many methods to operate on these instances. 
A double linked list is a chain of data structures called nodes. Each node has 3 members, one points to the next item or points to a null value if it is last node, one points to the previous item or points to a null value if it is first node and other has the data. 


The disadvantage of the linked list is that data can only be accessed sequentially and not in random order. To read the 1000th element of a linked list, you must read the 999 elements that precede it. 



List Definitions: 



list :- A list is a doubly linked list, where every element has a predecessor and successor. It is a sequence that supports both forward and backward traversal, as well as amortized constant time insertion and removal of elements at the beginning, end, or middle. 

container :- A container is a collection of objects of the same type .Containers are objects that contain and manage other objects and provide iterators that allow the contained objects (elements) to be addressed. A container has methods for accessing its elements. Every container has an associated iterator type that can be used to iterate through the container´s elements. 

iterator :- Iterators provide the interface to containers. They also provide a means to traverse the container elements. Iterators are pointers to nodes within a list. If an iterator points to an object in a range of objects and the iterator is incremented, the iterator then points to the next object in the range. 



Procedure To Create And Use List: 



1. include the generic List class declaration 


`include <List.vh> 


2. Declare list variable 


List#(integer) il; // Object il is a list of integer 


3. Declaring list iterator 


List_Iterator#(integer) itor; //Object s is a list-of-integer iterator 

List_iterator Methods 



The List_Iterator class provides methods to iterate over the elements of lists. 

The next() method changes the iterator so that it refers to the next element in the list. 
The prev() method changes the iterator so that it refers to the previous element in the list. 
The eq() method compares two iterators and returns 1 if both iterators refer to the same list element. 
The neq() method is the negation of eq(). 
The data() method returns the data stored in the element at the given iterator location. 



List Methods 



The List class provides methods to query the size of the list; obtain iterators to the head or tail of the list; 
retrieve the data stored in the list; and methods to add, remove, and reorder the elements of the list. 

The size() method returns the number of elements stored in the list. 
The empty() method returns 1 if the number elements stored in the list is zero and 0 otherwise. 
The push_front() method inserts the specified value at the front of the list. 
The push_back() method inserts the specified value at the end of the list. 
The front() method returns the data stored in the first element of the list. 
The back() method returns the data stored in the last element of the list. 
The pop_front() method removes the first element of the list. 
The pop_back() method removes the last element of the list. 
The start() method returns an iterator to the position of the first element in the list.
The finish() method returns an iterator to a position just past the last element in the list. 
The insert() method inserts the given data into the list at the position specified by the iterator. 
The insert_range() method inserts the elements contained in the list range specified by the iterators first and last at the specified list position. 
The erase() method removes from the list the element at the specified position. 
The erase_range() method removes from a list the range of elements specified by the first and last iterators. 
The set() method assigns to the list object the elements that lie in the range specified by the first and last iterators. 
The swap() method exchanges the contents of two equal-size lists. 
The clear() method removes all the elements from a list, but not the list itself. 
The purge() method removes all the list elements (as in clear) and the list itself. 


EXAMPLE 
module lists(); 
List#(integer) List1; 
List_Iterator#(integer) itor; 
initial begin 
List1 = new(); 
$display (" size of list is %d \n",List1.size()); 
List1.push_back(10); 
List1.push_front(22); 
$display (" size of list is %d \n",List1.size()); 
$display (" poping from list : %d \n",List1.front()); 
$display (" poping from list : %d \n",List1.front()); 
List1.pop_front(); 
List1.pop_front(); 
$display (" size of list is %d \n",List1.size()); 
List1.push_back(5); 
List1.push_back(55); 
List1.push_back(555); 
List1.push_back(5555); 
$display (" size of list is %d \n",List1.size()); 

itor = List1.start(); 
$display (" startn of list %d \n",itor.data()); 
itor.next(); 
$display (" second element of list is %d \n",itor.data()); 
itor.next(); 
$display (" third element of list is %d \n",itor.data()); 
itor.next(); 
$display (" fourth element of list is %d \n",itor.data()); 

itor = List1.erase(itor); 
$display (" after erasing element,the itor element of list is %d \n",itor.data()); 
itor.prev(); 
$display(" prevoious element is %d \n",itor.data()); 
end 

endmodule 
RESULT: 

size of list is 0 
size of list is 2 
poping from list : 22 
poping from list : 22 
size of list is 0 
size of list is 4 
startn of list 5 
second element of list is 55 
third element of list is 555 
fourth element of list is 5555 
after erasing element,the itor element of list is x 
prevoious element is 555 




Share:

0 comments:

Post a Comment

Search This Blog

Powered by Blogger.

Blog Archive