Systemverilog
Systemverilog
Verification AVM Testbench Structure Transactions Data Types User defined types Enumeration Parameterized types Arrays & Structures Dynamic Arrays Associative Arrays Queues / Lists Structures SV Scheduler Program Control Hierarchy Implicit port connections Packages Compilation Units 5 7 9 18 21 23 31 33 34 37 39 42 63 68 79 85 88 91 Tasks & Functions Task enhancements Function enhancements Dynamic Processes fork-join none Interprocess Sync & Communication semaphore mailbox Lab Classes Classes Constructors Lab Interfaces Simple bundled Modports Virtual Interfaces Router design Lab 98 99 101 108 110 114 116 118 120
Verification
In this section
Testbench
DUT
DUT
Support Models
Verification
Reactivity
Assertions
Message Service
Transactions - Definition
Representation of arbitrary activity in a device
Bounded by time Has attributes
Begin time
End time
Duration Time
Transaction Metaphors
Bus Operations
f()
Function Calls
{ for(i=0; g(i) } f i<4; i++)
read
write g0 g1 g2 g3
FSM
q
B A C D
Gantt Chart
r s
resource occupation
Transactions provide a medium for moving data around without doing low level conversions
Transaction traffic can be recorded or otherwise observed
Objective: keep as much of the testbench structure at the transaction level as possible
10
Why Transactions?
Easier to write transaction level components than RTL Easier to debug transaction level components than RTL More opportunities for reuse
standard interfaces standard APIs
11
12
Responder
Converts pin-level activity to transaction stream(s)
Monitor
Monitors pin-level activity for incorrect behavior Totally passive: no affect on DUT
13
Master
Bidirectional component: sends requests and receives responses Initiate activity May use responses to steer requests
Slave
Transaction level device driven by a responder Doesnt initiate activity but responds to it appropriately
14
Scoreboard
Tracks transaction level activity from multiple devices Keeps track of information that shows if DUT is functioning properly
Analysis port
Pass information from transactors (or lower) to analysis layer Link Transactors, Drivers & Monitors to Scoreboard Abstract, so Scoreboard does not interfere (slow, add wait-state etc) with correct behavior of the DUT
15
Scenario 2
1. Controller starts stimulus generator with initial constraints 2. Wait for coverage collector to say when certain goals are met 3. Controller sends stimulus generator modified/new constraints
16
SV for Verification
Misc Language Enhancements
Classes
SVA
Verilog 2001
Constrained Random
Functional Coverage
17
Datatypes
In this section
18
19
Initialization of variables
SystemVerilog offers more sophistication than Verilog 2001 Examples:
int a = 0;
Equiv: int a; initial a = 0;
int
b = a+2; c = $urandom_range(0,152)
// c between 0 and 152 inclusive
bit[31:0]
20
typedef
<base_data_type>
<type_identifier>
typedef
int
typ ; b = 10;
// //
typ becomes a new type these are 2 new variables of type typ
typ a = 1,
21
Literals
SystemVerilog allows easy specification of un-sized literal values with the ( ' ) apostrophe:
String literals are written as in Verilog, between double quotes SV adds new escaped characters:
" " " " \v " \f " \a " \x02 " // // // // vertical tab form feed bell hexadecimal number
22
Enumeration
Syntax:
enum [enum_base_type] { { enum_name_declaration {,enum_name_declaration} }} enum_base_type: default is int
Define an enumeration with enum enum {red, enum { a=5, enum bit[3:0] green, yellow} traf_lite1, // b=6, c=7 silver, gold} Values can be cast to integer types and auto-incremented b, c} vars; {bronze=4h3, A sized constant can be used to set size of the type
0 enum {red,
1 green,
yellow}
2 lite;
traf_lite2;
medal;
23
Enumerated Types
Enumerated Type
Define a new type
typedef enum {NO, YES} boolean; // boolean is NOT a SystemVerilog type // but it just became one
myvar will be checked for valid values in all assignments
boolean myvar;
blue,
yellow,
white,
black}
colors
initial begin my_colors = green; // invalid, needs to typecast // my_colors = 1; my_colors = colors'(2); // cast as blue case (my_colors) red: $display ("my_color is red"); blue: $display ("my_color is blue"); default: $display ("my_color is not blue or red"); endcase end endmodule
24
Enumeration Examples
Consider this enumeration
enum {red, green, yellow} lite1, lite2; // anonymous int type assumed
25
Enumeration Methods
SystemVerilog provides some methods to allow easy manipulation of enumerated types
function enum first() returns the value of the first member of the enumeration enum. function enum last() returns the value of the last member of the enumeration enum. function enum next(int unsigned N = 1) returns the Nth next enumeration value (default is the next one) starting from the current value of the given variable. Note: next() "wraps" to the first value when applied to the last function enum prev(int unsigned N = 1) returns the Nth previous enumeration value (default is the previous one) starting from the current value of the given variable. Note: prev() "wraps" to the last value when applied to the first function int num() returns the number of elements in the given enumeration. function string name() returns the string representation of the given enumeration value
26
27
<type> (<value>)
28
This code assigns 5 (or black) to col. Without $cast, this assignment is illegal -ORUse the function form of $cast to check if the assignment will succeed:
if
29
abc
0 1 2
et c
0 1 2
// null string // assigned from a string literal // concatenation, st1 becomes abc // st2 becomes etc
Supports relational operators ( ==, !=, <, <=, concatenation ({ }) and replication ( {n{ }} )
>, >= ),
30
Parameterized types
SystemVerilog extends Verilog parameters to support types.
This example shows a fifo, whose width, depth AND TYPE are parameterized:
module fifo #( parameter depth = 16, parameter width = 8, parameter type ft = bit ) ( input ft [width-1:0] datin, output ft [width-1:0] datout mem [depth-1:0];
// default width/depth // default width/depth // fifo is type bit (2-state) by default
input );
bit
r_w,
clk,
ft [width-1:0] . . . endmodule
Tip
o;
An easy way (as here) to switch between 2-state and 4-state operation of your design.
// override both parameter default values // override parameter ft to be type logic (4-state)
.clk(clk),
.r_w(r_w));
endmodule
31
Const
The const keyword effectively means the variable may not be changed by user code
Value is set at run-time and it can contain an expression with any hierarchical path name
const logic option = a.b.c ;
A const may be set during simulation within an automatic task (discussed later)
32
In this section
Dynamic Arrays Associative Arrays Queues Structure / Union Multi-dimensional Using Arrays Supported data types & operations Querying functions
33
Dynamic Arrays
Dynamic declaration of one-dimensional arrays
Syntax: data_type
array_name[]
;;
data_type
array_name[]
Allocates a anew array array_name of type data_type and size array_size Optionally assigns values of array to toarray_name If Ifno value is is assigned then element has default value of data_type
Declaration
= = new[ array_size
] ] [(array)]
;;
bit int
Resize
[3:0] data[
nibble[ ];
];
// //
of 4-bit of int
vectors
initial begin nibble = new[100]; data = new [256]; end int addr[ ] = new [50];
// //
resize resize
to 100-element to 256-element
array array
//
Create a 50-element
array
34
void delete()
int
my_addr[ ] = new[256];
initial begin ); $display("Size of my_addr = %0d", my_addr.size() my_addr.delete(); $display("Size of my_addr (after delete) = %0d", my_addr.size()); end
35
initial begin an_array = an_array = an_array[2] an_array = $display("1: an_array[3] an_array = $display("2: end
new[dyn_array.size()](dyn_array); dyn_array; = 222; new[150]; an_array[2] = %0d",an_array[2]); = 333; new[200](an_array); an_array[3] = %0d",an_array[3]);
// same as next line // same as line above // init location 2 // resize array - lose contents // init location 3 // resize array - save contents
size
36
Arrays Associative
Associative arrays ( sometimes called indexed arrays )
Support situations where data set size is totally unpredictable and elements may be added or removed individually to grow/shrink the array Implemented as a look up table and so require an index.
Syntax: data_type
array_id
[ index_type
];
// index type is the datatype to use as index // examples include string, int, class, struct
// associative array of bits (unspecified index) // unspecified index (*) implies any integral value // associative array of 8-bit vectors, indexed by string
initial begin string tom = tom; age [tom] = 21; tom is 21 years of age [2 ages available] age [joe] = 32; $display("%s is %d years of age ", tom, age[tom], "[%0d ages available]", end
age.num());
37
void delete(
Index is optional If index is specified, deletes the item at the specified index If index is not specified the all elements in the array are removed
function
int exists ( input index ); Checks if an element exists at the specified index within the given array. Returns 1 if the element exists, otherwise it returns 0 int first( ref index )
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
function
function
int
last(
ref
index )
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.
function
int
next(
ref
index );
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
function
int
prev(
ref
index
);
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
38
(tick) signifies cast overload and is required q1 = '{ n, q1 }; q1 = ' { q1, m }; item = q1[0]; item = q1[$]; n = q1.size(); q1 = q1[1:$]; q1 = q1[0:$-1]; // // // // // // // uses concatenate uses concatenate syntax to write syntax to write ) item ) item n to the left end of q1 m to the right end of q1
number of items
on q1
step through
the q1 list
39
Queue Methods
function function int size() (int index, queue_type item)
Returns the number of items in the queue. If the queue is empty, it returns 0.
void insert
Inserts the given item at the specified index position Q.insert (i, e) => Q = '{Q[0:i-1], e, Q[i:$]}
function
void delete
(int
index)
Q[i+1:$]}
Deletes the item at the specified index position Q.delete (i) => Q = '{Q[0:i-1],
function
queue_type
pop_front()
Removes and returns the first element of the queue e = Q.pop_front () => e = Q[0]; Q = Q[1:$]
function
queue_type
pop_back()
Removes and returns the last element of the queue e = Q.pop_back () => e = Q[$]; Q = Q[0:$-1]
function
void push_front
(queue_type
item);
Inserts the given element at the front of the queue Q.push_front (e) => Q = '{e, Q}
function
item);
40
41
Structures
Think of a structure as an object containing data members of any SV type
struct{ bit[7:0] my_byte; int my_data; real pi; } my_struct; // my_byte, my_data and pi are "members" of my_struct
Data members can be referenced individually (using the . operator) or altogether as a unit
Structures may: be packed or unpacked. be assigned as a whole pass to/from a function or task as a whole contain arrays
42
Packed
{bit[1:0]a0; bit[2:0] a1; bit[5:0] a2; bit[8:0]a3; } u_pkt;
a0 a1 a2 a3
struct
Unpacked
struct
packed { bit[1:0] a0; bit[2:0] a1; bit[5:0] a2; bit[8:0] a3; } p_pkt;
Default for structs Tool dependant implementation. Think of as a logical grouping of member elements Each member may be assigned differently
Much more useful in hardware Easily converted to bit-vectors May be accessed as a whole First member specified is most significant May be declared as signed for arithmetic Limitations Only integer types (bit, logic, int, reg, time) Unpacked arrays/structures are NOT allowed here If any member is 4-state, all members are cast to 4-state
43
44
Uses of structures
Structures are ideal way to encapsulate data "packets" Use as data or control abstraction in architectural models Use as abstraction for top-down I/O design
Behavioral: pass structures through ports, as arguments to tasks/functions, etc. Use to refine structure size/content RTL: break structure apart & define final I/O Verification: to encapsulate constraint/randomization weights
45
Multidimensional Arrays
SystemVerilog supports multi-dimensional arrays just like Verilog
bit [7:0] mem [4:1]; mem[ i ] [6:1] = 0; // byte-wide memory with 4 addresses, like Verilog // 2D+ indexing supported (like Verilog 2001)
packed
unpacked
The terms packed and unpacked to refer to how the data is actually stored in memory
packed => 8-bits to a byte, unpacked => 1 bit per word
a0 b3 b2 b1 b0 packed a1 a2 a3 unpacked
46
byte3
byte2
byte1
byte0
aa
aa[0]
= aa[0]
+ 1; // byte increment
bit
[3:0]
[7:0]
bb [1:0];
byte3 byte3
byte2 byte2
byte1 byte1
byte0 byte0
bb[1] bb[0]
bb[1]
= bb[0];
// word assignment
byte3 byte3
3:0 byte2
byte1 7:4
byte0 byte0
bb[1] bb[0]
bb[1][2][3:0]
47
bit bit
[3:0] [3:0]
[7:0] [7:0]
aa ; bb [10:1]
To access: start with unpacked dimensions proceeding left to right then continue with the packed dimensions, also proceeding left to right
10
7:0
bb[9]
= bb[8]
+ bb[7];
9 8 7 6
bb[10][1:0]
= bb [9][3:2]
10 9 8
48
unpacked a0 a1 a2 a3 [3:0]
Packed
Only bit-level types (reg, wire, logic, bit) Access whole array or slice as a vector All elements must be assigned identically Compatible with $monitor/$display etc. Allows arbitrary length integers/arithmetic
bit [3:0] b; // packed array of bits
bit
packed
bit
b3 b2 b1 b0 [3:0]
49
Array Examples
m=
24b0; Equivalent
[N] => [0:N-1]
nn [0:5]; nn [6];
50
initial begin var = 3; PA = PB; PA[7:4] = 'hA; PA[var -:4] = PA[var+1 +:4]; equiv: PA[3:0] = PA[7:4]; end
Verilog 2001 Syntax [ M -: N ] [ M +: N ] // negative offset from bit index M, N bit result // positive offset from bit index M, N bit result
bit[3:0][7:0]
MPA;
51
For more control, consider the dimensions of the array and use { } to match those dimensions exactly
int
k [1:3][1:4]
= {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};//
3 groups of 4
int
m [1:2][1:3]
{{0,1,2},
{3{4}}};
//
2 groups of 3
52
initial begin #10 $readmemh("hex.dat",PA); for(int i=0; i<=3;i++) $display("PA[%0h",i,"]: #10 $readmemh("hex.dat",PB); $display(""); for(int i=0; i<=3;i++) $display("PB[%0h",i,"]: #10 $readmemh("hex.dat",UA); $display(""); for(int i=0; i<=3;i++) $display("UA[%0h",i,"]: #10 $readmemh("hex_multi.dat",UB); $display(""); for(int i=0; i<=3;i++) for(int j=0; j<=1;j++) $displayh("UB[",i,"][",j,"]: end endmodule
%b",PA[i]);
00 01 AA FF
hex.dat
%b",PB[i]); [1:0] 00 10 20 30 40 50 60 70 01 11 21 31 41 51 61 71
%b",UA[i]); [7:0]
",UB[i][j]);
hex_multi.dat
53
string SA[10], qs[$]; int IA[*], qi[$]; qi = IA.find( x ) with ( x > 5 ); qs = SA.unique( s ) with ( s.tolower
// Find all items greater than 5
);
54
reverses all the elements of the array (packed or unpacked) sorts the unpacked array in ascending order sorts the unpacked array in descending order randomizes the order of the elements in the array
= { teacher", apple", student" };
struct { byte red, green, blue; } video [512]; // sort video using the red byte only video.sort() with ( item.red ); // sort by blue-green algorithm video.sort( sel ) with ( sel.blue << 8 + sel.green );
Reduce
sum() product() and() or() xor()
byte b[] int y;
returns the sum of all the array elements returns the product of all the array elements returns the bitwise AND ( & ) of all the array elements returns the bitwise OR ( | ) of all the array elements returns the logical XOR ( ^ ) of all the array elements
= { 1, 2, 3, 4 };
y = b.sum() ; y = b.product()
55
//
prints
${low|high} (array_id, N = 1) Returns the min|max bounds of a variable // min|max of $left and $right of dimension $increment(array_id, N = 1) Returns 1 if $left is greater than or equal to $right Returns 1 if $left is less than $right $size(array_id, N = 1) returns number of elements in the dimension ( $high - $low +1 ) ( was $length (now deprecated) )
56
initial $display(
6144
32
57
Unions
Also borrowed from C, SV supports packed and unpacked forms C unions are essentially the same as SV unpacked unions
Union is a specialized form of struct Memory footprint is the size of the largest member Used to reduce memory consumption of a design All members begin at the same memory address The member read must also be the most recently written
Their limitations make unpacked unions less useful for h/w Packed unions HOWEVER, are VERY useful
58
Packed Unions
A packed union contains 1 or more packed members
All members are the same size and occupy the same space Data may be written via one member, read by another Unlike C/C++ SV unions are independent of platform byte ordering The union may be accessed as a whole
a p_union
Characteristics
Easy conversion to bit-vectors May be accessed as a whole First member specified is most significant May be declared as signed for arithmetic Non-integer datatypes (e.g. real) are NOT allowed Unpacked arrays/structures are NOT allowed if any member is 4-state, all members are cast to 4-state
59
typedef
3 members
// Default unsigned union packed { my_packed_struct mps; bit [95:0] bits; bit [11:0] [7:0] bytes; } my_packed_union;
my_packed_union u1;
60
Structure Expressions
module mod1; typedef struct { logic [7:0] a; int b; } my_struct; my_struct s1 ;
NOTE
SV distinguishes between structure expressions (as shown here) and ordinary concatenations by the { syntax.
s1.a:
%h, s1.b:
%h",s1.a,
s1.b);
// assign by position // assign by name // default: new SV operator // assign by type, others default
Simulator output
my_struct s1.a: xx, s1.b: 00000000 my_struct s1.a: 05, s1.b: 00000006 my_struct s1.a: 06, s1.b: 00000005 my_struct s1.a: 07, s1.b: 00000007 my_struct s1.a: 01, s1.b: 00000009
end endmodule
61
Bit-stream casting
A bit-stream data type is any data type that may be represented as a serial stream of bits. This includes any SV type except handle, chandle, real, shortreal, or event. Bit-casting allows easy conversion between bit-stream types, for example to model packet transmission over a serial communication stream.
typedef struct { shortint c; byte payload c:42, [2] ; } pkt_t;
default:1};
NOTE
There are rules and limitations to the use of bit-stream casting. See the LRM for more information.
int_c;
Simulator output
// cast to stream
## Received: c: 42, payload[0]: 1, payload[1]: 11 ## Break at bit_cast.sv line 18
always @(int_c) begin // cast from stream pkt_b = pkt_t'(int_c); $display("Received: c: %0d, payload[0]: %0d, payload[1]: pkt_b.c, pkt_b.payload[0], pkt_b.payload[1]); end
%0d",
62
Scheduler
In this section
63
Processes
An SV description consists of connected threads of execution called processes Processes are objects
Can be evaluated Can have state Respond to changes on inputs Produce outputs
SV processes:
Procedural blocks
initial, always, always_ff, always_comb, always_latch
64
Events
SV simulation is event based update event A change in a variable or net evaluation event The evaluation of a process PLI callback Points where PLI application routines can be called from the simulation kernel Processes are sensitive to update events When an update event occurs All the processes that are sensitive to that event are considered for evaluation in an arbitrary order
65
Time
Simulation time is a value maintained by the simulator
Models the actual time it would take for the system description being simulated
All events scheduled at a particular time define a time slot Each time slot is divided into multiple regions
Events may be scheduled in these regions Provides for an ordering of particular types of events Allows for checkers and properties to sample data in a stable state
Simulation proceeds by executing and removing the events in the current time slot Time advances
When all the events are executed and removed from the current time slot time To the next non-empty time slot
66
Current events (processed in any order) Events to be evaluated after active events (e.g. # )
Active Inactive
NBA
Reactive Re-inactive
Execution of Program Block and pass/fail code from property expressions Events to be evaluated after reactive events (e.g. # )
67
Program Control
In this section
68
Operators
In addition to the standard Verilog operators, SystemVerilog adds C operators:
Assignment: Blocking assignments only
+=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, <<<=, >>>=
Power: **
69
Operators
In addition to the standard Verilog operators, SystemVerilog adds C operators:
Assignment: Blocking assignments only
+=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, <<<=, >>>=
Power: **
69
do loop
Syntax: do <statement> while <expression>
Like a while loop, but evaluates after the loop executes rather than before
do
Loop would NEVER execute if i >= 10 So programmer has to setup value of i before loop
70
// j is local
71
for multi-assignments
SystemVerilog allows multiple initialization or update assignments within the loop. Uses a simple comma-separated syntax. NOTE: All or none of the variables must be local
int k = 99;
// This declaration will be ignored by the following loop
initial for ( int j = 0, k = 10; j <= k; j++, k-#10 $display(" j: %0d k: %0d",j,k); initial #40 $display("
Global k:
%0d", k);
Simulator output
# # # # # # #
j: 0 k: 10 j: 1 k: 9 j: 2 k: 8 Global k: 99 j: 3 k: 7 j: 4 k: 6 j: 5 k: 5
72
for multi-assignments
SystemVerilog allows multiple initialization or update assignments within the loop. Uses a simple comma-separated syntax. NOTE: All or none of the variables must be local
int k = 99;
// This declaration will be ignored by the following loop
initial for ( int j = 0, k = 10; j <= k; j++, k-#10 $display(" j: %0d k: %0d",j,k); initial #40 $display("
Global k:
%0d", k);
Simulator output
# # # # # # #
j: 0 k: 10 j: 1 k: 9 j: 2 k: 8 Global k: 99 j: 3 k: 7 j: 4 k: 6 j: 5 k: 5
72
foreach loop
Syntax: foreach ( ( <array name>[<loop variables>] )) <statement>
int
Ary[10];
i iterates from 0 to 9
= %d",i,Ary[i]);
73
foreach examples
Multiple loop variables correspond to nested loops If used with associative arrays, the type of the loop variable is auto-cast to the type of the array index
int
mem[8][4];
= %d",i,j,mem[i][j]);
b iterates first from 7 down to 0, then col from 0 to 1, then row from 0 to 3
$display("Bit
%d of binmem[%d][%d] is %z",b,row,col,binmem[row][col][b]);
int
assoc[string];
s is cast as a string and iterates through all keys in the associative array
= %d",s,assoc[s]);
74
reg[3:0] b, a; for ( int i=0; i<52; i++ ) begin a = 1; #5 case(b) 1: continue; 0: break; endcase a = 0; end
jump to next iteration of loop NOTE break and continue may only be used inside a loop exit the loop (as in C )
75
Sparse model allocates memory only for addresses actually written / read!
232
76
Sol
78
Hierarchy
In this section
79
Synth
net
module
tri
tri
80
Module Ports
SV port declarations can be made within the parentheses of the module declaration
module MUX2 ( output logic input logic input [1:0] [1:0] [1:0] out, in_a, in_b, sel ) ;
Ports may be of ANY SystemVerilog type including events, structs, arrays, etc.
typedef struct { bit isfloat; struct { int i; } tagd; module mh1 (input ... endmodule
shortreal
f;
event e1,
input
int
in1,
81
Driving an SV variable
Verilog has only 1 resolved type net
Multiple assignments to same net get resolved Non-net types are unresolved so last assignment wins
In SV, a variable (i.e. not a net) of any type may be driven by just one of the following:
Arbitrary number of procedural assignments (like reg in Verilog) Single continuous assignment Single primitive/module output
Allows the simulator to spot a common Verilog problem of multiple drivers to a node Absolute rule because none of these types are resolved
82
Hierarchy
SystemVerilog adds several enhancements to design hierarchy:
timeunit and timeprecision specifications bound to modules Simplified named port connections, using .name Implicit port connections, using .* Interfaces to bundle connections between modules
83
module timespec; timeunit 1ns; timeprecision 0.01ns; initial #5.19 $display(Current endmodule
Precedence if timeunit / timeprecision not specified in a module: 1. 2. 3. 4.
timeunit & timeprecision are local to a module, they are not `directives that can affect modules compiled later in sequence.
time is
%f, $realtime);
If the module is nested, inherit from the enclosing module. Use the time units of the last `timescale specified within the compilation unit. Use the compilation units time units specified outside all other declarations. Set to the compilers default time units.
Questa vsim command has switches for globally setting the timeunit and timeprecision
84
d, sel);
.* syntax instantiation
mux U3 ( .*, .d(), .sel(sel1));
85
86
SV and hierarchy
Packages
A mechanism for sharing parameters, data, type, task, function, sequence and property declarations amongst modules, interfaces and programs.
Compilation units
A collection of one or more SystemVerilog source files compiled together
Compilation-unit scope
A scope local to the compilation unit, containing all declarations that lie outside of any other SV scope
$unit::
A name used to explicitly access the identifiers in the compilation-unit scope
87
Packages -1
Packages are explicitly named scopes declared at top of hierarchy
May contain types, variables, tasks, functions, sequences, and properties
package p; typedef enum { FALSE, TRUE } BOOL; const BOOL c = FALSE; endpackage Declaration assignments are performed before
any always/initial/program blocks execute
c = 0;
Package items may be referenced within modules, interfaces, etc. (even other packages)
Using fully resolved name (use the scope resolution operator "::" )
c inside of q )
88
Packages -2
Packages are explicitly named scopes declared at top of hierarchy
May contain types, variables, tasks, functions, sequences, and properties
package p; typedef enum { FALSE, TRUE } BOOL; const BOOL c = FALSE; endpackage package q; const int endpackage
c = 0;
Instead of a fully resolved reference an entire package or a package item may be imported However, if the identifier of an imported item is already used in the importing scope, that item is silently NOT imported
module foo2; import q::*; wire a = c; // import p::c; import p::*; wire b = p::c; endmodule
* is a wildcard, allowing ANY identifier in package to be referenced
// no need to reference package q since c is "imported" already // Import c from package p, BUT compile error: c already exists // c silently NOT imported, no error/warning posted // No error because fully referenced
89
Package example
package pkg_rmac; typedef typedef struct {bit[55:0] preamble ; bit [7:0] sfd ;} h_type; `include `include `include "tb_eth_defines.v" "eth_defines.v" "timescale.v"
typedef int int } frm; typedef int int int int } gap;
//
NOT USED
} fids; // Typedefs for stream_mp3_file typedef struct { int n64; int n244; int n428; int n608; int n792; int n972; int n1156; int n1340; int n1500; } distro; task
//============================== //=== REFERENCE SV PACKAGE === //============================== import pkg_rmac::*; stream_set . . . set; // used to configure
typedef struct { frm frame; distro dis; gap ifg; } stream_set; endpackage
90
91
CU Example -1
code.sv
typedef struct{ logic [9:0] addr; logic[31:0] } global_pkt; data; global_pkt unit_pkt; global_pkt in1); %h, data: %h",in1.addr,
task global_task (input $display($stime,,"addr: endtask module code; logic [7:0] x; global_pkt y;
in1.data);
initial begin #20; y.data = 2; #10; unit_pkt.data = 3; $unit::unit_pkt.addr global_task(unit_pkt); end endmodule
y.addr
= 2;
global_task(y);
VSIM 2>
= 3;
NOTICE
$unit:: is redundant
According to the default use model in SV each file is its own Compilation Unit so the typedef and task declarations are within the implicit CU of module code.
92
CU Example -2
code.sv
typedef struct{ logic [9:0] logic[31:0] } global_pkt; unit_pkt; addr; data;
ERROR!!
not refer to a scope. not refer to a scope. not refer to a scope. not refer to a scope. not refer to a scope. not refer to a scope.
global_pkt
task global_task (input $display($stime,,"addr: endtask module code; logic [7:0] x; global_pkt y;
in1.data);
name 'unit_pkt' does name 'unit_pkt' does name 'unit_pkt' does name 'unit_pkt' does name 'unit_pkt' does name 'unit_pkt' does
This compile fails because test_1 cannot see the declaration of global_task() since a local variable of the same name hides the external declaration of unit_pkt.
initial begin #20; y.data = 2; y.addr = 2; global_task(y); #10; unit_pkt.data = 3; unit_pkt.addr = 3; global_task(unit_pkt); end endmodule
test_1.sv
module test_1; logic unit_pkt; // local variable hides global
code U1(); initial NOTICE begin #10; unit_pkt.data = 1; // not compat. unit_pkt.addr = 1; global_task(unit_pkt); end endmodule
code
93
CU Example -3
code.sv
<os> vlog code.sv test_2.sv
typedef struct{ logic [9:0] addr; logic[31:0] } global_pkt; data;
ERROR!!
global_pkt
** Error: test_2.sv(10): (vlog-2164) Class or package '$unit' not found. ** Error: test_2.sv(11): (vlog-2164) Class or package '$unit' not found. ** Error: test_2.sv(12): (vlog-2164) Class or package '$unit' not found.
task global_task (input $display($stime,,"addr: endtask module code; logic [7:0] x; global_pkt y;
in1.data);
This compile fails because the implicit $unit scope works only within the same file. However, if we put both modules in a single file
initial begin #20; y.data = 2; y.addr = 2; global_task(y); #10; unit_pkt.data = 3; unit_pkt.addr = 3; global_task(unit_pkt); end logic endmodule code U1(); unit_pkt; // local variable hides global
test_2.sv
module test_2;
NOTICE
initial added $unit:: begin #10; $unit::unit_pkt.data = 1; $unit::unit_pkt.addr = 1; global_task($unit::unit_pkt); end endmodule
//
$unit::
needed to skip
local
variable
94
CU Example -4
code.sv
typedef struct{ logic [9:0] addr; logic[31:0] } global_pkt; data;
Since putting multiple modules in a single file is not a workable approach the QuestaSimTM compiler switch mfcu defines a custom CU: vlog mfcu <file1.sv> <file2.sv><fileN.sv>
global_pkt
task global_task (input $display($stime,,"addr: endtask module code; logic [7:0] x; global_pkt y;
in1.data); CU
initial begin #20; y.data = 2; y.addr = 2; global_task(y); #10; unit_pkt.data = 3; unit_pkt.addr = 3; global_task(unit_pkt); end endmodule
test_2.sv
module test_2; logic unit_pkt;
code U1(); initial begin #10; $unit::unit_pkt.data = 1; $unit::unit_pkt.addr = 1; global_task($unit::unit_pkt); end endmodule $unit typedef struct { . . . // $unit:: needed here test_1 code
95
In this section
Task enhancements Function enhancements Recursion Default arguments Explicit calls Pass by reference Data scope and lifetime
96
Static/Dynamic Variables
Remember, SystemVerilog is 100% backward compatible with both Verilog 1995 and 2001. Static ( Verilog 1995 )
Memory-allocation / initialization once, at compile time Exists for the entire simulation
May NOT be used to trigger an event May NOT be assigned by a non-blocking assignment May not be used to drive a port
97
98
task write_vector(
input
addr);
@(negedge clk); if (bus_error) return; data_bus = data; addr_bus = addr; write = 1; @(posedge clk); #5 write = 0; endtask
99
Tasks ( Recursion )
SystemVerilog makes major extensions to basic Verilog syntax.
Supports automatic keyword (from Verilog 2001) Unlike Verilog, all local variables are dynamically allocated at call time. Full recursion is supported (automatic variables/arguments stored on stack) Can do concurrent calls Can do recursive calls
task automatic my_task( input int local_a, int local_b); (local_a == local_b) begin my_task(local_a-1,local_b+1); return; end global_a = local_a; global_b = local_b; endtask if // detect where arguments are identical // fix by inc/decrementing // end this copy of task // drive the outputs
100
Functions
Extends the basic Verilog function syntax.
ANSI-C style formal declarations (plus new one: ref Arguments can be any SystemVerilog type Return value can be a structure or union Default direction is input, but also supports output Function-endfunction implies a begin-end structure return statement supported as well as assignment to function name Supports automatic keyword, allowing recursion just like tasks Supports return type of void )
function automatic int factorial (int n); // factorial 0 is 1 if (n==0) return (1); else return (factorial(n-1)*n); endfunction
101
// Invert the image ( pos -> neg, neg -> pos ) function void invert(); for(int ver=1; ver <= 150; ver++) for(int hor=1; hor <= 400; hor++) begin vidbuf[ver][hor].R = 255 - vidbuf[ver][hor].R; // invert vidbuf[ver][hor].B = 255 - vidbuf[ver][hor].B; // invert vidbuf[ver][hor].G = 255 - vidbuf[ver][hor].G; // invert end endfunction initial invert();
102
Notice Verilog placeholder syntax has a new significance for default arguments:
initial begin do_this(5,2,0); do_this(5,2); do_this( , ,0);
// data(5), addr(2), ctrl(0) // data(5), addr(2), default: ctrl(2) // ctrl(0) default: data(0), addr(0),
103
Pass by reference (C++ style, less confusing than C-style using pointers )
Arguments passed by reference are not copied into the subroutine 'space' Subroutine accesses the argument data via the reference If arguments change within subroutine, original updates immediately Reference is indicated by ref keyword
[type]
<name>, );
104
byte byte_array[1000:1]; function automatic int crc( ref for( int j= 1; j <= 1000; j++ crc ^= packet[j]; end endfunction initial int a = crc(byte_array); byte packet ) begin [1000:1] );
const is used here to prevent modification of the reference/original and is legal for both tasks and functions
task automatic show ( const ref bit[7:0] data ); for ( int j = 0; j < 8 ; j++ ) $display( data[j] ); // data can be read but not written endtask
105
MAX);
10
function automatic void v_factorial (int for (n=0; n<=m; n=n+1) $display("%d! = %d", n, factorial(n)); endfunction endmodule
m);
106
Static vs Automatic
static automatic storage allocated on instantiation and never de-allocated stack storage allocated on entry to a task, function or named block and de-allocated on exit.
avar;
initial begin static int svar2; automatic int avar2; end task automatic autotask; automatic int avar3; static int svar3; endtask initial $monitor endmodule (svar);
107
Dynamic Processes
In this section
108
Dynamic Processes
SystemVerilog defines 2 new special cases of forkjoin with associated keywords join_any & join_none
join
fork join
//
all
blocks finished
fork join_any
//
any block
finished
fork join_none
//
no waiting
at all
109
forkjoin_none
SystemVerilog replaces process by join_none
This allows any number of processes to be spawned simultaneously without any impact on the flow of the main process
task run_test; fork timeout( 1000 ); apply_stimulus(); verify_response(); join_none NOTE The child processes spawned by a forkjoin_none do not start executing until the parent process hits a blocking statement
@(sig); endtask
110
fork
With Dynamic processes SystemVerilog needed to provide more global detection that spawned processes have completed The wait fork statement is used to ensure that all child processes (spawned by the process where it is called) have completed execution
begin fork task1(); task2(); join_any fork task3(); task4(); join_none wait fork; end
111
fork
The disable fork statement terminates all active child processes of the process where it is called,
Termination is recursive, in other words it terminates child processes, grandchild processes, etc.
task test_with_timeout; fork // spawn off two child tasks in parallel, 1st to finish triggers off the join_any run_test(); timeout( 1000 ); join_any disable fork; // kills the slower task endtask task test_with_timeout; fork begin run_test(); disable timeout; end begin timeout( 1000 ); disable run_test; end join endtask // Verilog 1995
At first glance, this code may appear to do the same thing as the disable fork example above. However, what if the timeout task was a global one, used in many places? The disable timeout line would terminate this occurrence of timeout but ALSO any other occurrences that happen to be executing elsewhere in the system. disable fork terminates only copies of the timeout task spawned by the current block
112
Gotcha! disable
fork
Remember, disable fork recursively terminates all active child processes of the process where it is called,
module disable_fork; task semicolon; forever #10 $write(;"); endtask task gosub; fork semicolon; join_none #100; disable fork; $write("DISABLE"); #100 $display(); $stop; endtask : comma initial fork forever #10 $write(","); join_none
initial begin fork : full_stop forever #10 $write("."); join_none gosub; end endmodule
Simulation output
,;.,;.,;.,;.,;.,;.,;.,;.,;.DISABLE,,,,,,,,,,
113
In this section
Mailboxes Semaphores
114
115
Semaphore
semaphore S1 = new([# of keys]); // default is 0 keys new() function Prototype function new( int keyCount = 0); ) keyCount is the initial number of keys keyCount may increase beyond its initial value put() task Prototype e.g. S1.put(3); function void put( int keyCount = 1); keyCount = is the number of keys returned to the semaphore (default 1) get() task Prototype e.g. S1.get(); task get( int keyCount = 1); keyCount = is the number of keys to obtain from the semaphore (default 1) Process blocks on a FIFO basis if keyCount keys are not available try_get() function Prototype e.g. S1.try_get(3); function int try_get( int keyCount = 1); keyCount = is the number of keys to obtain from the semaphore (default 1) Process returns 0 if keyCount keys are not available
116
Semaphore Example
module semaphores; semaphore s1 = new(1); task t1(); for(int i = 0; i<3; i++) begin s1.get(1); #5; $display("t1 has semaphore"); s1.put(1); #5; end endtask task t2(); for(int i = 0; i<3; i++) begin s1.get(1); #5; $display("t2 has semaphore"); s1.put(1); #5; end endtask initial begin fork t1(); t2(); join_none #0; end endmodule
of of of of of of
117
Mailbox
mailbox [ #(type) ] MB1 = new([ bound ]); // Mailboxes default to singular (packed) type // bound is mailbox depth, default unbounded new() Prototype e.g. mailbox #(Packet) channel = new(5); function new( int bounded = 0); num() Prototype e.g. some_int_variable = MB1.num(); function int num(); // returns # of messages currently
in mailbox
put() Prototype e.g. MB1.put( sent_message ); task put( message); Store message in mailbox in FIFO order, block if mailbox full (bounded mailboxes only) get() Prototype e.g. MB1.get( rcvd_message ); task get( ref message); Remove message from mailbox in FIFO order, block if mailbox empty peek() Prototype task peek( ref message); Copy message from mailbox in FIFO order (dont remove), block if mailbox empty try_put(), try_get(), try_peek() Prototype function int try_put( message); function int try_get( ref message); function int try_peek( ref message); Non-blocking forms, return 0 if mailbox full/empty
118
Mailbox Example
module mailboxes; mailbox #(int) m = new(); task t1(); for(int i = 0; i<4; m.put(i); $display("T1 sent: #5; end endtask // create mailbox initial begin fork t1(); t2(); join_none #0; end endmodule
Output: # T1 sent: 0 # T2 received: # T1 sent: 1 # T2 received: # T1 sent: 2 # T2 received: # T1 sent: 3 # T2 received:
i++)
begin
%0d",i);
task t2(); int temp; while(1) begin m.get(temp); $display("T2 received: end endtask
0 1 2 3
%0d",temp);
119
driver
exp_mb
monitor
act_mb
120
checker compare
function
stimulus
act_mb
121
mbox.sv
checker compare
function
stimulus
act_mb
Sol
122
Classes
In this section
123
SV Classes - Overview
Object Oriented design is a common programming paradigm
Data and the means to manipulate is described together in a formal structure called a class
An instance of a class is referred to as an object SystemVerilog objects are dynamically created and destroyed
Memory allocation and deallocation (garbage collection) is handled automatically Since pointers are a key ingredient in the flexibility of classes, SystemVerilog implements them too, but in a safer form, called handles
Code minimization and reuse is facilitated through inheritance, parameterization and polymorphism
124
Classes
Class
Formal description Members Properties (data elements) Methods ( functions and tasks) Constructor ( new() )
Object
Instance of a class (e.g. pkt )
class Packet ; //properties cmd_type command; int unsigned address; status_type status; // methods task clean(); command = IDLE; endtask endclass Packet pkt = new();
address = 0;
125
user-provided Constructor
126
// declare object handle, does not create object itself, its value is null
pkt
null
127
pkt
packet object
// create object and assign to the handle pkt (pkt points to object created)
128
pkt
pkt
null
129
Copying Objects
OK, we can create/destroy objects How about duplicating one?
class C1 ; Packet pp; endclass C1 bb C1 cc bb; = new(); cc; = bb;
bb
C1 object
cc
bb
C1 bb, cc; bb = new(); cc = new bb;
NOTE SYNTAX No ( )s allowed
C1 object
cc
C1 object
Shallow Copy: Any nested objects will NOT be duplicated , only the members themselves (handle pp will be copied but not the object it points to)
bb cc
C1 object
C1 object
130
this
A predefined object handle that refers to the current object
Provides unambiguous reference to the object
class Packet; integer status; virtual function Packet clone(); Packet temp = new this; return(temp); endfunction endclass Packet orig_pkt, cloned_pkt;
orig_pkt this
Packet object
initial begin Packet orig_pkt = new(); orig_pkt.status = 55; cloned_pkt = orig_pkt.clone(); $display("cloned_pkt.status end
= %0d", cloned_pkt.status);
Simulation output # cloned_pkt.status = 55
131
Class example
class // ether_packet; Packet Fields preamble = 'h55555555555555; sfd = 'hab; dest, src; len; payld [ ]; Ethernet preamble sfd destination source length payload Packet Ethernet bit[55:0] bit [7:0] bit[47:0] bit[15:0] bit [7:0]
function new(int i); payld = new[i]; len = i; endfunction : new [47:0] lsrc, ldest, input [7:0] start_dat); src = lsrc; dest = ldest; len = payld.size(); if(start_dat > 0) for(int i = 0; i < len; i++) payld[i] = start_dat +i; endtask : load_frame function void print; $displayh("\t src: ", src); $displayh("\t dest: ", dest); $displayh("\t len: ", payld.size); for(int i = 0; i < len; i++) $displayh("\t payld[%0h]: %0h",i,payld[i]); $displayh(""); endfunction : print endclass : ether_packet task load_frame( input
Simulation
src: dest: len: payld[0]: payld[1]: payld[2]: payld[3]:
output
000000000055 000000000066 00000004 77 78 79 7a
initial begin ep = new (4); ep.load_frame('h55,'h66,'h77); ep.print(); // . . . ep = new(1); ep.load_frame('h22,'h33,'h44); ep.print(); // . . . ep = null; end endmodule
132
src[i]
src2snk[i]
snk[i]
Notice:
i);
Each source & sink object has a local mailbox handle. Those handles are null Why?
i);
task run(); while(1) begin in_chan.get(stim_pkt); $display("sink[%0d]: id, stim_pkt.field1); end endtask endclass : sink
Received packet
with
field1
= (%0d),
133
src[i]
src2snk[i]
snk[i]
Notice: 3 dynamic arrays: src, snk and src2snk Dynamic arrays, once initialized can hold multiple handles of each object type So, put all this together and.. We have a Lab exercise!
task run(); for(int i = 0; i <= id; i++) pkt_to_send = new(i); out_chan.put(pkt_to_send); end endtask endclass : source sink snk[]; source src[]; mailbox #(Packet) . . . endmodule
begin
src2snk[];
134
Instructions:
src2snk[i]
Using the code on the previous slide, implement the hardware shown here Complete the supplied module array_handles Edit the file array_handles.sv: Add an initial block that implements the following: Initialize each of the 3 dynamic arrays to a size of 5 elements (5x snk, 5x src & 5x src2snk) Create 5 objects to fill each array (snk[4]-snk[0], src[4]-src[0], src2snk[4]-src2snk[0]) NOTE: Initialize the snk and src object ids with their corresponding index HINT: Simple for-loops will be handy here
- Continued on next page -
135
src[i]
src2snk[i]
snk[i]
EXTRA CREDIT: Do this step by adding an argument to the constructor of sink/source classes
Call the run() method for all src and snk objects
HINT: Start corresponding objects simultaneously src[0] & snk[0], src[4] & snk[4] etc.
# source[0]: # sink[0]: # source[1]: # source[1]: # sink[1]: # sink[1]: # source[2]: # source[2]: # source[2]: # sink[2]: # sink[2]: # sink[2]: # source[3]: # source[3]: # source[3]: # source[3]:
Expected
Simulator
output
(0) = (0) (0) (1) = (0) = (1) (0) (1) (2) = (0) = (1) = (2) (0) (1) (2) (3)
Sent packet with Received packet Sent packet with Sent packet with Received packet Received packet Sent packet with Sent packet with Sent packet with Received packet Received packet Received packet Sent packet with Sent packet with Sent packet with Sent packet with
field1 = with field1 field1 = field1 = with field1 with field1 field1 = field1 = field1 = with field1 with field1 with field1 field1 = field1 = field1 = field1 =
136
Create handles (initialize the arrays) Create objects and assign to handles (using new() ) Connect objects (by assigning (copying) mailbox handles)
Sol
137
Mailbox handle
Mailbox object
sink handle
sink object
Mailbox handle: in-chan Packet handle: stim_pkt
0 task in_chan.get(stim_pkt)
packet objects
Only handles are passed, objects stay in same place 4once created, and are cleared only 1 no handle0 points to them Sol
138
Interfaces
In this section
Interface concepts & characteristics Simple bundled Methods Modports Importing methods
139
IO abstraction
source
reg a;
sink
a
if ( a == 1)
a = 0;
source
intf.a = 0;
interface intf
sink
if ( intf.a == 1)
reg a;
interface intf
sink
if (intf.rd_a() == 1)
reg a;
source/sink only call methods source/sink dont see low-level details like variables/structure, etc Easy to swap interface abstractions without any effect on source/sink
140
Interfaces
Great simulation efficiency can be achieved by modeling the blocks of a system at different levels of abstraction, behavioral, rtl, gate, etc. In Verilog, the I/O between blocks has always remained at the lowest pin level High-performance system-level simulation requires abstract inter-block communication.
module mmu(d, a, rw_, output [15:0] a; output rw_, en; inout [7:0] d; . . . endmodule en);
data addr
interface interf; tri [7:0] data; logic [15:0] addr; logic ena, rw_; endinterface module mmu(interf io.addr <= ad; . . . endmodule module mem(interf adr = io.addr; . . . endmodule module system; interf i1; mmu U1 (i1); mem U2 (i1); endmodule io);
MMU
rw_ ena
MEM
interface
module mem(d, a, rw_, en); input [15:0] a; input rw_, en; inout [7:0] d; Traditional . . . Verilog endmodule module system; tri [7:0] data; wire [15:0] addr; wire ena, rw_; mmu U1 (data, mem U2 (data, endmodule addr, addr, rw_, ena); rw_, ena);
io);
SystemVerilog
141
Interface characteristics
Interfaces bring abstraction-level enhancements to ports, not just internals An interface may contain any legal SystemVerilog code except module definitions and/or instances
This includes tasks, functions, initial/always blocks, parameters etc.
Bus timing, pipelining etc. may be captured in an interface rather than the connecting modules Interfaces are defined once and used widely, so it simplifies design Interfaces are synthesizable
142
sink
a
if ( a == 1)
a = 0;
source/sink can be abstracted but IO ( a ) must stay at low level IO operations are cumbersome, especially for abstract source/sink modules
143
cpuMod
memMod
module definition
Complete portlist
module
cpuMod ( input bit clk, bit gnt, inout logic [7:0] data, output bit req, bit start, logic[7:0] addr, logic[1:0] mode );
bit
rdy,
module definition
Complete portlist
... endmodule
module top; logic req, gnt, start, rdy; logic clk = 0; logic [1:0] mode; logic [7:0] addr, data; memMod mem(req, clk, cpuMod cpu(clk, gnt, endmodule
start, mode, addr, data, gnt, rdy); rdy, data, req, start, addr, mode);
Instantiate/connect everything
144
intf.a = 0;
reg a;
if ( intf.a == 1)
No port clutter All accesses are hierarchical ( through interface ) Simplifies source/sink declarations With no ports, who drives and who samples a All variables in interface are accessible ( no privacy/control )
145
a.gnt
<= a.req
& avail;
b, input
bit
clk);
= 0;
Instantiate/connect everything
// Instantiate the interface simple_bus sb_intf; memMod mem (sb_intf, clk); // Connect the interface to the module instance cpuMod cpu (.b( sb_intf), .clk(clk)); // Either by position or by name
endmodule
146
Interface Ports
Ports may be defined to an interface
simple_bus cpuMod
clk
memMod
This allows external connections to the interface to be made and hence automatically to all modules which bind to the interface Typically used for clk, reset, etc. simple_bus (input bit clk); // Define the interface simple_bus Interface req, gnt, start, rdy; with one input port clk [7:0] addr, data;
module memMod( simple_bus a ); logic avail; always @(posedge a.clk) a.gnt <= a.req & avail; endmodule module cpuMod(simple_bus b); ...
// the clk signal from the interface // a.req is in the simple_bus interface
endmodule
module top; logic clk = 0; simple_bus sb_intf1(clk); simple_bus sb_intf2(clk); memMod mem1(.a(sb_intf1)); cpuMod cpu1(.b(sb_intf1)); memMod mem2(.a(sb_intf2)); cpuMod cpu2(.b(sb_intf2)); endmodule
// Instantiate the interface // Instantiate the interface // Connect bus 1 to memory 1 // Connect bus 2 to memory 2
2 simple_bus instances
cpu/memory pair 1 cpu/memory pair 2
147
Interface Modports
Modport derives from keywords module and port They identify signal ownership from point of view of a module using that modport
source
intf.a = 0;
interface intf
sink
if ( intf.a == 1)
reg a;
modport
Modports specifically control variable access source/sink connect to a specific modport source/sink cant use resources not listed in their modport Multiple modules can connect to interface using the same modport so we may need to consider this in our implementation
148
Modports Example
modport keyword implies how the ports are accessed from the point of view of the module
interface i2; logic a, b, c, d, e, f; modport master (input a, b, output c, d, e); modport slave (output a, b, input c, d, f); endinterface
m i
master slave
i2 i
i);
i is port name of interface i2 Modport indicates direction Interface name acts as a type
i);
HINT: Any number of modules may connect to an interface via the same modport
149
Modport
Subgroup signals by purpose, timing and direction Specify direction of asynchronous signals Note: signals may appear in multiple modports
150
src2snk[i]
Class objects
RTL instance
Simple solution is to hierarchically address the module's ports ( or signals connected to the ports ) from the class
Issues Must hard code into class definition a hierarchical path to the port or signal Limits reusability of class What if you have multiple DUT / snks to connect?
src[i] snk[i] DUT
src2snk[i]
151
Must still hard code into the class the hierarchical path to the interface instance
src[i]
src2snk[i]
snk[i] DUT_IF
DUT
152
src2snk[i]
snk[i]
interface_type
v_if_name
153
154
module dut(
= !clk;
input int data_rcvd, input bit clk ); always @(posedge clk) begin $display("%m received data: %0d", data_rcvd); end endmodule
//
null
handle
4
);
function new ( virtual dut_if real_dut_if // map virtual interface to real interface v_dut_if = real_dut_if; 6 endfunction
task run(); while(1) begin in_chan.get(stim_pkt); // access real interface via virtual IF @( negedge v_dut_if.clk ) v_dut_if.data_rcvd = stim_pkt.field1; $display ("sink: Received packet with field1 = (%0d)", id, stim_pkt.field1); end endtask endclass : sink
155
Router design
156
top, test_router, router test_env, stimulus, driver, monitor, scoreboard router_if log_stim, log_mon, s2d_mb
scoreboard driver[i]
router_if
( router
driver[i]
157
Router Schematic
test_env
router_if()
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
driver
monitor
TB
valido[4] streamo[4]
dest
3 0 0 1 1 0 0
1 01 1
B 0 1 1
6 0 1 1 0
1 0 0
Example Waveform: shows packet #31 (Payload 1 byte: B6) entering port 4 routed to port 4
it rt-b Sta
158
scoreboard
driver[i]
router_if
( router
driver[i]
159
top_if
dut
router_if
( router
test_router
File top.sv Contains instantiations for: the interface router_if "top_if the router module "dut" the test_router module test
scoreboard
driver[i]
Virtual Interfaces
router_if
( router
stimulus[i]
s2d_mb[i]
driver[i]
161
Compile & run the code by typing: make -or- make gui
Sol
162
Classes
In this section
Inheritance
Rather than add additional functionality to a class by copying and modifying we extend classes by inheritance
class Packet ; //properties integer status; // methods task rst(); status = 0; endtask endclass Base class with properties/ methods Inherited properties/ methods Packet (parent or base class)
status rst()
class DerivedPacket //properties integer a,b,c; // methods task showstatus(); $display(status); endtask endclass
extends Packet ;
DerivedPacket inherits all of Packet, that is to say DerivedPacket "is a " Packet PLUS DerivedPacket has its own additional properties/methods
164
Inheritance Example
Inheritance approach is ideal for verification
Base-class v_generic_cpu
v_cpu2
165
Inheritance overriding
Derived classes may override the definition of a member inherited from the base class
"Hides" the overridden property or method To override a method the child method's signature must match the parent's exactly
class Packet int status ; = 4; Base class with properties/ methods
Packet
setstat(int status s)
function void setstat(int s); status=s; $display ("parent setstat"); endfunction endclass
DerivedPacket
Packet ; DerivedPacket setstat(int s) setstat(int s) overrides method of status function void setstat(int s); Packet status=s; $display ("child setstat"); DerivedPacket p = new(); endfunction initial begin endclass p.status = 44; // OK to access inherited property which setstat() p.setstat(33); // output is "child setstat" is called? end class DerivedPacket extends
166
super
The super keyword is used to refer to members of the base class
Required to access members of the parent class when the members are overridden in the child class You may only "reach up" one level (super.super is not allowed) Only legal from within the derived class Packet
class Packet int status ; = 4; s);
chkstat(int status s)
function bit chkstat(int return (status == s); endfunction endclass class DerivedPacket int status = 15; extends
DerivedPacket
Packet ;
chkstat(int s) chkstat(int status s)
s);
Cannot access status outside of object. super keyword legal only inside an object
status
Prints "4" because it explicitly refers to the base class member status
DerivedPacket p.super.status
167
// methods function new(); status = 0; endfunction endclass class DerivedPacket //properties integer a,b,c; extends Packet ;
ddB
dddB new()
Derived class with its own constructor When invoked, & before running any of its own code, new() invokes the new() method of its super-class, and so on up the hierarchy. Execution is root downward...
168
extends
Packet;
Solution 1
extends
Packet(5);
Solution 2
(pass constructor args)
169
Inheritance Puzzle #1
Inheritance is quite straightforward but can raise some confusing situationsConsider:
module poly1; DerivedPacket payld); class Packet ; der = new();
task build_packet(); build_payld(); // which build_payld() will this call? endtask endclass
The base class does not know anything about the derived class. So here build_packet() will call build_payld() in the base class even though it is overridden in the derived class Question How can we have the base class method call the overridden method in the derived class instead?
class DerivedPacket
extends
Packet ;
170
Virtual Methods
A virtual method in a base class is like a prototype for derived classes Variation on previous slide:
module poly3; class Packet ; virtual task build_payld(); $display(Packet payld); endtask task build_packet(); build_payld(); endtask endclass DerivedPacket der = new();
class DerivedPacket
extends
Packet ;
Here, program calls base method build_packet() which calls build_payld() but because build_payld() is declared virtual in the base class the local derived class method is called. Think of Virtual methods this way:
payld);
The implementation of a virtual method that is used is always the last one in a descent of the hierarchy ( or local to DerivedPacket in this case ).
171
More on is a
We said earlier that a derived-class object is also a 100% valid object of the base class Lets see
module is_a; Base aa, bb; Derived cc; class Base ; integer status; endclass class Derived extends integer fred; endclass Base;
bb
Base
aa
Base
initial
begin
LEGAL assignment!
Derived object is a valid base object so base handle can point to derived objects
cc
Derived Derived class Object
172
initial begin aa = new(); bb = new(); // returns 1 if ( $cast (aa, bb) ) $display(Objects are of compatible type); Base else Up $display("Should never see this"); end YES! module base2derived; endmodule Derived Base aa; Derived cc; initial begin aa = new(); cc = new(); if (!( $cast(cc, aa) )) // ILLEGAL Packet OK Packet // Illegal cast - from base to derived if // LEGAL ( $cast(aa,cc) ) // Legal - from derived to base ((
Down
NO!
// LEGAL $cast(cc, aa) )) // Now legal!!! - back to derived // But this is ALWAYS a compile error! cc = aa; end endmodule if
173
- Continued
on next
page -
174
Whats missing? We need better randomization of the packets Coming up: Object Oriented Randomization
Sol
175
static Properties/Methods
By default each instance of a class has its own copy of the properties and methods Use of the keyword static makes only one copy of the property or method that is shared by all instances static property
A property that is shared across all objects of the class Static properties may be accessed before an object of the class is created
class static_ex; static integer fileId = $fopen( "data", "r" ); static int val; static function void print_val(); $display("val = %0d", val); endfunction File: data endclass
a
module test; static_ex s1; // Only handle is required static_ex s2; bit[7:0] c; initial begin c = $fgetc( s1.fileId ); $display("%0s", c); s1.val = 22; s1.print_val(); s2.val = 44; Sim. Output s1.print_val(); # a end endmodule # val = 22
static method
A method shared across all objects of the class May only access static properties Callable from outside of the class, even before an object of that class is created
# val = 44
176
const Properties
The keyword const inside a class is consistent with elsewhere in SV A property that is declared const is protected from any modification. Two sub-types of const are defined:
Global constant ( declaration specifies value ) Instance constant
class gPacket; // global constant protected from modification const int size = 512; byte payload [size]; endclass
No initial value!
ignored
Q 6.2
class iPacket; const int size; byte payload []; function new(); size = $random % 4096; payload = new[ size ]; endfunction endclass
177
A local member is only visible within that class or by hierarchical reference from other instances of the same class
class Packet; local int i; int def; endclass Packet p = new(); p.def = 8; p.i = 5; // OK // ERROR!
Visible from outside class
Packet non-local
def
local
i
visible
178
status;
rst()
DerivedPacket
non-local local
status
class DerivedPacket //properties integer a,b,c; // methods task showstatus(); $display(status); endtask endclass
extends
Packet ;
a b c
showstatus()
rst()
//
ERROR
visible
179
status;
DerivedPacket
non-local protected
class DerivedPacket //properties integer a,b,c; // methods task showstatus(); $display(status); endtask endclass
extends
Packet ;
a b c
showstatus()
rst()
status
//
Now OK!
visible
Visible from outside class
180
extern
Allows separation of the declaration of a method ( in the class) from its definition outside of the class
virtual
function
int
send(int
value);
function
int
Packet ::
send(int
value);
181
Handles of a particular specialization (type) may not point to objects of a different specialization (type)
AA aa_512 = new(); AA #(.size(256)) my_aa = new(); initial begin // my_aa = aa_512; // Create a default specialization of generic class AA // Create a specialization of generic class AA (a new type) // Illegal - my_aa and aa_512 are different types
Questa runtime output from above code: # ** Fatal: Illegal assignment to object of class AA__1 from object of class AA__2
182
Parameterized Classes
Constructors allow for customization of objects at run time Parameters allow for customization of objects at compile time Parameters can be value parameters or type paramters Parameterization of a value:
class AA #( int size = 512 ); byte payload [size]; endclass AA #(.size(256)) my_aa = new();
size substituted by the value 512 at compile time
Parameterization of a type:
class BB #( type T = int ); T payload [512]; endclass BB bb_int = new(); BB #(string) bb_string = new();
Multiple parameters:
class CC #( type T = int, int T payload [size]; endclass CC #(.T(integer), .size(1024)) size = 512 );
cc_handle
= new();
183
);
Generic class
//class D_1 derived from default specialization of D_base class D_1 extends D_base ; endclass D_1 D_1_handle = new(); //class D_2 derived from specialization of D_base class D_2 extends D_base #(.T(string) ); D_2 D_2_handle = new();
T is string
endclass
T is int R is bit
//generic class D_3 derived from default specialization of D_base class D_3 #( type R = bit ) extends D_base; endclass D_3 D_3_handle = new(); //generic class D_4 derived from specialization of D_base class D_4 #( type R = bit ) extends D_base #(.T(R)); endclass D_4 #(.R(byte)) D_4_handle = new();
T is R which is byte
T is R
184
Polymorphism
Consider a base class that is multiply-derived into sub-classes, each of which over-rides a common virtual base method Polymorphism allows that any derived-class object referenced via the base class will invoke the appropriate method without any special programmer intervention.
class Display; integer v; virtual task Print(); $display(v (dec): endtask endclass
module poly5; HexDisplay hx = new(); OctDisplay oc = new(); Display poly; ; initial begin hx.v = habcd; oc.v = habcd; poly = hx; poly.Print(); poly = oc; poly.Print(); end endmodule
v (hex) v (oct)
extends
Display
extends
Display
Simulation output
: 0000abcd : 00000125715
185
class Ether_Packet
extends Packet;
class Token_Packet
extends Packet;
// methods function bit CRC(); $display("Ethernet CRC"); return(1); // Verify CRC according to // 802.3 (Ethernet) standard endfunction endclass
// methods function bit CRC(); $display("Token-ring CRC"); return(1); // Verify CRC according to // 802.5 (Token-ring) standard endfunction endclass
186
Virtual Classes - 2
class CRC_checker; integer idx = 0; Packet pkt_array[512]; // Array of ANY kind of packet p);
Arrays and other containers like lists, etc. usually require that all elements be of the same type.
function void add_to_array(Packet pkt_array[idx] = p; idx++; endfunction function void check_CRC(); for (i = 0; i < 512; i++; ) begin if (!pkt_array[i].CRC()) $display ("CRC Error"); end endfunction endclass
Inheritance allows either an Ether_Packet or a Token_Packet to be passed in as an argument and stored into the array.
Polymorphism means that regardless of which type of packet is stored in the array, the CORRECT CRC function will be called.
What's the big deal about polymorphism? It allows for more generic (i.e. reusable) code, where multiple alternative method definitions in derived classes can be dynamically bound at run time via a variable of the base ( or super ) class.
187
virtual
class
pure virtual
Do_Nothing_by_Default()
Empty virtual methods are also allowed. However, in a deriving class, these are interpreted as having a default implementation DO NOTHING!
188
The packets that are generated and sent by the source and received by the sink will be of the two new types which you will write, derived from the base packet type. These two new types differ in how they generate crc check fields. The base class mailbox will carry only derived class packets and every packet received by the sink object must be crc-checked. The check_crc() function will be called polymorphically.
- Continued
on next
page -
189
mailbox Object
Type = Packet
Receives packets from mailbox, checks crc and puts packets in the array
190
191
192
- Continued
on next
page -
193
194
i++)
function void init_pkt(int sz); payload = new[sz]; for (int i = 0; i<sz; i++) payload[i] = $random() % 256; payload values randomized gen_crc(); // crc++; // insert error by un commenting this line endfunction endclass
195
id id id id id
= = = = =
1 2 3 4 5
id id id id id
= = = = =
6 7 8 9 10
Sol
196
In this section
Stimulus Generation Methodologies Constraint blocks Randomize Random sequences Random Number Generation Scoreboarding
197
Stimulus Methodologies
3 common means of generating stimulus
Exhaustive stimulus Usually algorithm-driven based on implementation Breaks down on complex designs - impracticably large testspace Highly redundant by definition Directed stimulus Works for well-understood or simple designs Reduces redundancy but still very hard to get 100% coverage Random stimulus Usually transaction based (well defined transactions => good coverage) Spots corner cases humans couldnt predict Highly redundant for unconstrained random numbers
198
Random Testing
Concept:
Define the set of transactions needed for verification Randomize transaction parameters to achieve coverage
Theory:
Random testing will find all bugs identified by other means and more Beware: While this is theoretically true, it is also misleading Can lead to sloppy no-thought testing May require very long runs to achieve coverage
Best Strategy:
Directed Randomization Steer random paths by means of probabilities (weights) Weigh interesting cases more than uninteresting ones Initialize the system to interesting states before randomization
199
200
Randomness
True random numbers
Unpredictable sequence of random numbers In use, generates legal & illegal conditions Failing tests are not repeatable Usually harder to debug
Pseudo random
Generate a predictable series of highly random numbers Reuse the sequence in regression tests Reapply the same sequence in different tests
Constrained random
Start with true or pseudo random number streams Constraints use system knowledge to remove illegal numbers
201
addr; data;
word_aligned
{addr[1:0]
== 2b00;}
== 1 )
data: %h\n, mybus.addr, mybus.data);
%16h ,
else
$display (Randomization failed);
end
202
rand,
NOTE randc variables are assigned values before rand variables. Constraining a randc variable with a rand property is illegal
203
Constraint Block
A constraint block is a class member that controls randomization of the random variables in that class.
class ex1; rand int constraint endclass
Expression(s)
In addition, some special constructs are provided (to be discussed shortly): - distribution/weights dist - implication -> - alternate style of implication ifelse
204
a,b,c,d,e; con_ab { a > b; a < 256; con_c { c inside { [1:5], (a - b) >= 64; } 12, [(a-b):(a+b)] }; }
Multiple constraints are anded together
} w );
function automatic int count_ones ( bit [31:0] for( count_ones = 0; w != 0; w = w >> 1 ) count_ones += w & 1b1; endfunction constraint endclass con_ef { e == count_ones( f ) ; }
Functions are called before constraints are solved and their return values act like state variables
205
Overridden constraint
This allows constraints to be reused and modified without editing the base set
Enhance a test without rewriting (breaking) the original classes Reuse methods with different stimulus
206
loop variable
C2 constrains each element of the array A to be greater than twice its index.
207
Its generally better to modify constraints dynamically than to rewrite, recompile, and rerun
Alternative is to extend base class, instantiate and write code to use it
208
209
if
else )
rand int z; constraint con_mode_z { mode == sm -> {z < 10; z > 2;} mode == big -> z > 50; }
rand int z; constraint con_mode_z { if (mode == sm) {z < 10; z > 2;} else if (mode == big) z > 50; }
If mode is sm, z will be less than 10 and greater than 2, if mode is big, z will exceed 50 Q: What about other modes? A: .
210
Statistical weights module dist1; test_dist td = new(); bit rr; Weight is assigned to each value across range int result[6]; initial begin for (int i=0; i<1000; i++) begin rr = td.randomize(); result[td.x]++; Output: end 1 count = 99 for (int i=1; i<5; i++) 2 count = 111 $display("%0d count = %0d",i,result[i]); 3 count = 288 end 4 count = 502 endmodule
211
:/
2 , 5 := 3 , 6 := 4, 7 };
No weight: defaults to :=1 module dist2; test_dist td = new(); bit rr; Weight is divided equally across range int result[9]; initial begin for (int i=0; i<1000; i++) begin rr = td.randomize(); Output: result[td.x]++; 1 count = 54 end 2 count = 54 for (int i=1; i<8; i++) 3 count = 45 $display("%0d count = %0d",i,result[i]); 4 count = 57 end 5 count = 288 endmodule 6 count = 397 7 count = 105
212
randomize()
Randomize is a built-in virtual function that generates new random values for all active variables in an object. It CANNOT be overridden virtual function int randomize();
Randomize() works within constraints addr; data; {addr[1:0] == 2'b00;}
word_aligned
bus mybus = new(); initial repeat(50) begin if ( mybus.randomize() == 1 ) $display (addr: %16h , data: %h\n, else $display (Randomization failed); end Return value: 0 if solver fails to satisfy constraints
mybus.addr,
mybus.data);
213
randomize()
randomize()with
class Sum; rand bit[7:0] constraint endclass
with
is a way to add constraints in-line.
bit
[7:0]
a,b;
with
{ x < y;
z >= b; };
Local variables
Object variables
214
length;
c1 {(length<max) //
&& (limit>min);} RANDOMizable limit, length limit max, min max, limit STATE VARIABLES max, min length, max, min limit, length length, min
// // // //
Non-OO Randomization
So far randomization has been described as object-based There is also a randomization protocol which does not require class(es) std::randomize() allows randomization of data within the current scope
OO Example
Equivalent code
Non-OO Example
class stimc; rand bit [15:0] addr; rand bit [31:0] data; rand bit rd_wr; constraint c { addr < 1024; endclass
Call std::randomize()
function bit gen_stim( stimc bit success; success = p.randomize(); return p.rd_wr; endfunction
216
Function Prototype
function int object.rand_mode( returns the mode )
class Packet; rand int x,y; int k; constraint con_x { x <= y; } endclass Packet p = new(); Set p object rand_mode to inactive int stat_y; initial begin Set p.y rand_mode to active p.rand_mode(0); p.y.rand_mode(1); Check active mode of p.y stat_y = p.y.rand_mode(); // p.k.rand_mode(1); // illegal ! no rand_mode for k end
217
Constraint Control
Each object containing constraints also supports a method constraint_mode()
Allows constraints to be turned on/off at will. An inactive constraint will not affect randomization
Task Prototype
task object.constraint_mode(bit mode) mode = 0 means inactive, randomize()ignores constraint mode = 1 means active, constraint affects randomize()
Function Prototype
function int object.constraint_mode( returns the mode )
{ [1:4]
:= 1,
[5:9]
:= 2,
10 := 3 }; }
function int toggle_con_x ( Packet p ); ) if ( p.con_x.constraint_mode() p.con_x.constraint_mode(0); else p.con_x.constraint_mode(1) ; return( p.randomize() endfunction );
218
NOTE:
To use either of these in a derived class it is compulsory to add a call to its corresponding parent class method.
initial begin p = new(); for (int i = 0; i<20; i++) begin if(p.randomize() ==1); $display("addr = %0d",p.addr); end end endmodule
219
Random Case
The features discussed so far allow flexible randomization of variables But what about decision making?
randcase is a case statement that randomly selects one of its branches
module rand_case(); int results[3]; int w = 3; Output: initial begin 0 count = 93 for(int i=0; i<1000; i++) 1 count = 310 randcase 1: results[0]++; 2 count = 597 Weights are non-negative w: results[1]++; May be a variable 6: results[2]++; endcase for (int i=0; i<3; i++) $display("%0d count = %0d",i,results[i]); end endmodule
220
Random Sequences
Derived from theory behind language parsers randsequence
Generates randomized sequences for test Optional weights can be added
module randseq_1(); initial Start-point for (int i=0; i<10; i++) randsequence( main ) main : first second done; first : add | dec ; non-terminals second : pop | push ; done : { $display("done");} add : { $write("add "); } dec : { $write("dec "); } terminals pop : { $write("pop "); } push : { $write("push "); } endsequence endmodule
production Unchangeable sequence Random choice: a | b
; ; ; ; ;
Output:
# # # # # # # # # # dec add dec dec dec dec dec dec add dec push push pop pop pop push push pop pop push done done done done done done done done done done
221
Output:
# # # # # # # # # # dec dec add dec dec dec dec add add dec push push pop pop pop push push pop pop push done done done done done done done done done done
222
Status
Status
} ;
223
224
ifg
noise
ifg
data
ifg
data
forever // Rand. seq. of data & noise' eth packets and Inter-Frame-Gaps begin : loop randsequence ( traffic ) traffic : ifg frame ; | ;
// ratio of data to 'noise'
data : { randcase // Weighted random choice of packet size set.dis.n64 : siz = 64; set.dis.n244 : siz = 244; set.dis.n428 : siz = 428; set.dis.n608 : siz = 608; set.dis.n792 : siz = 792; set.dis.n972 : siz = 972; set.dis.n1156 : siz = 1156; set.dis.n1340 : siz = 1340; set.dis.n1500 : siz = 1500; endcase epkt.build_data_frame(siz, rfile); // Call of transactor method epkt.drive_MRx; };
typedef struct { int n64; int n244; int n428; int n608; int n792; int n972; int n1156; int n1340; int n1500; } distro; typedef int int } frm; typedef int int int int } gap; struct data; noise; {
typedef struct { frm frame; distro dis; gap ifg; } stream_set; stream_set set;
225
(38)
@(posedge mrx_clk);
(100)
@(posedge mrx_clk);
short:
(5)
@(posedge mrx_clk);
typedef struct { frm frame; distro dis; gap ifg; } stream_set; stream_set set;
random :
( $urandom_range(10,100))
@(posedge mrx_clk);
endsequence
226
Reactive Randomization
Reactivity refers to the use of feedback from some realtime DUT analysis (typically SVA or Functional Coverage) to control/refine the randomization We will discuss this in more detail in upcoming sections.
Stimulus Generator
Transactor Verification
DUT
Support Models
Reactivity
Assertions
Monitor
227
1 0
0 0 1 0 0 0
passthru
Initially, the testbench will be configured to constrain randomization so that all packets are pass-thru ( srce == dest ) until such time as all ports have been targeted (register passthru == 255 ) At that time, the testbench will dynamically modify itself so that pass-thru packets are no longer generated and randomization will continue until end of simulation
228
229
Whats missing? Some way to measure when were finished This version just declares a max # of packets (500) Coming Up: Functional coverage
Sol
230
-> (a==0);
b; }
a;
a 0 1 2 3 0
b 1 1 1 1 0
Prob .2 .2 .2 .2 .2
a 0 1 2 3 0
b 1 1 1 1 0
a 0 1 2 3 0
b 1 1 1 1 0
231
Custom Randomization
Even if no class members are tagged rand or randc, SystemVerilog will still call the pre_randomize() function when you call randomize(). You can use this to gain complete control over the randomization of variables
E.g. You can use different distributions such as (from Verilog 2001) $dist_normal( seed, mean, std_deviation ) $dist_exponential( seed, mean ) $dist_poisson( seed, mean ) $dist_chi_square( seed, degree_of_freedom ) $dist_t( seed, degree_of_freedom ) $dist_erlang( seed, k_stage, mean ) $dist_uniform( seed, start, end ) seed is an inout variable that is
All arguments are integer values. modified and reused by the algorithms
232
mx = 100);
bathtub
b = new();
b.randomize();
// Calls pre-randomize()
233
What happened?
Almost certainly, randomization changed due to code restructuring RNG environment wasnt stable!
234
SV RNG Stability
In SV each object or thread has an individual random number generator (RNG)
RNGs of different threads and objects do not interfere with each other This is known as random stability
Test environment must take stability into account SV solution is called Hierarchical Seeding
RNGs are controlled by manual seeding of objects/threads Seeds are passed down from the top level of hierarchy Single seed at the root thread can control all lower levels
235
236
Thread randomization system calls (Callable only from within the thread itself)
$urandom [seed] returns a new 32-bit unsigned random every time called seed is optional and works like Verilog 2001 $random $urandom_range([min,] max) returns a new 32-bit unsigned random number in the range min is optional and defaults to 0
237
238
Manual Seeding
Using srandom() to seed a threads RNG
std::process (Outside the scope of this class) A class defined in the std package. Allows fine control over processes spawned by forkjoin etc. Think of ::self. as similar to this.
integer x, y, z; fork begin process::self.srandom(100); x = $urandom; end begin y = $urandom; process::self.srandom(200); end join
Manual seeding of a root thread makes the entire sub tree stable, allowing it to be moved within the source code for example
239
Advanced Seeding
The built-in seeding control mechanisms are sufficient for most users:
Stability maintained per Object / per thread Manual srandom() seeding at top level propagated down
For more sophisticated projects SV provides RNG state save/load via simple strings which can be saved/read from a file, etc. etc.
// Note this is a process:: method! get_randstate() Returns state of RNG of a process as a string set_randstate(string) // Note this is a process:: method! Copies string into state of RNG
NOTE: string
240
241
Functional Coverage
In this section
Structural vs Functional Coverage Coverage Modeling Covergroup, Coverpoint, Cross Sequential & procedural sampling
242
Coverage
Coverage attempts to get a numerical handle on toughest question in verification: When can I get off this merry-go-round? Two types of coverage are popular in Design Verification (DV):
Structural Coverage (SC) Tool generated, e.g. Code Coverage, Toggle Coverage, etc. Functional Coverage (FC) Human generated metrics derived from Test Plan Usually makes sense to start FC after SC goals are met
243
Structural Coverage
HDL Structural Coverage has arisen from analysis of SW projects
Specifically the statistical analysis derived from instrumentation/analysis of executing code, including: How many times each line of code executed Paths, decisions, loops, procedures, etc.
Pros:
White-box view of design from within Tool generated, so less burden on designers Finds areas of a program not exercised Targets additional test cases to increase coverage Provides a measure of code coverage and indirectly of quality May identify redundant test cases that do not increase coverage
Cons:
Derived from work on linear languages (C, C++) What about concurrency of HDLs?
244
Functional Coverage
HDL Functional Coverage comes at the problem from a user or system view
It asks questions like: Have all typical operational modes been tested All error conditions? All corner cases? In other words: Are we making progress? Are we done yet?
Pros:
Black-box, external view Targets the stimulus/testbench more than the actual code Adaptable to more efficient transaction-level analysis, not just signal level Identifies overlap/redundancy in test cases Fits excellently with Assertion Based Verification & Constrained Random Fits with Transaction-based verification Strong support built-in to SV
Cons:
Considerable effort initially to implement
245
Mux/Demux block
Check truth table
s0 s3 1 0 s2 2 s1 0 1
a b c d
e f g h
Crossbar
Check all inputs have driven all outputs
246
247
SV Coverage Terminology
covergroup
A user-defined type like a class, which defines a coverage model Composed of a number of sub-elements including the following
coverpoint
Keywords
Describes a particular type of coverage event, how it will be counted as well as one or more bins to organize the count
cross
Defines a new coverage event by combining two or more existing coverpoints or variables
bins
A coverage event counting mechanism, automatically or user-defined
Clocking event
Defines when a coverpoint is sampled. Usually a clock but can also be the start/end of a method/task/function or can be manually triggered within procedural code
Guard ( iff
<expr> )
Optional condition that disables coverage at the covergroup, coverpoint, cross or bins level
248
Declaring a covergroup
covergroup
Similar to a class, a covergroup instance is created via new() Covergroups may be defined in a module, program, interface or class and even package and generate-blocks
Syntax:
covergroup name [ ( <list_of_args> <cover_option. > ; <cover_type_option. > ; <cover_point> ; <cover_cross> ; endgroup [ : identifier ] )] [ <clocking_event> ] ;
249
covergroup Example
covergroup is similar to a class
It defines a coverage model
module cover_group; bit clk; enum {sml_pkt, med_pkt, lrg_pkt} ether_pkts; bit[1:0] mp3_data, noise, inter_fr_gap;
Coverage sampling clock
covergroup net_mp3 () type_option.comment Options option.auto_bin_max Mp3 : coverpoint Junk: coverpoint Coverage points epkt: coverpoint Traffic: cross epkt, endgroup net_mp3 mp3_1 = new(); net_mp3 mp3_2 = new(); endmodule
@(posedge clk); = "Coverage model for network = 256; mp3_data; noise; ether_pkts; // 2 coverpoints Mp3;
MP3 player";
250
// embedded covergroup covergroup cov1 @(valid); cp_dest : coverpoint dest; cp_src : coverpoint src; endgroup function new(int i); payld = new[i]; len = i; cov1 = new(); endfunction : new endclass : packet
251
coverpoint
coverpoint coverpoint
[label :] { [ <coverage_option> ] bins name [ [ ] ] = { value_set } [ iff ( <expr> ) ]; bins name [ [ ] ] = ( transitions )[ iff ( <expr> ) ]; bins name [ [ ] ] = default [ sequence ][ iff ( <expr> ) ]; ignore_bins name = { value_set }; ignore_bins name = ( transitions ); illegal_bins name = { value_set }; illegal_bins name = ( transitions ); }
coverpoint
<expr> [ iff
( <expr>
)]
252
cpoints
cp;
rand bit [7:0] a; bit expr = 1; bit ok = 1; int arg = 66; covergroup cg_a (int val) @(smpl); cp_a : coverpoint a iff ( expr ) { bins val_bin = { val }; // i.e. 66 } endgroup function new(); cg_a = new(arg); endfunction endclass
Constructor must instantiate covergroup!
initial begin cp = new(); for (int i=0; i<10; i++) begin void'(cp.randomize()); -> smpl; $display("coverage = ", cp.cg_a.get_coverage() ); end end endmodule
// pass in argument to covergroup // Instantiation may also be in a function called by the constructor
253
Auto bins
If no user-defined bins are declared for a coverpoint,
bins are automatically created. Automatically created bins are named: auto[0] , auto[1] , auto[2], etc. The values inside of [ ] are the values of the expression bit bit [7:0] expr, a; clk,
ok;
covergroup cg_a @(posedge clk); option.auto_bin_max = 16; cp_a : coverpoint a iff endgroup
( expr );
No user-bins, so expect auto-bins Q: How many bins here and what distribution?
To prevent auto-bin explosion, the number of auto bins created for a coverpoint is defined as the lower of:
2N (where N is the number of bins required for full coverage of coverpoint) auto_bin_max, (a predefined coverage option (default 64) )
254
};
Dynamic Array of bins, 1 per value (20) Explicit array of 10 bins, Since specified range == 21 values are evenly distributed among available bins (2 per) with extra one going in last bin
255
Excluded bins
default default - catch the values that do not lie within the defined value bins sequence - catch transitions not included in the defined sequence bins are filtered from coverage including values included in other bins are same as ignore_bins but they trigger a runtime error message ignore_bins illegal_bins
!ok;
Per-bin guard expression
256
is
for
Goal/ Status At Least 100 100 1 1 1 1 1 188 253 Covered Covered Occurred Occurred Occurred Covered ZERO Occurred Occurred
(int i = 0; i<256; a = i;
i++)
begin
There are 255 transitions in the for loop: 1 illegal_bins ib3 (transition 5 => 6) 1 illegal_bins ib_66 (filters transition 65=>66 from oops_seq) 253 oops_seq default sequences
There are 256 values for a in the for loop: 65 bins some_range 1 illegal_bins ib_66 1 ignore_bins ib67
257
Transitions
The only way to track transitions is in user defined bins (no auto bins) The syntax for specifying transition sequences is a subset of the SVA sequence syntax
12 => 13 => 14
//
// Set of transitions. 1, 4 => 7, 8 ( i.e. 1 => 7, 1 => 8, 4 => 7, 4 => 8 ) val1[*4] ( i.e. 3[*2:4] ( i.e. 2[->3] ( i.e. 2[=3] ( i.e. default // Repeat val1 4 times val1 => val1 => val1 => val1 ) // Set of repetition sequences 3 => 3 => 3, 3 => 3 => 3 => 3 ) (not necessarily consecutive)
3 => 3 ,
repeat
sequence
coverage
258
enum bit[1:0]
always @ (posedge clk) if (rst) // Fully synchronous reset state <= #1 S0; else state <= #1 next_state;
259
Example fsm_cover - 2
covergroup cfsm @(negedge clk); type_option.comment = "Coverage of FSM"; type_option.strobe = 1; stat : coverpoint state { option.at_least = 1; bins valid = {S0,S1,S2}; bins S0_S0 = (S0 => S0); bins S0_S1 = (S0 => S1); bins S1_S0 = (S1 => S0); bins S1_S2 = (S1 => S2); bins S2_S0 = (S2 => S0); # COVERGROUP COVERAGE: illegal_bins ib = {2'b11}; # -----------------------------------------------------------------------------------# Covergroup Metric Goal/ Status bins oops = default; # At Least bins oops_seq = # -----------------------------------------------------------------------------------default sequence; # TYPE /test_fsm/u1/cfsm 83.3% 100 Uncovered } # Coverpoint cfsm::stat 83.3% 100 Uncovered # illegal_bin ib 0 ZERO endgroup # bin valid 12 1 Covered cfsm C0 = new(); # bin S0_S0 7 1 Covered endmodule # bin S0_S1 2 1 Covered
# bin S1_S0 0 1 ZERO # bin S1_S2 1 1 Covered # bin S2_S0 1 1 Covered # default bin oops 0 ZERO # default bin oops_seq 1 Occurred # # TOTAL COVERGROUP COVERAGE: 83.3% COVERGROUP TYPES: 1
260
cross
The cross construct specifies cross coverage between one or more crosspoints or variables
[label { :] cross <coverpoint list> [ iff ( <expr> )]
bins name = binsof bins name = binsof ignore_bins name = illegal_bins name }
(binname) op binsof (binname) op [ iff (expr) ]; (binname) intersect { value | [ range] } [ iff (expr) binsof (binname) ; = binsof (binname) ;
];
Expressions cannot be used directly in a cross but may be described in a new coverpoint which is made part of the cross binsof yields the bins of its expression ( optional intersect { } for more refinement ) intersect { } can specify a range of values or a single value Supported operators (op) are: !, &&, || illegal_bins, ignore_bins, iff etc are allowed as in coverpoints
261
Cross coverage
A coverpoint typically defines coverage for a single variable or expression.
Answers questions like: Have I entered every state of the FSM? Have I tested all operating modes?
typedef enum {s1, s2, s3} sts; sts state; typedef enum {a, b, c} mds; mds mode; covergroup cg @(posedge clk); cp_state : coverpoint state; cp_mode : coverpoint mode; cs_modstat: cross cp_state, cp_mode; endgroup
s1 s2 s3
cp_state bins
a b c
cp_mode bins
262
module simple_cross; event smpl; class scross; typedef enum {a,e,i,o,u} rand vowels v; bit inactive = 1; rand bit[2:0] cnt; covergroup cg @(smpl); a: cross cnt, v iff endgroup function new(); cg = new(); endfunction endclass
Implicit coverpoint cg::cnt has 8 bins ( cnt coverpoint ) cg::v has 5 bins ( # of vowels ) Auto cross points (and bins) is 8x5 = 40 Total of 53 bins generated
vowels;
(inactive);
scross sc = new(); initial for (int i=0; i<100; i++) void'(sc.randomize()); -> smpl; end endmodule
begin
COVERGROUP COVERAGE: # -----------------------------------------------------------------------------------# Covergroup Metric Goal/ Status # At Least # -----------------------------------------------------------------------------------# TYPE /simple_cross/scross/#cg# 96.7% 100 Uncovered # Coverpoint #cg#::cnt 100.0% 100 Covered # bin auto[0] 12 1 Covered ... # Coverpoint #cg#::v 100.0% 100 Covered # bin auto[a] 21 1 Covered ... # Cross #cg#::a 90.0% 100 Uncovered # bin <auto[0],auto[a]> 1 1 Covered ... # bin <auto[7],auto[e]> 0 1 ZERO ... # # TOTAL COVERGROUP COVERAGE: 96.7% COVERGROUP TYPES: 1
. Rest of report not shown .
263
covergroup cp_state:
cgb() @(posedge clk); coverpoint state{ bins s1 = {s1}; bins s2 = {s2}; bins s3 = {s3};
} cp_mode: coverpoint mode{ bins a = {a}; bins b = {b}; bins c = {c}; } cs_modstat: cross cp_state, cp_mode{ bins band = binsof (cp_state) && binsof bins bint = binsof (cp_state) intersect ignore_bins bout = binsof (cp_state.s2) } endgroup
bout 1
s1 s2 s3
2 0 0 1 0 0 1 3
a b c
band 3
bint 2
264
A number of built-in system_tasks and functions are also defined $set_coverage_db_name(name) - name the coverage db file written at end of simulation - load cumulative coverage info from a file $load_coverage_db(name) - returns overall coverage of all covergroups real:[0-100] $get_coverage() NOTE Coverage is internally calculated as a real and reported as a score 0-100
265
Coverage: option
A wide assortment of options can be selected at each covergroup, cross, etc. option (apply to most levels: covergroup, coverpoint, cross): weight=number goal=number name=string comment=string at_least=number detect_overlap=boolean auto_bin_max=number cross_num_print_missing =number per_instance=boolean - statistical weight within level - target coverage (instance) - specifies covergroup instance name if unspecified, name is auto generated - unique text appears in reports - minimum # of hits per bin - If set, a warning is given when overlap between 2 bins of a coverpoint - max # of auto-bins created - # of not covered cross-product bins - If true also track per covergroup instance (1) (0) (64) (0) (0) coverpoint, (default) (1) (100) ("")
266
Coverage: type_option
type_option - applies to covergroup,coverpoint (i.e. across all instances): or cross by type
- statistical weight within database (default = 1) - target goal for covergroup (default = 100) - unique text appears in reports (default = "") - If true, sample once per clk-event in the postponed region (default = 0)
Some settings exist as type_options AND options. What does this mean? Think of type_option as a default setting (for the type). Then, the option setting is useful to override the default on an instance basis. However, for this to work, the per_instance option must be set to true AND we need some way to set per-instance options for example by passing arguments to the covergroup constructor.
267
Clocking Event
The optional clocking event says when coverpoints should be sampled If omitted, the user must sample procedurally ( .sample method)
Sampling is performed when the clocking event triggers. Non-synchronous sources can yield multiple-trigger events which may mess-up coverage .strobe type_option works like $strobe in Verilog Triggers in postponed step Ensures that sampling happens only once per timestep
covergroup cg @(sig); type_option.comment = your_name_here; type_option.strobe = 1; a : coverpoint vara; // expression allowed b: coverpoint varb; c: cross a, vard; // 1 var & 1 coverpoint endgroup cg cg1 = new();
268
@@(end doit)
cgb cgb1 = new(); #1000 doit;
269
covergroup net_mp3; type_option.comment = Coverage model for network Mp3 : coverpoint mp3_data; // expression allowed Junk: coverpoint noise; Traffic: cross ether_pkts, Mp3; endgroup net_mp3 mp3_1 = new(); always @(posedge clk) if (i_want_2_cover) mp3_1.sample();
MP3 player;
270
Workspace Pane
271
Key Covered, Uncovered: Indicates whether or not at least has been met. Metric: Say a coverpoint has 10 bins. 9 have met their at least setting, 1 has not The metric for this would be 90%
272
273
274
Override base class task run2 (see next slide) Call $get_coverage() and report the value returned
Add code to trigger the router_cvg compare (trigger event smpl) covergroup after each successful
HINT
Not seeing your coverage value reported ? Simulation running forever ? Perhaps it is the base class run2() which is executing.
275
coverage group
task automatic run2(); while(1) begin task to override in derived class mon_mb.get(m_pkt); ++m_pkt_cnt; if (check.exists(m_pkt.pkt_id)) case( m_pkt.compare(check[m_pkt.pkt_id]) ) 0: begin $display("Compare error",,m_pkt.pkt_id,, check[m_pkt.pkt_id].pkt_id); pkt_mismatch++; $stop; if(`TRACE_ON) s_pkt.display; check[s_pkt.pkt_id].display; end 1: begin check.delete(m_pkt.pkt_id); srce = s_pkt.srce; dest = s_pkt.dest; end endcase else check[m_pkt.pkt_id] = m_pkt; report; end
Sol
276
?
QUESTION: Why is the Covergroups pane blank, even though we know there are covergroups defined in the code?
2 reasons: First, covergroups are created at runtime. Second, you must be in the top workspace
277
Calculating Coverage
The coverage of a coverage group, Cg , is the weighted average of the coverage of all items defined in the coverage group, and it is computed by the following formulae
i is the set of coverage items (cover-points and crosses) in the covergroup Wi is the weight associated with item i. Ci is the coverage of item i.
The coverage of each item, Ci, is a measure of how much the item has been covered, and its computation depends on the type of coverage item: coverpoint or cross
Coverpoint
# of bins that met goals
Cross
# of bins that met goals
Ci (user-defined bins) =
Total # of bins
Ci =
Bc + # user-bins - # user-excluded bins
Ci (auto-defined bins) =
MIN ( auto_bin_max, 2N ) Bc is the number of auto cross bins Bj is the number of bins in the jth coverpoint being crossed Bb is the number of cross products in all user-defined cross-bins
278
SVA
279
&& !red
&& !yellow
&& go );
Concurrent
Usable by other tools as well ( e.g. formal verification ) Clocked/sampled paradigm
Conc. assertions may be triggered in various ways (including procedural code), but time is spec'd internally and may include sequential checks over time
&& !yellow
&& go );
property
( traf_light
);
280
Immediate Assertions
Tested when the assert statement is executed in procedural code
time t; always @( posedge clk ) if ( state == REQ ) req_assert : assert ( req1 || req2 ) $display( "%m OK" ); else Notice if-else style where if is implicit. begin else is also optional in this context t = $time; Notice optional req_assert label #5 $display( "%m failed at time %0t",t ); and the use of %m to implicitly end insert that label in messages
NOTE assert statements resolve X and Z expression values much like if-else statements they will fail on 0, X or Z
281
Concurrent Assertions
In this section
282
Concurrent Assertions
Concurrent assert statements describe behavior over time.
clock-based (clock may be user-defined and avoid glitches!!!) Structured for simplicity, flexibility & reuse
Verification Statements
assert
, cover,
bind,
assume
Property Declarations
property
, disable
iff,
not,
|->,
|=>
and, or, intersect, <time_ shift>, *<repeat>, within, throughout, $past, $rose, $fell, sequence <Verilog expr, excl. +=, ++, -- etc.>, System functions: $countones, $inset, ended, matched
$stable,
$isunknown etc.
Boolean Expressions
283
Clock Tick
The timing model employed in a concurrent assertion specification is based on clock ticks A clock tick is an atomic moment in time
Spans no duration of time.
284
simulation ticks
Concurrent Assertions describe the sequence of changes in signals over time Introduces the concept of a clock to sample signal changes and capture the sequence
285
The value of variables used in an assertion are sampled in the Preponed region Iterative Regions (may iterate in same or to prior regions)
Current events (processed in any order) Events to be evaluated after active events (e.g. # )
Active Inactive
NBA
Reactive Re-inactive
Execution of Program Block and pass/fail code from property expressions Events to be evaluated after reactive events (e.g. # )
286
If we sample both signals on the posedge of clk The waveforms effectively become:
sequences
Assuming we start with req and ack hi SVA events are: e1 e2 e3 e4 ( !req ) ( !ack ) ( req ) ( ack )
Events:
e1
e2
e3
e4
Remember, this diagram shows what the signals look like from the point of view of the sampling clock
287
Boolean Expressions
1 Boolean Expressions
288
Sequences
2 Sequence Regular Expressions
A list of SV boolean expressions in linear order of increasing time Boolean test for whether a signal matches a given sequence or not Assumes an appropriate sampling clock and start/end times If all samples in the sequence match the simulation result then the assertion matches
Otherwise it is said to fail
289
Delay:
##N a a a a ##N ##1 ##0 ##1 b b b b ##1 c // represents a sequential delay of N cycles // a is true on current tick, b will be true on Nth tick after a // a is true on current tick, b will be true on next tick // a is true on current tick, so is b (Overlapping!) // a is true, b true on next tick, c true on following tick
290
Sequence Example
Using the sequence delay operator we can specify values over time
##1 !ack
&& ack)
Assuming we start with req and ack hi SVA events are: e1 e2 e3 e4 ( !req ) ( !ack ) ( req ) ( ack )
e1
e2
0
e3
1
e4
1 1
Sequence mismatch
Sequence end
Question: Although this assertion successfully detects the error shown, why is it a poor coding style?
Answer:
291
Sequence Block
Sequence blocks identify and encapsulate a sequence definition
sequence s1; @ (posedge clk) a ##1 b ##1 c; endsequence sequence s2 ; (!frame && (data==data_bus)) endsequence
== en);
Notice no clock is defined. This may be inherited from a higher hierarchical statement like property or assert (More on this later)
##1 s2
##1 end_sig;
// sequence as sub-expression
- same as ##1 (!frame && (data == data_bus)) ##1 (c_be[0:3] == en) ##1 end_sig;
start_sig
292
Property Block
3 Property Declarations
property p1; @ (posedge clk) (req && ack) ##1 !req endproperty
##1 !ack
&& ack);
293
Implication: |->
|=>
Using the implication ( |->, |=> ) operators you can specify a prerequisite sequence that implies another sequence
Typically this reduces failures that you expect and wish to ignore
<antecedent
seq_expr>
|->/|=>
( <consequent seq_expr>
);
Think of it this way: If the antecedent matches, the consequent must too. If the antecedent fails, the consequent is not tested and a true result is forced Such forced results are called vacuous and are usually filtered out. Two forms of the implication operator are supported: Overlapping form: ( a ##1 b ##1 c ) |-> ( d ##1 e ); If a/b/c matches, then d is evaluated on THAT tick Non-overlapping form: ( a ##1 b ##1 c ) |=> ( d ##1 e ); If a/b/c matches, then d is evaluated on the NEXT tick
294
Verification Directives
4 Verification Statement
assert verification directive can appear in modules, interfaces, programs and clocking domains
An edge in antecedent is more efficient ( fewer false triggers )
property ((req
|->
ack
##1 (!req && !ack) ##1 ( req && !ack) ##1 ( req && ack);
endproperty assert_p1: assert property (p1) begin $info("%m OK"); end else begin $error("%m Failed");
ACTION BLOCK
end
295
modelsim.ini has SVA settings ; IgnoreSVAInfo = 0 default value is set to ignore (=1) ; IgnoreSVAWarning = 0 default value is set to ignore (=1) ; IgnoreSVAError = 1 default value is set to enable (=0) ; IgnoreSVAFatal = 1 default value is set to enable (=0)
296
== 3'h2) == 3'h3);
== 3'h0)
|=>
s_count3;
Sampling clock
NOTE: The counter will NOT increment correctly the first time it advances past 2!
297
Do:
<unix> vlib work <vsim> vlog +acc=a sva_ex.sv <vsim> vsim assertdebug sva_ex
<vsim> run all
Wave
vlog [ sv ] <files>
The QuestaSimTM simulation environment will load In the main QuestaSim window: 1. 2. select View / Coverage / Assertions (This opens the Analysis pane to display your assertion activity) in Workspace pane, right-click on sva_ex design unit and select Add / Add to Wave ( This opens and populates the wave viewer pane )
Analysis Report
3.
If desired, undock the Wave pane from the QuestasimTM window by clicking the undock icon
298
Question
Why does the assertion fail at 100ns when the counter error (1 to 4) happens at time 60ns?
299
300
The Dataflow Pane now shows waveform data for that assertion and clicking on a signal transition on that waveform... will show the dataflow diagram for that signal or transition
301
302
NOP
IDLE
opcodes
RD_WD
RD_WD_1
WT_BLK
WT_BLK_1
WT_WD
WT_WD_1
RD_WD_2
WT_BLK_2
WT_WD_2
WT_BLK_3
states
WT_BLK_4
WT_BLK_5
Sol
303
Sequences
In this section
304
##1 s2(a,b)
##1 end_sig;
// sequence as sub-expression
&& (a == data_bus))
##1 (c_be[0:3]
== b)
##1 end_sig;
305
Sequence Operators
Available sequence operators (in order of precedence):
[*N] [=N] [->N] / [*M:N] / [=M:N] / [->M:N] - consecutive repetition operator - non-consecutive repetition - goto repetition (non-consecutive, exact) - all sequences expected to match, end times may differ - all sequences expected to match, end times are the SAME - 1 or more sequences expected to match - expression expected to match throughout a sequence - containment of a sequence expression - sequence delay specifier
306
Range
Range: a ##[3:5] a ##[3:$] b // a is true on current tick, b will be true 3-5 ticks from current tick b // a is true on current tick, b will be true 3 or more ticks from now
SVA Coding Style Tips 1. Avoid very large delimiters ( a##[1:1023] ) because they may consume cpu time and resources. Use signals instead. 2. Open-ended delay ranges can be a problem since they cannot fail. At end of simulation, if they havent matched not a fail either Consider adding a guard assertion around them to define a timeout period ( see intersect operator in next section )
307
Consecutive Repetition
Consecutive Repetition: a [*N] Examples:
a ##1 b ##1 b ##1 b ##1 c a ##1 b [*3] ##1 c
[*N]
- same - same -
b ##1 b ##1 b
308
Examples:
property p_consec_repetition; @(posedge clk) d |-> a [*1:2] endproperty ##1 b;
same as: (a ##1 b)
309
Example:
property p_consec_repetition; @(posedge clk) d |-> a [*1:$] endproperty
Succeeds!
##1 b;
310
a [*0:M]
Example:
property p_range_rep_0_exb; @(posedge clk) a |-> (a ##1 b [*0:1] endproperty same as: (a ##1 b ##1 c)
##1 c);
311
Code in examples_sva/range_repetition_0.sv
312
Goto Repetition
[->N]
Example:
a ##1 b [->4] ##1 c // a followed by exactly // 4 not-necessarily-consecutive bs, // with last b followed next tick by c
a !b b !b b !b b !b b c
There may be any number (including zero) of ticks where b is false before and between but not after the 4 repetitions of b
313
314
Example:
a ##1 b [->3:4]
##1 c;
a !b b !b b !b b c a !b b !b b !b b !b b c
There may be any number (including zero) of ticks where b is false before and between but not after the 3:4 repetitions of b
315
Examples
##1 c
316
Example:
a ##1 b[=4] ##1 c // a, then exactly 4 repeats of b, then c
VERY important c does not have to follow immediately after the last b
a !b b !b b !b b !b b !b c
317
Example:
a ##1 b[=3:4] ##1 c VERY important c does not have to follow immediately after the last b
a !b b !b b !b b !b c a !b b !b b !b b !b b !b c
There may be any number (including zero) of ticks where b is false before, between and after the 3:4 repetitions of b
318
319
SVA Coding Style Tip V-C functions have an overhead consider whether a simple boolean level isnt enough
$fell
( expression ( expression
[,
clocking_event] [, clocking_event]
) )
$stable
True if no change between the previous sample of expression and current sample
&& c)
##1 $fell(d)
Rising edge on LSB of a, followed by b & c not changing, followed by a falling edge on LSB of d
320
The clocking event (posedge clk) is applied to $rose $rose is true whenever the sampled value of b changed to 1 from its sampled value at the previous tick of the clocking event.
321
##1 !sig;
322
or / intersect
s1 s2 s2 o_s
##1 f;
a_s i_s
Examples:
// both expressions must match // (first to match waits for the other) // a_s endtime is later of s1 or s2 // both expressions must match // (both sequences must end at same time) // Here: i_s matches only if e occurs // 1 cycle after d
s2;
323
req
throughout
( gnt [->1]
req must stay true until the first time gnt is sampled true sequence burst_rule; @(posedge clk) $fell (burst) ##0 (!burst) throughout endsequence
(##2 (!trdy
[*3]));
Here, when burst goes true (low), it is expected to stay low for the next 2 ticks and also for the following 3 clock ticks, during which trdy is also to stay low.
324
Caution ! - throughout
The throughout sequence must be carefully described
req gnt clk
throughout
req
throughout
( gnt [->1]
Works great because req doesnt deactivate until 1 tick after gnt goes active But what if the specification permits req to drop asynchronously with gnt?
req
throughout a
gnt clk
At sample point a (the last of the throughout clause ), req is already false so the assertion fails In this case it might be easier to say: req [*1:$] ##1 gnt
Warning: This may never fail if simulation ends before gnt
325
System clock Serial clock ( sys_clk Reset ( active low ) Load data and start transmission Byte of data to transmit Done flag (low during transmission Serial bitstream out 16 )
U1
Checker routines
In each lab you will be given "specification" waveforms on which you will base the assertions you write
326
sys_rst_l xmit
1 sys_clk
1
1 sys_clk
done
uart_out
Start bit 0
b0
327
1 sys_clk
done
uart_out
Start bit 0
b0
From the waveforms, we can derive these 2 sequences: 1. "s_rst_sigs" assert uart_out(hi) and done(lo) 1 sys_clk after sys_rst_l(negedge) 2. "s_rst_done" assert done(hi) and xmit(lo) 1 sys_clk after sys_rst_l goes inactive(posedge) and remain so until xmit(posedge) 3. Also, lets combine those 2 sequences into another parent sequence: 4. "s_rst_pair" assert that s_rst_sigs and s_rst_done both match.
328
This code asserts a property (p_post_rst), which uses our parent sequence (s_rst_pair) to specify the behavior of the UART signals done and uart_out at reset. For now, well place the assertions inside the testbench test_u_xmit.sv: So, lets write the 3 missing sequences
329
sys_clk
sys_rst_l xmit
1 sys_clk
1
done
uart_out
Start bit 0
b0
330
sys_clk
sys_rst_l xmit
1 sys_clk
2
done
uart_out
Start bit 0
b0
((xmit)[->1]));
331
sys_rst_l xmit
1 sys_clk
1
1 sys_clk
done
uart_out
Start bit 0
b0
332
((xmit)[->1]));
($fell(sys_rst_l))
|->
s_rst_pair;
fully");
333
Signals xmit pulse lasts 16 sys_clk (1 uart_clk) sys_clk uart_clk sys_rst_l System clock Serial clock ( sys_clk Reset ( active low ) Load data and start transmission Byte of data to transmit Done flag (low during transmission Serial bitstream out
Stop bit 1
16 )
data
XX
byte
4
XX
Data unchanging while xmit hi
done
1 sys_clk
Start bit 0
uart_out
b0
b1
b2
b3
b4
b5
b6
b7
334
property
$rose(xmit)
|->
s_xmit_done;
335
. . .
336
Sequence Expressions
In this section
337
Sequence Expressions
There are several more ways to create logical expressions over sequences Sequence Expressions
(seq1) within seq.ended (seq2) - contain seq1 within seq2 - detect end of seq within another sequence
338
( b) ##1 b[*6]
);
Here, a must be high for 5 consecutive cycles contained within the second expression
339
##1 e1.ended
##1 branch_back;
e1 matches
rule matches
340
Given:
sequence abc; @(posedge clk) endsequence a ##1 b ##1 c; sequence def; @(negedge clk) endsequence d ##[2:5] e ##1 f;
);
// level sensitive initial wait( abc.triggered || def.triggered $display( Either abc or def succeeded"
.triggered indicates the sequence has reached its endpoint in the current timestep. It is set in the Observe Region and remains true for the rest of the time step
) );
@ unblocks the always block each time the sequence endpoint is reached i.e. each time it matches
NOTE:
Both controls imply an instantiation of the sequence (i.e. assert property(seq)) Only clocked sequences are supported Local sequences only (Hierarchical references are not supported)
341
sequence s_pass_thru_0 ; @(posedge clk) $rose(valid[0]) ##1 !stream[0] ##1 !stream[0] ##1 !stream[0]; endsequence sequence s_pass_thru_1 ; @(posedge clk) $rose(valid[1]) ##1 !stream[1] ##1 !stream[1] ##1 stream[1]; endsequence // 2 6 not shown ; stream[7] stream[7];
always @( s_pass_thru_0) begin if (`TRACE_ON) $display("Passthru passthru[ 0] = 1; end always @( s_pass_thru_1) begin if (`TRACE_ON) $display("Passthru passthru[ 1] = 1; end // 2 6 not shown
0 ");
1 ");
sequence s_pass_thru_7 @(posedge clk) $rose(valid[7]) ##1 ##1 stream[7] ##1 endsequence
7 ");
342
Property Blocks
In this section
Operators
343
Optional arguments
property p1(a,b,c,d); @ (posedge clk) disable iff (reset) c ##1 d ); (a) |-> not ( b ##[2:3] endproperty
implication
Property Block 2
Properties are often built from sequences (though NOT vice-versa) Properties can appear in modules, interfaces, programs, clocking domains
SVA Coding Style Tips Always use disable iff to disable assertions during reset Be cautious, during reset some assertions must still be verified ( reset control logic? )
MAC Property example property p_valid_states; @(negedge MRxClk) disable iff(Reset) $onehot( {StateIdle, StatePreamble, StateSFD, StateData0, StateData1, endproperty rx_statesm_valid : assert property( p_valid_states
StateDrop
} );
);
345
not Operator
The keyword not
May be before the declared sequence or sequential expression May be before the antecedent Makes the property true, if it otherwise would be false Makes the property false if it otherwise would be true
sequence s1; a ##1 b; endsequence property p1_not; @(posedge clk) endproperty
p1_not is true if a is never true, or if it is, one clock tick later b is never true
not s1;
p2_not is true if the implication antecedent is never true, or if it is, the consequent sequential expression succeeds
property p2_not; @(posedge clk) not (c && d) |-> not a ##1 b; endproperty
346
or,
and Operators
or - property evaluates to true if, and only if, at least one of property expressions (s1, s2) evaluates to true
sequence s1; a ##1 b; endsequence property p_or; @ (posedge clk) endproperty sequence s2; b ##1 c; endsequence
t1 |->
s1 or s2 ;
and - property evaluates to true if, and only if, both property expressions evaluate to true
property p_and; @ (posedge clk) endproperty t2 |-> ( (a ##1 b) and (c |=> d) ) ;
If t2, then sequence (a##1b) must match and if c then we must see d 1 tick later.
347
disable
iff Clause
Called the reset expression The reset expression is tested independently for different evaluation attempts of the property Enables the use of asynchronous or preemptive resets
The values of variables used in the reset expression are those in the current simulation cycle, i.e., not sampled If the reset expression evaluates true then the evaluation attempt of the property is aborted immediately Neither a pass nor a failure is reported property p1; @(negedge clk) disable iff(reset) a |=> (b ##1 c ##1 d); endproperty
Note that reset goes active asynchronously to the clk and the property goes inactive immediately
348
expression2
Optional gating expression to the clocking_event
sequence s_rd_3; ##3 (out_busData endsequence property p_rd_3; @(posedge clk) endproperty
== mem[$past(
busAddr,3
)]);
read |->
s_rd_3;
SVA Coding Style Tips 1. Try to use ##N to avoid possibility of referencing an undefined value ( $past (x, N) ) property p1; @ (posedge clk) (a) |-> ##2 ( b == $past ( b, 2 )); $past has overhead recording/logging values over time Rule: Keep # ticks < 100
2.
349
$past()
$past is evaluated in the current occurrence of posedge clk Returns the value of b sampled at the previous occurrence of posedge clk
always @(posedge clk) if (enable) q <= d; always @(posedge clk) assert property (done |=> (out
== $past(q,
2,enable))
);
350
In this section
351
SV allows local variables to be defined/assigned in a sequence or property The variable can be assigned at the end point of any subsequence
Place the subsequence, comma separated from the sampling assignment, in parentheses
##1 c[*2];
x = e) ##1 c[*2];
352
x = e )
##1 ( c[*2
],
x = x + 1 );
For every attempt, a new copy of the variable is created for the sequence ( i.e. local variables are automatic ) All SV types are supported The variable value can be tested like any other SystemVerilog variable Hierarchical references to a local variable are not allowed It also allows pure/automatic functions
353
When read is true, temp samples the memory (indexed by busAddr) The sequence matches 3 cycles later, if temp equals out_busData
SVA Coding Style Tip Formal Verification tools cant handle local variables because its impossible to produce equiv. RTL code.
354
xmit[*15];
1
s_xmit_nc_data;
|=>
Next, lets try it with a local variable within the property We need a variable update clause to sample data at the start of a write ( $rose(xmit) )
SVA Coding Style 1 $stable, like all value change functions is useful but somewhat inefficient Uses a local variable which is more efficient, but Formal Verification tools cant handle local variables
Lastly, check the sampled value against data repeatedly until end of the xmit pulse
property p_xmit_nc_data; bit[7:0] x_byte; @(posedge sys_clk) ($rose(xmit), x_byte = data) (data == x_byte) throughout xmit[*15]; endproperty
|=>
355
xyz matched!
);
356
357
d_1
8
d_2
d_3
d_out
8
d_in
d_out
always @ (posedge clk) begin if(valid) d_1<= #5 d_in; d_2 <= #5 d_1; d_3 <= #5 d_2; d_out<= #5 ~d_3; end
Sol
clk valid
358
Verification Directives
In this section
359
a |->
( b ##1 c );
ACTION BLOCK
assert property (p1(rst,in1,in2)) begin $info("%m OK"); end else begin $error("%m Failed");
end
360
[*0:5]
embedded assertion
always @( posedge clk) if ( !reset ) do_reset; else if ( mode ) if (!arb) st <= REQ2; `ifdef SVA PA: assert `endif property (s1);
( reset
) |->
s1;
property(p1);
SVA Coding Style Tips: Use embedded assertions for properties that are implementation-specific, rather than ones that are based on the design spec. Specification assertions should be concurrent. Enclose embedded assertions in ifdef statements (not all design tools may accept them)
361
Cover Directive
Like assert, the cover statement is a verification directive which identifies properties or sequences of interest
Where they differ is that cover simply identifies properties to be tracked for coverage statistic purposes
NOT enforced as behavioral checks. In response to a cover directive, the simulator will gather and report metrics on the specified sequences or properties, including:
# of times attempted # of passes # of failures property p1(a,b,c); disable iff (a) endproperty cover_c1:
362
Controlling Assertions
$assertoff [ levels [, list_of_modules_or_assertions ]
)
Stop checking all specified assertions ( until subsequent $asserton Assertion checks already in progress are unaffected
$asserton $assertkill
[ levels [ levels
[, [,
list_of_modules_or_assertions list_of_modules_or_assertions
] ] ] ]
Re-enable checking of specified assertions. Same as $assertoff except assertions in progress are aborted too.
Optional levels argument specifies how many hierarchical levels the command should affect
SVA Coding Style Tip: These are more efficient than adding disable iff (reset) to every property but may be more difficult to use in complex test environments e.g. with multiple concurrent test processes
363
Bind Directive
As we saw, embedded assertions have advantages/disadvantages Another approach is to keep verification code separate from the design and use the bind directive to associate them.
bind can connect a module, interface or program instance (with checkers?) to a module / instance by implicitly instantiating the checker within the target. bind may appear in a module, an interface or a compilation unit scope target
bind <module> <module_instance>
assertions container
<module> <program> <interface> <instance_name> (signals, .. );
cpu1
cpu2
module cpu_chk (input clk, a,b,c,d); property p1; @ (posedge clk) a |-> endproperty cpu_p1: assert property (p1); endmodule
cpu_chk
bind
cpu
cpu_chk
CHK1( clk,
enable,
d_out,
d_in,
val );
364
module bind_ex; my_if my_if_inst(); my_design m1(.clk(my_if_inst.clk), .b(my_if_inst.b) ); my_design m2(.clk(my_if_inst.clk), .b(my_if_inst.b) ); bind my_design my_svas MS (.clk, endmodule interface my_if(); bit clk = 0; logic b = 0; always #20 clk = !clk; always @(negedge clk) endinterface
.d);
p1 passed p1 passed
b++;
SVA Coding Style Tips: When verifying design blocks it is usually better to capture assertions in a separate module/interface and use a bind statement to connect to the design block. This equates to black-box testing and avoids Verif. Engineers modifying design modules.
365
("p_rd_wd
That is not at the same hierarchical level as the sm module which is: test_sm.sm_seq0.sm_0 But that is OK!
not shown
366
Clock Specification
The sampling clock of a property/sequence may be specified in several ways 1. Specified within the property ( clk1 below ) property p1; @(posedge clk1) ap1: assert property (p1); 2. a ##2 b; endproperty
Inherited from a sub-sequence ( clk2 below ) sequence s1; @(posedge clk2) a ##2 b; endsequence property p1; not s1; endproperty ap1: assert property (p1);
3.
Inherited from an embedding procedural block ( clk3 below ) always @(posedge clk3) assert property ( not ( a ##2 b ));
367
Multi-clock Support
Most systems have more than a single clock SV assertions allow for this by supporting the use of multiple clocks, even within a single property/assert
The concatenation operator ( ##1 ) is used: sequence m_clk_ex; @(posedge clk0) endsequence
##1
@(posedge clk1)
b;
Here (above code), assuming a matches on clk0, b is checked on the next edge of clk1 Implication is supported but ONLY the non-overlapping form |=>
property m_clk_ex2; @(posedge clk0) a ##1 @(posedge clk1) |=> @(posedge clk2) c; endproperty property m_clk_ex3; m_clk_ex |=> m_clk_ex2; endproperty
368
Multi-clock Sequences - 2
Only the ##1 operator may be used to concatenate multiply clocked sequences:
@(posedge clk0) @(posedge clk0) @(posedge clk0) seq1 ##0 seq3 ##2 seq5 intersect @(posedge clk1) @(posedge clk1) @(posedge clk1) seq2 seq4 seq6
Multi-clock sequences/properties:
must have well-defined start/end times, clock transitions subsequences must not admit empty matches
@(posedge clk0)
Here, seq1, seq2 & seq3 must not allow empty matches like: sig3[*0:1]
369
sequence s1; @(posedge clk2) endsequence sequence s2; @(posedge clk) endsequence property p_ended; @ (posedge clk) endproperty
b;
c ##1 s1.ended
##1 d;
t1 |->
s2;
370
t1 |->
s2;
371
uart_out
data
XX
byte
XX
done
Start bit 0 Stop bit 1
uart_out
b0
b1
b2
b3
b4
b5
b6
b7
372
Sol
373
Sample Solutions
374
initial begin for(int i = 0; i< cnt; i++) begin index = $random(); big_mem[index] = TRUE; end $display("big_mem has %0d entries", big_mem.num()); if( big_mem.first(index) ) $display("the smallest index is %0d", index); if (big_mem.last(index) ) $display("the largest index is %0d", index); $display("Here are the addresses:"); if (big_mem.first(index) ) do $display(index); while (big_mem.next(index)); end endmodule
Back
375
task stimulus(); packet stim_pkt; for (int i = 0; i < 256; i++) stim_pkt.pid = i; $display("Sending pkt: ",i);
begin
376
function // if(
bit
compare (packet
exp_pkt,
if(act_pkt.pid
== 22) act_pkt.pid
(exp_pkt == act_pkt) ) begin $display("Compared packet: ",exp_pkt.pid); return 1; end else begin $display("ERROR: pid mismatch in packet # %0d",exp_pkt.pid); return 0; end endfunction
Back
377
378
// null handle
function new( mailbox #(Packet) mb, int i ); out_chan = mb; // specify an external mailbox to drive id = i; endfunction task run(); . . . endtask endclass : source
Back
379
endinterface:
router_if top_if(SystemClock); test_router test(top_if); router dut( .rst ( top_if.rst ), .clk ( top_if.clock ), .valid ( top_if.valid ), .stream ( top_if.stream ), .streamo ( top_if.streamo ), .busy ( top_if.busy ), .valido ( top_if.valido ) ); bind dut router_assertions ... RA (.*);
380
virtual
router_if
mb;
r_if;
. . . mailbox #(Packet)
test_env . . .
t_env;
router_if
r_if,
this.r_if
= r_if;
this.id = id; this.mb = mb; endfunction . . . class test_env; virtual router_if . . . function new (virtual r_if;
initial begin reset(); pt_mode = 1; // set to pass thru mode to start t_env = new(r_if); //create test env // start things running t_env.run; end . . . class monitor; virtual router_if . . . mailbox #(Packet)
r_if; log_mb;
router_if
routr);
function
r_if = routr; . . . for ( int id = 0; id < `ROUTER_SIZE; id++) begin s2d_mb[id] = new(10); s[id] = new(.id(id), .mb(s2d_mb[id]), .log_mb(log_stim) ); d[id] = new(.id(id), .mb(s2d_mb[id]), m[id] = new(.id(id), .log_mb(log_mon), end endfunction
int id, virtual router_if mailbox #(Packet) this.id = id; this.r_if = r_if; this.log_mb = log_mb; endfunction . . . .r_if(r_if)); .r_if(r_if));
new (
r_if, log_mb );
Back
381
endinterface:
router_if top_if(SystemClock); test_router test(top_if); router dut( .rst ( top_if.rst ), .clk ( top_if.clock ), .valid ( top_if.valid ), .stream ( top_if.stream ), .streamo ( top_if.streamo ), .busy ( top_if.busy ), .valido ( top_if.valido ) ); bind dut router_assertions ...
Back
RA (.*);
382
Back
383
class Pkt_type_2
extends
Packet;
function void gen_crc(); crc = payload.product(); endfunction virtual function bit check_crc(); if (payload.product() == crc) return(1); else return(0); endfunction endclass
384
task automatic send_pkt(input Packet pkt_to_send, int i); pkt_to_send.init_pkt(i); // initialize packet out_chan.put(pkt_to_send); // write out packet $display("source: Sent packet, id = %0d", pkt_to_send.pkt_id); endtask endclass // source
385
function new(int n_pkts); num_pkts = n_pkts; endfunction task run(); Packet rcvd_pkt; for(int i = 0; i<num_pkts; i++) begin in_chan.get(rcvd_pkt); // get Packet object if (rcvd_pkt.check_crc()) begin // check crc $display("sink: Received a good packet, id = %0d",rcvd_pkt.pkt_id); r_pkts[rcvd_pkt.pkt_id] = rcvd_pkt; //put in end else $display("ERROR: Received a BAD packet, id = %0d",rcvd_pkt.pkt_id); end endtask endclass // sink
array
Back
386
payload_sz inside
payload.size()
class Packet constraint } . . . } . . . endclass valid { }; constraint dest inside endclass { [0:7]
extends p_thru {
BasePacket;
(passthru!=8'hff)
-> dest
== srce;
387
id);
388
Back
389
);
390
391
else begin check[m_pkt.pkt_id] = m_pkt; end if(current_coverage == 100) begin $display("\n********************************"); $display(" Coverage goal met: 100 !!! $display("********************************"); report; $display("********************************"); $display("********************************\n"); $stop; end report; end endtask endclass : scoreboard
");
Back
392
state==IDLE
== IDLE;
property p_wt_wd; @(posedge clk) state==IDLE state == WT_WD_1 ##1 state endproperty
property p_wt_blk; @(posedge clk) state==IDLE && opcode == WT_BLK |=> state == WT_BLK_1 ##1 state == WT_BLK_2 ##1 state == WT_BLK_3 ##1 state == WT_BLK_4 ##1 state == WT_BLK_5 ##1 state == IDLE; endproperty property p_rd_wd; @(posedge clk) state==IDLE state == RD_WD_1 ##1 state endproperty && opcode == RD_WD |=> == RD_WD_2 ##1 state == IDLE;
393
assert
assert property(p_wt_wd) else $display ("p_wt_wd assert property(p_wt_blk) else $display ("p_wt_blk assert property(p_rd_wd) else $display ("p_rd_wd
Back
394
##1 !uart_clk[*8]
##1 uart_clk;
xmit[*16]
##1 !xmit;
395
property property
(p_pipe); (p_pipe_2);
Back
396
. . . . . . property p_val_bit_stream; logic [7:0] cmp; @(posedge uart_clk) ($rose(xmit), cmp = data) |-> !uart_out ##1 (uart_out == cmp[0], cmp = cmp>>1)[*8] ##1 uart_out; endproperty
. . . . . . . . . u_xmit U1( .* );
. . . . . . // assertions
bind U1 my_assertions
A1 ( .*
);
endmodule
bitstream
incorrect");
Back
397
DPI
In this section
Calling C code from SystemVerilog Calling SystemVerilog from C code Passing data and parameters
398
Introduction to DPI
SystemVerilog adds a new interface to foreign languages called DPI
DPI-C is the C and C++ language interface
When passing data across the boundary, DPI automatically converts SystemVerilog-specific types to C types and vice-versa.
399
.h .c
gcc
.so
-shared -g -o my_lib.so my_c_file.c
Specify the library on the command line when starting the simulator
my_lib
top_module
400
Import Declarations
Import declarations are very similar to regular SystemVerilog task and function declarations.
They can occur anywhere that SystemVerilog task or function definitions are legal.
Import declarations provide a "local" task or function name with a foreign implementation
Calling a foreign task or function is syntactically identical to calling a "native" SystemVerilog task or function
If the C code accesses any SV data that is not a parameter, or calls exported tasks/functions, then you must specify the context keyword
= ] task
tname ([params]);
401
import_ex1.sv
#include #include
my_lib.c
random\n");
<os> vlib work <os> vlog -dpiheader dpiheader.h import_ex1.sv <os> gcc -Ipath_to_questasim_home/include -shared <os> vlog import_ex1.sv <os> vsim -c -sv_lib my_lib import_ex1 <vsim> run Init Rand Generating random 383100999 <vsim>
-g -o my_lib.so
my_lib.c
402
When you compile the SV code, you can tell the compiler to generate a C header file with the declarations that you need: <unix> vlog top_module.sv -dpiheader dpi_types.h
403
Export Declarations
Export declarations are very similar to regular SystemVerilog task and function declarations.
The export declaration and the actual SystemVerilog definition can occur in any order.
Exported tasks cannot be called from C functions that are imported as functions
Upholds the normal SystemVerilog restriction on calling tasks from functions
Function export syntax:
export
"DPI-C"
[c_name = ]
function
data_type
fname ([params]);
export
"DPI-C"
[c_name = ]
404
seed 12345");
my_lib.c
#include "dpi_types.h"
dpi_types.h will be created by the
int my_C_task() { SystemVerilog compiler int num; printf("Starting C task\n"); init_rand(); num = SVrand(); printf ("Got %d from SV\n",num); return 0; }
-dpiheader
<os> gcc -Ipath_to_questasim_home/include <os> vsim -c -sv_lib my_lib export_ex1 <vsim> run Starting C task Got 1238934 from SV <vsim>
405
DPI defines several new C data types that correspond to SystemVerilog types When declaring C functions, use the appropriate data type to match what is expected in SystemVerilog
SystemVerilog-compatible types are the only data types that can be transferred in either direction.
406
Passing Parameters
Parameter types can be:
void, byte, shortint, int, longint, real, shortreal, chandle, string Scalar values of type bit and logic Packed one-dimensional arrays of bit and logic Enumerated types User-defined types built from the above types with: struct unpacked array typedef
Output parameters of functions and tasks are represented are passed by reference (i.e. a C pointer to the appropriate type)
407
C Type
sv_x
NOTE: For more complicated data types such as vectors and arrays, see the SystemVerilog P1800 LRM, Annex P
408
initial begin print_logic(A); A = 1; print_logic(A); A = 1'bX; print_logic(A); A = 1'bZ; print_logic(A); end endmodule
#include "dpi_types.h" void print_logic(svLogic logic_in) { switch (logic_in) { case sv_0: printf("Just received break; case sv_1: printf("Just received break; case sv_z: printf("Just received break; case sv_x: printf("Just received break; } }
-dpiheader
$ gcc -I$path_to_questasim_home/include $ vsim -c -sv_lib my_lib data_ex1 vsim> run Just received a value of logic 0. Just received a value of logic 1. Just received a value of logic X. Just received a value of logic Z. vsim>
409
output int
#include
"dpi_types.h"
int doit( const int val) { int result; Double(val,&result) printf ("Got value %d from Double\n",result); return 0; }
-dpiheader
$ gcc -Ipath_to_questasim_home/include $ vsim -c -sv_lib my_lib data_ex2 vsim> run Got value 4 from Double Got value 10 from Double vsim>
410