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).
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.
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
end3. 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 cycles4. The Corner Cases That Matter
A robust write FSM must get these right — they're where naive engines break:
- Decoupled AW/W.
Wdata can arrive beforeAW(a manager that buffers data), orAWlong before anyW. The engine must not assume order; latchAWwhen it comes and only consumeWonce an address is in hand (or buffer earlyWbeats). The two-flag approach generalizes: don't gateWonAWin the same cycle. - Mid-burst stalls. Either side may stall: the manager drops
WVALID, or the slave dropsWREADY(e.g. backpressure from memory). The beat counter advances only onWVALID && WREADY; nothing else. - WLAST consistency.
WLASTmust assert on exactly beatAWLEN(counting from 0). A robust slave either trusts the count (and treats a mismatchedWLASTas a protocol error) or usesWLASTas the authority — but the two must agree; a disagreement is a real bug worth flagging. - One response only. Exactly one
Bper burst, after the final beat commits, held untilBREADY. EmittingBearly (beforeWLAST) or emitting two responses corrupts the manager's outstanding tracking. - Error accumulation. If any beat errors (e.g. a
DECERR/SLVERRcondition), the singleBreports the aggregate — typically the "worst" response across the burst — since there's only one response for the whole transaction.
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 ofRbeats carrying both data and per-beat response, ending onRLAST— 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.