Skip to content

AMBA AXI · Module 15

AXI Write FSM

Design a robust full-AXI4 write-side state machine — accept the address (AW), stream the burst data beats (W) tracking WLAST and the beat count, commit to memory with WSTRB, and return exactly one B response — including the decoupled-AW/W and back-pressure corner cases.

Chapter 15.1's Lite write engine handled a single data beat. A full AXI4 write must handle a burst: one address (AW) followed by AWLEN+1 data beats on W, the last flagged by WLAST, all answered by exactly one B response. This chapter designs the write-side FSM rigorously — accept the address, stream and count the data beats while applying WSTRB per beat, detect the end of burst, and generate a single response — and works through the corner cases that separate a textbook sketch from a robust engine: AW and W arriving decoupled or simultaneously, the manager stalling mid-burst, and WLAST consistency. This is the engine inside every AXI4 slave and the write path of every interconnect port.

1. What the Write FSM Must Do

The write side has three jobs, sequenced but partly overlapping: capture the burst address/parameters from AW; receive the data beats from W, counting them and honoring WSTRB, until WLAST; then emit one B response carrying the aggregate status. Unlike Lite, the data phase is multi-beat, so the FSM must track which beat it's on and compute each beat's target address from the burst type (INCR/WRAP/FIXED).

AW descriptor feeds address generator and beat counter; W beats with WSTRB and WLAST stream into memory; one B response returns after the last beat.AW captureaddr/len/size/typeAddress genper-beat addressBeat counter0 … AWLENW beatsWDATA + WSTRBCommitWSTRB-masked writeB responseone per burst12
Figure 1 — the write engine's responsibilities. The AW channel delivers the burst descriptor (address, length, size, type); the W channel streams AWLEN+1 data beats under WSTRB, the last marked WLAST; a beat counter and address generator place each beat; and exactly one B response is returned after the final beat is committed. The data phase is the multi-beat part absent in AXI4-Lite.

2. The State Machine

A clean four-state FSM captures the flow: IDLE (wait for / accept AW), DATA (stream W beats, counting until WLAST), RESP (assert BVALID until BREADY), with AW capture allowed to happen early. Because AW and W are independent, the engine latches the address whenever AW handshakes and gates the data phase on having an address.

Write FSM: IDLE to DATA on AW captured, DATA self-loop per W beat, DATA to RESP on WLAST, RESP to IDLE on BREADY.AW capturedW beat (count++)WLASTBREADYIDLEDATARESP
Figure 2 — the write FSM. IDLE captures the AW burst descriptor; DATA accepts W beats, applying WSTRB and incrementing the beat counter on each WREADY/WVALID, staying until the beat marked WLAST (which must coincide with the final count); RESP asserts BVALID with the aggregate response and holds until BREADY, then returns to IDLE for the next burst.
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
typedef enum logic [1:0] { W_IDLE, W_DATA, W_RESP } wstate_e;
wstate_e wstate;
 
logic [ADDR_W-1:0] addr_q;          // current beat address
logic [7:0]        len_q;           // AWLEN latched
logic [7:0]        beat_q;          // beats accepted so far
logic [2:0]        size_q;
logic [1:0]        burst_q;
logic [1:0]        bresp_q;         // accumulated response
 
assign s_awready = (wstate == W_IDLE);
assign s_wready  = (wstate == W_DATA);
 
always_ff @(posedge aclk) begin
  if (!aresetn) begin
    wstate <= W_IDLE; beat_q <= '0; s_bvalid <= 1'b0; bresp_q <= 2'b00;
  end else case (wstate)
    W_IDLE: if (s_awvalid && s_awready) begin
      addr_q  <= s_awaddr; len_q <= s_awlen; size_q <= s_awsize;
      burst_q <= s_awburst; beat_q <= '0; bresp_q <= 2'b00;
      wstate  <= W_DATA;
    end
    W_DATA: if (s_wvalid && s_wready) begin
      // commit this beat (WSTRB-masked) at addr_q; accumulate any error
      bresp_q <= bresp_q | beat_resp;
      addr_q  <= next_addr(addr_q, size_q, burst_q, len_q);  // INCR/WRAP/FIXED
      beat_q  <= beat_q + 8'd1;
      if (s_wlast) begin
        s_bvalid <= 1'b1; s_bresp <= bresp_q | beat_resp;
        wstate   <= W_RESP;
      end
    end
    W_RESP: if (s_bvalid && s_bready) begin
      s_bvalid <= 1'b0; wstate <= W_IDLE;
    end
  endcase
end

3. The Burst on the Wire

A length-4 INCR write shows the timing: one AW handshake, four W beats (the fourth with WLAST), then one B. The manager may stall WVALID mid-burst; the slave simply holds WREADY and waits — the beat counter only advances on a completed handshake.

4-beat INCR write burst

9 cycles
One AW handshake, four W beats with a mid-burst stall, WLAST on the fourth beat, then one B response OKAY.AWW beats (stall @4)WLASTB = OKAYmanager stallmanager stalllast beatlast beatACLKAWVALIDAWREADYWVALIDWREADYWDATA..D0 D1 .WLASTBVALIDBRESP......OK BREADYt0t1t2t3t4t5t6t7t8
Figure 3 — a 4-beat INCR write burst. AW handshakes once (cycle 1). Four W beats transfer (cycles 2–6) with a manager stall at cycle 4 where WVALID drops — no beat is counted that cycle. WLAST marks the fourth beat (cycle 6). After the last beat commits, BVALID asserts with BRESP=OKAY (cycle 7) and is accepted by BREADY. One address, four data beats, one response.

4. The Corner Cases That Matter

A robust write FSM must get these right — they're where naive engines break:

  • Decoupled AW/W. W data can arrive before AW (a manager that buffers data), or AW long before any W. The engine must not assume order; latch AW when it comes and only consume W once an address is in hand (or buffer early W beats). The two-flag approach generalizes: don't gate W on AW in the same cycle.
  • Mid-burst stalls. Either side may stall: the manager drops WVALID, or the slave drops WREADY (e.g. backpressure from memory). The beat counter advances only on WVALID && WREADY; nothing else.
  • WLAST consistency. WLAST must assert on exactly beat AWLEN (counting from 0). A robust slave either trusts the count (and treats a mismatched WLAST as a protocol error) or uses WLAST as the authority — but the two must agree; a disagreement is a real bug worth flagging.
  • One response only. Exactly one B per burst, after the final beat commits, held until BREADY. Emitting B early (before WLAST) or emitting two responses corrupts the manager's outstanding tracking.
  • Error accumulation. If any beat errors (e.g. a DECERR/SLVERR condition), the single B reports the aggregate — typically the "worst" response across the burst — since there's only one response for the whole transaction.
Five corner cases: decoupled AW/W, mid-burst stalls, WLAST consistency, one response, error accumulation.Decoupled AW/Wany orderMid-burst stallscount on handshake onlyWLAST = countmust agreeOne Bafter final beatError accumulateworst across burstRobust engineall five handled12
Figure 4 — the corner-case checklist for a robust write FSM. Decoupled AW/W ordering, mid-burst stalls on either side, WLAST-vs-count consistency, exactly-one B response, and error accumulation across beats into a single response. Each is a common failure point; a write engine that handles all five is protocol-robust.

5. Common Misconceptions

6. Debugging Insight

7. Verification Insight

8. Interview Questions

9. Summary

The AXI4 write FSM turns one address and a stream of data beats into exactly one response. IDLE captures the AW burst descriptor (address, length, size, type); DATA accepts W beats — committing each WSTRB-masked beat at a per-beat address derived from the burst type, advancing the beat counter only on a completed WVALID && WREADY handshake, and accumulating any beat error — until the beat marked WLAST; RESP asserts a single BVALID with the aggregate response and holds it until BREADY. The defining differences from the Lite engine are the multi-beat data phase (counting, per-beat addressing, per-beat WSTRB) and the requirement of exactly one aggregated response for the whole burst.

Robustness lives in the corner cases: decoupled AW/W (never assume ordering), mid-burst stalls on either side (count on handshake only), WLAST/count consistency (they must agree — flag mismatches), one response only (after the final commit, held until accepted), and error accumulation (the single B reports the worst beat). Verification sweeps burst length × type, injects stalls at every position, exercises AW/W ordering, and asserts the count-equals-length and one-response invariants. Next, we design the symmetric read-side engine — one address, many data beats with RLAST, and no separate response channel.

10. What Comes Next

You've built the write engine; next comes its mirror image, the read engine:

  • 15.4 — AXI Read FSM (coming next) — the read-side state machine: one AR, a stream of R beats carrying both data and per-beat response, ending on RLAST — and why it's simpler than the write side.

Previous: 15.2 — AXI4-Lite Register Bank. Related: 3.1 — AXI4 Write Channel for the channel basics, 7.1 — Burst Fundamentals and 7.5 — Burst Address Calculation for the per-beat addressing, and 6.7 — Write Strobes (WSTRB) for byte enables.