System Verilog Testbench Constructs PDF
System Verilog Testbench Constructs PDF
System Verilog Testbench Constructs PDF
Testbench Constructs
VCS®/VCSi™Version X-2005.06 LCA
August 2005
Comments?
E-mail your comments about this manual to
[email protected].
Copyright Notice and Proprietary Information
Copyright 2005 Synopsys, Inc. All rights reserved. This software and documentation contain confidential and proprietary
information that is the property of Synopsys, Inc. The software and documentation are furnished under a license agreement and
may be used or copied only in accordance with the terms of the license agreement. No part of the software and documentation may
be reproduced, transmitted, or translated, in any form or by any means, electronic, mechanical, manual, optical, or otherwise, without
prior written permission of Synopsys, Inc., or as expressly provided by the license agreement.
Destination Control Statement
All technical data contained in this publication is subject to the export control laws of the United States of America.
Disclosure to nationals of other countries contrary to United States law is prohibited. It is the reader’s responsibility to
determine the applicable regulations and to comply with them.
Disclaimer
SYNOPSYS, INC., AND ITS LICENSORS MAKE NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Registered Trademarks (®)
Synopsys, AMPS, Arcadia, C Level Design, C2HDL, C2V, C2VHDL, Cadabra, Calaveras Algorithm, CATS, CSim,
Design Compiler, DesignPower, DesignWare, EPIC, Formality, HSPICE, Hypermodel, iN-Phase, in-Sync, Leda, MAST,
Meta, Meta-Software, ModelAccess, ModelTools, NanoSim, OpenVera, PathMill, Photolynx, Physical Compiler,
PowerMill, PrimeTime, RailMill, Raphael, RapidScript, Saber, SiVL, SNUG, SolvNet, Stream Driven Simulator,
Superlog, System Compiler, Testify, TetraMAX, TimeMill, TMA, VCS, Vera, and Virtual Stepper are registered
trademarks of Synopsys, Inc.
Trademarks (™)
abraCAD, abraMAP, Active Parasitics, AFGen, Apollo, Apollo II, Apollo-DPII, Apollo-GA, ApolloGAII, Astro, Astro-Rail,
Astro-Xtalk, Aurora, AvanTestchip, AvanWaves, BCView, Behavioral Compiler, BOA, BRT, Cedar, ChipPlanner, Circuit
Analysis, Columbia, Columbia-CE, Comet 3D, Cosmos, CosmosEnterprise, CosmosLE, CosmosScope, CosmosSE,
Cyclelink, Davinci, DC Expert, DC Expert Plus, DC Professional, DC Ultra, DC Ultra Plus, Design Advisor, Design
Analyzer, Design Vision, DesignerHDL, DesignTime, DFM-Workbench, DFT Compiler, Direct RTL, Direct Silicon
Access, Discovery, DW8051, DWPCI, Dynamic-Macromodeling, Dynamic Model Switcher, ECL Compiler, ECO
Compiler, EDAnavigator, Encore, Encore PQ, Evaccess, ExpressModel, Floorplan Manager, Formal Model Checker,
FoundryModel, FPGA Compiler II, FPGA Express, Frame Compiler, Galaxy, Gatran, HDL Advisor, HDL Compiler,
Hercules, Hercules-Explorer, Hercules-II, Hierarchical Optimization Technology, High Performance Option, HotPlace,
HSPICE-Link, iN-Tandem, Integrator, Interactive Waveform Viewer, i-Virtual Stepper, Jupiter, Jupiter-DP, JupiterXT,
JupiterXT-ASIC, JVXtreme, Liberty, Libra-Passport, Library Compiler, Libra-Visa, Magellan, Mars, Mars-Rail, Mars-
Xtalk, Medici, Metacapture, Metacircuit, Metamanager, Metamixsim, Milkyway, ModelSource, Module Compiler, MS-
3200, MS-3400, Nova Product Family, Nova-ExploreRTL, Nova-Trans, Nova-VeriLint, Nova-VHDLlint, Optimum Silicon,
Orion_ec, Parasitic View, Passport, Planet, Planet-PL, Planet-RTL, Polaris, Polaris-CBS, Polaris-MT, Power Compiler,
PowerCODE, PowerGate, ProFPGA, ProGen, Prospector, Protocol Compiler, PSMGen, Raphael-NES, RoadRunner,
RTL Analyzer, Saturn, ScanBand, Schematic Compiler, Scirocco, Scirocco-i, Shadow Debugger, Silicon Blueprint,
Silicon Early Access, SinglePass-SoC, Smart Extraction, SmartLicense, SmartModel Library, Softwire, Source-Level
Design, Star, Star-DC, Star-MS, Star-MTB, Star-Power, Star-Rail, Star-RC, Star-RCXT, Star-Sim, Star-SimXT, Star-
Time, Star-XP, SWIFT, Taurus, Taurus-Device, Taurus-Layout, Taurus-Lithography, Taurus-Process, Taurus-
Topography, Taurus-Visual, Taurus-Workbench, TimeSlice, TimeTracker, Timing Annotator, TopoPlace, TopoRoute,
Trace-On-Demand, True-Hspice, TSUPREM-4, TymeWare, VCS Express, VCSi, Venus, Verification Portal, VFormal,
VHDL Compiler, VHDL System Simulator, VirSim, and VMC are trademarks of Synopsys, Inc.
Service Marks (SM)
MAP-in, SVP Café, and TAP-in are service marks of Synopsys, Inc.
SystemC is a trademark of the Open SystemC Initiative and is used under license.
ARM and AMBA are registered trademarks of ARM Limited.
All other product or company names may be trademarks of their respective owners.
1
SystemVerilog Testbench Constructs 1
The new version of VCS has implemented some of the SystemVerilog
testbench constructs. As testbench constructs they must be in a
program block (see “Program Blocks” on page 1-2).
class classA;
function void vfunc(input in1, output out1);
.
.
.
endfunction
.
.
.
endclass
endprogram
bit clk = 0;
logic [31:0] data;
logic ctrl;
module clkmod;
.
.
.
prog prog1 (clk,data,ctrl); // instance of the program
.
.
.
endmodule
Arrays
Dynamic Arrays
Dynamic arrays are unpacked arrays with a size that can be set or
changed during simulation. The syntax for a dynamic array is as
follows:
The currently supported data types for dynamic arrays are as follows:
program prog;
.
.
.
bit bitDA1 [];
bit bitDA2 [];
bit bitDA3 [];
bit bitSA1 [100];
logic logicDA [];
.
.
.
initial
begin
bitDA1 = new[100];
bitDA2 = new[100] (bitDA2);
bitDA3 = new[100] (bitSA1);
logicDA = new[100];
end
.
.
.
endprogram
bitDA1 = new[3];
$display("bitDA1 after sizing, now size = %0d",bitDA1.size);
bitDA1.delete;
$display("bitDA1 after sizing, now size = %0d",bitDA1.size);
logic lFA1[2];
VCS displays:
lDA1 size = 0
lDA1[1] = 1
lDA1[0] = 0
lDA1 size = 2
logic lDA1[];
logic lDA2[];
initial
begin
lDA1=new[2];
$display("lDA2 size = %0d",lDA2.size);
lDA1[1]=1;
lDA1[0]=0;
lDA2=lDA1;
$display("lDA2[1] = %0d", lDA2[1]);
$display("lDA2[0] = %0d", lDA2[0]);
$display("lDA2 size = %0d",lDA2.size);
end
endprogram
lDA2 size = 0
lDA2[1] = 1
lDA2[0] = 0
lDA2 size = 2
Associative Arrays
An associative array has a lookup table for the elements of its declared
data type. Its index is a data type which serves as the lookup key for
the table. This index data type also establishes an order for the
elements.
Where:
data_type
Is the data type of the associative array.
array_id
Is the name of the associative array.
Wildcard Indexes
You can enter the wildcard character as the index.
Using the wildcard character permits entering any integral data type
as the index. Integral data types represent an integer (shortint,
int, longint, byte, bit, logic, reg, integer, and also packed
structs, packed unions, and enum.
program m;
bit [2:0] AA1[*];
int int1;
logic [7:0] log1;
initial begin
int1 = 27;
log1 = 42;
AA1[456] = 3'b101;
AA1[int1] = 3'b000; // index is 27
AA1[log1] = 3'b111; // index is 42
end
endprogram
String Indexes
A string index specifies that you can index the array with a string. You
specify a string index with the keyword string.
program p;
initial begin
a["sa"] = 8;
a["bb"] = 15;
a["ec"] = 29;
a["d"] = 32;
a["e"] = 45;
a[string_variable] = 1;
end
endprogram
num
Returns the number of entries in the array.
delete
Removes all entries from an array. If you specify an index, this
method removes the entry specified by the index.
exists
Returns a 1 if the specified entry exists.
first
Assigns the value of the smallest or alphabetically first entry in
the array. Returns 0 if the array is empty and returns 1 if the array
contains a value.
last
Assigns the value of the largest or alphabetically last entry in the
array. Returns 0 if the array is empty and returns 1 if the array
contains a value.
next
Finds the entry whose index is greater than the given index. If
there is a next entry, the index variable is assigned the index of
the next entry, and the function returns 1. Otherwise, variable is
unchanged, and the function returns 0
prev
Finds the entry whose index is smaller than the given index. If
there is a previous entry, the index variable is assigned the index
of the previous entry, and the function returns 1. Otherwise,
variable is unchanged, and the function returns 0.
number of entries = 5
string "sa" is in a
the first entry is "bb"
bb : 15
d : 32
e : 45
Queues
The variables in the queue are its elements. Each element in the
queue has a number: 0 is the number of the first, you can specify the
last element with the $ (dollar sign) symbol. The following are some
examples of queue declarations:
You also assign values to the elements using the element number,
for example:
intque = {0,intque};
intque = {intque, 4};
Removing elements from a queue are not yet supported, for example:
Queue Methods
There are the following built-in methods for queues:
size
Returns the size of a queue.
program prog;
int intque [$] = {1,2,3};
initial
begin
for (int i = 0; i < intque.size; i++)
$display(intque[i]);
end
endprogram
insert
Inserts new elements into the queue. This method takes two
arguments: the first is the number of the element, the second is
the new value.
program prog;
string strque [$] = {"first","second","third","forth"};
delete
Removes an element from the queue, specified by element
number. If you don’t specify an element number, this method
deletes all elements in the queue.
string strque [$] = {"first","second","third"};
initial
begin
for (int i =0; i<strque.size; i++)
$write(strque[i]," ");
$display(" ");
strque.delete(1);
for (int i =0; i<strque.size; i++)
$write(strque[i]," ");
end
initial
begin
for( int i = 0; i < intque.size; i++)
$write(intque[i]," ");
intque.push_front(0);
intque.push_back(4);
$write(" \n");
for( int i = 0; i < intque.size; i++)
1 2 3
0 1 2 3 4
Classes
class B;
int q = 3;
function int send (int a);
send = a * 2;
endfunction
task show();
$display("q = %0d", q);
endtask
endclass
Note:
See “Class Packet Example” on page 1-42 for a more complex
example of a class declaration. The name of the class is "Packet."
Note:
See section 11, "Classes" of the SystemVerilog LRM v3.1a for a
formal definition of class.
class_name handle_name;
handle_name = new();
task show();
$display("q = %0d", q);
endtask
endclass
initial begin
B b1; //declare handle, b1
b1 = new; //create an object by calling new
end
endprogram
The above two steps can be merged into one for instantiating a class
at the time of declaration:
For example:
B b1 = new;
function new([arguments]);
// body of method
endfunction
handle_name = new([arguments]);
program P;
When called, new() will print the value passed to it as the value of
command.
The value of q is 4.
If a property is not initialized by the constructor, it is implicitly
initialized, just like any other variable, with the default value of its data
type (see section 5.2, Table 5-1 in the SystemVerilog LRM v3.1a for
details).
class Packet;
...
endclass
Packet p1;
Packet p1; creates a variable, p1, that can hold the handle of an
object of class Packet. The initial default value of p1 is null. The
object does not yet exist, and p1 does not contain an actual handle,
until an instance of type Packet is created as shown below:
Packet p2;
p2 = p1;
In this case, there is still only one object. This single object can be
referred to with either variable, p1 or p2.
p2 = new p1;
Static Properties
Example
program test;
class Parcel;
static int count = 2;
function new();
count++;
endfunction
endclass
initial begin
Parcel pk1 = new;
Parcel pk2 = new;
Parcel pk3 = new;
5 Parcel
5 Parcel
5 Parcel
In the above example, every time an object of type Parcel is created,
the new() function is invoked and the static variable count is
incremented. The final value of count is "5." If count is declared as
non-static, the output of the above program is:
3 Parcel
3 Parcel
3 Parcel
Xvdata_Class data;
initial begin
data = new();
data.pi = 42; //illegal and will generate
//compile time error
end
endprogram
The line, data.pi=42, is not valid and yields the following compile
time error message:
program P;
virtual class Base;
virtual task print(string s);
$display("Base::print() called from %s", s);
endtask
Polymorphism
The ability to call a variety of functions using the exact same interface
is called polymorphism.
This example illustrates how the two classes derived from Packet
implement their own specific version of the display() method.
MyPacket mp;
YourPacket yp;
Packet p; //abstract base class
initial
begin
mp = new;
yp = new;
p = mp; // mp referenced by p
p.display();// calls display in MyPacket
p = yp;
p.display();// calls display in YourPacket
end
endprogram
Output:
See page 123 of the SystemVerilog LRM 3.1a for examples of using
a variable in the base class to hold references to subclass objects.
super keyword
The super keyword is used from within a derived class to refer to
properties of the parent class. It is necessary to use super when the
property of the derived class has been overridden, and cannot be
accessed directly.
Base b1;
Extended e1;
initial begin
b1 = new; // b1 points to instantiated object of Base
e1 = new; // e1 points to object of Extended
b1.p = 1; //property "p" of Base initialized to 1
b1.display(); //will print out "Base: p=1"
e1.p = 2; //"p" of Base is now 2
e1.q = 3; //"q" of Extended initialized to 3
e1.display(); //prints "Base: p=2 Extended: q=3"
end
endprogram
Output of the above program is:
Base: p=1
Base: p=2
Extended: q=3
When using the super keyword within the constructor, new, it must
be the first statement executed in the constructor. This is to ensure
the initialization of the superclass prior to the initialization of the
subclass.
Casting
program sample;
class Base;
integer p;
virtual task display();
$write("\nBase: p=%0d\n", p);
endtask
endclass
$cast(enum1, enum2)
class ClassA;
...
endclass
ClassA
Class_a
Class_ab
Base Class
Class_b
Subclass
ClassA
Class_a
Class_ab
Base Class
Class_b
Subclass
function new();
super.new(5);
endfunction
If included, the call to super() must be the first executable statement
(that is, not a declaration) in the constructor.
Properties
• local
• public
• protected
“public” is the default protection level for class members Using public
when declaring a property allows global access to that member via
class_name.member.
instance_name.property_name
Methods
Tasks or functions, known as “methods,” can be designated as
local, public, or protected. They are public by default.
program access_object_method;
class B;
int q = 3;
function int send (int a);
send = a * 2;
endfunction
task show();
$display("q = %0d", q);
endtask
endclass
initial begin
B b1; //declare handle
b1 = new; // instantiate
b1.show(); //access show() of object b.1
$display("value returned by b1.send() = %0d",
b1.send(4));//access send()of object b.1
end
endprogram
q = 3
value returned by b1.send() = 8
“this” keyword
The this keyword is used to unambiguously refer to properties or
methods of the current instance. For example, the following
declaration is a common way to write an initialization task:
program P;
class Demo;
integer x;
task new (integer x);
this.x = x;
endtask
endclass
endprogram
The x is now both a property of the class and an argument to the task
new(). In the task new(), an unqualified reference to x will be resolved
by looking at the innermost scope, in this case the subroutine
argument declaration. To access the instance property, we qualify it
with this to refer to the current instance.
program P;
class Demo;
integer x=4;
function integer send(integer x);
this.x = x*3;
endfunction
task show();
$display("The value of x in the object of type
Demo is = %d", send(this.x));
endtask
endclass
intial begin
integer x=5;
Demo D =new;
D.show();
$display("The value of the global variable x is
%0d", x);
end
endprogram
Random Variables
You need variables to which VCS assigns random values. There are
two types of random variables and two different keywords to begin
their declarations:
rand
Specifies a standard random variable
randc
Specifies a random-cyclic variable.
The following is an example of a standard random variable
declaration:
Variable randbit1 has eight bits so its possible values range from
0 to 255. The chances that VCS assigns any of these values is
precisely 1/256.
If this were a standard random variable, after VCS assigns the 3 value,
there is a 1/4 chance that VCS assigns the 3 again, but because it is
a random-cyclic variable, after VCS assigns the 3, there is no chance
that 3 will also be the next assigned value.
class Bus;
rand bit [15:0] addr;
rand bit [15:0] data;
.
.
.
endclass
Constraint Blocks
class myclass;
rand logic [1:0] log1,log2,log3;
randc logic [1:0] log4;
constraint c1 {log1 > 0;}
constraint c2 {log2 < 3;}
endclass
myclass mc = new;
initial
repeat (10)
if(mc.randomize()==1)
$display("log1 = %0d log2=%0d log3=%0d log4=%0d",
mc.log1, mc.log2, mc.log3, mc.log4);
endprogram
program test;
class base;
rand int r_a;
endclass
base b = new;
initial begin
int ret;
ret = b.randomize with {r_a > 0; r_a <= 10;} ;
// where my declaration {r_a >0 ; r_a <= 10; }
// is now a constraint block
if(ret == 1)
$display("Randomization success");
else
$display("Randomization Failed");
end
endprogram
Inheritance
Constraints follow the same rules of inheritance as class variables,
tasks, and functions.
class myclass;
rand logic [1:0] log1,log2,log3;
randc logic [1:0] log4;
constraint c1 {log1 > 0;}
constraint c2 {log2 < 3;}
endclass
myclass2 mc = new;
Set Membership
You can use the inside operator to specify a set of possible values
that VCS randomly applies to the random variable.
class myclass;
rand int int1;
constraint c1 {int1 inside {1, [5:7], [105:107]};}
endclass
myclass mc = new;
initial
repeat (10)
if(mc.randomize()==1)
$display("int1=%0d",mc.int1);
endprogram
Constraint c1 specifies that the possible values for int1 are as follows:
• 1
• a range beginning with 5 and ending with 7
• a range beginning with 105 and ending with 107
The $display system task displays the following:
int1=1
int1=7
int1=5
int1=107
int1=106
int1=5
int1=5
int1=6
int1=107
int1=1
Weighted Distribution
You can use the dist operator to specify a set of values or ranges
of values, where you give each value or range of values a weight,
and the higher the weight, the more likely VCS is to assign that value
to the random variable.
program prog;
class myclass;
rand int int1;
constraint c1 {int1 dist {[1:2] := 1, [6:7] :/ 5, 9 :=10};}
endclass
myclass mc = new;
int i;
initial begin
for(i = 1; i < 10; i++) stats[i] = 0;
repeat (1700)
if(mc.randomize()==1) begin
stats[mc.int1]++;
//$display("int1=%0d",mc.int1);
end
for(i = 1; i < 10; i++)
$display("stats[%d] = %d", i, stats[i]);
end
endprogram
value of int number of times int has this value fraction of the simulation time
1 106 1/17
2 98 1/17
3 0
4 0
5 0
6 248 2.5/17
7 251 2.5/17
8 0
9 998 10/17
program prog;
class Bus;
randc bit randcvar;
bit norandvar;
initial
begin
bus.norandvar = 0;
#5 bus.norandvar = 1;
#5 bus.norandvar = 0;
#5 $finish;
end
initial
repeat (15)
#1 if (bus.randomize() ==1)
$display("randcvar = %0b norandvar = %0b at %0t",
bus.randcvar, bus.norandvar,$time);
endprogram
randcvar = 0 norandvar = 0 at 1
if else Constraints
An alternative to an implication constraint is the if else constraint.
The if else constraint allows a constraint or constraint set on the
else condition.
program prog;
class Bus;
randc bit [2:0] randcvar;
bit norandvar;
constraint c1 { if (norandvar == 1)
randcvar == 0;
else
randcvar inside {[1:3]};}
endclass
initial
begin
bus.norandvar = 0;
#5 bus.norandvar = 1;
#5 bus.norandvar = 0;
#5 $finish;
end
initial
repeat (15)
#1 if (bus.randomize() ==1)
$display("randcvar = %0d norandvar = %0b at %0t",
bus.randcvar, bus.norandvar,$time);
endprogram
constraint c1 { if (norandvar == 1)
randcvar == 0;
else
randcvar inside {[1:3]};}
randcvar = 1 norandvar = 0 at 1
randcvar = 2 norandvar = 0 at 2
randcvar = 3 norandvar = 0 at 3
randcvar = 3 norandvar = 0 at 4
randcvar = 0 norandvar = 1 at 5
randcvar = 0 norandvar = 1 at 6
randcvar = 0 norandvar = 1 at 7
randcvar = 0 norandvar = 1 at 8
randcvar = 0 norandvar = 1 at 9
Global Constraints
Global constraints are described in detail on page 139 of the
SystemVerilog 3.1a LRM.
program prog;
class myclass;
rand bit [7:0] randvar;
endclass
Variable Ordering
In an implication like the following:
The select variable “implies” that data is 0, in this case, when select
is 1, data is 0.
The default behavior is for the constraint solver to solve for both select
and data at the same time. Sometimes you can assist the constraint
solver by telling it to solve for one variable first. You can do this with
another constraint block that specifies the order in which the
constraint solver solves the variables:
Note:
Ordering also changes the distribution of values.
Randomize Methods
randomize()
Variables in an object are randomized using the randomize() class
method. Every class has a built-in randomize() method.
randomize()
Generates random values for active random variables, subject to
active constraints, in a specified instance of a class. This method
returns a 1 if VCS generates these random values, otherwise it
returns 0. Examples of the use of this method appear frequently
in previous code examples.
The official description of random constraint methods begins on page
145 of the SystemVerilog 3.1a LRM.
class size;
rand bit [7:0] s; //random variable s
constraint con_size {
s > 0;
s < 50;
}
endclass
class Pkt;
integer header[7];
rand bit [7:0] payload[];
size sz;
function void pre_randomize();
/* Randomize the sz.s variable and instantiate
the dynamic array. */
integer res;
sz = new();
res = sz.randomize(); /* calling randomize() on
object sz of class size. Randomizes rand
variable s (constrained to >0 and <50 */
endfunction
endclass
Pkt pkt;
integer success,i;
initial begin
pkt = new(); //instantiate pkt
payload.size = 12
Randomization Succeeded
payload.size = 17
Randomization Succeeded
payload.size = 8
Randomization Succeeded
payload.size = 40
Randomization Succeeded
payload.size = 10
Randomization Succeeded
Controlling Constraints
Syntax:
task object[.constraint_identifier]::constraint_mode
(bit ON | OFF);
or
function int
object.constraint_identifier::constraint_mode();
For detailed discussion, see section 12.8 of the SystemVerilog 3.1a
LRM.
‘define N 5
program test;
class bus;
rand bit [15:0] addr;
constraint word_align {addr[0] == 1'b0;}
constraint addr_range{addr >= 0 && addr <= 15;}
endclass
bus bb = new;
initial begin
generateRandomAddresses(`N);
Syntax:
`define N 5
program test;
class bus;
rand bit [15:0] addr;
rand bit [31:0] data;
constraint CC { data > 0; addr > 0; addr < 255; data
< 512;}
endclass
bus bb = new;
initial begin
// By default all random variables are ON
if (bb.addr.rand_mode() && bb.data.rand_mode())
begin
$display("======both random variables ON
======");
end
else
$display("Error with rand_mode");
In-line Constraints
You can use the randomize() method and the with construct to
declare in-line constraints outside of the class for the random
variables, at the point where you call the randomize()
method.program prog;
class Bus;
rand bit [2:0] bitrand1;
endclass
endprogram
bitrand1 = 100
bitrand1 = 100
bitrand1 = 0
bitrand1 = 100
bitrand1 = 100
bitrand1 = 0
bitrand1 = 100
bitrand1 = 100
bitrand1 = 0
bitrand1 = 100
program test;
class A;
rand logic [7:0] x;
real r = 1;
A a;
int d1,d2,d3,d4;
initial begin
a = new;
a.srandom(r);//the r is the seed for RNG of a
d1 = a.randomize();
if(d1 == 1) //if randomize() is successful
d2 = a.x; //assign value of the variable x in a to d2
a.srandom(r+1);
d1 = a.randomize();
if(d1 == 1)
d3 = a.x;
a.srandom(r);
d1 = a.randomize();
if(d1 == 1)
d4 = a.x;
if((d2 == d4) && (d2 != d3))
$display("test passed");
else
$display("test failed");
end
endprogram
test passed
Semaphores
program prog;
initial
begin:initial1
#1 sem1.get(1);
$display("initial1 takes 1 key at %0t", $time);
#6 sem1.put(1);
$display("initial1 returns 1 key at %0t",$time);
#1 sem1.get(1);
$display("initial1 takes 1 key at %0t", $time);
end
initial
begin:initial2
#5 sem1.get(2);
$display(" inital2 takes 2 keys at %0t",$time);
#5 sem1.put(1);
$display(" inital2 returns 1 key at %0t",$time);
end
endprogram
In this program there are two initial blocks, labeled by the label on
their begin-end blocks, initial1 and intital2.
The initial block initial2 could be rewritten to use the try_get method
to see if a certain number of keys are available, for example:
initial
begin:initial2
#5 if(sem1.try_get(2))
begin
sem1.get(2);
$display("inital2 takes 2 keys at %0t",$time);
end
#5 sem1.put(1);
end
endprogram
Semaphore Methods
Semaphores have the following built-in methods:
new (number_of_keys)
You use this method with the semaphore keyword. It specifies
the initial number of keys in the semaphore.
put(number_of_keys)
Increments the number of keys in the semaphore.
Mailboxes
program prog;
initial
begin
repeat(3)
begin
#5 mbx.put(k);
i = mbx.num();
Mailbox Methods
Mailboxes use the following methods:
new()
Along with the mailbox keyword, declares a new mailbox. You
cannot yet specify the maximum number of messages with this
method.
num()
Returns the number of messages in the mailbox.
put(expression)
Puts another message in the mailbox.
get(variable)
Assigns the value of the first message to the variable. VCS
removes the first message so that the next message becomes
the first method. If the mailbox is empty, VCS suspends simulation
of the process (initial block, task, etc.) until a put method put a
message in the mailbox.
try_get(variable)
Assigns the value of the first message to the variable. If the
mailbox is empty, this method returns the 0 value. If the message
is available, this method returns a non-zero value. After returning
the value, VCS executes the next statement.
Events
Persistent Trigger
Merging Events
Event Comparison
task t1;
event evt1;
#5 -> evt1;
endtask
initial
t1;
initial
@(t1.evt1) $display("t1.evt1 happened at %0t",$time);
endprogram
t1.evt1 happened at 5
Persistent Trigger
The triggered property persists on a named event throughout the
time step when it is triggered, preventing a race condition, for
example, when a named event is triggered and is evaluated in an
event control during the same time step.
program prog;
event evt1,evt2;
initial
-> evt1;
initial
initial
fork
-> evt2;
begin
wait (evt2.triggered);
$display("evt2 occurred");
end
join
endprogram
evt1 triggered
evt2 occurred
Merging Events
You can assign a SystemVerilog named event to another named
event. When you do, they alias each other and when VCS executes
a line calling for the triggering of one of these events, VCS triggers
both named events.
program prog;
initial
begin
evt2 = evt3; // this is an alias
initial
#1 @ (evt1) $display("evt1 triggerred");
initial
#1 @ (evt2) $display("evt2 triggerred");
initial
#1 @ (evt3) $display("evt3 triggerred");
endprogram
evt1 triggerred
evt2 triggerred
evt3 triggerred
IMPORTANT:
When you merge events, the merger takes effect only in
subsequent event controls or wait statements.
program prog;
event evt1;
initial
begin
evt1 = null;
#5 -> evt1;
end
initial
#1 @(evt1) $display("evt1 triggered");
initial
begin
#5 wait (evt1.triggered);
$display("evt1 occurred");
end
endprogram
program prog;
initial
begin
evt1 = evt2;
if (evt1 == evt2)
$display("evt1 == evt2");
if (evt1 === evt2)
$display("evt1 === evt2");
if (evt1 != evt3)
$display("evt1 != evt3");
if (evt3 != null)
$display("evt3 != null");
end
endprogram
evt1 == evt2
evt1 === evt2
evt1 != evt3
evt3 != null
clocking_identifier
specifies the name of the clocking block being declared.
clocking_event
specifies an event that acts as the clock for the clocking block
(e.g., posedge, negedge of a clocking signal):
@(posedge clk)
clocking_dir
is the direction of the signal: input, output or inout. If specifying
more than one clocking_dir, they must be in the order
input...output:
input clocking_skew output clocking_skew
clocking_skew
determines how long before the synchronized edge the signal is
sampled, or how long after the synchronized edge the signal is
driven. A clocking_skew can consist of an edge identifier and a
delay control, just an edge identifier, or just the delay control. The
edge identifiers are posedge and negedge. The edge can be
specified only if the clocking event is a singular clock(that is, a
simple edge of a single signal like @(posedge clk), @(clk),
@(negedge top.clk), etc.).The delay control is introduced by "#"
followed by the delay value. The following are examples of legal
clocking_skews:
input #0 i1;
output negedge #2 i2;
input #1 output #2;
The skew for an input signal is implicitly negative (that is, sampling
occurs before the clock event). The skew for an output signal is
implicitly positive (that is, the signal is driven after the clock event).
Note: #1step is the default input skew unless otherwise specified.
However, an explicit #1step skew is not yet supported.
signal_identifier
is the name of a signal in the clocking block and identifies a signal
in the scope enclosing the clocking block declaration (and unless
a hierarchical_identifier is specified). For example:
input #1 i1;
hierarchical_identifier
specifies the hierarchical path to the signal being assigned to the
signal_identifier. For example:
input negedge #2 i = top.i2;
`timescale 1ns/1ns
module top;
reg out3;
reg out1;
reg clk = 0;
p1 p(out3,clk,out1);
initial
#200 $finish;
@(cb.out1);
$display($time,,,cb.out1);
end
endprogram
The output of the above program is:
0 x
30 0
130 0
150 1
The skew for input and inout signals determines how long before
clocking_event the signal is sampled. The skew for output and inout
signals determines how long after the clock_event the signal is driven.
Clock
For more details see section 15.3 of the SystemVerilog LRM 3.1a.
Hierarchical expressions
@(cb1);
Therefore, @(cb1) is equivalent to @(posedge clk).
Input sampling
• When the skew is #0, the signal value in the Observed region
corresponds to the value sampled.
• When the skew is not #0, then the signal value at the Postponed
region of the timestep skew time-units prior to the clocking event
corresponds to the value sampled.
• When the skew is #1step, the signal value in the Preponed region
corresponds to the value sampled.
Note:
See section 14.3 of the SystemVerilog LRM 3.1a for definitions of
Observed, Postponed and Preponed regions.
Synchronous events
Syntax
@ (expression);
expression
denotes clocking block input or inout, or a slice, which may include
dynamic indices. The dynamic indices are evaluated when
@(expression) executes.
For examples, see pages 189-190 of the SystemVerilog LRM3.1a
Synchronous drives
The output (or inout) signals defined in a clocking block are used to
drive values onto their corresponding signals in the DUT at a specified
time. That is, the corresponding signal changes value at the indicated
clocking event as indicated by the output skew.
Note: For the syntax for specifying a synchronous drive, see section
15.14 of the SystemVerilog LRM 3.1a.
initial
begin
@ (cb1); //synchronising with clocking event
cb1.a <= 0; //drive at first posedge
cb1.b <= 0; //drive after skew on first posedge
##2 cb1.a <= 1;
##1 cb1.b <= 1; //drive after 3 clock cycles
end
When the same net is an output from multiple clocking blocks, then
the net is driven to its resolved signal value. When the same variable
is an output from multiple clocking blocks, then the last drive
determines the value of the variable.
e1:
Is an instance name for the expect statement. You can use any
unique name you want, followed by a colon (:).
expect
The expect keyword.
(@(posedge clk) ##1 in1 && in2)
Is the property of the expect statement. Such properties are
enclosed in parentheses. This property is the following:
@(posedge clk)
the clock signal is clk, the clocking event is a rising edge
(posedge) on clk. Using the posedge keyword means that it,
with the clock signal, are an expression and so are also
enclosed in parentheses.
##1
Is a clock delay. It specifies waiting for one clocking event, then
evaluating the expression.
in1 && in2
Is an expression. If true, VCS executes the first action block
called the success block. if false VCS executes the second
action blockafter the keyword else, called the failure block.
Here is another example of an expect statement. This one calls for
evaluating the expression after a range of clocking events.
module test;
logic log1,log2,clk;
initial
begin
log1=0;
log2=0;
clk=0;
#33 log1=1;
#27 log2=1;
#120 $finish;
end
always
#5 clk=~clk;
initial
begin
end
endprogram
The $display system tasks in the failure and success action blocks
display the following:
failure at 15 in test.tbpb1.e1
success at 65 in test.tbpb1.e2
interface SBus;
logic req, grant;
endinterface
module m;
SBus sbus1();
SBus sbus2();
.
.
.
endmodule
program P;
virtual SBus bus;
initial
begin
bus = m.sbus1; // setting the reference to a real
// instance of Sbus
$display(bus.grant); // displaying m.sbus1.grant
bus.req <= 1; // setting m.sbus1.req to 1
#1 bus = m.sbus2;
bus.req <= 1;
end
endprogram
Scope of Support
Example.
interface SBus;
logic req, grant;
modport REQ(input req);
endinterface
program P;
virtual Sbus.REQ sb;
The semantic meaning is the same as in the example above with the
difference that sb is now a reference only to a portion of Sbus and
writing assignments are subject to modport direction enforcement so
that, for example, "sb.req = 1" would become illegal now (violates
input direction of the modport REQ).
Event Expression/Structure
Null Comparison
We support:
• NULL assignment
virtual vi = 0;
class C;
virtual I vi;
• Comparison of vi variables
By definition, vi1 == vi2 iff they refer to the same instance of an
interface (or both NULL).
Coverage
VCS collects all the coverage data during simulation and generates
a database. VCS provides a tool to read the database and generate
text or html reports (see page-118) .
program prog;
initial
repeat (15)
#5 clk = ~clk;
initial
begin
#40 my_color = blue;
#23 my_color = yellow;
end
endprogram
• The enumerated data type colors, with members named red, blue,
and yellow (whose default values are 0, 1, and 2).
• A variable of type colors called my_color
• A covergroup named cg1 that specifies the following:
- the clocking event that is the rising edge on signal clk.
- the coverage point that is to monitor the values of the variable
my_color. The identifier of the coverage point, for hierarchical
name purposes, is cp1.
• an instantiation of covergroup cg1 using the new method.
program P;
class MyClass;
int m_a;
covergroup Cov @(posedge clk);
coverpoint m_a;
endgroup
function new();
Cov = new;
endfunction
endclass
endprogram
• The keyword bins specifies one or more bins for coverage data.
• The name some_name is an identifier for all the bins. It is the root
bin name.
• The empty square brackets [] specifies there will be a separate
bin for each value in the specified range.
• The range of value follows the equal sign = and is in the nested
set of curly braces { }. This range is 1 through 20. The range is
always specified as lowest_value:highest_value.
Coverage point data will have 20 bins, the first named some_name_1
and the last named some_name_20.
You can specify different bins for different value ranges, for example:
coverpoint data
{
bins first_ten = {[1:10]};
bins second_ten = {[11:20]};
}
Here the coverage information about when the coverage point data
has the values 1 to 10 is in the bin named first_ten, and the information
about when data has the values from 11 to 20 is in the bin named
second_ten.
coverpoint data
{
bins bin1 = {[1:5]};
bins bin2 = {[6:10]};
bins bin3 = default;
}
In this example coverage information about when data has the values
1-10 is in bins bin1 and bin2, information about all other values is in
bin3.
coverpoint data
{
bins bin1 = {[0:3],5,7,[9:10]};
bins bin2 = {4,6,8};
bins bin3 = default;
}
When you instantiate the covergroup, you can make the covergroup
a generic covergroup and then pass integers to specify value ranges
in the new method, for example:
coverpoint data
{
bins from0 = (0=>1),(0=>2),(0=>3);
bins tran1234 = (1=>2=>3=>4);
bins bindef = default;
}
You can use range lists to specify more than one starting value and
more than one ending value, for example:
coverpoint data
{
illegal_bins badvals = {7,11,13};
illegal_bins badtrans = (5=>6,6=>5);
bins bindef = default;
}
Cross coverage is when there are two coverage points that you want
VCS to compare to see if all the possible combinations of the possible
values of the two coverage points occurred during simulation.
Consider the following example:
program prog;
bit clk;
bit [1:0] bit1,bit2;
initial
begin
clk = 0;
repeat (200)
begin
bit1 = $random();
bit2 = $random();
#5 clk = ~clk;
#5 clk = ~clk;
end
end
endprogram
In covergroup cg1 there are two coverpoints labled bit1 and bit2. In
addition,there is the following:
Similarly, cross bin bin2 gets a hit whenever either bin hicp1vals
of coverpoint cp1 gets a hit, or bin hicp2vals of cover point cp2
gets a hit. Cross bin bin3 gets a hit if any bin of cover point cp1
whose value range overlaps with the range [0:1] gets a hit and, for
the same sample event occurrence, any bin of cover point cp2 whose
value range overlaps with the range [0:3] also gets a hit. In this
example, cross bin bin3 gets a hit when bin lowcp1vals of cover
point cp1 gets a hit and bin lowcp2vals of cover point cp2 also
gets a hit.
In case none of the user defined cross bins are matched, then VCS
automatically creates an auto cross bin to store the hit count for each
unique combination of the cover point bins.
Coverage Options
You can specify options for the coverage of a covergroup with the
type_option.option=argument keyword and argument for
specifying options, for example:
type_option.weight = integer;
Specifies the weight of the covergroup when calculating the
overall coverage. Specify an unsigned integer. The default weight
value is 1.
type_option.goal = integer;
Specifies the target goal of the covergroup. Specify an integer
between 0 and 100. The default goal is 90.
Note: "Coverage number" is a percentage. If all bins of a covergroup
are covered, then the coverage number for that covergroup is
100%.
type_option.comment = "string";
A comment in the report on the covergroup.
You can also apply these option to coverage points, for example:
initial
begin
cg1_1.option.weight = 10;
cg1_1.option.goal = 75;
.
.
.
end
instance_name.option.at_least=integer
Specifies the minimum number of hits in a bin for VCS to consider
the bin covered.
instance_name.option.auto_bin_max=integer
Specifies the maximum number of bins for a coverage point when
you don’t define the bins for a coverage point.
instance_name.option.detect_overlap=boolean
The boolean argument is 1 or 0. When boolean is 1, VCS
displays a warning message when there is an overlap between
the range list or transitions list of two bins for the coverage point.
instance_name.option.name[=string]
This option is used to specify a name for the covergroup instance.
If a name is not specified, a name is automatically generated.
instance_name.option.per_instance=boolean
The boolean argument is 1 or 0. When boolean is 1, VCS keeps
track of coverage data for the instance.
• get_coverage()
• get_inst_coverage()
• set_inst_name(string)
• sample()
• stop()
• start()
get_coverage()
Calculates the coverage number for the covergroup type (see
page 109 for definition). Return type: real.
Below is an example of using get_coverage() to calculate the
coverage number of a covergroup:
program test();
reg clk = 0;
reg [2:0] var = 3'b001;
class A;
covergroup covType @(clk); //covergroup, covType, defined
//in class A,
cp1: coverpoint var {
function new;
covType = new(); //instantiate the embedded covergroup
endfunction
endclass
A A_inst;
initial begin
repeat (10) begin
#5 clk = ~clk;
var = var + 1;
/* get_coverage() calculates the number of the embedded
covergroup covType as a whole */
$display("var=%b coverage=%f\n", var,
A_inst.covType.get_coverage());
end
end
initial
A_inst = new();
endprogram
Output of program:
var=010 coverage=0.000000
var=011 coverage=16.666666
var=100 coverage=33.333332
var=101 coverage=50.000000
var=111 coverage=83.333336
var=000 coverage=100.000000
var=001 coverage=100.000000
var=010 coverage=100.000000
var=011 coverage=100.000000
get_inst_coverage()
Calculates the coverage number for coverage information related
to the covergroup instance. Return type: real.
program test();
reg clk = 0;
reg [2:0] var = 3'b001;
covType cov1;
initial begin
repeat (5) begin
#5 clk = ~clk;
var = var + 1;
$display("var=%b coverage=%f\n", var,
initial
cov1 = new(2);
endprogram
The output of the program is:
var=010 coverage=-1.000000
var=011 coverage=-1.000000
var=100 coverage=-1.000000
var=101 coverage=-1.000000
var=110 coverage=-1.000000
set_inst_name(string)
The instance name is set to string. Return type: void.
In the example below, cov1 is the name of an instance that is of
type covType, declared as such (covType cov1; cov1 =
new(2);). The name is changed to new_cov1 after calling
set_inst_name("new_cov1").
program test();
reg clk = 0;
reg [2:0] var = 3'b001;
initial
begin
cov1 = new(2);
$display("Original instance name is %s\n",
cov1.option.name);
cov1.set_inst_name("new_cov1");//change instance name
$display("Instance name after calling set_inst_name()
is %s\n", cov1.option.name);
end
endprogram
sample()
sample() triggers sampling of the covergroup instance. Return
void.
program test();
reg clk = 0;
reg [2:0] var = 3'b001;
initial
cov1 = new();
initial begin
repeat (10) begin
#10 clk = ~clk;
var = var + 1;
end
end
initial begin
repeat (40) begin
#3 cov1.sample();
end
end
endprogram
stop()
When called, collecting of coverage information is stopped for that
instance. Return type: void. See the get_coverage(), stop(), start()
example on page 116.
start()
When called, collecting of coverage information resumes for that
instance. Return type: void. See the get_coverage(), stop(), start()
example on page 116.
covType cov1;
initial begin
repeat (10) begin
#5 clk = ~clk;
var = var + 1;
$display("var=%b covergae=%f\n", var,
cov1.get_coverage());
end
end
initial
begin
cov1 = new(2);
cov1.stop();
cov1.option.weight = 5;
#30 cov1.start();
end
endprogram
OUTPUT:
var=010 covergae=0.000000
var=011 covergae=0.000000
var=100 covergae=0.000000
var=101 covergae=0.000000
var=111 covergae=0.000000
var=000 covergae=16.666666
var=001 covergae=33.333332
var=010 covergae=33.333332
var=011 covergae=33.333332
During simulation VCS writes a .db file named after the program. For
the code example above, VCS writes the prog.db file in the current
directory. This file is the coverage database file, it contains all the
information VCS needs to write a coverage report. There are two
types of coverage reports:
Coverage Summary
Number of coverage types: 1
Number of coverage Instances: 1
Cumulative coverage: 100.00
Instance coverage: 0.00
==============================================================================
= Cumulative report for cg1
==============================================================================
Summary:
Coverage: 100.00
Goal: 90
prog.db
The report begins with a summary of the coverage for the covergroup
cg1. There is 100% coverage, meaning that VCS saw all possible
values for the coverage point(s) in the covergroup.
• The coverage point, in this case variable my_color, reached all its
possible values.
• There were no user defined bins.
• VCS created bins for the coverage point named auto_blue,
auto_red, and auto_yellow, all named after the members of the
enumerated type colors, blue, red, and yellow.
• There were four hits for bin auto_red, this means that during
simulation, there were four clocking events (rising edge on signal
clk) where VCS detected that the value of the variable my_color
was red..
• There were two hits for bins auto_blue and auto_yellow.
click
here
The report shows one covergroup cg1. Click on cg1 to see information
about covergroup cg1.
The report shows one coverage point, cp1. Click on cp1 to see
information about coverage point cp1.