| `include "svunit_defines.svh" | |
| import svunit_pkg::*; | |
| module apb_slave_unit_test; | |
| 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 | |
| initial begin | |
| // Dump waves | |
| $dumpvars(0, apb_slave_unit_test); | |
| end | |
| endmodule |