Verification Suite using SystemVerilog

 

The device under test is the synchronous RAM,

`timescale 1 ns/10 ps

module memory(input  logic           clock       ,       // Clock 
              input  logic  [7:0]    address     ,       // Memory address 
              input  logic  [7:0]    data_in     ,       // input data 
              output logic  [7:0]    data_out    ,       // Output data 
              input  logic           write       ,       // 1 is write mode, 0 is read mode 
              input  logic           enable              // Activate the circuit 
             );


logic [7:0] mem [255:0];


always @ (posedge clock)
begin
  if(enable)                        //Enable the circuit 
    if(write)                       //Write mode 
      mem[address] = data_in;
    else                            //Read mode 
      data_out = mem[address];
  else
    data_out = 8'd0;
end

endmodule

The idea here is to try writing into all the available memory spaces and reading from it. Then compare the same with written value to confirm the functionality. The verification platform contains systemverilog interfaces, a testcase, a driver, a monitor and a scoreboard.

The interface:

The interface construct encapsulates communication between blocks. This allows to use single interface instead many signals, which allows maintainability and readability. Interfaces usually contains something called ‘modports’ which is a short form for module ports. This provides direction information for interface ports and controls the use of tasks and functions within certain modules.

`ifndef INTERFACE
`define INTERFACE

// Input to the DUT is output to the interface
interface input_intf(input bit clock);
logic [7:0] address;
logic [7:0] data_in;
logic enable;
logic write;
int errors;


modport ip(input clock,output address, data_in,enable,write, errors);
endinterface

//output to the DUT is input to the interface
interface output_intf(input bit clock);
logic [7:0] data_out;


modport op( input clock,data_out);

endinterface


`endif

 

Driver:

`ifndef DRIVER
`define DRIVER

`include "interface.sv"
class driver;


mailbox drvr2sb;

virtual input_intf.ip in;
virtual output_intf.op out;
function new(virtual input_intf.ip in_new,virtual output_intf.op out_new,mailbox drvr2sb);
begin
this.in = in_new;
this.out = out_new;
this.drvr2sb = drvr2sb;
end
endfunction : new

task start();
begin
reg [7:0] address;
reg [7:0] data_in;
//why extra reg??

in.enable = 1'b1;
address = $random;
data_in = $random;
drvr2sb.put(data_in);
write_to(address,data_in);
repeat(4) @ (posedge in.clock)
read(address);

end
endtask : start

task write_to (logic [7:0] address, logic [7:0] data_in);
begin
in.write = 1'b1;
in.address = address;
in.data_in = data_in;
@(posedge in.clock)
in.write = 1'b0;
end
endtask : write_to


task read (logic [7:0] address);
begin
in.write = 1'b0;
in.address = address;
@ (posedge in.clock)
in.write = 1'b0;
end
endtask : read


endclass
`endif

 

Receiver:

`ifndef RECEIVER
`define RECEIVER

class receiver;
virtual input_intf.ip in;
virtual output_intf.op out;

mailbox rcvr2sb;

function new(virtual output_intf.op out_new, mailbox rcvr2sb);
begin
this.out= out_new;
this.rcvr2sb =  rcvr2sb;
end
endfunction : new

task start();
begin
reg [7:0] rcvr_box;

    repeat(2) @(posedge out.clock)
    rcvr_box = out.data_out;
    rcvr2sb.put(rcvr_box);
    $display("%0t : Output Monitor: Byte received from DUT: %b", $time, rcvr_box);

end
endtask

endclass

`endif

 

Scoreboard:

`ifndef SCOREBOARD 
`define SCOREBOARD 
 
class scoreboard; 
 
mailbox drvr2sb; 
mailbox rcvr2sb; 
virtual input_intf.ip in; 
 
function new(mailbox drvr, mailbox rcvr, virtual input_intf.ip in_new); 
this.drvr2sb = drvr; 
this.rcvr2sb = rcvr; 
this.in = in_new; 
endfunction : new 
 
task start(); 
begin 
 
reg [7:0] sent_byte; 
reg [7:0] recv_byte; 
 
    drvr2sb.get(sent_byte); 
    $display(" %0t : Scoreboard : byte %b received from driver", $time, sent_byte); 
 
    rcvr2sb.get(recv_byte); 
    $display(" %0t : scoreboard : byte %b received from output monitor", $time, recv_byte); 
 
    if(sent_byte == recv_byte) 
        begin 
           $display("%0t : Scoreboard: Byte sent to DUT match byte received fro, DUT", $time); 
        end 
 
     else 
        begin 
           $display(" %0t : Scoreboard : ERROR! Byte sent to DUT is not byte received from DUT", $time); 
           in.errors++; 
        end 
end 
endtask 
 
endclass 
 
 
`endif
 

 

Environment:

`ifndef ENVIRONMENT
`define ENVIRONMENT

class environment;

virtual input_intf.ip in;
virtual output_intf.op out;

driver drv;
mailbox drvr2sb;
receiver rcvr;
mailbox rcvr2sb;
scoreboard sb;

function new(virtual input_intf.ip in_new, virtual output_intf.op out_new);
this.in = in_new;
this.out = out_new;
$display(" %0d : Environment : created env object", $time);
endfunction : new

function void build();
$display("%0d : Environment : start of build()", $time);
$display("%0d : Environment : end of build()", $time);

drvr2sb = new();
drv = new(in,out,drvr2sb);
rcvr2sb = new();
rcvr = new(out,rcvr2sb);
sb = new(drvr2sb, rcvr2sb, in);
endfunction : build

task reset();
$display("%0d : Environment : start of reset()", $time);
in.address <= 0;
in.data_in <= 0;
in.enable <= 0;
in.write <= 0;
out.data_out <= 0;
repeat(4) @(posedge in.clock);
$display("%0d : Environment : end of reset()", $time);
endtask : reset



/*task cfg_dut();
$display("%0d : Environment : start of cfg_dut()", $time);
$display("%0d : Environment : end of cfg_dut()", $time);
endtask : cfg_dut
*/

task start();
$display("%0d : Environment : start of start()", $time);
drv.start();
rcvr.start();
sb.start();
$display("%0d : Environment : end of start()", $time);
endtask : start


task wait_for_end();
$display("%0d : Environment : start of wait_for_end()", $time);
$display("%0d : Environment : end of wait_for_end()", $time);
endtask : wait_for_end

task run();
$display("%0d : Environment : start of run()", $time);
build();
reset();
//cfg_dut();
start();
wait_for_end();
report();
$display("%0d : Environment : end of run()", $time);
endtask : run

task report();
$display("\n\n**************************************************");
if(0 == in.errors)
$display("**************TEST PASSED**************");
else
$display("**************Test failed with %0d errors ********", in.errors);
$display("***************************************************\n\n");
endtask : report

endclass

`endif

 

Testcase:

`ifndef TESTCASE
`define TESTCASE
`include "interface.sv"
`include "environment.sv"

program testcase(input_intf.ip in, output_intf.op out);
environment env;
initial
begin
$display("**********Start of Testcase*************");
env = new(in,out);
env.run();
#1000;
$display("*************End of Testcase**************");
end
endprogram

`endif

 

Top:

`ifndef TOP
`define TOP

`timescale 1ns/10ps

module top();
bit clock;

input_intf in(clock);

output_intf out(clock);

testcase tc(in, out);

memory dut (.clock(in.clock),.address(in.address), .data_in(in.data_in), .data_out(out.data_out), .write(in.write), .enable(in.enable));

initial clock =1'b0;
always #5 clock = ~clock;

endmodule
`endif

 

Output transcript:

# **********Start of Testcase*************
#  0 : Environment : created env object
# 0 : Environment : start of run()
# 0 : Environment : start of build()
# 0 : Environment : end of build()
# 0 : Environment : start of reset()
# 35 : Environment : end of reset()
# 35 : Environment : start of start()
# 14500 : Output Monitor: Byte received from DUT: 10000001
#  14500 : Scoreboard : byte 10000001 received from driver
#  14500 : scoreboard : byte 10000001 received from output monitor
# 14500 : Scoreboard: Byte sent to DUT match byte received from DUT
# 145 : Environment : end of start()
# 145 : Environment : start of wait_for_end()
# 145 : Environment : end of wait_for_end()
# 
# 
# **************************************************
# **************TEST PASSED**************
# ***************************************************
# 
# 
# 145 : Environment : end of run()
# *************End of Testcase**************
# 1
# Simulation stop requested.
~

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.