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. ~