blob: e2edb810e7b6f6fd1cd8a5141a93caa133d4a2f7 [file]
`include "svunit_defines.svh"
`include "apb_slave.sv"
module apb_slave_unit_test;
import svunit_pkg::svunit_testcase;
string name = "apb_slave_ut";
svunit_testcase svunit_ut;
logic [7:0] addr;
logic [31:0] data, rdata;
//===================================
// This is the UUT that we're
// running the Unit Tests on
//===================================
reg clk;
reg rst_n;
reg [7:0] paddr;
reg pwrite;
reg psel;
reg penable;
reg [31:0] pwdata;
wire [31:0] prdata;
// clk generator
initial begin
clk = 0;
forever begin
#5 clk = ~clk;
end
end
apb_slave my_apb_slave(.*);
//===================================
// Build
//===================================
function void build();
svunit_ut = new(name);
endfunction
//===================================
// Setup for running the Unit Tests
//===================================
task setup();
svunit_ut.setup();
//-----------------------------------------
// move the bus into the IDLE state
// before each test
//-----------------------------------------
idle();
//-----------------------------
// then do a reset for the uut
//-----------------------------
rst_n = 0;
repeat (8) @(posedge clk);
rst_n = 1;
endtask
//===================================
// Here we deconstruct anything we
// need after running the Unit Tests
//===================================
task teardown();
svunit_ut.teardown();
/* Place Teardown Code Here */
endtask
//===================================
// All tests are defined between the
// SVUNIT_TESTS_BEGIN/END macros
//
// Each individual test must be
// defined between `SVTEST(_NAME_)
// `SVTEST_END
//
// i.e.
// `SVTEST(mytest)
// <test code>
// `SVTEST_END
//===================================
`SVUNIT_TESTS_BEGIN
//************************************************************
// Test:
// single_write_then_read
//
// Desc:
// do a write then a read at the same address
//************************************************************
`SVTEST(single_write_then_read)
addr = 'h32;
data = 'h61;
write(addr, data);
read(addr, rdata);
`FAIL_IF(data !== rdata);
`SVTEST_END
//************************************************************
// Test:
// write_wo_psel
//
// Desc:
// do a write then a read at the same address but insert a
// write without psel asserted during setup to ensure mem
// isn't corrupted by a protocol error.
//************************************************************
`SVTEST(write_wo_psel)
addr = 'h0;
data = 'hffff_ffff;
write(addr, data);
write(addr, 'hff, 0, 0);
read(addr, rdata);
`FAIL_IF(data !== rdata);
`SVTEST_END
//************************************************************
// Test:
// write_wo_write
//
// Desc:
// do a write then a read at the same address but insert a
// write without pwrite asserted during setup to ensure mem
// isn't corrupted by a protocol error.
//************************************************************
`SVTEST(write_wo_write)
addr = 'h10;
data = 'h99;
write(addr, data);
write(addr, 'hff, 0, 1, 0);
read(addr, rdata);
`FAIL_IF(data !== rdata);
`SVTEST_END
//************************************************************
// Test:
// _2_writes_then_2_reads
//
// Desc:
// Do back-to-back writes then back-to-back reads
//************************************************************
`SVTEST(_2_writes_then_2_reads)
addr = 'hfe;
data = 'h31;
write(addr, data, 1);
write(addr+1, data+1, 1);
read(addr, rdata, 1);
`FAIL_IF(data !== rdata);
read(addr+1, rdata, 1);
`FAIL_IF(data+1 !== rdata);
`SVTEST_END
`SVUNIT_TESTS_END
//-------------------------------------------------------------------------------
//
// write ()
//
// Simple write method used in the unit tests. Includes options for back-to-back
// writes and protocol errors on the psel and pwrite.
//
//-------------------------------------------------------------------------------
task write(logic [7:0] addr,
logic [31:0] data,
logic back2back = 0,
logic setup_psel = 1,
logic setup_pwrite = 1);
// if !back2back, insert an idle cycle before the write
if (!back2back) begin
@(negedge clk);
psel = 0;
penable = 0;
end
// this is the SETUP state where the psel,
// pwrite, paddr and pdata are set
//
// NOTE:
// setup_psel == 0 for protocol errors on the psel
// setup_pwrite == 0 for protocol errors on the pwrite
@(negedge clk);
psel = setup_psel;
pwrite = setup_pwrite;
paddr = addr;
pwdata = data;
penable = 0;
// this is the ENABLE state where the penable is asserted
@(negedge clk);
pwrite = 1;
penable = 1;
psel = 1;
endtask
//-------------------------------------------------------------------------------
//
// read ()
//
// Simple read method used in the unit tests. Includes options for back-to-back
// reads.
//
//-------------------------------------------------------------------------------
task read(logic [7:0] addr, output logic [31:0] data, input logic back2back = 0);
// if !back2back, insert an idle cycle before the read
if (!back2back) begin
@(negedge clk);
psel = 0;
penable = 0;
end
// this is the SETUP state where the psel, pwrite and paddr
@(negedge clk);
psel = 1;
paddr = addr;
penable = 0;
pwrite = 0;
// this is the ENABLE state where the penable is asserted
@(negedge clk);
penable = 1;
// the prdata should be flopped after the subsequent posedge
@(posedge clk);
#1 data = prdata;
endtask
//-------------------------------------------------------------------------------
//
// idle ()
//
// Clear the all the inputs to the uut (i.e. move to the IDLE state)
//
//-------------------------------------------------------------------------------
task idle();
@(negedge clk);
psel = 0;
penable = 0;
pwrite = 0;
paddr = 0;
pwdata = 0;
endtask
endmodule