13-VerificationExample
13-VerificationExample
and
Verification Example
Syntax:
virtual interface_name instance_name;
example:
virtual mem_intf intf;
• Virtual interface must be initialized before using it. i.e, Virtual interface must be
connected/pointed to the actual interface.
• Accessing the uninitialized virtual interface results in a run-time fatal error.
• Virtual interfaces can be declared as class properties, which can be initialized
using a procedure or by an argument to new().
• Virtual interface variables can be passed as arguments to the tasks, functions, or
methods.
• All the interface variables/Methods can be accessed via virtual interface handle.
i.e virtual_interface.variable
12/25/2024 Verification with System Verilog 3
Verification flow examples
(without the use of modport, clocking blocks and monitor blocks)
Verification of an adder unit
Generator generates random signals (called transactions) and puts in mail box.
Driver takes from mail box and sends them to DUT through interface.
(interface needs to be defined before calling the driver).
(mailbox connects generator and driver and is defined in environment class)
assign c = tmp_c;
endmodule
Step 2: Define Transaction class
• Transaction.sv
– Fields required to generate the stimulus are declared in the transaction class.
– Transaction class can also be used as placeholder for the activity monitored by
monitor on DUT signals.
– So, first step is to declare the 'Fields‘ (inputs, outputs, signals) in the transaction class.
– To generate the random stimulus, declare the fields as 'rand'.
– Add display() method to display Transaction properties.
class transaction;
//declaring the transaction items
rand bit [3:0] a;
rand bit [3:0] b;
bit [6:0] c; //c is output. Hence not defined as random
//mailbox, to generate and send the packet to driver (this mailbox has to be passed from environment)
mailbox gen2driv;
//constructor
//Getting the mailbox handle from env. The environment class has the mailbox since the transaction packet is
// to be shared between the generator and driver
// main task : To generate(create and randomize) required number of transaction packets and
// put into mailbox
task main(); // We need to use ‘task’ and not ‘function’ since we are dealing with time/ events
repeat(packet_count)
begin
trans = new();
if( !trans.randomize() )
% ‘randomize’ will generate random values for all ‘rand’ properties a and return a ‘1’ or will fail and return a ‘0’
% randomize function may not work in modelsim, hence randomize numbers may be manually usuing rand function.
$fatal("Gen:: trans randomization failed"); // randomize and check if succeeded
else
begin
trans.display("[ Generator ]");
gen2driv.put(trans); // put in mailbox for driver to see
end
end
endclass
Step 4: Define Interface
• interface.sv
Endinterface
Step 4: Define Driver class
• driver.sv
(Receive the stimulus generated from generator and drive to DUT by assigning
transaction class values to interface signals)
– Declare interface and mailbox. ( can u guess what type of interface ? Why?)
– Get the interface and mailbox handle from environment through constructor.
– Add reset task, which initializes the Interface signals to default values.
– Add drive task to drive the transaction packet to interface signal.
– Add local variable to track the number of packets driven, and increment the
variable in drive task.
(This will be useful to end the test-case/Simulation. i.e compare the generated
packet’s and driven packet’s data. If both are same then end the simulation)
Driver class
class driver
//variable used to count the number of transactions
int no_transactions;
// define a handle for transaction. since we will be reading a transaction from the mailbox
transaction trans;
//constructor
// Obtain mailbox and virtual interface handles from environment
task reset; // We need to use ‘task’ and not ‘function’ since we are dealing with time/ events
endtask
Driver class (continued)
//Main task : drives the transaction items to interface signals
task main;
forever begin
gen2driv.get(trans); // get the transaction from mailbox that was filled by generator
@(posedge vif.clk); // at rising edge read the value of a, b from generator and give to interface
vif.valid <= 1;
vif.a <= trans.a;
vif.b <= trans.b;
@(posedge vif.clk); // at next rising edge read the value of c from interface and write to transaction
vif.valid <= 0;
trans.c <= vif.c;
@(posedge vif.clk); // at next rising edge, display that a transaction has happened and increment count
trans.display("[ Driver ]");
no_transactions++;
end
endtask
endclass
Step 5: Define Environment class
• environment.sv
Environment is a container class that contains Mailbox, Generator and Driver.
Creates the mailbox, generator and driver, shares the mailbox handle across the
Generator and Driver.
– Create mailbox, generator and driver and pass interface through new() constructor.
– Generator and Driver activity can be divided and controlled in three methods.
class environment;
//constructor
// Interface needs to be brought in to environment from ‘top -> test ’
function new(virtual intf vif);
this.vif = vif;
//creating the mailbox (Same handle will be shared across generator and driver)
gen2driv = new();
task test();
fork
gen.main();
driv.main();
join_any // as soon as generate is finished, go to post_test and wait for packet Gen ending
endtask
task post_test();
wait(gen. PacketGenerationEnded.triggered);
wait(gen.repeat_count == driv.no_transactions);
endtask
`include "environment.sv“
initial
// Interface needs to be brought in to environment from ‘top -> test ’
begin
//creating environment
env = new(intf);
//calling ‘run’ of env, it inturn calls generator and driver main tasks.
env.run();
end
endprogram
Top Level Test bench
• TbenchTop.sv
• This is the top most file, which connects the
DUT and Testbench.
• ‘TestBenchTop’ consists of DUT, Test and
Interface instances.
• Interface connects the DUT and TestBench.
Top level test
`include "interface.sv"
`include "random_test.sv"
Generator generates random signals (called transactions) and puts in mail box.
Driver takes from mail box and sends them to DUT through interface.
(interface needs to be defined before calling the driver).
Layered Testbench
without scoreboard
and monitor
no_transactions++;
trans.display("[ Scoreboard ]");
end
endtask
endclass
`include "transaction.sv"
`include "generator.sv"
Environment Code
`include "driver.sv"
`include "monitor.sv"
`include "scoreboard.sv"
class environment;
//mailbox handle's
mailbox gen2driv;
mailbox mon2scb; task test();
//constructor
fork
//virtual interface function new(virtual intf vif); gen.main();
//get the interface from test driv.main();
virtual intf vif;
this.vif = vif; mon.main();
scb.main();
//creating the mailbox (Same handle will be join_any
shared across generator and driver) endtask
gen2driv = new();
mon2scb = new(); task post_test();
wait(gen.ended.triggered);
wait(gen.repeat_count == driv.no_transactions); //Optional
//creating generator and driver
gen = new(gen2driv); wait(gen.repeat_count == scb.no_transactions);
mon = new(vif,mon2scb);
//run task
scb = new(mon2scb);
task run;
endfunction
pre_test();
test();
// post_test();
task pre_test(); $finish;
driv.reset(); endtask
endtask
endclass
Where to look for codes
Verificationguide.com
testbench.in
Chipverify.com