SystemVerilog Testbench
SystemVerilog Testbench
SystemVerilog Testbench
Look for
coding tips!
Checks Testbench
Creates correctness
stimulus Verification
Environment Identifies
Executes Test transactions
transactions
Transactor Scoreboard Checker Observes
Supplies data data
to the DUT from DUT
Driver Assertions Monitor
DUT
Testbench Design
Start with a fully randomizable testbench
Run many randomized simulation runs
Analyze cumulative coverage and coverage holes
Then with minimal code changes:
Add constrained stimulus to fill coverage holes
Finally:
Make few directed tests to hit the remaining holes
Coverage-Driven Productivity
With
Methodology gain
VIP
Goal Directed
% Coverage
Methodology
Self-checking
random environment
development time
Time
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
Source
code
tracing
Active
threads
Local
variables
Examples
$VCS_HOME/doc/examples
Email Support:
[email protected]
SystemVerilog LRM
www.Accellera.org or www.eda.org/sv
reset
request[1:0]
grant[1:0]
clock
arb.sv
clock
mem cpu
top
module mem ( module cpu (
input bit req, input bit clk,
bit clk, bit gnt,
bit start, bit rdy,
wire [1:0] mode, inout wire [7:0] data,
wire [7:0] addr, output bit req,
inout wire [7:0] data, bit start,
output bit gnt, wire [1:0] mode,
bit rdy); wire [7:0] addr);
… …
module top;
logic req, gnt, start, rdy;
bit clk;
always #10 clk = !clk;
logic [1:0] mode;
logic [7:0] addr;
wire [7:0] data;
mem m1(req, clk, start, mode, addr, data, gnt, rdy);
cpu c1(clk, gnt, rdy, data, req, start, mode, addr);
endmodule
SystemVerilog Testbench with VCS 05/07/2007
Testbench Environment -- Interfaces 22
Named Bundle of Signals
The RTL code is connected with bundled signals
simple_bus
clk
mem cpu
top
clock
data
clock
Design
Testbench
Sample inputs Drive outputs
before clock at clock
SystemVerilog Testbench with VCS 05/07/2007
Testbench Environment – Top Block 33
Step 3
Create top module
Scoping Rules
SystemVerilog defines a global scope, $root,
outside any module or program
Define global items such as shared enums
Use parameters for global constants, not macros
`timescale 1ns/1ns
typedef enum {IDLE, RUN, WAIT} fsm_state_t; root.sv
parameter TIMEOUT = 1_000_000;
module state_machine(…);
fsm_state_t state, next_state; dut.sv
endmodule
program test;
fsm_state_t state; test.sv
initial #TIMEOUT $finish;
endprogram
SystemVerilog Testbench with VCS 05/07/2007
Testbench Environment -- Communication 35
DUT visibility
The program block can see all signals & routines in
the design
A module can not see anything in program block
Use absolute hierarchical path to access DUT
Start with $root, then top-level instance name, DUT, etc.
Use care when calling DUT routines from program
Good practice is to use a function to get info
Don’t try to trigger DUT code
SV accesses ports & XMR signals immediately
(asynchronously)
in case of error…
“test.sv", 7: top.t1.a1: started at 55ns failed at 55ns
Offending '(arbif.cb.grant == 1)‘
arbif.cb.request <= 1;
repeat (2) @arbif.cb;
a1: assert (arbif.cb.grant==1)
success++;
else
$error(“No grant received”); Custom
end message
Run with
debugger
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.
j = q.pop_back(); // {7,0,2,3,4,5} j = 6
q.push_back(8); // {7,0,2,3,4,5,8} Insert at back
j = q.pop_front(); // {0,2,3,4,5,8} j = 7
$display(q.size); // “6”
foreach (q[i]) $display(q[i]);
SystemVerilog Testbench with VCS 05/07/2007
Checking Results with Queues 47
Driver Monitor
DUT
SystemVerilog Testbench with VCS 05/07/2007
SV Language Basics 48
Array Methods
Search through arrays (fixed, dynamic, queue, assoc.)
Many more methods will be implemented, such as sort…
Returns a queue or scalar
a.sum of single bit values returns 0/1
Unless you compare to wider value: a.sum == 32’h3
Also available: product, and, or, xor
int q[$] = {1,3,5,7}, tq[$]; IEEE changed array
int d[] = {9,1,8,3,4}; const from {0,1} to ’{0,1}
int f[6] = {1,6,2,6,8,6}; (VCS issues Warning for
old usage)
$display(q.sum, q.product); // 16 105
LRM requires
tq = q.min(); // {1}
a queue
tq = q.max(); // {7}
tq = f.unique; // {1,6,2,8}
tq = d.find with (item > 3); // {9,8,4}
tq = d.find_index with (item > 3); // {0,2,4}
SystemVerilog Testbench with VCS 05/07/2007
SV Language Basics 50
string s = “SystemVerilog”;
$display(s.getc(0),, s.toupper());
s = {s, “3.1b”}; // string concat
s.putc(s.len()-1, “a”); // change b-> a
$display(s);
$display(s.substr(2, 5)); // 4 characters
a, b: input logic
u, v: output bit [15:0]
SystemVerilog Testbench with VCS 05/07/2007
Lab 1 54
Verify an arbiter
Objective
Verify the arbiter’s reset
Verify arbiter handles simple requests and grants
Verify proper handling of request sequences
Key Topics
Port list, clocking block, program block, assert, drive samples
and check responses.
Time Allotted
45 minutes
HDL OOP
Verilog SystemVerilog
Block definition module class
A complete Object
house An object is an instance of a class
Address of Handle
a house Type-safe pointer to an object – can not be corrupted
Light Properties
switches Variables contained in the instance of the class
Methods
Turn on/off
switches Tasks/functions (algorithms) that operate on the properties in
this instance of the class
SystemVerilog Testbench with VCS 05/07/2007
OOP Basics 61
Class Example Variables & methods are
class Transaction; public by default
// properties (variables)
logic [31:0] src, dst, data[1024], crc;
logic [7:0] kind;
// methods
function void display;
$display(“Tr: %h, %h”, src, dst);
endfunction
Drives
transactions Monitor
Driver
into the DUT
Puts data
DUT
into
transactions
SystemVerilog Testbench with VCS 05/07/2007
OOP Basics 65
Accessing Class Members
Reference properties by pre-pending the object handle
class Transaction;
bit [31:0] src, dst, data[1024];
bit [7:0] kind;
function void display;
$display(“Tr: %h, %h”, src, dst);
endfunction
endclass
Transaction tr;
initial begin
tr = new();
tr.src = 5;
tr.dst = 7;
tr.display();
end
initial initial
tr = new(); tr = new(5); // dst uses default
endprogram endprogram
SystemVerilog Testbench with VCS 05/07/2007
Static attribute 67
class Thing;
int data;
endclass
… t1
Thing t1, t2; // Two handles
initial begin
t1 = new(); // Allocate first thing data=1
t1.data = 1;
t2 = new(); // Allocate second
t2.data = 2; t2
t2 = t1; // Second Thing is lost
t2.data = 5; // Modifies first thing
$display(t1.data); // Displays “5”
end
class Thing;
int data;
endclass
… t1
Thing t1, t2; // Two handles
initial begin
t1 = new(); // Allocate first thing data=1
t1.data = 1;
t2 = new(); // Allocate second
t2.data = 2; t2
t2 = t1; // Second Thing is lost
t2.data = 5; // Modifies first thing
$display(t1.data); // Displays “5” data=2
end
class Thing;
int data;
endclass
… t1
Thing t1, t2; // Two handles
initial begin
t1 = new(); // Allocate first thing data=1
t1.data = 1;
t2 = new(); // Allocate second
t2.data = 2; t2
t2 = t1; // Second Thing is lost
t2.data = 5; // Modifies first thing
$display(t1.data); // Displays “5” data=2
end
class Thing;
int data;
endclass
… t1
Thing t1, t2; // Two handles
initial begin
t1 = new(); // Allocate first thing data=5
t1.data = 1;
t2 = new(); // Allocate second
t2.data = 2; t2
t2 = t1; // Second Thing is lost
t2.data = 5; // Modifies first thing
$display(t1.data); // Displays “5”
end
id=5 id=5
body stuff body stuff
t2 t2
id=5
body
SystemVerilog does not currently support deep
object copy – look for it in a future IEEE version
To do a deep copy of all objects, make a copy() method
for all objects nested inside the class.
SystemVerilog Testbench with VCS 05/07/2007
Inheritance 73
BadTr bt;
bt = new; BadTr =
bt.src = 42; Transaction + bad_crc
bt.bad_crc = 1;
Cell.display()
Print ATM cell data if I’m at ATM cell
Print Ethernet MCA data if I’m an Ethernet packet
Print Sonet frame data if I’m a Sonet frame
Print USB packet data if I’m a USB packet
class Transaction;
rand bit [31:0] src, dst, data[]; // Dynamic array
randc bit [2:0] kind; // Cycle through all kinds
constraint c_len
{ data.size inside {[1:1000]}; } // Limit array size
endclass
Transaction tr;
initial begin
tr = new();
assert(tr.randomize());
send(tr);
end
endprogram
class C;
rand bit [5:0] a[];
Array size constraint cc {
a.size inside {[1:5]}; // Output
array[0] > 0; a[0] = 1;
Single element a[1] = 2;
foreach (a[i])
if (i > 0) a[2] = 33;
Multiple elements
a[i] > a[i-1]); a[3] = 39;
} a[4] = 40;
function void pre_randomize;
a.delete; // Needed in 2005.06
endfunction
endclass
class Nesting;
Make instances rand rand SubClass data;
endclass
Or they won’t be randomized
Don’t call randomize() in new() constructor
Test may want to change constraints first
Use rand_mode to make a variable random / non-random
env.first.rand_mode(0);
Just replace result of randomization for a directed test
SystemVerilog Testbench with VCS 05/07/2007
Randomization 95
More Tricks and Techniques
Need to modify a constraint in a test?
Use a variable in the constraint
rand int size;
int max_size = 100;
constraint c {
size inside {[1:max_size]}; }
Port0 port0
Data Self-
port1 port1
Generation DUT Checking
--- ---
Create stream of
port7 port7 Check received
transactions
transactions
Functional
Coverage
join join_any
join_none
// Timeout example
fork : check_block
wait (arbif.cb.grant == 1); // May never complete
#1000 $display(“@%0d: Error, grant never received”, $time);
join_any
disable check_block;
Features
FIFO with no size limit
get/put are atomic operations, no possible race conditions
Can suspend a process
Default mailbox has no data type
Queuing
of multiple threads is fair
mailbox mbx; // Declare a mailbox
mbx = new(); // allocate mailbox
mbx.put(p); // Put p object into mailbox
mbx.get(p); // p will get object removed from FIFO
success = mbx.try_get(p); // Non-blocking version
mbx.peek(p); // Look but don’t remove, can block
success = mbx.try_peek(p); // Non-blocking version
count = mbx.num(); // Number of elements in mailbox
SystemVerilog Testbench with VCS 05/07/2007
Communication Between Threads 104
Mailbox Example
program mailbox_example(…);
mailbox mbx = new();
Generator g = new(); Get data from mailbox
Driver d = new();
initial begin class Driver;
fork Allocate mailbox Transaction t;
g.main();
d.main(); task main;
join repeat (10) begin
end mbx.get(t);
endprogram @(posedge busif.cb.ack);
busif.cb.addr <= t.addr;
class Generator; busif.cb.kind <= t.kind;
Transaction t; …
task main; end
repeat (10) begin endtask
t = new();
assert(t.randomize());
mbx.put(t);
end
endtask
endclass
Put data into mailbox
SystemVerilog Testbench with VCS 05/07/2007
Communication Between Threads 105
Semaphore
Features
Variable number of keys can be put and removed
Controlled access to a shared object, such as sharing a bus from models
Thinkof two people wanting to drive the same car – the key is a
semaphore
Be careful – you can put back more keys than you took out!
Syntax
semaphore sem;
sem = new(optional_initial_keycount = 0);
sem.get(optional_num_keys = 1);
sem.put(optional_num_keys = 1);
Semaphore Example
program automatic test;
semaphore sem;
initial begin Allocate a semaphore, 1 key available
sem = new(1);
…
fork
task sequencer();
sequencer();
repeat($random()%10) @bus.cb;
sequencer();
sendTrans();
join
endtask
end
…
task sendTrans();
sem.get(1);
@bus.cb;
bus.cb.addr <= t.addr;
Wait for bus to be available bus.cb.kind <= t.kind;
bus.cb.data <= t.data;
When done, replace key sem.put(1);
endtask
endprogram
SystemVerilog Testbench with VCS 05/07/2007
Communication Between Threads 107
Events
Synchronize concurrent threads
Features
Synchronize parallel threads
Sync blocks process execution until event is triggered
Events connect triggers and syncs
Can be passed into tasks
event ev; // Declare event
-> ev; // Trigger an event
@ev; // Block process, wait for future event
wait (ev.triggered); // Block process, wait for event,
// including this timeslot
// Reduces race conditions
driver = new(ev); // Pass event into task
Objective
Write a structured testbench to learn more about classes,
randomization, threads and mailboxes
Verify that a basic transaction can be created, randomized, and
sent through the design
Time Allotted
1 hour
apb_trans
apb_gen
apb_mbox
apb_master DUT
enable_1
soc_1
data_1[7:0]
RX_1
4x4
enable_3
ATM
soc_3
data_3[7:0]
RX_3 Switch
Interface
module top; instances
Interface logic clk = 0;
name
Rx Rx0(clk), Rx1(clk), Rx2(clk), Rx3(clk);
Tx Tx0(clk), Tx1(clk), Tx2(clk), Tx3(clk);
task sendCell();
Rx.Rcb.soc <= 0; // Drive signal w/clocking block
...
endtask
endclass
Time Allotted
1 hour
mon2scb
apb_trans scoreboard
apb_gen mas2scb
apb_monitor
apb_mbox
apb_master DUT
$set_coverage_db_name ( name );
Sets the filename of the coverage database into which
coverage information is saved at the end of a simulation run.
$load_coverage_db ( name );
Load from the given filename the cumulative coverage
information for all coverage group types.
constraint addr_c {
Constraint addr inside {[0:8’hBF]};
Block }
constarint data_c {
data.size <= 1024;
}
Procedural
Code task display();
$display(“ %s, %h”, pkt.trans_type.name(), a
endtask
Coverage
covergroup pktCov;
Group coverpoint addr,data,trans_type;
endgroup
endclass
SystemVerilog Testbench with VCS 05/07/2007
Coverage Driven Verification 137
Directed
Add Testcase Functional
constraints Coverage
class packet;
rand bit [31:0]addr;
rand bit [7:0] data[];
rand transtype_t trans_type;
rand bit[7:0] pktSize;
constraint packetSize_c {
pktSize inside {[0:1024]};
data.size() == pktSize;
}
endclass
SystemVerilog Testbench with VCS 05/07/2007
Constrain the Randomness (Design Spec) 140
Design Spec:
• The valid address range is between 0 and 8’hBF.
• Address 8’hBB is not writable
Implementation: See below.
class packet;
rand bit [31:0]addr;
rand bit [7:0] data[];
... Implication
rand transtype_t trans_type; Constraints
constraint addr_c {
(trans_type == WRITE) -> addr != 8'hBB;
addr inside {[0:8’hBF]};
}
endclass
Test Plan:
Test device with WRITE type , data size 20 bytes at address
8’h55.
Implementation:
Override constraint custom_c. Same testbench as before.
constraint packet::custom_c {
pktSize == 20;
trans_type == WRITE;
addr == 8’h55;
}
constraint packet::custom_c {
addr dist {[8’h80:8’hBF] := 90, [0:8’h7F] := 10};
trans_type == WRITE;
}
program automatic test;
packet pkt;
initial begin
pkt = new();
repeat(50) if (pkt.randomize())
transmit(pkt);
end
endprogram
SystemVerilog Testbench with VCS 05/07/2007
Derive Coverage Model From Test Plan 144
Test Plan:
• Define 3 address regions: 0:0x3F, 0x40:0x7F and 0x80:0xBF
• Test with packets of all types = 2 bins
• Test with packets targeted to all address regions = 3 bins
• Test with all permutations of all packets types to all address
regions = 6 bins
• Implementation:
• Do not write directed test for each test item
• Instead map each test item into an executable coverage point
• Run random suite of tests and collect functional coverage.
• Analyze coverage results and to improve functional coverage
either run more random tests or for hard-to-reach coverage
points create a more constrained test (Directed random).
covergroup pktCov;
coverpoint trans_type; // Creates 2 bins
coverpoint addr { // Item 2: Creates 3 bins
bins low_range = {[0:0x3F]};
bins mid_range = {[0x40:0x7F]};
bins hi_range = {[0x80:0xBF]};
}
cross trans_type, dst; // Item 5: Creates 6 bins
endgroup
Time Allotted
1 hour
Test Tests
Scenario Generators
Functional Coverage
Functional Transactor Self Check Checker
DUT
Signal
class Transaction;
Data modeled using classes rand enum {READ, WRITE}
kind;
Packets rand bit [ 7:0] sel;
Frames rand bit [31:0] addr;
rand bit [31:0] data;
Cells endclass
Instructions
Pixels
Samples
Flows through the verification environment
100,000+ instances created and freed during a
simulation
100+ in existence at any given time
Duplicated only when necessary
Tests
Created Accumulated Freed
here here here
Generators
Duplicated
here
Created
Freed DUT here
here
sw_driver sw_driver
mbx.put(tr);
apb.write(...);
Mailbox
apb_master
task write(...); mbx.get(tr);
apb_master
Procedural Interface
interface object
mii_phy
phy.get(tr);
Test
eth_gen mac_layer
gmii_phy
mac.get(tr); phy.get(tr);
mac.put(tr); phy.put(tr);
xgmii_phy
phy.get(tr);
class apb_xactor;
function new(mailbox mgen, mdrv); generator
(xactor)
task main();
forever begin
mgen.get(t); transactor
// process transaction t (xactor)
mdrv.put(t);
end
endclass
driver DUT
(xactor)
Randomizable objects
Data streams
Configuration
Error injection
Election
Atomic generators atomic generator
blueprint
Modifying constraints Copy
Run-time generator control
Inserting directed stimulus
scenario generator
Scenario generators scenario
Atomic scenarios
Grammar-based scenarios
Defining new scenarios
Modifying scenario distributions
SystemVerilog Testbench with VCS 05/07/2007
Randomizable Aspects 162
Disturbance Injection
class cfg;
... ahb_mstr
endclass
Downloaded
into DUT via...
Entirely DUT-specific
Can only detect errors
Detected errors identified in planning stage
Each error detection mechanism part of coverage model
Ensure that opportunity to check error existed
No error was actually found
Where do I go next?
Complete the labs / and QuickStart
($VCS_HOME/doc/examples)
Read the Verification Methodology Manual
Take the VMM-Basic and Advanced classes
THANK YOU!!!
SystemVerilog Testbench with VCS 05/07/2007