Synopsys Test Bench
Synopsys Test Bench
SystemVerilog Testbench
Workshop
Student Guide
50-I-052-SSG-001 2005.06-SP1
www.synopsys.com
Copyright Notice and Proprietary Information
Copyright 2006 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.
“This document is duplicated with the permission of Synopsys, Inc., for the exclusive use of
__________________________________________ and its employees. This is copy number __________.”
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.
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, 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, 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, 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.
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.
Day 1
Day 2
Unit 5: Concurrency
Unit Objectives ................................................................................................................ 5-2
Day 1 Review................................................................................................................... 5-3
Day 1 Review (Building Testbench Files)....................................................................... 5-4
Day 1 Review (Testbench Architecture) ......................................................................... 5-5
Concurrency in Simulators .............................................................................................. 5-6
Creating Concurrent Processes ........................................................................................ 5-7
How Many Child Processes? ........................................................................................... 5-8
Join Options ..................................................................................................................... 5-9
Process Execution .......................................................................................................... 5-10
Day 3
Customer Support
Synopsys Support Resources ........................................................................................ CS-2
SolvNet Online Support Offers: ................................................................................... CS-3
SolvNet Registration is Easy ........................................................................................ CS-4
Support Center: AE-based Support............................................................................... CS-5
Other Technical Sources ............................................................................................... CS-6
Summary: Getting Support ........................................................................................... CS-7
Name
Company
Job Responsibilities
EDA Experience
Main Goal(s) and Expectations for this Course
i- 2
Restrooms Smoking
Meals Recycling
i- 3
i- 4
i- 5
i- 6
DAY
1
1 The Device Under Test (DUT)
i- 7
DAY
2
5 Concurrency
6 Inter-Process Communications
i- 8
DAY
3 Object Oriented Programming (OOP)
9 – Inheritance
10 Functional Coverage
CS Customer Support
i- 9
Definition of
Recommendation
Acronyms
i- 10
Lab Exercise: A lab is associated with this unit, module, or concept.
Recommendation: Recommendations to the students, tips, performance boost, etc.
For Further Reference: Identifies pointer or URL to other references or resources.
Under the Hood Information: Information about the internal behavior of the tool.
Caution: Warnings of common mistakes, unexpected behavior, etc.
Definition of Acronyms: Defines the acronym used in the slides.
Question: Marks questions asked on the slide.
Group Exercise: Test for Understanding (TFU), which requires the students to work in groups.
DAY
1
1 The Device Under Test (DUT)
1- 2
A router:
16 x 16 crosspoint switch
valid_n [15:0]
router valido_n [15:0]
reset_n
clock
1- 3
The router has 16 input and 16 output ports. Each input and output port consists of 3 signals, serial
data, frame and valid. These signals are represented in a bit-vector format, din[15:0], frame_n[15:0],
valid_n[15:0], dout[15:0], frameo_n[15:0] and valido_n[15:0].
To drive an individual port, the specific bit position corresponding to the port number must be
specified. For example, if input port 3 is to be driven, then the corresponding signals shall be din[3],
frame_n[3] and valid_n[3].
To sample an individual port, the specific bit position corresponding to the port number must be
specified. For example, if output port 7 is to be sampled, then the corresponding signals shall be
dout[7], frameo_n[7] and valido_n[7].
inputs outputs
frame_n[0] port port
frameo_n[0]
valid_n[0] 0 0 valido_n[0]
din[0] dout[0]
1 1
2 2
3 3
4 4
partial view
1- 4
1- 5
clock
din[i] x A0 A1 A2 A3 d0 .... x dn-1 dn x
valid_n[i] x x x x x
frame_n[i]
clock
dout[i] x x d0 d1 x x d2 d3 dn-3 x dn-2 dn-1 x
valido_n[i] x x
frameo_n[i]
1- 7
clock
reset_n
frame_n[i]
15 clock cycles
1- 8
During these 15 clock cycles, the router is performing self-initialization. If you attempt to drive a
packet through the router during this time, the self-initialization will fail and the router will not work
correctly afterwards.
1- 9
1- 10
DAY
1
1 The Device Under Test (DUT)
2- 2
Architecture/ End
Idea Algorithm Spec RTL Gate GDSII ASIC product
Transformations
2- 3
Pass
√
Tape out!
???
Debug Debug
Fail testbench RTL code
2- 4
Phases of verification
Preliminary Broad-Spectrum Corner-case
Verification Verification Verification
Goal
% Coverage
Difficult to reach
Corner-case
Verification
Time
Build verification
environment
2- 5
The process of reaching the verification goal starts with the definition of the verification goal.
What does it mean to be done with testing? Typically, the answer lie in the functional coverage spec
within a verification plan. The goal is then to reach 100% coverage of the defined functional
coverage spec in the verification plan.
Once the goal has been defined, the first step in constructing the testbench is to build the verification
environment.
To verify the the environment is set up correctly, preliminary verification tests are usually executed
to wring out the rudimentary RTL and testbench errors.
When the testbench environment is deemed to be stable, broad-spectrum verification based on
random stimulus generation is utilized to quickly detect and correct the majority of the bugs in both
RTL code and testbench code.
Based on functional coverage analysis, the random-based tests are then constrained to focus on
corner-cases not yet reached via broad-spectrum testing.
Finally, for the very difficult to reach corner cases, customized directed tests are used to bring the
coverage up to 100%.
Verification is complete when you reach 100% coverage as defined in the verification plan.
Checks Checks
Configure
completeness correctness
DUT interface
2- 6
router.v
Discard
router.test_top.v router.vr.tmp router.if.vrh
simv
2- 7
2- 8
router.v must be the last entry in the ntb_template command.
2- 11
clock
var_a
din[3]
variable = interface.cb.signal;
No delay attribute (## num)
Variable is assigned the sampled value
Sampling of output signal is not allowed
Examples:
data[i] = router.cb.dout[7];
all_data = router.cb.dout;
@(posedge router.cb.frameo_n[7]);
$display(“router.cb.din = %b\n”, router.din); //error
if(router.cb.din[3] == 1’b0) //error
2- 14
2- 17
If the DUT module was already constructed with SystemVerilog interface, the connection would
simplify to:
router dut(top_io);
Configure
Generator Coverage
router.tb.sv
Transactor Self Check Transactor
router.test_top.sv
Driver Monitor
router.if.sv
DUT
router.v
2- 18
2- 19
Build Simulation
Environment
Generate Template Files
30 min
program automatic router_test;
initial begin
$vcdpluson; Write Test Code
$display(“Hello”);
end
initial begin
reset();
end Compile & Simulate
task reset(); ...
endprogram
DUT
2- 21
2- 22
Compile:
vcs -sverilog –debug top.sv test.sv dut.sv
Run:
simv +user_tb_runtime_options
-l logfile Create log file
-gui Run GUI
-ucli Run with new command line debugger
-i cmd.key Execute UCLI commands
2- 26
Active
threads
Source
code
tracing
Watch
variables
Local
variables
2- 28
DAY
1
1 The Device Under Test (DUT)
3- 2
Comments:
// …
/* … */ (Do not nest!) /* /* */ */
Number Format:
<size>’<base><number>
’b (binary) :[01xXzZ]
’d (decimal) :[0123456789]
’o (octal) :[01234567xXzZ]
’h (hexadecimal) :[0123456789abcdefABCDEFxXzZ]
Can be padded with ‘_’ for readability:
16’b_1100_1011_1010_0010
32’h_beef_cafe
3- 4
Examples:
bit flag; bit[15:0] sample, temp = 16’hdeed;
byte a = -55, b;
byte unsigned ref_data = ’hff;
3- 5
Explicit 2-state variables allow more compiler optimizations, giving better performance.
BUT – they will not propagate X or Z, so keep away from DUT
Examples:
shortint temp = 256;
int sample, ref_data = -9876;
longint a, b; longint unsigned testdata;
3- 6
Examples:
integer temp = ’1, ref_data = ’x;
reg[15:0] sample;
sample = router.cb.dout[da];
3- 7
3- 8
In SystemVerilog, the old reg type has been extended so it can be driven by single drivers (gates,
modules, continuous assignments) like a wire. It has a new name logic. It can not have multiple
drivers – use a wire.
Example:
real alpha, beta, coverage_result;
alpha = 100.3;
beta = alpha;
coverage_result = $get_coverage();
if (coverage_result == 100) ...;
3- 9
Example:
string name, s = “Now is the time”;
for (int i=0; i<4; i++) begin
name = $psprintf(“string%0d”, i);
$display(“%s, upper: %s”, name, name.toupper());
end
s.putc(s.len()-1, s.getc(0)); // change e->s
$display(s.substr(s.len()-4, s.len()-1)); 3- 10
The resulting print out on terminal is:
st = 0, n_st = IDLE
The reason st is printed as 0 is because enum variables default to 0 if not initialized or assigned an
enum value.
dimension numbers
3 1 2
same as:
Dynamic Arrays:
type array_name[] [=initial_value];
Array size allocated at runtime with constructor
Out-of-bounds read/write results in simulation error
Single dimension only
Examples:
reg[7:0] ID[], array1[] = new[16];
reg[7:0] data_array[]; Returns size of array
ID = new[100]; // allocate memory
data_array = new[ID.size()] (ID); // copy
data_array = new[$size(ID)] (ID); // copy
data_array = ID; // copy
ID = new[ID.size() * 2] (ID); // double the size
data_array.delete(); // de-allocate memory
3- 13
Queues:
type array_name[$] [=initial_value];
Array memory allocated and de-allocated at runtime with:
push_back(), push_front(), insert()
pop_back(), pop_front(), or delete()
3- 14
3- 17
3- 18
Compile and simulate the above code, you will see something like the following result:
data[0] = 172
data[1] = 29
data[2] = 191
data[3] = 201
3- 19
Example:
program test_program;
bit[7:0] SQ_array[$] = {2, 1, 8, 3, 5};
bit[7:0] SQ[$];
int idx[$];
SQ = SQ_array.find() with ( item > 3 );
// SQ[$] contains 8, 5
idx = SQ_array.find_index() with ( item > 3 );
// idx[$] contains 2, 4
endprogram
3- 20
Example:
program test_program;
int array[] = new[5];
int idx[$], Value[$];
foreach(array[i])
array[i] = 4 – i;
Value = array.find_first() with ( item > 3 );
// Value[0] = 4
idx = array.find_first_index() with ( item < 0 );
// idx.size() = 0;
endprogram
3- 22
Examples of other array methods are: (please check release note and LRM for support)
.find_last()
.find_last_index()
.unique()
.unique_index()
.sum()
.product()
.and()
.or()
.xor()
.min()
.max()
.reverse()
.sort()
.rsort()
.shuffle()
3- 24
File I/O (from Verilog 2001):
program test();
/* Assume file contains:
0123
4567
89
*/
initial begin
int i, file;
file = $fopen("stimulus.txt", "r");
while (! $feof(file)) begin
if ($fscanf(file, "%d", i) == 0) break;
$display("i = %0d", i);
end
$fclose(file);
end
endprogram
{} concatenation
Assignment:
= += -= *= /= %= <<= >>= &= |= ^= ~&= ~|= ~^=
3- 26
3- 27
In Verilog, the == and != operator will return x as the result if any operand contains x or z. The if
statement then treats x as a failure. Therefore, in the example above, if either sample or ref contains
x or z, the else condition will always execute.
Conditional:
if (x==7) a=7; else a=8;
a = (x == y) ? 7 : 8;
case statements
Loops:
repeat(…) begin … end
for(…) begin … end
3- 28
Subroutines in program
block defaults to static
can be made automatic function automatic int factorial(int n);
Subroutines in class static int id = 0;
defaults to automatic int my_id = id++; Pass by value
if (n < 2) factorial = 1;
Subroutine variables else factorial = n * factorial(n-1);
defaults to subroutine endfunction
scope and lifetime. Can be … function name returns value
made automatic or static Result = factorial(my_value);
3- 29
Since functions can not block, you will not be able to call a task within a function.
To make your subroutines as flexible as possible (usable in both function and task), you should
develop your subroutines are functions if you know for sure that time passage will not be required.
3- 30
program test();
initial begin
reg[15:0] B = 100, C = 0, D = 0, E = 0;
byte A[] = {1,3,5,8,13};
T3(A, B, C, D, E);
foreach(A[i])
$display(A[i]);
$display(B, C, D, E);
end
endprogram What will be displayed on screen?
3- 31
Argument direction type
a[] ref byte
b ref bit[15:0]
c ref bit[15:0]
u output bit[15:0]
v output bit[15:0]
3- 34
3- 36
Bytes[0][3] Bytes[0][1][6]
Bytes[0] 7 65 4 3 21 0 7 65 4 3 21 0 7 65 4 3 21 0 7 65 4 3 21 0
Bytes[1] 7 65 4 3 21 0 7 65 4 3 21 0 7 65 4 3 21 0 7 65 4 3 21 0
Bytes[2] 7 65 4 3 21 0 7 65 4 3 21 0 7 65 4 3 21 0 7 65 4 3 21 0
Bytes[2] = 32’hbeef_deed;
Bytes[2] 1 01 1 1 11 0 1 11 0 1 11 1 1 10 1 1 11 0 1 11 0 1 10 1
3- 37
3- 38
DAY
1
1 The Device Under Test (DUT)
4- 2
Configure
Generator Coverage
Driver Monitor
DUT
4- 3
modport
modport
Collection
async signals SVTB
DUT DUT signals
of signals clock block
program
SystemClock
clock
data
var_a
din[3]
expression evaluates
Statement executes here
Apply drive here
Next statement executes
router.cb.din[3] = 1’b1; //error
##1 router.cb.dout[3] <= 1’b1; //error
##2 router.din[3] <= 1’b1; //error
4- 6
##2 router.cb.din <= var_a; next_statement; is similar to:
#2 router.cb.din <= var_a; next_statement;
In that, time advances first, var_a is then evaluated, the assignment is scheduled for the non-blocking
region (+output delay) and next_statement is executed.
clock
var_b
var_a
variables
signal driven after delay
router.din[3]
1 3
cycle cycles
4- 7
variable = interface.cb.signal;
No delay attribute (## num)
Variable is assigned the sampled value
Sampling of output signal is not allowed
Examples:
data[i] = router.cb.dout[7];
all_data = router.cb.dout;
@(negedge router.frameo_n[7]); //error
$display(“din = %b\n”, router.cb.din); //error
if(router.cb.din[3] == 1’b0) begin … end //error
4- 8
4- 9
router.cb.frameo_n[7]
4- 10
The negedge will be detected at clock edge D (not C).
This is the edge that you need your monitor transactors to be at when observing the output of the
DUT. The monitoring routines at clock edge D acts as the capture flip-flop for the signals launched
by clock edge C.
clock
0 100 200 300 400 500
reset_n
frame_n
valid_n
4- 11
SystemVerilog’s behavior is exactly the same as Verilog.
Non-blocking assignments does not advance time for the next line.
##0 means current simulation time. ##1 means next valid clock edge.
In either case, synchronous signals can only be driven at a valid clock edge + output skew.
Generator,
Transactor & reset()
Device Drivers Compile & Simulate
Generator
Transactor
Check Result with GUI
Driver
DUT
4- 12
4- 13
DAY
2
5 Concurrency
6 Inter-Process Communications
Concurrency 5-1
© 2006
SVTB
Unit Objectives
5- 2
Concurrency 5-2
© 2006
SVTB
Day 1 Review
Phases of verification
Preliminary Broad-Spectrum Corner-case
Verification Verification Verification
Goal
% Coverage
Directed
Verification
Time
Build verification
environment
5- 3
Concurrency 5-3
© 2006
SVTB
Day 1 Review (Building Testbench Files)
router.v
Discard
router.test_top.v router.vr.tmp router.if.vrh
simv
5- 4
Concurrency 5-4
© 2006
SVTB
Day 1 Review (Testbench Architecture)
Checks Checks
Configure
completeness correctness
DUT interface
5- 5
Concurrency 5-5
© 2006
SVTB
Concurrency in Simulators
process 2 statement a;
Ready events
Future events
5- 6
Concurrency 5-6
© 2006
SVTB
Creating Concurrent Processes
int a, b, c;
fork
statement0;
begin
statement1;
statement2;
end
join_all | join_any | join_none
statement3;
Concurrency 5-7
© 2006
SVTB
How Many Child Processes?
fork
fork begin
begin C:
A: recv();
recv(); send();
end end
begin join
send();
end
join
fork
begin
D: begin
fork send();
recv(); recv();
B: send(); end
join check();
end
join
5- 8
Concurrency 5-8
© 2006
SVTB
Join Options
5- 9
Concurrency 5-9
© 2006
SVTB
Process Execution
5- 10
Concurrency 5-10
© 2006
SVTB
Process Execution Model
One executing process, all other processes reside on queues
READY - to be executed at current simulation time
WAIT - blocked from execution until wait condition is met
When the executing process goes into a wait state, it moves
to a WAIT queue, the next READY process then executes
Simulation time advances when all processes are in WAIT
Executing thread
At start of simulation: process blocked process
program READY WAIT
process blocked process
Concurrency 5-11
© 2006
SVTB
Subtleties in Concurrency (1/5)
a = 0;
fork
begin
while ( a != 5 )
if ( $time > MAX_TIME )
$finish;
end
begin
##5 bus.reg <= 1’b1;
a = 5;
end
join
5- 12
Concurrency 5-12
© 2006
SVTB
Subtleties in Concurrency (2/5)
Concurrency 5-13
© 2006
SVTB
Subtleties in Concurrency (3/5)
Child processes share the same parental variables
program fork_join1;
initial begin Can the child process assess a and b?
integer a=0, b=1;
fork What are the final values of a and b?
begin
integer d=3;
a = b + d;
end
begin
integer e=4;
b = a + e;
end
join
$display(“a = %0d”, a);
$display(“b = %0d”, b);
end
endprogram
5- 14
Concurrency 5-14
© 2006
SVTB
Subtleties in Concurrency (4/5)
5- 15
Concurrency 5-15
© 2006
SVTB
Subtleties in Concurrency (5/5)
Simulation output:
Driving port 16
Driving port 16 What happened to ports 0-15?
Driving port 16 Why did simulation stop at time 0?
Driving port 16
…
Simulation stopped at time 0
5- 16
Concurrency 5-16
© 2006
SVTB
Unroll the for-loop
program test;
initial begin
int i = 0; { send(i) }
fork READY
send(i); { send(i) }
join_none
i++; // i = 1; { send(i) }
fork
send(i);
join_none
i++; // i = 2;
{ send(i) }
fork
send(i);
join_none
Scheduled for execution
i++; // i = 3; at current simulation time
… (repeated 16 times total) But i = 16 before they execute
end
endprogram Simulation terminates when all procedural
code inside program block reaches end
5- 17
Concurrency 5-17
© 2006
SVTB
Solution (1/2): automatic Variable
automatic variables:
Copied from parent when the child process is queued
Concurrency 5-18
© 2006
SVTB
Solution (2/2): Wait Control
5- 19
Another mechanism you can use is wait(…) or @(…). Example:
Concurrency 5-19
© 2006
SVTB
Disable Forked Processes
Watch-dog timer:
disable fork terminates all child processes
program automatic test;
task recv();
fork: recv_wd_timer
begin
@(negedge router.cb.frameo_n[da]);
end
begin
repeat(1000) @(router.cb);
$display(“Timed out!”);
error_handler(); // user subroutine
end
join_any: recv_wd_timer
disable fork; // kill all child processes
// disable recv_wd_timer; // kill children in named block
get_payload();
endtask
endprogram
5- 20
The consequence of disable fork is to kill ALL child processes. This include all other fork-join
constructs within the executing process. This may not be desirable. One way to manage this is to
label the fork-join construct and disable just the named fork-join block. Example:
Concurrency 5-20
© 2006
SVTB
Helpful Debugging Features
5- 21
Concurrency 5-21
© 2006
SVTB
Unit Objectives Review
5- 22
Concurrency 5-22
© 2006
SVTB
Agenda
DAY
2
5 Concurrency
6 Inter-Process Communications
6- 2
6- 3
6- 4
6- 5
6- 6
->eventN;
event variables are handles
Assigning an event to another makes both event the
same event
Example:
event a, b, c;
a = b;
-> c;
-> a; // also triggers b
-> b; // also triggers a
a = c;
b = a;
-> a; // also triggers b and c
-> b; // also triggers a and c
-> c; // also triggers a and b
6- 7
Process Process
1 resource 2
6- 9
6- 10
class semaphore;
function new(int keyCount = 0);
task put(int keyCount = 1);
// the following is blocking:
task get(int keyCount = 1);
// the following is non-blocking: 1 for success 0 for failure
function int try_get(int keyCount = 1);
endclass
6- 11
T T T T
T T T T T T T T
6- 12
sem[0]
Before
T
T T
sem[0].get(2);
sem[0]
After
T
if (!sem[0].try_get(2)) // does not block
$display(“Failed”);
sem[0].get(2); // blocks until two keys are available
6- 13
sem[0]
Before
T
sem[0].put(2);
sem[0]
T After
T T
6- 14
6- 15
process process
1 data 2
6- 16
6- 17
#(type T = dynamic_singular_type) is not yet supported.
Bounded size is not yet supported.
try_put() is not yet supported.
unbounded
string
6- 18
Typed mailbox is not yet supported.
Bounded mailbox is not yet supported.
mbox
16’hcafe
“café”
6- 19
try_put() is not yet supported.
16’hcafe
mailbox mbox = new();
“café”
mbox.put(test_data);
mbox.put(“cafe”);
mbox.get(test_data);
$display(“test_data = %0h”, test_data); // test_data = cafe
status = mbox.try_get(test_data); // status = -1
mbox.get(test_data); // simulation error!
6- 20
16’hcafe
“café”
string s;
mailbox mbox = new();
mbox.put(test_data);
mbox.put(“café”);
$display(“# of message = %0d”, mbox.num()); // 2 messages
mbox.peek(test_data); // still 2 messages left
status = mbox.try_peek(test_data); // still 2 messages
mbox.get(test_data);
mbox.get(s);
status = mbox.try_peek(test_data); // status = 0;
mbox.peek(s); // blocks, if new message is not string, type error!
6- 21
Add Concurrent
Monitor & Self-check
Add Monitor & Self-Check
90 min
Self-check
send() Transactor
Validate self-check
Driver Monitor
DUT
6- 22
6- 23
DAY
2
5 Concurrency
6 Inter-Process Communications
7- 2
Project A Project B
Configure Configure
Re-usable
Transactor Self Check Transactor Transactor Self Check Transactor
DUT A DUT B
7- 3
7- 4
program Main;
class DriveXactor; Handle
driver1
DriveXactor driver1; Handle
DriveXactor driver2; driver2
driver2 = new();
… Memory
endprogram
Handle
class Packet; obj_hdl
Packet obj_hdl = new();
Memory
7- 5
Classes can be declared inside the program block or outside the program block ($root). When
declared inside the program block, the class definition is only visible within the program block in
which the class is declared. When declared outside the program block, the class definition is
accessible by all program blocks.
With VCS2005.06-SP1, when compiling SystemVerilog code in which classes are declared at the
$root scope, the “–ntb_opts svp” compile switch must be set.
program Main;
class DriveXactor;
bit[3:0] sa, da;
byte payload[];
task send();
...
endclass
DriveXactor driver;
initial begin
driver = new();
driver.sa = 3; // access property
driver.da = 7; // access property
driver.send(); // access method
end
endprogram
7- 6
7- 7
7- 9
7- 11
See next slide for answer.
7- 12
Every time a constructor task new() is called, new memory is allocated. The handle is removed
from the old memory and re-assigned to the new memory. If there are no events scheduled in the old
memory, the old object memory is reclaimed by the garbage collector.
compare()
Returns match, mismatch and other status base on results
of comparing object variables to variables of another object
Simplifies self-check
copy()
Copy selected variables or nested objects
Useful when exact duplication is not desirable
7- 15
7- 16
16x16
ROUTER
reset_n
SystemClock
7- 18
7- 19
DAY
2
5 Concurrency
6 Inter-Process Communications
8- 2
B[31:0]
+ 32
32
A day?
A week?
A year?
8- 3
It will take over 500 years to verify this simple adder.
8- 4
Goal
% Coverage
Difficult to reach
Corner-case
Verification
Directed*
Time
Build verification
environment
8- 5
8- 6
Because memory for payload array is not allocated, the size of payload array will always be 0.
If sa and da were to be changed to int type, then the full range of integer values will be possible.
This means that there is a 50% chance for sa and da values to be negative numbers.
8- 10
8- 13
8- 15
Let’s assume that the first randomization of the pkt object above resulted in picking payload.size() to
be 5. Since, in the beginning there are no memory already allocated for pkt.payload, therefore
randomize() will allocate payload array to payload = new[5] and populate all five indices with
random value.
For the second randomization, let’s assume that payload.size() is picked to be 7. Since the existing
memory size is insufficient, randomize() will allocate payload array to payload = new[7] (payload)
and populate all seven indices with random value.
For the third randomization, let’s assume that payload.size() is picked to be 3. Since there is
sufficient memory, randomize() will simply randomize the contents of indices 0 through 2. If you
were to display the size of the payload array at this point, the payload.size() will be 7 NOT 3. For
many applications, this will lead to errors.
To prevent this behavior from becoming a problem, you should de-allocate the payload array before
randomization. The proper place to do this is in the pre_randomize() method.
8- 19
Sometime, the constraint defined within the object being randomized is insufficient to get the desired
result. The with { … } construct allows one to solve this problem without the need to go back and
modify the original definition of the class. The constraints specified with the with { … } construct is
added to the constraints already defined in the original class definition.
For this construct to work effectively, the constraints defined within the original class definition
should be as broad as possible within the limits of the DUT spec.
CA a = new();
a.randomize(); // random variables: x, y state variables: v, w
a.randomize( x ); // random variables: x state variables: y, v, w
a.randomize( v, w ); // random variables: v, w state variables: x, y
a.randomize( w, x ); // random variables: w, x state variables: y, v
8- 21
8- 22
If a constraint block is declared as static, then calls to constraint_mode() shall affect all instances of
the specified constraint in all objects. Thus, if a static constraint is set to OFF, it is off for all
instances of that particular class.
8- 23
Encapsulate data
in Packet Class
90 min
configure Encapsulate data
in Packet Class
gen() Packet object
Driver Monitor
DUT
8- 24
8- 25
DAY
3 Object Oriented Programming (OOP)
9 – Inheritance
10 Functional Coverage
CS Customer Support
9- 2
Object-oriented programming
packet
New classes derived from original (base) class
Inherits all contents of base class
class MyPacket extends Packet; my_packet
DA task display();
SA UML
...
DATA endtask
Packet CRC
function bit[31:0] compute_crc();
...
endfunction
Can override
MyPacket methods
in base class
is_good function bit[31:0] compute_crc()
crc = super.compute_crc();
if (!is_good) crc = $random;
endfunction
Can call overridden
behavior
9- 3
MyPacket
Compatible Derived class
OK pkt = my_pkt;
task transmit(Packet pkt);
...
Error my_pkt = pkt;
endtask
OK $cast(my_pkt, pkt);
9- 4
DA
function bit[31:0] compute_crc();
SA ...
DATA endfunction
CRC
Packet p1 = new();
MyPacket p2 = new();
function bit[31:0] crc(Packet pkt);
p1.crc = p1.compute_crc();
crc = pkt.compute_crc();
P2.crc = p2.compute_crc();
endfunction
p1.crc = crc(p1);
p2.crc = crc(p2);
9- 5
If compute_crc() is virtual
p
my_packet extends packet
DA
virtual
SA function bit[31:0] compute_crc();
DATA ...
CRC endfunction
is_good virtual
function bit[31:0] compute_crc();
...
endfunction
Packet p1 = new();
MyPacket p2 = new();
function bit[31:0] crc(Packet pkt);
p1.crc = p1.compute_crc();
crc = pkt.compute_crc();
P2.crc = p2.compute_crc();
endfunction
p1.crc = crc(p1);
p2.crc = crc(p2);
9- 6
DA task display();
SA ...
DATA endtask
Packet CRC
function bit[31:0] compute_crc();
...
MyPacket endfunction
9- 7
DA task display();
SA ...
DATA endtask
Packet CRC
function bit[31:0] compute_crc();
...
MyPacket endfunction
9- 8
9- 9
class A;
protected int a;
function int get_a(); begin get_a = a; endfunction
function new(int b) begin a = b; endfunction
endclass
class B extends A; Mismatching argument list
int b = 1000;
task print_a(); begin $display("a is %d", get_a()); endtask
function new(); begin super.new(); endfunction
endclass
class C extends B;
int a;
function new(int c); begin super.new(); a = c; endfunction
endclass ...
9- 10
9- 11
9- 12
DAY
3 Object Oriented Programming (OOP)
9 – Inheritance
10 Functional Coverage
CS Customer Support
10- 2
Preliminary
Verification Difficult to reach
Corner-case
Verification
Time
Build verification
environment
10- 3
The process of reaching the verification goal starts with the definition of the verification goal.
What does it mean to be done with testing? Typically, the answer lie in the functional coverage
spec within a verification plan. The goal is then to reach 100% coverage of the defined functional
coverage spec in the verification plan.
Once the goal has been defined, the first step in constructing the testbench is to build the
verification environment.
To verify the the environment is set up correctly, preliminary verification tests are usually
executed to wring out the preliminary RTL and testbench errors.
When the testbench environment is deemed to be stable, broad-spectrum verification based on
random stimulus generation is utilized to quickly detect and correct the majority of the bugs in
both RTL code and testbench code.
Based on functional coverage analysis, the random-based tests are then constrained to focus on
corner-cases not yet reached via broad-spectrum testing.
Finally, for the very difficult to reach corner cases, customized directed tests are used to bring the
coverage up to 100%.
Verification is complete when you reach 100% coverage as defined in the verification plan.
Generator Coverage
Driver Monitor
DUT
10- 4
0 0 0 0 0 1 O u t[ 0 ]
0 1 0 0 1 0 In [0 ] 2 to 4 O u t[ 1 ]
In [1 ] D ecod er O u t[ 2 ]
1 0 0 1 0 0
O u t[ 3 ]
1 1 1 0 0 0
10- 5
S1
1
0
1
S4 S2 1
1 0
S3
Goal: Check all input ports have driven all output ports
0 0
0 1
0 2
… …
15 14
15 15
10- 7
Cross correlation
10- 8
10- 9
The covergroup can also be embedded inside a class. The advantage of creating the covergroup
inside the class definition is that the covergroup automatically has access to all properties of the
class without having an I/O argument. The down side is that, this covergroup can not be re-used.
class Scoreboard;
Packet pkt2send, pkt2cmp;
bit[3:0] sa, da;
covergroup router_cov;
coverpoint sa;
coverpoint da;
cross sa, da;
option.goal = 100;
endgroup
function new(...);
router_cov = new(); // still need to be constructed
endfunction
task check();
...
if (pkt2send.compare(pkt2cmp, message)) begin
sa = pkt2send.sa;
da = pkt2send.da;
router_cov.sample();
coverage_result = $get_coverage();
if ((coverage_result == 100) || (...)
->DONE;
end
endtask
endclass
10- 11
@(router.cb);
(50% covered)
$display(“%0d covered”, $get_coverage());
x = 9; Var bin #Hit Var bin #Hit
y = 9; auto[0:7] 1 auto[0:7] 2
@(router.cb); x x
auto[8:f] 1 auto[8:f] 1
x = 3; (75% covered)
y auto[8:f] 2 auto[0:7] 1
y = 5; y
@(router.cb); auto[8:f] 2
(100% covered)
$display(“%0d covered”, $get_coverage());
10- 12
10- 13
10- 14
10- 15
10- 16
10- 17
coverpoint x {
option.auto_bin_max = 4; // just for x
bins lower = { [1:8] };
...
endgroup
10- 18
at_least (1):
Minimum number of times for a bin to be hit to be
considered covered
auto_bin_max (64):
Maximum number of bins that can be created
automatically
Each bin contains equal number of values
goal (90):
Percentage as an integer for a coverage group,
cross, or sample to be considered covered
weight (1):
Multiplier for coverage bins
10- 19
cross_auto_bin_max (231-1):
Maximum number of bins that can be created
automatically
Beyond this number, hits are dropped
per_instance (0):
Specifies whether to collect coverage statistics
cumulatively or per instance for a coverage group
10- 20
10- 21
10- 22
configure
30 min Functional
build()
Coverage
Implement
reset()
functional coverage
gen() coverage
DUT
Stop simulation
if coverage goal is met
10- 23
10- 24
DAY
3 Object Oriented Programming (OOP)
9 – Inheritance
10 Functional Coverage
CS Customer Support
11- 2
Goal
% Coverage
Difficult to reach
Corner-case
Verification
Time
Build verification
environment
11- 3
The process of reaching the verification goal starts with the definition of the verification goal.
What does it mean to be done with testing? Typically, the answer lie in the functional coverage spec
within a verification plan. The goal is then to reach 100% coverage of the defined functional
coverage spec in the verification plan.
Once the goal has been defined, the first step in constructing the testbench is to build the verification
environment.
To verify the the environment is set up correctly, preliminary verification tests are usually executed
to wring out the preliminary RTL and testbench errors.
When the testbench environment is deemed to be stable, broad-spectrum verification based on
random stimulus generation is utilized to quickly detect and correct the majority of the bugs in both
RTL code and testbench code.
Based on functional coverage analysis, the random-based tests are then constrained to focus on
corner-cases not yet reached via broad-spectrum testing.
Finally, for the very difficult to reach corner cases, customized directed tests are used to bring the
coverage up to 100%.
Verification is complete when you reach 100% coverage as defined in the verification plan.
Drive DUT
Driver Observes data Monitor
from DUT
11- 4
Create individual
Test Cases Testcase
Creates Configure
Test Scenarios
Generator Coverage
Transactors
Transactor Self Check Transactor
Device Drivers
Driver Monitor
and Monitors
Signals
(interface) DUT
11- 5
% Coverage
Generator Coverage Configure
Time
Driver Monitor
DUT
11- 6
Philosophy
Base Classes
One environment many tests
Coding Guidelines
Coverage-driven
Modeling Approach Coding Standards
Transactions Data & Transactions
Variant Data Transactors
Transactor Control Verification Environments
Transactor Interfacing
Simulation Control Building Blocks
Transaction Interface
Class Library
Message Service
Event Notification
11- 7
Approaches Directed
Reuse Add Testcase Functional
constraints Coverage
Across tests
Across blocks Minimal Code Identify
Modifications holes
Across systems
Across projects
One verification environment, many tests
Minimize test-specific code
11- 9
wait_for_end();
Controls stop();
Transactor Self Check Transactor
Configuration cleanup();
Driver Monitor
Start of simulation report();
End of simulation
DUT
Pass/Fail report
11- 10
DUT
11- 13
The first step in constructing a SystemVerilog RVM testbench is to build the environment class.
This class must inherit from the vmm_env base class.
Within the environment class, 9 methods must be overriden: gen_cfg(), build(), reset_dut(),
cfg_dut(), start(), wait_for_end(), stop(), cleanup(), report().
Within the overriden methods, the super class method must be called first.
Once this skeleton structure is built, it can be instantiated and tested immediately within a
SystemVerilog program block.
11- 14
If the program block consists only of:
program automatic router_test;
`include “vmm.sv”
`include “dut_env.sv”
initial begin
dut_env env = new();
env.run();
end
endprogram
Simulation will run and finish at time 0 with the following message:
Simulation PASSED on /./ (/./) at 0 (0 warnings, 0 demoted errors & 0 demoted warnings)
$finish at simulation time 0
If you want to trace the method executions for debugging purposes, then through the default log
instance in the vmm_env class, you can turn on tracing and see the result as shown in slide. (Note:
this should be done after the build() phase of the RVM environment is executed.
env.log.set_verbosity(vmm_log::TRACE_SEV);
Simulation PASSED on /./ (/./) at 0 (0 warnings, 0 demoted errors & 0 demoted warnings)
$finish at simulation time 0
11- 16
If the program block consists only of:
program automatic router_test;
`include “vmm.sv”
`include “dut_cfg.sv”
`include “dut_env.sv”
initial begin
dut_env env = new();
env.run();
end
endprogram
Simulation will run and finish at time 0 with the following message:
Simulation PASSED on /./ (/./) at 0 (0 warnings, 0 demoted errors & 0 demoted warnings)
$finish at simulation time 0
If you want to see what the configuration object contains, you can use the display() method of the
configuration object: (Note: this should be done after the gen_cfg() phase of the RVM environment
is executed.
env.cfg.display();
RVM-SV (VMM) Overview 11-16
© 2006
SVTB
Set Specific RVM Testcase Configuration
RVM philosophy: one environment, many tests
Limit modification to the program block
program automatic router_test;
`include “vmm.sv”
`include “dut_cfg.sv”
`include “dut_env.sv”
initial begin
dut_env env = new();
env.cfg.run_for_n_packets.rand_mode(0);
env.cfg.num_of_drivers.rand_mode(0);
env.cfg.num_of_receivers.rand_mode(0);
env.cfg.run_for_n_packets = 16;
env.cfg.num_of_drivers = 16;
env.cfg.num_of_receivers = 16;
env.gen_cfg();
env.cfg.display();
env.run(); [Configuration] run_for_n_packets = 16, num_of_drivers = 16, num_of_receivers = 16
end [Configuration] valid input ports: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
endprogram [Configuration] valid output ports: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
Simulation PASSED on /./ (/./) at 0 (0 warnings, 0 demoted errors & 0 demoted warnings)
$finish at simulation time 0
11- 17
Although the properties within the configuration object are all set to be random variables, you can
still set these properties to ones of your choosing in the program block.
One way is as shown in the slide: disable randomization then set the properties to your chosen value.
The second way it can be done is to extend from the existing configuration class, modify the
constraint, then replace the configuration object in the environment object with the new
configuration object as shown below:
program automatic router_test;
`include "vmm.sv"
`include “dut_cfg.sv"
`include “dut_env.sv"
class testConfig extends dut_cfg;
constraint test {
run_for_n_packets == 16;
num_of_drivers == 16;
num_of_receivers == 16;
}
endclass
initial begin
dut_env env = new();
testConfig cfg = new();
env.cfg = cfg;
env.gen_cfg();
env.cfg.display();
env.run();
end
endprogram
11- 19
If the program block consists only of:
program automatic router_test;
`include “vmm.sv”
`include “dut_cfg.sv”
`include “Packet.sv”
`include “dut_env.sv”
initial begin
dut_env env = new();
env.run();
end
endprogram
Simulation will run and finish at time 0 with the following message:
Simulation PASSED on /./ (/./) at 0 (0 warnings, 0 demoted errors & 0 demoted warnings)
$finish at simulation time 0
If you want to see what the generator created, you can modify the post_randomize() method in
randomized_obj with a call to the display() method. To do this, first, extend the existing Packet class
with a new testPacket class defintion and add the new post_randomize() method. Then, instantiate
and replace the randomize_obj in the generator with the newly created one. (Note: this should be
done after the build() phase of the RVM environment is executed)
11- 20
11- 21
endprogram
11- 24
11- 26
11- 27
11- 28
Approaches Directed
Reuse Add Testcase Functional
constraints Coverage
Across tests
Across blocks Minimal Code Identify
Modifications holes
Across systems
Across projects
One verification environment, many tests
Minimize test-specific code
11- 29
11- 30
Classes
RVM-
RVM-OV RVM-
RVM-SV
rvm_log vmm_log
rvm_env vmm_env
rvm_data vmm_data
rvm_channel_class vmm_channel
rvm_xactor vmm_xactor
rvm_notify vmm_notify
rvm_broadcast vmm_broadcast
rvm_scheduler vmm_scheduler
11- 32
Macros RVM-
RVM-OV RVM-
RVM-SV
rvm_fatal `vmm_fatal
rvm_error `vmm_error
rvm_warning `vmm_warning
rvm_note `vmm_note
rvm_trace `vmm_trace
rvm_debug `vmm_debug
rvm_verbose `vmm_verbose
rvm_channel `vmm_channel
rvm_atomic_gen `vmm_atomic_gen
rvm_scenario_gen `vmm_scenario_gen
rvm_OO_callback `vmm_callback
11- 33
RVM-
RVM-OV RVM-
RVM-SV task
rvm_env::gen_cfg() vmm_env::gen_cfg() No "_t"
rvm_env::build() vmm_env::build()
rvm_env::reset_dut_t() vmm_env::reset_dut()
rvm_env::cfg_dut_t() vmm_env::cfg_dut() "_t" -> task
rvm_env::start_t() vmm_env::start()
rvm_env::wait_for_end_t() vmm_env::wait_for_end()
rvm_env::stop_t() vmm_env::stop()
rvm_env::cleanup_t() vmm_env::cleanup()
rvm_env::report() vmm_env::report()
11- 34
11- 35
Becomes (RVM-SV)
log.set_verbosity(vmm_log::DEBUG_SEV);
Class-
Class-level enum
in SV
11- 36
Does not
exist
Waiting for next transaction (RVM-OV)
vmm_xactor::next_transaction(chan)
rvm_xactor::next_transaction_t(chan)
Deprecated
Use (RVM-SV)
vmm_xactor::wait_if_stopped_or_empty(chan);
chan.peek(tr);
rvm_xactor::wait_if_stopped_or_empty_t(chan);
tr = chan.peek_t();
Notifications automatically handled
(XACTOR_IDLE, XACTOR_BUSY)
11- 37
11- 38
Physical interfaces
In OV
Define interface for each clocking domain, connect using
hdl_node
Define virtual port
11- 39
Physical interfaces
In SV
Define interface for each signal bundle
– Signals defined as wire
– One clocking block per clocking domain
– One modport per agent
Instantiate interface in top-level module, connect using
continuous assign
Class written using virtual modport
11- 40
11- 41
2. Empower Yourself:
solvnet.synopsys.com
Online technical information and
access to support resources
Documentation & Media
CS- 2
CS- 3
CS- 4
Fastest access
Contact us:
Web: Enter A Call from solvnet.synopsys.com
See http://www.synopsys.com/support
for local support resources
CS- 5
CS- 6
CS- 7