0% found this document useful (0 votes)
15 views

Digital design through system verilog

Uploaded by

Sai
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

Digital design through system verilog

Uploaded by

Sai
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

Layered TB in SV

1.signal layer:
This layer connects the TestBench to the RTL design. It consists of interface, clocking, and
modport constructs.
2.command layer:
This layer contains lower-level driver and monitor components, as well as the assertions.
This layer provides a transaction-level interface to the layer above and drives the physical
pins via the signal layer.
3.functional layer:
This layer contains higher-level driver and monitor components, as well as the self-checking
structure (scoreboard/tracker).

4.scenario layer:
This layer uses generators to produce streams or sequences of transactions that are applied
to the functional layer. The generators have a set of weights, constraints or scenarios
specified by the test layer. The randomness of constrained-random testing is introduced
within this layer.
5.test layer:
Tests are located in this layer. Test layer can interact with all the layers. This layer allows to
pass directed commands to functional and command layer.
SystemVerilog TestBench Architecture

TESTBENCH ARCHITECTURE in SV

Fig. Testbench architecture

About TestBench

Testbench or Verification Environment is used to check the functional


correctness of the Design Under Test (DUT) by generating and driving a
predefined input sequence to a design, capturing the design output and
comparing with-respect-to expected output.

Verification environment is a group of class’s performing specific operation.


i.e, generating stimulus, driving, monitoring, etc. and those classes will be
named based on the operation

TestBench Components

Name Type Description

Defines the pin level activity generated by agent (to drive to


transaction class
DUT through the driver) or the activity has to be observed
by agent (Placeholder for the activity monitored by the
monitor on DUT signals)

Generates the stimulus (create and randomize the


generator class
transaction class) and send it to Driver

Receives the stimulus (transaction) from a generator and


driver class drives the packet level data inside the transaction into pin
level (to DUT

Observes pin level activity on interface signals and converts


monitor class into packet level which is sent to the components such as
scoreboard

An agent is a container class, which groups the class’s


agent class (generator, driver, and monitor) specific to an interface or
protocol

Receives data items from monitors and compares them with


expected values.
scoreboard class
Expected values can be either golden reference values or
generated from the reference model

The environment is a container class for grouping higher


environment class
level components like agent’s and scoreboard

The test is responsible for,


test program
 Configuring the testbench
 Initiate the testbench components construction process
 Initiate the stimulus driving

This is the topmost file, which connects the DUT and


testbench_top class TestBench. It consists of DUT, Test and interface instances,
the interface connects the DUT and TestBench

TestBench Hierarchy

SystemVerilog TestBench hierarchy


TestBench Architecture

SystemVerilog Testbench

SystemVerilog TestBench Example — Adder


Let’s Write the SystemVerilog TestBench for the simple design “ADDER”.
Before writing the SystemVerilog TestBench, we will look into the design
specification.

ADDER:
Below is the block diagram of ADDER.

“Adder” Design block diagram


Adder is,

 fed with the inputs clock, reset, a, b and valid.


 has output is c.

The valid signal indicates the valid value on the a and b, On valid signal
adder will add the a and b, drives the result in the next clock on c.
Adder add/Sum the 4bit values ‘a’ and ‘b’, and drives the result on c in the
next clock.

waveform diagram:

“Adder” Waveform

waveform snapshot from EPWave – EDAPlayground

‘ADDER’ TestBench With Monitor and


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

SystemVerilog TestBench

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

You might also like