0% found this document useful (0 votes)
161 views7 pages

SystemVerilog Testbench Example - Adder

This document describes a SystemVerilog testbench for verifying an adder module. It includes the adder design, interface definitions, a transaction object to generate random inputs, a driver to stimulus the adder, a monitor to check outputs, a scoreboard to compare actual and expected outputs, and a testbench module that instantiates the design and runs the test. The environment class manages the different verification components by connecting their interfaces and mailboxes.

Uploaded by

vibhorkrnitrkl
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
161 views7 pages

SystemVerilog Testbench Example - Adder

This document describes a SystemVerilog testbench for verifying an adder module. It includes the adder design, interface definitions, a transaction object to generate random inputs, a driver to stimulus the adder, a monitor to check outputs, a scoreboard to compare actual and expected outputs, and a testbench module that instantiates the design and runs the test. The environment class manages the different verification components by connecting their interfaces and mailboxes.

Uploaded by

vibhorkrnitrkl
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

System

Verilog
Testbench
adder
Example
SystemVerilog Testbench Adder Example

Here is an example of how a SystemVerilog testbench can be constructed to verify the


functionality of a simple adder. Remember that the goal here is to develop a modular and scalable
testbench architecture with all the standard verification components in a testbench.

Design

// An adder is combinational logic and does not


// have a clock

// Module definition for the adder


module my_adder(
adder_if _if // Input/output interface for the adder
);
// Combinational logic block
always_comb begin
// Check if the reset signal is asserted
if (_if.rstn) begin
// If reset is active, clear the sum and carry
_if.sum <= 0;
_if.carry <= 0;
end else begin
// If not in reset, perform addition operation
// Concurrently assign the sum of 'a' and 'b' to 'sum' and 'carry'
{_if.carry, _if.sum} <= _if.a + _if.b;
end
end
endmodule

Interface

// Adder interface contains all signals that the adder requires


// to operate
interface adder_if();
logic rstn;
logic [7:0] a;
logic [7:0] b;
logic [7:0] sum;
logic carry;
endinterface

// Although an adder does not have a clock, let us create a mock clock
// used in the testbench to synchronize when value is driven and when
// value is sampled. Typically combinational logic is used between
// sequential elements like FF in a real circuit. So, let us assume
// that inputs to the adder are provided at some posedge clock. But because
// the design does not have a clock in its input, we will keep this clock
// in a separate interface that is available only to testbench components
interface clk_if();
logic tb_clk;
initial tb_clk <= 0;
always #10 tb_clk = ~tb_clk;
endinterface

Transaction Object

// To verify that the adder adds, we also need to check that it


// does not add when rstn is 0, and hence rstn should also be
// randomized along with a and b.
class Packet;
rand bit rstn;
rand bit [7:0] a;
rand bit [7:0] b;
bit [7:0] sum;
bit carry;

// Print contents of the data packet


function void print(string tag = "");
$display("T=%0t %s a=0x%0h b=0x%0h sum=0x%0h carry=0x%0h", $time, tag, a,
b, sum, carry);
endfunction

// This is a utility function to allow copying contents in


// one Packet variable to another.
function void copy(Packet tmp);
this.a = tmp.a;
this.b = tmp.b;
this.rstn = tmp.rstn;
this.sum = tmp.sum;
this.carry = tmp.carry;
endfunction
endclass

Driver

class driver;
virtual adder_if m_adder_vif;
virtual clk_if m_clk_vif;
event drv_done;
mailbox drv_mbx;

task run();
$display("T=%0t [Driver] starting ...", $time);

// Try to get a new transaction every time and then assign


// packet contents to the interface. But do this only if the
// design is ready to accept new transactions
forever begin
Packet item;
$display("T=%0t [Driver] waiting for item ...", $time);
drv_mbx.get(item);
@(posedge m_clk_vif.tb_clk);
item.print("Driver");
m_adder_vif.rstn <= item.rstn;
m_adder_vif.a <= item.a;
m_adder_vif.b <= item.b;
->drv_done;
end
endtask
endclass

Monitor

class monitor;
virtual adder_if m_adder_vif;
virtual clk_if m_clk_vif;
mailbox scb_mbx; // Mailbox connected to scoreboard

// Mailbox connected to scoreboard


task run();
$display("T=%0t [Monitor] starting ...", $time);

// Check forever at every clock edge to see if there is a


// valid transaction and if yes, capture info into a class
// object and send it to the scoreboard when the transaction
// is over.
forever begin
Packet m_pkt = new();
@(posedge m_clk_vif.tb_clk);
#1;
m_pkt.a = m_adder_vif.a;
m_pkt.b = m_adder_vif.b;
m_pkt.rstn = m_adder_vif.rstn;
m_pkt.sum = m_adder_vif.sum;
m_pkt.carry = m_adder_vif.carry;
m_pkt.print("Monitor");
scb_mbx.put(m_pkt);
end
endtask
endclass

Generator

class generator;
int loop = 10;
event drv_done;
mailbox drv_mbx;

task run();
for (int i = 0; i < loop; i++) begin
Packet item = new;
item.randomize();
$display("T=%0t [Generator] Loop:%0d/%0d create next item", $time, i +
1, loop);
drv_mbx.put(item);
$display("T=%0t [Generator] Wait for driver to be done", $time);
@(drv_done);
end
endtask
endclass

Environment

// The environment class manages the verification components - generator,


driver, monitor, and scoreboard.
class env;
generator g0; // Generator instance for generating random
transactions
driver d0; // Driver instance for driving transactions to the
design
monitor m0; // Monitor instance for capturing transactions and
sending to the scoreboard
scoreboard s0; // Scoreboard instance for checking data integrity
mailbox scb_mbx; // Mailbox for communication between scoreboard and
monitor
virtual adder_if m_adder_vif; // Virtual interface handle for the adder
virtual clk_if m_clk_vif; // Virtual interface handle for the clock
event drv_done; // Event indicating driver completion
mailbox drv_mbx; // Mailbox for communication between
generator and driver

function new();
// Initialize instances
d0 = new;
m0 = new;
s0 = new;
scb_mbx = new();
g0 = new;
drv_mbx = new;
endfunction

virtual task run();


// Connect virtual interface handles
d0.m_adder_vif = m_adder_vif;
m0.m_adder_vif = m_adder_vif;
d0.m_clk_vif = m_clk_vif;
m0.m_clk_vif = m_clk_vif;

// Connect mailboxes between components


d0.drv_mbx = drv_mbx;
g0.drv_mbx = drv_mbx;
m0.scb_mbx = scb_mbx;
s0.scb_mbx = scb_mbx;

// Connect event handles


d0.drv_done = drv_done;
g0.drv_done = drv_done;

// Start all components using fork join_any


fork
s0.run();
d0.run();
m0.run();
g0.run();
join_any
endtask
endclass

Scoreboard

class scoreboard;
mailbox scb_mbx;

task run();
forever begin
Packet item, ref_item;
scb_mbx.get(item);
item.print("Scoreboard");

// Copy contents from received packet into a new packet so


// just to get a and b.
ref_item = new();
ref_item.copy(item);

// Let us calculate the expected values in carry and sum


if (ref_item.rstn) begin
{ref_item.carry, ref_item.sum} = ref_item.a + ref_item.b;
end else begin
{ref_item.carry, ref_item.sum} = 0;
end

// Now, carry and sum outputs in the reference variable can be compared
// with those in the received packet
if (ref_item.carry != item.carry) begin
$display("[%0t] Scoreboard Error! Carry mismatch ref_item=0x%0h
item=0x%0h", $time, ref_item.carry, item.carry);
end else begin
$display("[%0t] Scoreboard Pass! Carry match ref_item=0x%0h
item=0x%0h", $time, ref_item.carry, item.carry);
end

if (ref_item.sum != item.sum) begin


$display("[%0t] Scoreboard Error! Sum mismatch ref_item=0x%0h
item=0x%0h", $time, ref_item.sum, item.sum);
end else begin
$display("[%0t] Scoreboard Pass! Sum match ref_item=0x%0h
item=0x%0h", $time, ref_item.sum, item.sum);
end
end
endtask
endclass
Test

// The test class is responsible for instantiating the environment and


running the test.
class test;
env e0; // Environment instance for verification components
mailbox drv_mbx; // Mailbox for communication between the test and the
environment

function new();
drv_mbx = new(); // Initialize mailbox for driver communication
e0 = new(); // Instantiate the environment
endfunction

virtual task run();


e0.d0.drv_mbx = drv_mbx; // Connect the driver mailbox from the
environment to the test
e0.run(); // Run the environment
endtask
endclass

Testbench TOP

// Testbench module to instantiate design, interface, start clocks, and run


the test
module tb;
bit tb_clk; // Testbench clock
clk_if m_clk_if(); // Clock interface instance
adder_if m_adder_if(); // Adder interface instance
my_adder u0(m_adder_if); // Instantiate the adder module

initial begin
test t0; // Test instance
t0 = new; // Create a new test instance

// Connect interfaces between test and environment


t0.e0.m_adder_vif = m_adder_if;
t0.e0.m_clk_vif = m_clk_if;

t0.run(); // Run the test

// Once the main stimulus is over, wait for some time


// until all transactions are finished and then end
// simulation. Note that $finish is required because
// there are components that are running forever in
// the background like clk, monitor, driver, etc
#50 $finish;
end
endmodule

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy