Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
    • SRAM and ROM
    • Register Files
    • Valid/Ready Handshake
    • AXI-Lite
      • Channel Overview
      • A Minimal AXI-Lite Slave
      • Responses, Strobes and Errors
      • Throughput and Backpressure
      • AXI-Lite End to End into a CSR
    • AXI-Stream
    • Bus Integration
    • Synchronous FIFO
    • Register-Map and CSR RTL
    • Memory Reliability
    • Peripheral RTL Integration
    • Full AXI4: RTL Roadmap
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹AXI-Lite
  1. Topics
  2. RTL Design
  3. Memory & Buses
  4. AXI-Lite
  5. Throughput and Backpressure

Part 7 · Memory & Buses · Intermediate

Throughput and Backpressure

Registered ready paths, back-to-back transactions, and why a minimal slave retires one at a time.

On this page

    Why this matters

    The minimal slave takes three clock edges per write and two per read, not one per cycle. Assuming back-to-back means one transaction per cycle overcounts write throughput by a factor of three.

    After this lesson you can: count the edges per write and per read in the minimal slave, and name its limits and the fixes beyond the minimal design.

    Where the registers sit

    In the minimal slave every valid, data and response output is registered, while every ready is combinational. AWREADY and WREADY decode the pairing flags and BVALID; ARREADY is simply !RVALID.

    Each ready path decodes local registered state, with no combinational path from a channel input to its output here. That is a useful timing structure, but clock closure still requires target implementation and timing reports. A master must offer VALID without waiting for READY and hold VALID and payload until the handshake edge.

    Back-to-back transactions

    A new write half cannot be accepted while its response is pending: AWREADY and WREADY stay low until the B handshake clears BVALID. A new read address likewise waits until the R handshake clears RVALID.

    Count the edges in the listing for the best case with BREADY and RREADY always high. A write needs a capture edge, a commit edge that raises BVALID, and a clearing edge before the next address is accepted: three edges per write. A read needs a capture edge and a clearing edge: two edges per read.

    Each slot is one clock cycle. The master offers AW and W together and holds them, so VALID stands for both AWVALID and WVALID, and READY is AWREADY && WREADY. BREADY is high throughout. Call the edge that ends slot 0 edge E.

    • Slot 0: VALID and READY are both high, so the pair is captured at E.

    • Slot 1: READY drops because the pair flags are set. The commit happens at E+1.

    • Slot 2: BVALID is high and BREADY is high, so B is accepted at E+2.

    • Slot 3: READY returns and the second pair is captured at E+3. Three edges per write, not one.

    The read strip uses the same rule with one fewer step. The address is captured at the end of slot 0, RVALID is high in slot 1 and clears against RREADY, and ARREADY returns in slot 2 for the next capture: two edges per read.

    Why the minimal slave is slow

    Three limits serialize everything: one outstanding transaction per channel, no staging of the next address or data beat while a response is pending, and the pairing wait when AW and W arrive cycles apart.

    A faster AXI4-Lite slave can queue addresses and data, pipeline responses, and track several outstanding transactions without IDs. Responses must stay in order: pair queued AW and W entries in arrival order, retain each response until accepted, and return reads in accepted address order. This topic's minimal implementation deliberately accepts only one outstanding read and one outstanding write. IDs and response reordering are separate full-AXI features.

    Limit

    Cost in cycles

    Fix (beyond minimal)

    AW/W pairing

    Commit waits for the slower half

    Accept halves into FIFOs so channels never block each other

    B before next AW

    Three edges per write at best

    Pipeline responses; track multiple outstanding writes

    R before next AR

    Two edges per read at best

    Queue read addresses and pipeline in-order responses; no IDs required

    Common mistakes

    Common pitfall

    Assuming back-to-back means one transaction per cycle overcounts this slave by 3x on writes. The pairing flags plus the response handshake set the real rate: count capture, commit and clear edges instead of guessing.

    Interview

    Likely question: “Where is the throughput bottleneck in a minimal AXI-Lite slave?” One outstanding transaction per direction, response-gated readies, and the AW/W pairing wait. FIFOs and pipelined in-order responses permit multiple outstanding Lite transactions without adding IDs.

    Check yourself BREADY is high throughout. A write pair is captured on edge 10. On which edge is the next write address captured at the earliest?

    Edge 13: edge 11 commits and raises BVALID, edge 12 clears it against BREADY, and the readies return only after that edge.

    Check yourself When does a registered READY path pay off, and what does it cost?

    It pays off when the combinational ready fan-in grows too slow for the clock. It costs one cycle of handshake latency on that channel and a skid or FIFO to avoid dropping beats.

    Testbench

    The slave again with sixteen writes then sixteen reads. AW and W are offered independently at the earliest falling edge after each acceptance, with BREADY/RREADY always high. The checker counts actual rising-edge handshakes and requires three-edge spacing for AW, W and B, and two-edge spacing for AR and R. Best-case trace: capture pair at E, commit after E+1, accept B at E+2, capture next pair at E+3.

    axilite_regs.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    module axilite_regs #(
      parameter int AW = 8,
      parameter int DW = 32
    ) (
      input  logic             clk,
      input  logic             rst_n,
      input  logic             s_awvalid,
      output logic             s_awready,
      input  logic [AW-1:0]    s_awaddr,
      input  logic             s_wvalid,
      output logic             s_wready,
      input  logic [DW-1:0]    s_wdata,
      input  logic [DW/8-1:0]  s_wstrb,
      output logic             s_bvalid,
      input  logic             s_bready,
      output logic [1:0]       s_bresp,
      input  logic             s_arvalid,
      output logic             s_arready,
      input  logic [AW-1:0]    s_araddr,
      output logic             s_rvalid,
      input  logic             s_rready,
      output logic [DW-1:0]    s_rdata,
      output logic [1:0]       s_rresp
    );
      localparam [1:0] OKAY = 2'b00;
      localparam [1:0] SLVERR = 2'b10;
    
      if (DW != 32 || AW < 3) begin : g_bad_contract
        $error("axilite_regs requires DW=32 and AW>=3 (four-byte register stride)");
      end
    
      logic [DW-1:0] reg0, reg1;
      logic aw_seen, w_seen;
      logic [AW-1:0] awaddr_q;
      logic [DW-1:0] wdata_q;
      logic [DW/8-1:0] wstrb_q;
      logic [1:0] bresp_q, rresp_q;
    
      assign s_awready = !aw_seen && !s_bvalid;
      assign s_wready = !w_seen && !s_bvalid;
      assign s_arready = !s_rvalid;
      assign s_bresp = bresp_q;
      assign s_rresp = rresp_q;
    
      function automatic logic [DW-1:0] apply_wstrb(
        input logic [DW-1:0] old_v,
        input logic [DW-1:0] new_v,
        input logic [DW/8-1:0] strb
      );
        logic [DW-1:0] tmp;
        int i;
        begin
          tmp = old_v;
          for (i = 0; i < DW/8; i++) begin
            if (strb[i])
              tmp[i*8 +: 8] = new_v[i*8 +: 8];
          end
          apply_wstrb = tmp;
        end
      endfunction
    
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
          aw_seen <= 1'b0;
          w_seen <= 1'b0;
          awaddr_q <= '0;
          wdata_q <= '0;
          wstrb_q <= '0;
          s_bvalid <= 1'b0;
          bresp_q <= OKAY;
          s_rvalid <= 1'b0;
          rresp_q <= OKAY;
          s_rdata <= '0;
          reg0 <= '0;
          reg1 <= '0;
        end else begin
          if (s_awvalid && s_awready) begin
            aw_seen <= 1'b1;
            awaddr_q <= s_awaddr;
          end
          if (s_wvalid && s_wready) begin
            w_seen <= 1'b1;
            wdata_q <= s_wdata;
            wstrb_q <= s_wstrb;
          end
          if (aw_seen && w_seen && !s_bvalid) begin
            case (awaddr_q[AW-1:2])
              0: begin
                reg0 <= apply_wstrb(reg0, wdata_q, wstrb_q);
                bresp_q <= OKAY;
              end
              1: begin
                reg1 <= apply_wstrb(reg1, wdata_q, wstrb_q);
                bresp_q <= OKAY;
              end
              default: begin
                bresp_q <= SLVERR;
              end
            endcase
            s_bvalid <= 1'b1;
            aw_seen <= 1'b0;
            w_seen <= 1'b0;
          end
          if (s_bvalid && s_bready)
            s_bvalid <= 1'b0;
          if (s_arvalid && s_arready) begin
            case (s_araddr[AW-1:2])
              0: begin
                s_rdata <= reg0;
                rresp_q <= OKAY;
              end
              1: begin
                s_rdata <= reg1;
                rresp_q <= OKAY;
              end
              default: begin
                s_rdata <= '0;
                rresp_q <= SLVERR;
              end
            endcase
            s_rvalid <= 1'b1;
          end
          if (s_rvalid && s_rready)
            s_rvalid <= 1'b0;
        end
      end
    endmodule
    

    Remember

    • A write needs a capture edge, a commit edge that raises BVALID, and a clearing edge: three edges. A read needs a capture and a clearing edge: two.

    • Three limits serialise everything: one outstanding transaction per channel, no staging while a response is pending, and the AW/W pairing wait.

    • A faster slave can queue and pipeline, but responses must stay in order.

    How this was checked

    Source checker, run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It runs sixteen writes then sixteen reads with BREADY and RREADY always high, counts rising-edge handshakes, and requires three-edge spacing for AW, W and B and two-edge spacing for AR and R. Physical timing signoff is a separate step.

    Keep going

    • Interview: run a mock interview on this topic

    Related topics

    • A Minimal AXI-Lite Slave

    • AXI-Lite End to End into a CSR

    Previous

    205 / 350

    Next: AXI-Lite End to End into a CSR

    Up next

    Up nextAXI-Lite End to End into a CSR

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Channel Overview
    • A Minimal AXI-Lite Slave
    ACLKVALIDREADYBVALID
    Two back-to-back writes with BREADY high: the second pair is captured three edges after the first
    ACLKARVALIDARREADYRVALID
    Two back-to-back reads with RREADY high: the second address is captured two edges after the first