System Verilog Training
System Verilog Training
for
Version 4.7 Copyright (c) 2007 Willamette HDL, Inc.
This entire document is copyright Willamette HDL Inc. Content may not be copied or redistributed in whole or in part. All trademarks used in this document are the property of their respective owners. QuestaSimTM is a Trademark of Mentor Graphics Corporation
NOTE This document is copyright material of WHDL Inc. It may not be copied or reproduced for any reason.
Course Outline
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 123 126 135 141 145 148 153 156 159
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 Function Calls
f() { for(i=0; i<4; i++) g(i) } f read write g0 g1 g2 g3
FSM
B A D C
Gantt Chart
q 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;
20
21
Literals
SystemVerilog allows easy specification of un-sized literal values with the ( ' ) apostrophe:
'0, '1, 'x, 'X, 'z, 'Z // Notice, no base specifier needed reg [23:0] a = 'z; // All bits of a are set to z
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: Syntax:
enum [enum_base_type] { enum_name_declaration enum [enum_base_type] { enum_name_declaration {,enum_name_declaration} } {,enum_name_declaration} } enum_base_type: default is int enum_base_type: default is int
Define an enumeration with enum enum enum Values can be cast to integer types and auto-incremented { a=5, b, c} vars; // b=6, c=7 A sized constant can be used to set size of the type
enum
enum bit[3:0] {bronze=4h3, silver, gold} medal; // All medal members are (must be) 4-bits
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 boolean myvar;
module enum_types; typedef enum {red, green, blue, yellow, white, black} colors ; colors my_colors; initial begin my_colors = green; // my_colors = 1; // invalid, needs to typecast 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
Willamette HDL Inc. 2007
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
28
29
// null string // assigned from a string literal // concatenation, st1 becomes abc // st2 becomes etc
Supports relational operators ( ==, !=, <, <=, >, >= ), concatenation ({ }) and replication ( {n{ }} )
e.g. (a<b) is true because a precedes b alphabetically
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 parameter parameter ( input ft output ft depth = 16, width = 8, type ft = bit ) [width-1:0] datin, [width-1:0] datout
// default width/depth // default width/depth // fifo is type bit (2-state) by default
ft [width-1:0] mem [depth-1:0]; . . . endmodule module use_fifo; logic [31:0] i, o; bit clk, r_w; fifo
Tip
An easy way (as here) to switch between 2-state and 4-state operation of your design.
#( .depth(64), .width(32), // override both parameter default values .ft(logic) ) // override parameter ft to be type logic (4-state) U1(.datout(o), .datin(i), .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
Willamette HDL Inc. 2007
33
Dynamic Arrays
Dynamic declaration of one-dimensional arrays
Syntax: Syntax: data_type array_name[] ; data_type array_name[] ;
Declares a dynamic array array_name of type data_type Declares a dynamic array array_name of type data_type Allocates a new array array_name of type data_type and size array_size Allocates a new array array_name of type data_type and size array_size Optionally assigns values of array to array_name Optionally assigns values of array to array_name If no value is assigned then element has default value of data_type If no value is assigned then element has default value of data_type
data_type array_name[] = new[ array_size ] [(array)] ; data_type array_name[] = new[ array_size ] [(array)] ;
Declaration
bit [3:0] nibble[ ]; int data[ ]; initial begin nibble = new[100]; data = new [256]; end
// Dynamic array of 4-bit vectors // Dynamic array of int // resize to 100-element array // resize to 256-element array
Resize
34
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
// same as next line // same as line above // init location 2 // resize array - lose contents // init location 3 // resize array - save contents
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 ]; Example: bit i_array[*]; bit [7:0] age [string];
// 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]", age.num()); end
37
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 function 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
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 syntax to write n to the left end of q1 // uses concatenate syntax to write m to the right end of q1 // read leftmost ( first ) item n from list // read rightmost ( last ) item m from list // determine number of items on q1 // delete leftmost ( first ) item of q1 // delete rightmost ( last ) item of q1
for (int i=0; i < q1.size(); i++)// step through a list using integers (NO POINTERS) begin end q1 = ' { }; // clear the q1 list
39
Queue Methods
function int size()
Returns the number of items in the queue. If the queue is empty, it returns 0.
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
a0 a1 a2 a3
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 unpacked
Willamette HDL Inc. 2007
a1 a2 a3
46
byte3
byte2
byte1
byte0
aa
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]
47
6 5 4 3 2 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 7:0
9 8 7 6
7:0 7:0
7:0
bb[10][1:0] = bb [9][3:2] ;
10 9 8
48
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
packed
bit
b3 b2 b1 b0 [3:0]
49
Array Examples
24b0; Equivalent
[N] => [0:N-1]
50
support:
51
For more control, consider the dimensions of the array and use { } to match those dimensions exactly
int m [1:2][1:3] =
52
initial begin #10 $readmemh("hex.dat",PA); for(int i=0; i<=3;i++) $display("PA[%0h",i,"]: %b",PA[i]); #10 $readmemh("hex.dat",PB); $display(""); for(int i=0; i<=3;i++) $display("PB[%0h",i,"]: %b",PB[i]); #10 $readmemh("hex.dat",UA); $display(""); for(int i=0; i<=3;i++) $display("UA[%0h",i,"]: %b",UA[i]);
00 01 AA FF
hex.dat
[1:0] 00 10 20 30 40 50 60 70 01 11 21 31 41 51 61 71
#10 $readmemh("hex_multi.dat",UB); [7:0] $display(""); for(int i=0; i<=3;i++) for(int j=0; j<=1;j++) $displayh("UB[",i,"][",j,"]: ",UB[i][j]); end hex_multi.dat endmodule
53
Search
find() find_index() find_first() find_first_index() find_last() find_last_index() min() max() unique() unique_index() returns all the elements satisfying the given expression returns the indexes of all the elements satisfying the given expression returns the first element satisfying the given expression returns the index of the first element satisfying the given expression returns the last element satisfying the given expression returns the index of the last element satisfying the given expression returns the element with the minimum value returns the element with the maximum value returns all elements with unique values returns the indexes of all elements with unique values with clause is optional under certain conditions
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 // Find all unique lowercase strings
54
string s[] = { teacher", apple", student" }; s.reverse(); // s becomes { student", apple", teacher" }; struct { byte red, green, blue; } video [512]; video.sort() with ( item.red ); // sort video using the red byte only video.sort( sel ) with ( sel.blue << 8 + sel.green ); // sort by blue-green algorithm
Reduce
sum() product() and() or() xor() 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
55
// prints 2
${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) )
Willamette HDL Inc. 2007
56
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
Willamette HDL Inc. 2007
59
60
Structure Expressions
module mod1; typedef struct { logic [7:0] a; int b; } my_struct; my_struct s1 ; initial begin $monitor("my_struct s1.a: %h, s1.b: %h",s1.a, s1.b); #10 #10 #10 #10 s1 s1 s1 s1 = = = = '{5, 6}; '{b:5, a:6}; '{default: 7}; '{int:9, default:1}; // 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: xx, s1.b: 00000000 my_struct s1.a: 05, s1.b: 00000006 my_struct s1.a: 05, s1.b: 00000006 my_struct s1.a: 06, s1.b: 00000005 my_struct s1.a: 06, s1.b: 00000005 my_struct s1.a: 07, s1.b: 00000007 my_struct s1.a: 07, s1.b: 00000007 my_struct s1.a: 01, s1.b: 00000009 my_struct s1.a: 01, s1.b: 00000009
NOTE
SV distinguishes between structure expressions (as shown here) and ordinary concatenations by the { syntax.
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 {
Must be same width
pkt_t pkt_t
pkt_a = '{ c:42, default:1}; pkt_b; // bit-stream is modeled here as a simple int
NOTE
There are rules and limitations to the use of bit-stream casting. See the LRM for more information.
int int_c;
Simulator output
// cast to stream
## Received: c: 42, payload[0]: 1, payload[1]: 1 Received: c: 42, payload[0]: 1, payload[1]: 1 ## Break at bit_cast.sv line 18 Break at bit_cast.sv line 18
always @(int_c) begin pkt_b = pkt_t'(int_c); // cast from stream $display("Received: c: %0d, payload[0]: %0d, payload[1]: %0d", pkt_b.c, pkt_b.payload[0], pkt_b.payload[1]); end
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
do loop
Syntax: Syntax: do <statement> while <expression> 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-- ) // j and k are local #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: Syntax: foreach ( <array name>[<loop variables>] ) <statement> foreach ( <array name>[<loop variables>] ) <statement>
int Ary[10];
i iterates from 0 to 9
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];
b iterates first from 7 down to 0, then col from 0 to 1, then row from 0 to 3
int assoc[string];
s is cast as a string and iterates through all keys in the associative array
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
77
Sol
Willamette HDL Inc. 2007
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 [1:0] out, input logic [1:0] in_a, in_b, input [1:0] sel ) ;
Ports may be of ANY SystemVerilog type including events, structs, arrays, etc.
typedef struct { bit isfloat; struct { int i; shortreal f; } n; } tagd; // nested structure module mh1 (input event e1, input int in1, output tagd out1); ... endmodule
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
Willamette HDL Inc. 2007
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
timeunit & timeprecision are local to a module, they are not `directives that can affect modules compiled later in sequence.
Questa vsim command has switches for globally setting the timeunit and timeprecision
Willamette HDL Inc. 2007
84
.* 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 package q; const int c = 0; endpackage
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 c = 0; endpackage
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; // no need to reference package q since c is "imported" already // import p::c; // Import c from package p, BUT compile error: c already exists import p::*; // c silently NOT imported, no error/warning posted
* is a wildcard, allowing ANY identifier in package to be referenced
89
Package example
package pkg_rmac; typedef struct {bit[55:0] preamble ; bit [7:0] sfd ;} h_type; typedef enum { _, Preamble, SFD, Destination_MAC, Source_MAC, Length, Packet_Num, Payload, CRC } fids; // Typedefs for stream_mp3_file task typedef struct { int n64; int n244; int n428; int n608; int n792; int n972; int n1156; int n1340; int n1500; } distro; `include "tb_eth_defines.v" `include "eth_defines.v" `include "timescale.v" module tb_rmac( input wire [3:0]MTxD, . . . // NOT USED
typedef struct { int sendmp3; int noise; } frm; typedef int int int int } gap; struct { normal; long; short; random;
//============================== //=== 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] data; } global_pkt; global_pkt unit_pkt; task global_task (input global_pkt in1); $display($stime,,"addr: %h, data: %h",in1.addr, in1.data); endtask module code; logic [7:0] x; global_pkt y; initial begin #20; y.data = 2; y.addr = 2; #10; unit_pkt.data = 3; $unit::unit_pkt.addr = 3; global_task(unit_pkt); end endmodule
global_task(y);
VSIM 2>
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] addr; logic[31:0] data; } global_pkt; global_pkt unit_pkt; task global_task (input global_pkt in1); $display($stime,,"addr: %h, data: %h",in1.addr, in1.data); endtask module code; logic [7:0] x; global_pkt y; 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
ERROR!!
** Error: test_1.sv(10): Component name 'unit_pkt' does not refer to a scope. ** Error: test_1.sv(10): Component name 'unit_pkt' does not refer to a scope. ** Error: test_1.sv(10): Component name 'unit_pkt' does not refer to a scope. ** Error: test_1.sv(11): Component name 'unit_pkt' does not refer to a scope. ** Error: test_1.sv(11): Component name 'unit_pkt' does not refer to a scope. ** Error: test_1.sv(11): Component name 'unit_pkt' does not refer to a scope.
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.
test_1.sv
module test_1; logic unit_pkt; code U1(); initial NOTICE begin #10; unit_pkt.data = 1; // not compat. with local variable type unit_pkt.addr = 1; global_task(unit_pkt); end endmodule // local variable hides global
93
CU Example -3
code.sv
typedef struct{ logic [9:0] addr; logic[31:0] data; } global_pkt; global_pkt unit_pkt; task global_task (input global_pkt in1); $display($stime,,"addr: %h, data: %h",in1.addr, in1.data); endtask module code; logic [7:0] x; global_pkt y; 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
ERROR!!
** 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.
This compile fails because the implicit $unit scope works only within the same file. However, if we put both modules in a single file
test_2.sv
module test_2; logic unit_pkt; code U1(); // local variable hides global
NOTICE
initial added $unit:: begin #10; $unit::unit_pkt.data = 1; // $unit:: needed to skip local variable $unit::unit_pkt.addr = 1; global_task($unit::unit_pkt); end endmodule
Willamette HDL Inc. 2007
94
CU Example -4
code.sv
typedef struct{ logic [9:0] addr; logic[31:0] data; } global_pkt; global_pkt unit_pkt; task global_task (input global_pkt in1); $display($stime,,"addr: %h, data: %h",in1.addr, in1.data); endtask module code; logic [7:0] x; global_pkt y; initial begin #20; y.data = 2; y.addr = 2; global_task(y); # Loading work.code_sv_unit # Loading work.test_2 run -all # 10000000 addr: 001, data: 00000001 # 20000000 addr: 002, data: 00000002 # 30000000 addr: 003, data: 00000003
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>
CU
test_2.sv
module test_2;
logic unit_pkt; // local variable hides global #10; unit_pkt.data = 3; code U1(); unit_pkt.addr = 3; global_task(unit_pkt); initial begin end #10; $unit::unit_pkt.data = 1; // $unit:: needed here endmodule $unit::unit_pkt.addr = 1; global_task($unit::unit_pkt); end endmodule
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
Willamette HDL Inc. 2007
97
98
task write_vector( input int data, logic[11:0] addr); @(negedge clk); if (bus_error) return; // cancel operation if bus_error true data_bus = data; addr_bus = addr; write = 1; @(posedge clk); return is supported in tasks but NOT return(value) #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); if (local_a == local_b) begin my_task(local_a-1,local_b+1); return; end global_a = local_a; global_b = local_b; endtask // 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); if (n==0) return (1); // factorial 0 is 1 else return (factorial(n-1)*n); endfunction
101
function void invert(); // Invert the image ( pos -> neg, neg -> pos ) 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
104
byte byte_array[1000:1];
function automatic int crc( ref byte packet [1000:1] ); for( int j= 1; j <= 1000; j++ ) begin crc ^= packet[j]; end endfunction initial int a = crc(byte_array);
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
Willamette HDL Inc. 2007
105
10
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.
initial begin static int svar2; // redundant automatic int avar2; // also allowed inside static tasks/functions end task automatic autotask; automatic int avar3; // redundant! automatic by default static int svar3; // static across simultaneous calls to task endtask initial $monitor (svar); // svar2, svar3 & avar2, avar3 are not visible endmodule
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
fork join_any
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 @(sig); endtask NOTE The child processes spawned by a forkjoin_none do not start executing until the parent process hits a blocking statement
110
111
112
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
Willamette HDL Inc. 2007
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. function new( int bounded = 0); num() Prototype function int num(); put() Prototype task put( message); mailbox #(Packet) channel = new(5);
e.g. some_int_variable = MB1.num(); // returns # of messages currently in mailbox e.g. MB1.put( sent_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(); // 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:
task t1(); for(int i = 0; i<4; i++) begin m.put(i); $display("T1 sent: %0d",i); #5; end endtask task t2(); int temp; while(1) begin m.get(temp); $display("T2 received: %0d",temp); end endtask
0 1 2 3
119
driver
exp_mb
checker compare
DUT
monitor
act_mb
120
checker compare
function
stimulus
act_mb
121
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; address = 0; endtask endclass Packet pkt = new();
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
C1 object
C1 object
Willamette HDL Inc. 2007
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; // create new Packet object return(temp); // return cloned object endfunction endclass Packet orig_pkt, cloned_pkt; initial begin Packet orig_pkt = new(); orig_pkt.status = 55; cloned_pkt = orig_pkt.clone(); $display("cloned_pkt.status = %0d", cloned_pkt.status); end
orig_pkt this
Packet object
131
Class example
class ether_packet; // Ethernet bit[55:0] bit [7:0] bit[47:0] bit[15:0] bit [7:0] Packet Fields preamble = 'h55555555555555; sfd = 'hab; dest, src; len; payld [ ]; Ethernet Packet preamble sfd destination source length payload
function new(int i); payld = new[i]; len = i; endfunction : new task load_frame( input [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
module test_ether(); ether_packet ep ; 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
Simulation output
src: dest: len: payld[0]: payld[1]: payld[2]: payld[3]: src: dest: len: payld[0]: 000000000055 000000000066 00000004 77 78 79 7a 000000000022 000000000033 00000001 44
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 //
132
src[i]
src2snk[i]
snk[i]
Notice: 3 classes, Packet, sink and source (on next slide) Each source & sink object has a local mailbox handle. Those handles are null Why?
task run(); while(1) begin in_chan.get(stim_pkt); $display("sink[%0d]: Received packet with field1 = (%0d), id, stim_pkt.field1); end endtask endclass : sink
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!
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]:
(0)
(0) (1)
136
Create handles (initialize the arrays) Create objects and assign to handles (using new() ) Connect objects (by assigning (copying) mailbox handles)
Sol
Willamette HDL Inc. 2007
137
Mailbox handle
sink handle
sink object
Mailbox object
0 task in_chan.get(stim_pkt)
packet objects
Only handles are passed, objects stay in same place 1 4once created, and are cleared only when no handle0 3 2 points to them Sol
Willamette HDL Inc. 2007
138
Interfaces
In this section
Interface concepts & characteristics Simple bundled Methods Modports Importing methods
139
IO abstraction
source
reg a; a = 0;
sink
a
if ( a == 1)
source
intf.a = 0;
interface intf
sink
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_, en); interface interf;
output [15:0] a; output rw_, en; inout [7:0] d; . . . endmodule tri [7:0] data; logic [15:0] addr; logic ena, rw_; endinterface module mmu(interf io); io.addr <= ad; . . . endmodule module mem(interf io); adr = io.addr; . . . endmodule module system; interf i1; mmu U1 (i1); mem U2 (i1); endmodule
data addr
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, addr, rw_, ena); mem U2 (data, addr, rw_, ena); endmodule
Willamette HDL Inc. 2007
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 definition
Complete portlist
... endmodule module top; logic req, gnt, start, rdy; // req is logic not bit here logic clk = 0; logic [1:0] mode; logic [7:0] addr, data; memMod mem(req, clk, start, mode, addr, data, gnt, rdy); cpuMod cpu(clk, gnt, rdy, data, req, start, addr, mode); endmodule
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
cpuMod
simple_bus
memMod
always @(posedge clk) a.gnt <= a.req & avail; endmodule module cpuMod( simple_bus b, input bit clk); ... endmodule module top; logic clk = 0;
// 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
Willamette HDL Inc. 2007
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. interface simple_bus (input bit clk); // Define the interface simple_bus Interface logic req, gnt, start, rdy; with one input port clk logic [7:0] addr, data;
logic [1:0] mode; endinterface: simple_bus module memMod( simple_bus a ); logic avail; always @(posedge a.clk) a.gnt <= a.req & avail; endmodule module cpuMod(simple_bus b); 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 // Uses just the interface
// the clk signal from the interface // a.req is in the simple_bus interface
...
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
Willamette HDL Inc. 2007
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 is port name of interface i2 Modport indicates direction Interface name acts as a type
module s (i2 i); ... endmodule module top; i2 itf; m u1(.i(itf.master)); s u2( .i(itf.slave)); endmodule
HINT: Any number of modules may connect to an interface via the same modport
Willamette HDL Inc. 2007
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
Willamette HDL Inc. 2007
v_if_name ;
153
154
module dut( input int data_rcvd, input bit clk ); always @(posedge clk) begin $display("%m received data: %0d", data_rcvd); end endmodule class sink; mailbox #(Packet) in_chan; // null handle virtual dut_if v_dut_if; 4 int id = 1;
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
Willamette HDL Inc. 2007
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] monitor[i]
router_if
stimulus[i] stimulus[i]
s2d_mb[i]
driver[i] driver[i]
router ( ixi )
Virtual Interfaces
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 0 1 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
Willamette HDL Inc. 2007
it rt-b Sta
158
scoreboard
driver[i] monitor[i]
router_if
stimulus[i] stimulus[i]
s2d_mb[i]
driver[i] driver[i]
router ( ixi )
Virtual Interfaces
159
top_if
router_if
test_router
File top.sv Contains instantiations for: the interface router_if "top_if the router module "dut" the test_router module test
router ( ixi )
dut
scoreboard
driver[i] monitor[i]
router_if
stimulus[i] stimulus[i]
s2d_mb[i]
driver[i] driver[i]
router ( ixi )
Virtual Interfaces
161
Compile & run the code by typing: make -or- make gui
Sol
162
Classes
In this section
163
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 extends Packet ; //properties integer a,b,c; // methods task showstatus(); $display(status); endtask endclass Additional properties/ methods
DerivedPacket inherits all of Packet, that is to say DerivedPacket "is a " Packet PLUS DerivedPacket has its own additional properties/methods
Willamette HDL Inc. 2007
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; function void setstat(int s); status=s; $display ("parent setstat"); endfunction endclass Base class with properties/ methods
Packet
setstat(int s) status
DerivedPacket
DerivedPacket class DerivedPacket extends Packet ; 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
Willamette HDL Inc. 2007
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) Packet Only legal from within the derived class
class Packet ; int status = 4; function bit chkstat(int s); return (status == s); endfunction endclass class DerivedPacket extends Packet ; int status = 15; function void chkstat(int s); $display(super.status); endfunction Cannot access status endclass
Prints "4" because it explicitly refers to the base class member status outside of object. super keyword legal only inside an object
chkstat(int s) status
DerivedPacket
chkstat(int s) status chkstat(int s) status
167
dddB new()
class DerivedPacket extends Packet ; //properties integer a,b,c; Derived class with its own constructor // methods function new(); a = 0; b = 0; c = 0; endfunction endclass
Willamette HDL Inc. 2007
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
class DerivedPacket1 extends Packet; //properties // methods function new(); Solution 1 super.new(5); endfunction endclass
class DerivedPacket2 extends Packet(5); //properties // methods function new(); endfunction Solution 2
(pass constructor args)
endclass
169
Inheritance Puzzle #1
Inheritance is quite straightforward but can raise some confusing situationsConsider: module poly1;
class Packet ; task build_payld(); $display(Packet payld); endtask DerivedPacket der = new(); initial der.build_packet(); endmodule
Simulation output Packet payld
task build_packet(); build_payld(); // which build_payld() will this call? endtask endclass class DerivedPacket extends Packet ; task build_payld(); // over-ridden method $display(DerivedPacket payld); endtask endclass
Willamette HDL Inc. 2007
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?
170
Virtual Methods
A virtual method in a base class is like a prototype for derived classes Variation on previous slide:
class Packet ; virtual task build_payld(); $display(Packet payld); endtask task build_packet(); build_payld(); endtask endclass module poly3; DerivedPacket der = new(); initial der.build_packet(); endmodule
Simulation output DerivedPacket payld
class DerivedPacket extends Packet ; task build_payld(); $display(DerivedPacket payld); endtask endclass
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: 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 Base; integer fred; endclass
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
172
initial begin aa = new(); bb = new(); if ( $cast (aa, bb) ) // returns 1 $display(Objects are of compatible type); Base else $display("Should never see this"); Up end YES! module base2derived; endmodule Base aa; Derived cc; Derived initial begin aa = new(); cc = new(); Packet Packet OK if (!( $cast(cc, aa) )) // ILLEGAL // Illegal cast - from base to derived if ( $cast(aa,cc) ) // LEGAL // Legal - from derived to base
Down
NO!
if (( $cast(cc, aa) )) // LEGAL // Now legal!!! - back to derived cc = aa; // But this is ALWAYS a compile error! end endmodule
Willamette HDL Inc. 2007
173
174
Add function new() takes an argument (p_id) of type bit[7:0] with a default value of 1 Uses argument (p_id) to initialize the pkt_id field of the inherited base class Compile & run the code by typing: make -or- make gui
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 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; // instance constant protected from all but constructor byte payload []; function new(); size = $random % 4096; // only one assignment (in constructor) is allowed payload = new[ size ]; endfunction endclass
Willamette HDL Inc. 2007
177
Packet non-local
def
local
i
visible
178
local
status
DerivedPacket
non-local
a b c
showstatus() rst()
local
status
// ERROR
visible
Willamette HDL Inc. 2007
179
DerivedPacket
non-local protected
a b c
class DerivedPacket extends Packet ; //properties integer a,b,c; // methods task showstatus(); $display(status); endtask endclass
showstatus()
rst()
status
// Now OK!
visible
Visible from outside class
Willamette HDL Inc. 2007
180
extern
Allows separation of the declaration of a method ( in the class) from its definition outside of the class
DECLARE the method class Packet; ... extern protected virtual function int send(int value); endclass
181
Handles of a particular specialization (type) may not point to objects of a different specialization (type)
AA aa_512 = new(); // Create a default specialization of generic class AA AA #(.size(256)) my_aa = new(); // Create a specialization of generic class AA (a new type) initial begin // my_aa = aa_512; // 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
Willamette HDL Inc. 2007
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 ); compile time T payload [512]; endclass BB bb_int = new(); // object containing 512 ints BB #(string) bb_string = new(); // object containing 512 strings
Multiple parameters:
class CC #( type T = int, int size = 512 ); T payload [size]; endclass CC #(.T(integer), .size(1024)) cc_handle = new(); // type integer, size 1024
Willamette HDL Inc. 2007
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(); endclass
T is string
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;
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
virtual task Print(); $display(v (dec): ", v); endtask endclass class HexDisplay extends Display ; task Print(); // over-ridden method $displayh("v (hex) : ",v); endtask endclass class OctDisplay extends Display ; task Print(); // over-ridden method $displayo("v (oct) : ",v); endtask endclass
Willamette HDL Inc. 2007
Simulation output
v (hex) : 0000abcd v (oct) : 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
Arrays and other containers like lists, etc. usually require that all elements be of the same type.
function void add_to_array(Packet p); pkt_array[idx] = p; idx++; Inheritance allows either an Ether_Packet or a endfunction Token_Packet to be passed in as an argument
and stored into the array.
function void check_CRC(); for (i = 0; i < 512; i++; ) begin if (!pkt_array[i].CRC()) $display ("CRC Error"); end endfunction endclass
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 Packet ; pure virtual function bit NoDefault(); virtual function bit Do_Nothing_by_Default() endfunction endclass
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.
189
mailbox Object
Type = Packet
Receives packets from mailbox, checks crc and puts packets in the array
190
191
192
193
194
195
id id id id id
= = = = =
1 2 3 4 5
id id id id id
= = = = =
6 7 8 9 10
Sol
Willamette HDL Inc. 2007
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
object
$display (addr: %16h , data: %h\n, mybus.addr, mybus.data); $display (Randomization failed);
end
Willamette HDL Inc. 2007
202
NOTE randc variables are assigned values before rand variables. Constraining a randc variable with a rand property is illegal
Willamette HDL Inc. 2007
203
Constraint Block
A constraint block is a class member that controls randomization of the random variables in that class.
class ex1; rand int a,b;
Expression(s)
In addition, some special constructs are provided (to be discussed shortly): dist - distribution/weights -> - implication ifelse - alternate style of implication
Willamette HDL Inc. 2007
204
function automatic int count_ones ( bit [31:0] w ); for( count_ones = 0; w != 0; w = w >> 1 ) count_ones += w & 1b1; Functions are called before endfunction constraint con_ef { e == count_ones( f ) ; } endclass
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
Willamette HDL Inc. 2007
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
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
211
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();
returns 1 if successful, otherwise 0
class bus; randc bit[15:0] addr; rand bit[31:0] data; constraint word_aligned {addr[1:0] == 2'b00;} endclass bus mybus = new(); Return value: 0 if solver fails to satisfy constraints initial repeat(50) begin if ( mybus.randomize() == 1 ) $display (addr: %16h , data: %h\n, mybus.addr, mybus.data); else $display (Randomization failed); end Randomize() works within constraints
213
randomize() with
randomize()with is a way to add constraints in-line.
In-line constraints act in parallel with embedded constraint blocks.
class Sum; rand bit[7:0] x,y,z; constraint con { z == x+y; } endclass
bit [7:0] a,b; task MyTask (Sum n ); int succeeded; succeeded = n.randomize() with { x < y; endtask
Object variables
z >= b; };
Local variables
214
STATE VARIABLES max, min length, max, min limit, length length, min
215
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 function bit gen_stim( stimc p ); bit success; success = p.randomize(); return p.rd_wr; endfunction
function bit gen_stim(); bit success; success = randomize( addr, data, rd_wr ) with { addr < 1024 ; }; return rd_wr ; endfunction Note syntax! ... endmodule
Call std::randomize()
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
Willamette HDL Inc. 2007
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
class Packet; rand int x; constraint con_x { x dist { [1:4] := 1, [5:9] := 2, 10 := 3 }; } endclass 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
Willamette HDL Inc. 2007
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
# # # # # #
done done push dec push Illegal Status done done push dec push
223
224
ifg
noise
ifg
data
ifg
data
forever begin : loop // Rand. seq. of data & noise' eth packets and Inter-Frame-Gaps randsequence ( traffic ) traffic : ifg frame ; frame : data := set.frame.data | noise:= set.frame.noise ; // 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); epkt.drive_MRx; // Call of transactor method };
Willamette HDL Inc. 2007
typedef struct { int n64; int n244; int n428; int n608; int n792; int n972; int n1156; int n1340; int n1500; } distro; typedef struct { int data; int noise; } frm; typedef int int int int } gap; struct { normal; long; short; random;
typedef struct { frm frame; distro dis; gap ifg; } stream_set; stream_set set;
225
@(posedge mrx_clk);
short:
typedef struct { frm frame; distro dis; gap ifg; } stream_set; set;
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
Support Models
DUT
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
Willamette HDL Inc. 2007
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 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
function new(int mn = 10, int mx = 100); mean = mn ; MAX = mx; endfunction function void pre_randomize(); val = $dist_exponential(seed,mean); val = (val > MAX) ? MAX : val; if ($urandom_range(1)) val = MAX - val; endfunction endclass
// 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.
get_randstate() // Note this is a process:: method!
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
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
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> )] [ <clocking_event> <cover_option. > ; <cover_type_option. > ; <cover_point> ; <cover_cross> ; endgroup [ : identifier ] ] ;
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
Options
Coverage points
covergroup net_mp3 () @(posedge clk); type_option.comment = "Coverage model for network MP3 player"; option.auto_bin_max = 256; Mp3 : coverpoint mp3_data; Junk: coverpoint noise; epkt: coverpoint ether_pkts; Traffic: cross epkt, Mp3; // 2 coverpoints endgroup net_mp3 mp3_1 = new(); net_mp3 mp3_2 = new(); endmodule
Cross coverage between coverpoints
250
covergroup cov1 @(valid); // embedded covergroup cp_dest : coverpoint dest; cp_src : coverpoint src; endgroup function new(int i); payld = new[i]; len = i; cov1 = new(); endfunction : new endclass : packet
Willamette HDL Inc. 2007
251
coverpoint
coverpoint indicates an integral variable or an integral expression to be covered Events are counted in bins which are either auto or user-defined coverpoint syntax
guard expressions
[label :] coverpoint <expr> [ iff ( <expr> )] { [ <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 ); }
252
cpoints cp; 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
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!
// 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 [7:0] a; bit expr, clk, ok; covergroup cg_a @(posedge clk); option.auto_bin_max = 16; cp_a : coverpoint a iff ( expr ); endgroup
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 - catch the values that do not lie within the defined value bins default sequence - catch transitions not included in the defined sequence bins ignore_bins are filtered from coverage including values included in other bins illegal_bins are same as ignore_bins but they trigger a runtime error message
NOTE: You may NOT combine default with illegal/ignore
bit [7:0] a; bit expr = 1; bit ok = 0; covergroup cg_a @(smpl); cp_a : coverpoint a iff ( expr ) { bins some_range = { [0:65] }; ib_66 will exclude chk_66 from bins chk_66 = {66}; coverage ignore_bins ib_67 = {67}; illegal_bins ib_66 = {66}; illegal_bins ib3 = ( 4, 5 => 6 ) iff !ok; bins oops_val = default; Per-bin guard expression bins oops_seq = default sequence; } endgroup
Excluded from coverage
256
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
1, 4 => 7, 8 // Set of transitions. ( 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. // Repeat val1 4 times val1 => val1 => val1 => val1 ) // Set of repetition sequences 3 => 3 , 3 => 3 => 3, 3 => 3 => 3 => 3 ) // goto repetition (not necessarily consecutive) =>2=>...=>2=>...=>2 ) // Not-necessarily-consecutive repeat =>2=>...=>2=>...=>2=>... ) // other values, ignored for coverage
default sequence
258
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 (binname) op binsof (binname) op [ iff (expr) ]; bins name = binsof (binname) intersect { value | [ range] } [ iff (expr) ]; ignore_bins name = binsof (binname) ; illegal_bins name = binsof (binname) ; }
If cross specifies a variable, a coverpoint for that variable is implied 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
Implicit coverpoint cg::cnt has 8 bins ( cnt coverpoint ) cg::v has 5 bins ( # of vowels )
class scross; Auto cross points (and bins) is 8x5 = 40 typedef enum {a,e,i,o,u} vowels; Total of 53 bins generated rand vowels v; bit inactive = 1; Implies coverpoints for v, cnt rand bit[2:0] cnt; covergroup cg @(smpl); a: cross cnt, v iff (inactive); # COVERGROUP COVERAGE: # -----------------------------------------------------------------------------------endgroup # Covergroup Metric Goal/ Status # At Least function new(); # -----------------------------------------------------------------------------------cg = new(); # TYPE /simple_cross/scross/#cg# 96.7% 100 Uncovered endfunction # Coverpoint #cg#::cnt 100.0% 100 Covered # bin auto[0] 12 1 Covered endclass ... scross sc = new(); initial for (int i=0; i<100; i++) begin void'(sc.randomize()); -> smpl; end endmodule
# 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 cgb() @(posedge clk); cp_state: coverpoint state{ bins s1 = {s1}; bins s2 = {s2}; bins s3 = {s3}; bout s1 s2 s3 } 1 cp_mode: coverpoint mode{ 2 0 0 bins a = {a}; 0 1 1 bins b = {b}; bins c = {c}; band 0 0 3 } 3 cs_modstat: cross cp_state, cp_mode{ bint 2 bins band = binsof (cp_state) && binsof (cp_mode.c); bins bint = binsof (cp_state) intersect {[s1:s2]}; ignore_bins bout = binsof (cp_state.s2) && binsof (cp_mode.b); } endgroup
Willamette HDL Inc. 2007
a b c
264
265
Coverage: option
A wide assortment of options can be selected at each covergroup, coverpoint, cross, etc. option (apply to most levels: covergroup, coverpoint, cross): weight=number goal=number name=string comment=string at_least=number - 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 (1) (0) (64) (0) (0) (default) (1) (100) ("")
detect_overlap=boolean - If set, a warning is given when overlap between 2 bins of a coverpoint auto_bin_max=number - max # of auto-bins created
cross_num_print_missing =number - # of not covered cross-product bins per_instance=boolean - If true also track per covergroup instance
266
Coverage: type_option
type_option - applies to covergroup,coverpoint or cross by type (i.e. across all instances): - 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)
269
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 covergroup after each successful compare (trigger event smpl) Detect when coverage is achieved (100) and stop simulation
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
Willamette HDL Inc. 2007
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) =
Ci =
Total # of 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
Willamette HDL Inc. 2007
278
SVA
279
always @( posedge clk ) traf_light : assert ( green && !red && !yellow && go );
Failure triggers a default message
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
property traf_light; ( @ ( posedge clk ) ( green && !red && !yellow && go ); endproperty do_traf_prop : assert 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 Property Declarations Sequence Regular Expressions Boolean Expressions
4 3 2
and, or, intersect, <time_ shift>, *<repeat>, within, throughout, $past, $stable, $rose, $fell, sequence
<Verilog expr, excl. +=, ++, -- etc.>, System functions: $countones, $inset, $isunknown etc. ended, matched
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
(req && ack) ##1 !req ##1 !ack ##1 req ##1 (req && 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: Because this assertion targets 2 signals, both signals should be specified throughout.
Willamette HDL Inc. 2007
291
Sequence Block
Sequence blocks identify and encapsulate a sequence definition
sequence s1; @ (posedge clk) a ##1 b ##1 c; endsequence
##1 end_sig;
292
Property Block
3 Property Declarations
property p1; @ (posedge clk) (req && ack) ##1 !req ##1 !ack ##1 req ##1 (req && ack); endproperty
Sequence described in property
Willamette HDL Inc. 2007
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
Willamette HDL Inc. 2007
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 p1; ((req && ack) ##1 !req) |-> ack endproperty assert_p1:
##1 (!req && !ack) ##1 ( req && !ack) ##1 ( req && ack);
assert property (p1) begin $info("%m OK"); end else begin $error("%m Failed"); end
ACTION BLOCK
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
sequence s_count3; (cnt == 3'h1) ##1 (cnt == 3'h2) ##1 (cnt == 3'h3); endsequence property p_count3; @(posedge clk) (cnt == 3'h0) |=> s_count3; endproperty
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.
Analysis Report
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 ) If desired, undock the Wave pane from the QuestasimTM window by clicking the undock icon
Willamette HDL Inc. 2007
3.
298
Question
Why does the assertion fail at 100ns when the counter error (1 to 4) happens at time 60ns?
Willamette HDL Inc. 2007
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
sequence s2 (data,en); // sequence with name AND arguments (!frame && (data ==data_bus)) ##1 (c_be[0:3] == en); endsequence sequence s3; start_sig ##1 s2(a,b) endsequence
Where:
##1 end_sig;
// sequence as sub-expression
##1 end_sig;
305
Sequence Operators
Available sequence operators (in order of precedence):
[*N] / [*M:N] [=N] / [=M:N] [->N] / [->M:N] and intersect or throughout within ## - 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] b // a is true on current tick, b will be true 3-5 ticks from current tick a ##[3:$] 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
b [*3]
- same -
b ##1 b ##1 b
308
Examples:
property p_consec_repetition; @(posedge clk) d |-> a [*1:2] ##1 b; endproperty
same as: (a ##1 b)
309
Example:
property p_consec_repetition; @(posedge clk) d |-> a [*1:$] ##1 b; endproperty
Succeeds!
310
a [*0:M]
Example:
property p_range_rep_0_exb; @(posedge clk) a |-> (a ##1 b [*0:1] ##1 c); endproperty same as: (a ##1 b ##1 c) or same as: (a ##1 c)
311
property p_range_rep_0_exa; @(posedge clk) a |-> (a[*0:1] ##1 b ##1 c); endproperty
Code in examples_sva/range_repetition_0.sv
Willamette HDL Inc. 2007
312
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
Willamette HDL Inc. 2007
313
314
Example:
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
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
// followed sometime by c
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
Willamette HDL Inc. 2007
318
319
SVA Coding Style Tip V-C functions have an overhead consider whether a simple boolean level isnt enough
sequence s1; $rose(a) ##1 $stable(b && c) ##1 $fell(d) ; endsequence 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
322
##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
323
req must stay true until the first time gnt is sampled true sequence burst_rule; @(posedge clk) $fell (burst) ##0 (!burst) throughout (##2 (!trdy [*3])); endsequence
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.
Willamette HDL Inc. 2007
324
Caution ! - throughout
The throughout sequence must be carefully described
req gnt clk
throughout
req
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.
Willamette HDL Inc. 2007
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
331
sys_rst_l
1
xmit
1 sys_clk 1 sys_clk
2
done
uart_out
Start bit 0
b0
332
A: Because intersect implies that both sequences have the same start and completion times
333
Signals xmit pulse lasts 16 sys_clk 2 (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 p_xmit_hi16; @(posedge sys_clk) $rose(xmit) |-> s_xmit_hi16; endproperty property p_xmit_done; @(posedge sys_clk) $rose(xmit) |-> s_xmit_done; endproperty property p_xmit_nc_data; @(posedge sys_clk) ($rose(xmit)) |=> s_xmit_nc_data; endproperty
A: For efficiency, If we didnt qualify this check it would happen throughout simulation, very wasteful of resources
Willamette HDL Inc. 2007
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 (seq2) seq.ended - contain seq1 within seq2 - detect end of seq within another sequence
338
Here, a must be high for 5 consecutive cycles contained within the second expression
339
e1 matches
rule matches
340
Given:
sequence abc; @(posedge clk) a ##1 b ##1 c; endsequence // edge-triggered always @ (abc) $display( abc succeeded" ); sequence def; @(negedge clk) d ##[2:5] e ##1 f; endsequence // 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)
Willamette HDL Inc. 2007
341
Router/coverage/router_assertions.sv
always @( s_pass_thru_0) begin if (`TRACE_ON) $display("Passthru 0 "); passthru[ 0] = 1; end always @( s_pass_thru_1) begin if (`TRACE_ON) $display("Passthru 1 "); passthru[ 1] = 1; end // 2 - 6 not shown always @( s_pass_thru_7) begin if (`TRACE_ON) $display("Passthru 7 "); passthru[ 7] = 1; end endmodule
342
Property Blocks
In this section
Operators
343
Optional arguments
property p1(a,b,c,d); @ (posedge clk) disable iff (reset) (a) |-> not ( b ##[2:3] c ##1 d ); 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, StateDrop } ); endproperty rx_statesm_valid : assert property( p_valid_states );
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
p1_not is true if a is never true, or if it is, one clock tick later b is never true
property p1_not; @(posedge clk) not s1; endproperty property p2_not; @(posedge clk) not (c && d) |-> not a ##1 b; endproperty
p2_not is true if the implication antecedent is never true, or if it is, the consequent sequential expression succeeds
346
and - property evaluates to true if, and only if, both property expressions evaluate to true
property p_and; @ (posedge clk) t2 |-> ( (a ##1 b) and (c |=> d) ) ; endproperty
If t2, then sequence (a##1b) must match and if c then we must see d 1 tick later.
347
348
expression2
Optional gating expression to the clocking_event
sequence s_rd_3; ##3 (out_busData == mem[$past( busAddr,3 )]); endsequence
code in file: examples_sva/past_1.sv
SVA Coding Style Tips 1. 2. 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
Willamette HDL Inc. 2007
349
$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
352
##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
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
);
356
357
d_1
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
360
always @( posedge clk) if ( !reset ) do_reset; else if ( mode ) if (!arb) st <= REQ2; `ifdef SVA PA: assert property (s1); `endif
Enabling condition is always current with design changes, etc. GOTCHA: Design flaws may be masked
property p1; @( posedge clk ) ( reset && mode && !arb ) |-> s1; endproperty ap1: assert 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)
Willamette HDL Inc. 2007
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: not @clk ( b ##1 c );
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
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 |-> ##1 (b !== (c ^ d)); endproperty cpu_p1: assert property (p1); endmodule bind cpu cpu_chk CHK1( clk, enable, d_out, d_in, val );
cpu_chk
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, .d); endmodule interface my_if(); bit clk = 0; logic b = 0; always #20 clk = !clk; always @(negedge clk) b++; endinterface
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
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) a ##2 b; endproperty ap1: assert property (p1); 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 ));
2.
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) b |=> @(posedge clk2) c; endproperty property m_clk_ex3; m_clk_ex |=> m_clk_ex2; endproperty
Willamette HDL Inc. 2007
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 @(posedge clk1) seq2 seq3 ##2 @(posedge clk1) seq4 seq5 intersect @(posedge clk1) seq6
Multi-clock sequences/properties:
must have well-defined start/end times, clock transitions subsequences must not admit empty matches
@(posedge clk0) seq1 ##1 @(posedge clk1) seq2 |=> @(posedge clk2)seq3;
Here, seq1, seq2 & seq3 must not allow empty matches like: sig3[*0:1]
369
370
sequence s1 must match sometime after c and before d Code in examples_sva/multi_clk_match.sv Inc. 2007 Willamette HDL
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
Willamette HDL Inc. 2007
373
Sample Solutions
374
Back
375
376
function bit compare (packet exp_pkt, act_pkt); // if(act_pkt.pid == 22) act_pkt.pid = 44; // uncomment to inject error
if( (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
Willamette HDL Inc. 2007
377
snk[i]
378
class source; mailbox #(Packet) out_chan; // null handle Packet pkt_to_send; int id; 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
Willamette HDL Inc. 2007
379
380
virtual router_if
. . . mailbox #(Packet) mb;
r_if;
test_env t_env; . . . initial begin reset(); pt_mode = 1; // set to pass thru mode to start t_env = new(r_if); //create test env t_env.run; // start things running end . . .
function new (int id, virtual router_if r_if, mailbox #(Packet) mb);
this.r_if = r_if;
this.id = id; this.mb = mb; endfunction . . . class test_env; virtual router_if . . . r_if;
class monitor; virtual router_if r_if; . . . mailbox #(Packet) log_mb; function new ( int id, virtual router_if r_if, mailbox #(Packet) log_mb ); this.id = id; this.r_if = r_if; this.log_mb = log_mb; endfunction . . .
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]), .r_if(r_if)); m[id] = new(.id(id), .log_mb(log_mon), .r_if(r_if)); end endfunction
Willamette HDL Inc. 2007
Back
381
382
Back
Willamette HDL Inc. 2007
383
384
385
Back
Willamette HDL Inc. 2007
386
endclass
387
388
Back
Willamette HDL Inc. 2007
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
Willamette HDL Inc. 2007
392
property p_nop; @(posedge clk) state==IDLE && opcode == NOP |=> state == IDLE; endproperty property p_wt_wd; @(posedge clk) state==IDLE && opcode == WT_WD |=> state == WT_WD_1 ##1 state == WT_WD_2 ##1 state == IDLE; 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 && opcode == RD_WD |=> state == RD_WD_1 ##1 state == RD_WD_2 ##1 state == IDLE; endproperty
393
assert_p_nop1: assert property(p_nop) else $display ("p_nop error"); assert_p_wt_wd1: assert property(p_wt_wd) else $display ("p_wt_wd error"); assert_p_wt_blk1: assert property(p_wt_blk) else $display ("p_wt_blk error"); assert_p_rd_wd1: assert property(p_rd_wd) else $display ("p_rd_wd error");
Back
Willamette HDL Inc. 2007
394
Back
395
396
Back
Willamette HDL Inc. 2007
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 gcc
.so
Specify the library on the command line when starting the simulator
<os> vsim -sv_lib 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
401
import_ex1.sv
#include <stdlib.h> #include <dpiheader.h> int init_rand() { printf("Init Rand\n"); srand(12345); return(0); }
my_lib.c
<os> vlib work <os> vlog -dpiheader dpiheader.h import_ex1.sv <os> gcc -Ipath_to_questasim_home/include -shared -g -o my_lib.so my_lib.c <os> vlog import_ex1.sv <os> vsim -c -sv_lib my_lib import_ex1 <vsim> run Init Rand Generating random 383100999 <vsim>
402
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:
404
my_lib.c
<os> vlib work <os> vlog export_ex1.sv -dpiheader dpi_types.h <os> gcc -Ipath_to_questasim_home/include -shared -g -o my_lib.so my_lib.c <os> vsim -c -sv_lib my_lib export_ex1 <vsim> run Starting C task Got 1238934 from SV <vsim>
Willamette HDL Inc. 2007
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
NOTE: For more complicated data types such as vectors and arrays, see the SystemVerilog P1800 LRM, Annex P
408
a value of logic 0.\n"); a value of logic 1.\n"); a value of logic Z.\n"); a value of logic X.\n");
$ vlib work $ vlog data_ex1.sv -dpiheader dpi_types.h $ gcc -I$path_to_questasim_home/include -shared -g -o my_lib.so my_lib.c $ 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>
Willamette HDL Inc. 2007
409
int doit( const int val) { int result; Double(val,&result) printf ("Got value %d from Double\n",result); return 0; }
$ vlib work $ vlog data_ex2.sv -dpiheader dpi_types.h $ gcc -Ipath_to_questasim_home/include -shared -g -o my_lib.so my_lib.c $ vsim -c -sv_lib my_lib data_ex2 vsim> run Got value 4 from Double Got value 10 from Double vsim>
410