Ready-to-run snippets

Code Examples

Ready-to-run Verilog, SystemVerilog, and UVM examples. Click any to open it live in the IDE.

← All examples

APB Completer with Four Registers

Verilog Bus Protocols

A minimal APB completer with four 32-bit registers, driven by APB write and read tasks.

Open in IDE
design.v
// A minimal APB completer: four 32-bit registers at 0x0, 0x4, 0x8 and 0xC.
// No wait states (PREADY tied high) and no errors (PSLVERR tied low).
module apb_regs (
  input             PCLK,
  input             PRESETn,
  input             PSEL,
  input             PENABLE,
  input             PWRITE,
  input      [11:0] PADDR,
  input      [31:0] PWDATA,
  output reg [31:0] PRDATA,
  output            PREADY,
  output            PSLVERR
);
  reg [31:0] r [0:3];
  integer    i;

  wire [1:0] idx = PADDR[3:2];              // word index: byte address bits 3:2

  // A write takes effect in the Access phase: PSEL and PENABLE both high
  always @(posedge PCLK) begin
    if (!PRESETn) begin
      for (i = 0; i < 4; i = i + 1)
        r[i] <= 32'h0;
    end
    else if (PSEL && PENABLE && PWRITE) begin
      r[idx] <= PWDATA;
    end
  end

  // Read data is driven during the transfer
  always @(*) begin
    if (PSEL && !PWRITE)
      PRDATA = r[idx];
    else
      PRDATA = 32'h0;
  end

  assign PREADY  = 1'b1;
  assign PSLVERR = 1'b0;
endmodule
testbench.v
// Testbench: an APB requester with write and read tasks
module tb;
  reg         PCLK    = 0;
  reg         PRESETn = 0;
  reg         PSEL    = 0;
  reg         PENABLE = 0;
  reg         PWRITE  = 0;
  reg  [11:0] PADDR   = 0;
  reg  [31:0] PWDATA  = 0;
  wire [31:0] PRDATA;
  wire        PREADY;
  wire        PSLVERR;
  reg  [31:0] rdata;

  apb_regs dut (
    .PCLK    (PCLK),
    .PRESETn (PRESETn),
    .PSEL    (PSEL),
    .PENABLE (PENABLE),
    .PWRITE  (PWRITE),
    .PADDR   (PADDR),
    .PWDATA  (PWDATA),
    .PRDATA  (PRDATA),
    .PREADY  (PREADY),
    .PSLVERR (PSLVERR)
  );

  always #5 PCLK = ~PCLK;

  // Setup phase: PSEL high, PENABLE low. Access phase: PENABLE high until PREADY.
  task apb_write(input [11:0] addr, input [31:0] data);
    begin
      @(posedge PCLK);
      PSEL    <= 1;
      PENABLE <= 0;
      PWRITE  <= 1;
      PADDR   <= addr;
      PWDATA  <= data;
      @(posedge PCLK);
      PENABLE <= 1;
      @(posedge PCLK);
      while (!PREADY)
        @(posedge PCLK);
      $display("%0t  write 0x%h = 0x%h%s", $time, addr, data, PSLVERR ? "  PSLVERR" : "");
      PSEL    <= 0;
      PENABLE <= 0;
    end
  endtask

  task apb_read(input [11:0] addr, output [31:0] data);
    begin
      @(posedge PCLK);
      PSEL    <= 1;
      PENABLE <= 0;
      PWRITE  <= 0;
      PADDR   <= addr;
      @(posedge PCLK);
      PENABLE <= 1;
      @(posedge PCLK);
      while (!PREADY)
        @(posedge PCLK);
      data = PRDATA;
      $display("%0t  read  0x%h = 0x%h%s", $time, addr, data, PSLVERR ? "  PSLVERR" : "");
      PSEL    <= 0;
      PENABLE <= 0;
    end
  endtask

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars(0, tb);
    #22 PRESETn = 1;
    apb_write(12'h004, 32'hCAFE_0001);
    apb_write(12'h008, 32'h1234_5678);
    apb_read (12'h004, rdata);
    apb_read (12'h008, rdata);
    #20 $finish;
  end
endmodule
Admin mode — edit and delete controls are visible on each row. Use the IDE to add new snippets via File → Save as Snippet.