‘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.