mbits-mirafra / axi4_avip

MIT License
22 stars 25 forks source link

apb_slave #63

Closed mahadevaswamy05 closed 1 year ago

mahadevaswamy05 commented 1 year ago

Here we are the module examples of the apb_slave code

For enabling the waveforms refer

mahadevaswamy05 commented 1 year ago

Example of the Module - APB_SLVAE

1.Here we developed code the(UUT File) by using a module, click to expand:

Details

```systemverilog module apb_slave #( addrWidth = 8, dataWidth = 32 ) ( input clk, input rst_n, input [addrWidth-1:0] paddr, input pwrite, input psel, input penable, input [dataWidth-1:0] pwdata, output logic [dataWidth-1:0] prdata ); logic [dataWidth-1:0] mem [256]; logic [1:0] apb_st; const logic [1:0] SETUP = 0; const logic [1:0] W_ENABLE = 1; const logic [1:0] R_ENABLE = 2; // SETUP -> ENABLE always @(negedge rst_n or posedge clk) begin if (rst_n == 0) begin apb_st <= 0; prdata <= 0; end else begin case (apb_st) SETUP : begin // clear the prdata prdata <= 0; // Move to ENABLE when the psel is asserted if (psel && !penable) begin if (pwrite) begin apb_st <= W_ENABLE; end else begin apb_st <= R_ENABLE; end end end W_ENABLE : begin // write pwdata to memory if (psel && penable && pwrite) begin mem[paddr] <= pwdata; end // return to SETUP apb_st <= SETUP; end R_ENABLE : begin // read prdata from memory if (psel && penable && !pwrite) begin prdata <= mem[paddr]; end // return to SETUP apb_st <= SETUP; end endcase end end endmodule ```

mahadevaswamy05 commented 1 year ago

2.In this example we have UUT file which file name called apb_slave.sv. and in this file they implemented the apb design logic. and another file which is auto-generated one in this file we implemented the test cases and all.

image

mahadevaswamy05 commented 1 year ago

3.More about the UUT file. example file name is apb_slave.sv

i. firstly they implemented the reset logic in the task. it's the idle state logic.

    always @(negedge rst_n or posedge clk) begin
    if (rst_n == 0) begin
    apb_st <= 0;
    prdata <= 0;
    end

ii. Setup state logic they implemented using the if conditions.

  else begin
    case (apb_st)
      SETUP : begin
        // clear the prdata
        prdata <= 0;

        // Move to ENABLE when the psel is asserted
        if (psel && !penable) begin
          if (pwrite) begin
            apb_st <= W_ENABLE;
          end

          else begin
            apb_st <= R_ENABLE;
          end
        end
      end

iii. write pwdata to memory, it's kind of the write operation.


 W_ENABLE : begin
        // write pwdata to memory
        if (psel && penable && pwrite) begin
          mem[paddr] <= pwdata;
        end

        // return to SETUP
        apb_st <= SETUP;
      end

iv. read prdata from memory so it's the read operation.

         R_ENABLE : begin
        // read prdata from memory
        if (psel && penable && !pwrite) begin
          prdata <= mem[paddr];
        end
mahadevaswamy05 commented 1 year ago

4.For generating the unit test template file we will use the below command creat_unit_test.pl apb_slave.sv

image

mahadevaswamy05 commented 1 year ago

5.More about the test 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 automatic 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 automatic 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

mahadevaswamy05 commented 1 year ago

6. Using the below command we're running the unit test template file

runSVUnit -s questa

image

muneebullashariff commented 1 year ago

This example shows as how to perform unit testing for a use-case protocol like APB. Thus, unit_testing can be used even for more complicated protocols/projects.

mahadevaswamy05 commented 1 year ago

Here we explain the test cases about the single write and read test cases

- Single write then read test cases.(do a write than a read at the same address). and see the below snippets for this test case.


 `SVTEST(single_write_then_read)
    addr = 'h32;
    data = 'h61;

    write(addr, data);
    read(addr, rdata);
    `FAIL_IF(data !== rdata);
  `SVTEST_END

Just follow the below write task for a write operation logic

write

```systemverilog task automatic write(logic [7:0] addr, logic [31:0] data, logic back2back = 0, logic setup_psel = 1, logic setup_pwrite = 1); if (!back2back) begin @(negedge clk); psel = 0; penable = 0; end @(negedge clk); psel = setup_psel; pwrite = setup_pwrite; paddr = addr; pwdata = data; penable = 0; @(negedge clk); pwrite = 1; penable = 1; psel = 1; endtask ````

Just follow the below read task for a read operation logic

Read

```systemverilog task automatic 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 ````

mahadevaswamy05 commented 1 year ago

Here we explain the test cases about Single write then read test cases with checking p_select

- Single write then read test cases with checking p_select(do a write then a read at the same address but insert a write without psel asserted during setup to ensure memory isn't corrupted by a protocol error). and

and see the below snippets for this test case.

 `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

Just follow the below write task for a write operation logic

write

```systemverilog task automatic write(logic [7:0] addr, logic [31:0] data, logic back2back = 0, logic setup_psel = 1, logic setup_pwrite = 1); if (!back2back) begin @(negedge clk); psel = 0; penable = 0; end @(negedge clk); psel = setup_psel; pwrite = setup_pwrite; paddr = addr; pwdata = data; penable = 0; @(negedge clk); pwrite = 1; penable = 1; psel = 1; endtask ````

Just follow the below read task for a read operation logic

Read

```systemverilog task automatic 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 ````

mahadevaswamy05 commented 1 year ago

We are explaining the write-to-write operation.

(we are passing value to the pwrite is 0 or 1). and see the below snippets for this test case.

 `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

Just follow the below write task for a write operation logic

write

```systemverilog task automatic write(logic [7:0] addr, logic [31:0] data, logic back2back = 0, logic setup_psel = 1, logic setup_pwrite = 1); if (!back2back) begin @(negedge clk); psel = 0; penable = 0; end @(negedge clk); psel = setup_psel; pwrite = setup_pwrite; paddr = addr; pwdata = data; penable = 0; @(negedge clk); pwrite = 1; penable = 1; psel = 1; endtask ````

Just follow the below read task for a read operation logic

Read

```systemverilog task automatic 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 ````

mahadevaswamy05 commented 1 year ago

Here we are explaining the test cases about two_write then two_read operation

and see the below snippets for this test case.


 `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

Just follow the below write task for a write operation logic

write

```systemverilog task automatic write(logic [7:0] addr, logic [31:0] data, logic back2back = 0, logic setup_psel = 1, logic setup_pwrite = 1); if (!back2back) begin @(negedge clk); psel = 0; penable = 0; end @(negedge clk); psel = setup_psel; pwrite = setup_pwrite; paddr = addr; pwdata = data; penable = 0; @(negedge clk); pwrite = 1; penable = 1; psel = 1; endtask ````

Just follow the below read task for a read operation logic

Read

```systemverilog task automatic 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 ````

mahadevaswamy05 commented 1 year ago

Follow the below picture for APB output

Image