‘ADDER’ TestBench With Monitor and Scoreboard
Table of Contents
TestBench Architecture

Only monitor and scoreboard are explained here, Refer to ‘ADDER’ TestBench Without Monitor, Agent, and Scoreboard for other components.
Monitor
- Samples the interface signals and converts the signal level activity to the transaction level.
- Send the sampled transaction to Scoreboard via Mailbox.
- Below are the steps to write a monitor.
1. Writing monitor class.
class monitor; ------ endclass
2. Declare interface and mailbox, Get the interface and mailbox handle through the constructor.
//creating virtual interface handle
virtual intf vif;
//creating mailbox handle
mailbox mon2scb;
//constructor
function new(virtual intf vif,mailbox mon2scb);
//getting the interface
this.vif = vif;
//getting the mailbox handles from environment
this.mon2scb = mon2scb;
endfunction
3. Sampling logic and sending the sampled transaction to the scoreboard.
task main;
forever begin
transaction trans;
trans = new();
@(posedge vif.clk);
wait(vif.valid);
trans.a = vif.a;
trans.b = vif.b;
@(posedge vif.clk);
trans.c = vif.c;
@(posedge vif.clk);
mon2scb.put(trans);
trans.display("[ Monitor ]");
end
endtask
4. Complete monitor code.
class monitor;
//creating virtual interface handle
virtual intf vif;
//creating mailbox handle
mailbox mon2scb;
//constructor
function new(virtual intf vif,mailbox mon2scb);
//getting the interface
this.vif = vif;
//getting the mailbox handles from environment
this.mon2scb = mon2scb;
endfunction
//Samples the interface signal and send the sample packet to scoreboard
task main;
forever begin
transaction trans;
trans = new();
@(posedge vif.clk);
wait(vif.valid);
trans.a = vif.a;
trans.b = vif.b;
@(posedge vif.clk);
trans.c = vif.c;
@(posedge vif.clk);
mon2scb.put(trans);
trans.display("[ Monitor ]");
end
endtask
endclass
Scoreboard
Scoreboard receives the sampled packet from the monitor and compare with the expected result, an error will be reported if the comparison results in a mismatch.
class scoreboard; ------ endclass
1. Declaring the mailbox and variable to keep count of transactions, connecting handle through the constructor,
//creating mailbox handle
mailbox mon2scb;
//used to count the number of transactions
int no_transactions;
//constructor
function new(mailbox mon2scb);
//getting the mailbox handles from environment
this.mon2scb = mon2scb;
endfunction
2. logic to compare the received result with the expected result,
Note: As the DUT behavior is simple, a single line is added for generating the expected output.
Complex designs may use the reference model to generate the expected output.
(trans.a+trans.b) == trans.c
//Compares the Actual result with the expected result
task main;
transaction trans;
forever begin
mon2scb.get(trans);
if((trans.a+trans.b) == trans.c)
$display("Result is as Expected");
else
$error("Wrong Result.\n\tExpeced: %0d Actual: %0d",(trans.a+trans.b),trans.c);
no_transactions++;
trans.display("[ Scoreboard ]");
end
endtask
3. Complete scoreboard code.
class scoreboard;
//creating mailbox handle
mailbox mon2scb;
//used to count the number of transactions
int no_transactions;
//constructor
function new(mailbox mon2scb);
//getting the mailbox handles from environment
this.mon2scb = mon2scb;
endfunction
//Compares the Actual result with the expected result
task main;
transaction trans;
forever begin
mon2scb.get(trans);
if((trans.a+trans.b) == trans.c)
$display("Result is as Expected");
else
$error("Wrong Result.\n\tExpeced: %0d Actual: %0d",(trans.a+trans.b),trans.c);
no_transactions++;
trans.display("[ Scoreboard ]");
end
endtask
endclass
Environment
Here only updates are mentioned. i.e adding monitor and scoreboard to the previous example.
1. Declare the handles,
//generator and driver instance generator gen; driver driv; monitor mon; //---NEW CODE--- scoreboard scb; //---NEW CODE--- //mailbox handle's mailbox gen2driv; mailbox mon2scb; //---NEW CODE--- //virtual interface virtual intf vif;
2. In Construct Method, Create
- Mailbox (mon2scb)
- Monitor
- Scoreboard
and pass the interface handle through the new() method.
//constructor
function new(virtual intf vif);
//get the interface from test
this.vif = vif;
//creating the mailbox (Same handle will be shared across generator and driver)
gen2driv = new();
mon2scb = new(); //---NEW CODE---
//creating generator and driver
gen = new(gen2driv);
driv = new(vif,gen2driv);
mon = new(vif,mon2scb); //---NEW CODE---
scb = new(mon2scb); //---NEW CODE---
endfunction
3. Calling monitor and scoreboard tasks,
task pre_test();
driv.reset();
endtask
task test();
fork
gen.main();
driv.main();
mon.main(); //---NEW CODE---
scb.main(); //---NEW CODE---
join_any
endtask
task post_test();
wait(gen.ended.triggered);
wait(gen.repeat_count == driv.no_transactions);
wait(gen.repeat_count == scb.no_transactions); //---NEW CODE---
endtask
4. Complete environment class code.
`include "transaction.sv"
`include "generator.sv"
`include "driver.sv"
`include "monitor.sv"
`include "scoreboard.sv"
class environment;
//generator and driver instance
generator gen;
driver driv;
monitor mon;
scoreboard scb;
//mailbox handle's
mailbox gen2driv;
mailbox mon2scb;
//virtual interface
virtual intf vif;
//constructor
function new(virtual intf vif);
//get the interface from test
this.vif = vif;
//creating the mailbox (Same handle will be shared across generator and driver)
gen2driv = new();
mon2scb = new();
//creating generator and driver
gen = new(gen2driv);
driv = new(vif,gen2driv);
mon = new(vif,mon2scb);
scb = new(mon2scb);
endfunction
//
task pre_test();
driv.reset();
endtask
task test();
fork
gen.main();
driv.main();
mon.main();
scb.main();
join_any
endtask
task post_test();
wait(gen.ended.triggered);
wait(gen.repeat_count == driv.no_transactions); //Optional
wait(gen.repeat_count == scb.no_transactions);
endtask
//run task
task run;
pre_test();
test();
post_test();
$finish;
endtask
endclass
Edit and Execute Simple adder TestBench code in EDA Playground.
