SystemVerilog TestBench Example - ADDER with Monitor and Scoreboard


-: Internal Links :-       
 Monitor                      
 Scoreboard                  
 Environment         
 EDAPlayground Link  

 'ADDER' TestBench With Monitor and Scoreboard 


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 convert the signal level activity to transaction level.
  • Send the sampled transaction to Scoreboard via Mailbox.
  • Below are the steps to write monitor.
1. Writing monitor class.

class monitor;
  ------

endclass


2. Declare interface and mailbox, Get the interface and mailbox handle through 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 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 receive's the sampled packet from monitor and compare with the expected result, error will be reported if the comparison results mismatch.

class scoreboard;

  ------  
  
endclass


1. Declaring the mailbox and variable to keep count of transactions,  connecting handle through 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, single line is added for generating the expected output.
          Complex design's may use 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 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 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.


Execute the above code on 

Click on EDA playground image.

Leave your Comments here,

"Your valuable inputs are required to improve the quality"