Digital design through system verilog
Digital design through system verilog
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
About TestBench
TestBench Components
TestBench Hierarchy
SystemVerilog Testbench
ADDER:
Below is the block diagram of ADDER.
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
SystemVerilog TestBench
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.
class monitor;
------
endclass
2. Declare interface and mailbox, Get the interface and mailbox handle
through the constructor.
//creating virtual interface handle
mailbox mon2scb;
//constructor
this.vif = vif;
this.mon2scb = mon2scb;
endfunction
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);
end
endtask
class monitor;
//constructor
this.vif = vif;
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);
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
mailbox mon2scb;
int no_transactions;
//constructor
this.mon2scb = mon2scb;
endfunction
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
task main;
transaction trans;
forever begin
mon2scb.get(trans);
if((trans.a+trans.b) == trans.c)
$display("Result is as Expected");
else
no_transactions++;
end
endtask
class scoreboard;
mailbox mon2scb;
int no_transactions;
//constructor
this.mon2scb = mon2scb;
endfunction
task main;
transaction trans;
forever begin
mon2scb.get(trans);
if((trans.a+trans.b) == trans.c)
$display("Result is as Expected");
else
no_transactions++;
end
endtask
endclass
Environment
Here only updates are mentioned. i.e adding monitor and scoreboard to
the previous example.
generator gen;
driver driv;
//mailbox handle's
mailbox gen2driv;
//virtual interface
Mailbox (mon2scb)
Monitor
Scoreboard
//constructor
this.vif = vif;
//creating the mailbox (Same handle will be shared across generator and driver)
gen2driv = new();
gen = new(gen2driv);
driv = new(vif,gen2driv);
endfunction
driv.reset();
endtask
task test();
fork
gen.main();
driv.main();
join_any
endtask
task post_test();
wait(gen.ended.triggered);
wait(gen.repeat_count == driv.no_transactions);
endtask
`include "generator.sv"
`include "driver.sv"
`include "monitor.sv"
`include "scoreboard.sv"
class environment;
generator gen;
driver driv;
monitor mon;
scoreboard scb;
//mailbox handle's
mailbox gen2driv;
mailbox mon2scb;
//virtual interface
this.vif = vif;
//creating the mailbox (Same handle will be shared across generator and driver)
gen2driv = new();
mon2scb = new();
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 == scb.no_transactions);
endtask
//run task
task run;
pre_test();
test();
post_test();
$finish;
endtask
endclass