AMBA AXI · Module 7
Burst Length, Size & Beats
The foundation of AXI data transfer — what a beat is, how burst length is AxLEN+1, how transfer size is 2^AxSIZE bytes per beat, the total-bytes formula, and the AXI3 vs AXI4 length limits.
AXI is a burst-based protocol: a single address transaction can move many data items. Module 6 introduced AxLEN and AxSIZE as signals; this module treats bursts as first-class, and it starts here with the three quantities every burst is built from — the beat, the burst length, and the transfer size. Getting these exactly right is foundational: every burst type, every per-beat address, the 4 KB rule, and narrow/unaligned handling in the rest of Module 7 are arithmetic on top of these definitions. This chapter pins down each term, the formulas that connect them, and the AXI3↔AXI4 limits.
1. The Beat — One Data Transfer
A beat is a single data transfer on a data channel — one successful VALID/READY handshake that moves up to one bus-width of data. On the write-data channel a beat is one WVALID&WREADY cycle carrying one WDATA word (with its WSTRB); on the read-data channel a beat is one RVALID&RREADY cycle carrying one RDATA word (with its RRESP). "Beat" is AXI's unit of data; a burst is just an ordered sequence of beats sharing one address transaction.
The width of a beat — how many bytes it can carry — is set by AxSIZE (Section 3), and is at most the data bus width. The number of beats is set by AxLEN (Section 2).
2. Burst Length — AxLEN + 1
The burst length is the number of beats in the burst, and it is AxLEN + 1. AxLEN is the encoded value, offset by one so that the minimum legal burst (one beat) is encoded as AxLEN = 0:
AxLEN | Beats in burst |
|---|---|
0 | 1 |
1 | 2 |
3 | 4 |
15 | 16 |
255 | 256 (AXI4 INCR only) |
The "+1" is the single most common off-by-one in AXI: a burst of 4 beats is AxLEN = 3, not 4. The field width — and therefore the maximum length — differs by version and burst type (Section 5).
3. Transfer Size — 2^AxSIZE Bytes per Beat
AxSIZE sets the number of bytes transferred per beat, as a power of two: bytes/beat = 2^AxSIZE. It must not exceed the data bus width.
AxSIZE | Bytes per beat |
|---|---|
0 | 1 |
1 | 2 |
2 | 4 |
3 | 8 |
4 | 16 |
5 | 32 |
6 | 64 |
7 | 128 |
A beat whose AxSIZE equals the full bus width is a full-width transfer (all byte lanes usable); a smaller AxSIZE is a narrow transfer that uses only some lanes each beat (Chapter 7.7). AxSIZE is fixed for the whole burst — every beat is the same size.
burst-beats — 4-beat burst (AxLEN=3), 4 bytes/beat (AxSIZE=2)
6 cycles4. Total Data and Why Bursts Exist
The total data a burst moves follows directly:
bytes transferred ≈ (AxLEN + 1) × 2^AxSIZE
i.e., beats × bytes-per-beat. (For INCR/WRAP the address advances across those bytes; for FIXED the same address is rewritten each beat — same byte count, different addressing, Chapter 7.2.) A full-width 64-bit bus (AxSIZE = 3, 8 bytes) doing a 16-beat burst (AxLEN = 15) moves 16 × 8 = 128 bytes from one address transaction.
That "one address transaction" is the whole point. Bursts amortize the address-phase and arbitration overhead across many beats: the manager arbitrates and issues an address once, then streams AxLEN+1 beats. This is what makes AXI efficient for memory and DMA traffic — without bursts, every data word would pay a full address handshake and arbitration round.
5. AXI3 vs AXI4 Length Limits
The maximum burst length depends on the version and the burst type:
AxLEN width | INCR max | FIXED / WRAP max | |
|---|---|---|---|
| AXI3 | 4 bits | 16 beats | 16 beats |
| AXI4 | 8 bits | 256 beats | 16 beats |
AXI4 widened AxLEN to 8 bits and raised the INCR ceiling to 256 beats, while FIXED and WRAP remain capped at 16 beats (a WRAP length must also be 2, 4, 8, or 16 — Chapter 7.4). AXI3's uniform limit was 16 beats for all types. This matters at AXI3↔AXI4 bridges: a 256-beat AXI4 INCR burst cannot pass through to an AXI3 side unchanged — it must be split into ≤16-beat bursts. (And independently of length, no burst may cross a 4 KB address boundary — Chapter 7.6.)
6. The Arithmetic in Code
The three quantities are worth writing down as functions, because every burst bug in §7 is one of these expressions computed wrongly. This is the address progression AMBA defines, for all three burst types.
// One place for the burst arithmetic. DATA_BYTES is the data bus width in bytes.
function automatic int beats_in_burst(input logic [7:0] axlen);
return int'(axlen) + 1; // the +1 encoding (§2)
endfunction
function automatic int bytes_per_beat(input logic [2:0] axsize);
return 1 << axsize; // 2^AxSIZE (§3)
endfunction
// Per-beat address. `beat` is 0-based: beat 0 is the first transfer.
// FIXED : every beat reuses the start address.
// INCR : beat 0 uses the (possibly unaligned) start address; every later
// beat is aligned to the transfer size, per the AMBA definition.
// WRAP : like INCR, but the address wraps back to the container's lower
// boundary once it reaches the upper one.
function automatic longint unsigned beat_address(
input longint unsigned start_addr,
input logic [7:0] axlen,
input logic [2:0] axsize,
input logic [1:0] axburst, // 00=FIXED 01=INCR 10=WRAP
input int beat
);
int nbytes = bytes_per_beat(axsize);
int nbeats = beats_in_burst(axlen);
longint unsigned aligned = (start_addr / nbytes) * nbytes;
case (axburst)
2'b00: beat_address = start_addr; // FIXED
2'b01: beat_address = (beat == 0) ? start_addr // INCR
: aligned + longint'(beat) * nbytes;
2'b10: begin // WRAP
longint unsigned container = longint'(nbeats) * nbytes;
longint unsigned lower = (start_addr / container) * container;
longint unsigned next = aligned + longint'(beat) * nbytes;
beat_address = lower + ((next - lower) % container);
end
default: beat_address = start_addr; // 2'b11 reserved
endcase
endfunctionTwo details in there are the ones people get wrong. INCR's first beat is not aligned — it uses the address the master drove, which may sit mid-word; only the subsequent beats step from the aligned base. And WRAP's container is beats × bytes_per_beat, not the bus width or the total transfer — which is exactly why WRAP lengths are restricted to 2, 4, 8 or 16 (§5): any other count would make the container a non-power-of-two and the wrap boundary would stop being a simple address mask. Where a burst may sit relative to a 4 KB page is a separate constraint entirely, developed in the 4 KB boundary rule.
7. Checking a Burst Is Legal
The rules stated in §2–§5 are all mechanically checkable. This is a passive checker — it observes an address channel and its data channel, and never drives anything.
// Passive. `DATA_BYTES` is this interface's data-bus width in bytes.
module axi_burst_legality #(parameter int DATA_BYTES = 8) (
input logic aclk, aresetn,
// address channel
input logic axvalid, axready,
input logic [7:0] axlen,
input logic [2:0] axsize,
input logic [1:0] axburst,
// data channel (R or W)
input logic dvalid, dready, dlast
);
// ---- NORMATIVE: a beat may not be wider than the bus ----
property p_size_fits_bus;
@(posedge aclk) disable iff (!aresetn)
(axvalid && axready) |-> ((1 << axsize) <= DATA_BYTES);
endproperty
// ---- NORMATIVE: WRAP length must be 2, 4, 8 or 16 beats ----
property p_wrap_length_legal;
@(posedge aclk) disable iff (!aresetn)
(axvalid && axready && axburst == 2'b10) |-> (axlen inside {1, 3, 7, 15});
endproperty
// ---- NORMATIVE: FIXED and WRAP are capped at 16 beats ----
property p_fixed_wrap_max16;
@(posedge aclk) disable iff (!aresetn)
(axvalid && axready && axburst != 2'b01) |-> (axlen <= 15);
endproperty
// ---- NORMATIVE: AxBURST 2'b11 is reserved ----
property p_burst_type_legal;
@(posedge aclk) disable iff (!aresetn)
(axvalid && axready) |-> (axburst != 2'b11);
endproperty
a_size_fits : assert property (p_size_fits_bus)
else $error("AxSIZE=%0d asks for %0d bytes/beat on a %0d-byte bus", axsize, 1<<axsize, DATA_BYTES);
a_wrap_len : assert property (p_wrap_length_legal)
else $error("WRAP burst with AxLEN=%0d (%0d beats) - must be 2/4/8/16", axlen, axlen+1);
a_fixed_wrap : assert property (p_fixed_wrap_max16)
else $error("Non-INCR burst longer than 16 beats (AxLEN=%0d)", axlen);
a_burst_type : assert property (p_burst_type_legal)
else $error("AxBURST = 2'b11 is reserved");
// ---- NORMATIVE: exactly AxLEN+1 beats, with LAST on the final one ----
// A counter is needed because the property spans the whole burst.
int expected, seen;
always_ff @(posedge aclk or negedge aresetn) begin
if (!aresetn) begin
expected <= 0;
seen <= 0;
end
else begin
if (axvalid && axready) begin
expected <= int'(axlen) + 1; // latch the promised beat count
seen <= 0;
end
if (dvalid && dready) begin
if (dlast) begin
// LAST must land on exactly the promised beat.
a_beat_count: assert (seen + 1 == expected)
else $error("burst ended on beat %0d but AxLEN promised %0d", seen + 1, expected);
seen <= 0;
end
else begin
// A non-LAST beat must not exceed the promised count.
a_no_overrun: assert (seen + 1 < expected)
else $error("beat %0d with no LAST - burst overran AxLEN+1 = %0d", seen + 1, expected);
seen <= seen + 1;
end
end
end
end
endmoduleWhat each property is for, and what its failure looks like. a_size_fits catches a master that confuses AxSIZE with a byte count — driving AxSIZE=4 on a 32-bit bus asks for 16 bytes per beat from a 4-byte interface, and the message prints both numbers so the confusion is obvious on sight. a_wrap_len catches the illegal WRAP length, which otherwise produces silently wrong addresses because the wrap container is no longer a power of two. a_beat_count and a_no_overrun are the pair that catch the +1 error, and they fail in opposite directions: a master encoding "4 beats" as AxLEN=4 sends five beats, so a_no_overrun fires on the fifth; a slave that asserts LAST a beat early trips a_beat_count instead. Which one fires tells you which side made the mistake.
A caution on scope: these are the checks that follow from this chapter's quantities. They do not constitute an AXI protocol checker — handshake stability lives with the VALID/READY handshake, boundary legality with the 4 KB rule, and lane-level behaviour with narrow and unaligned transfers.
8. Proving the Arithmetic
A short self-checking bench pins the three burst types against hand-computed addresses, and confirms the checker rejects the two classic illegal cases.
module tb_burst_math;
`include "axi_burst_math.svh"
int errors = 0;
task automatic chk(input longint unsigned got, exp, input string what);
if (got !== exp) begin
errors++;
$error("[FAIL] %s: got 0x%0h expected 0x%0h", what, got, exp);
end
endtask
initial begin
// ---- INCR: 4 beats x 4 bytes from an ALIGNED start 0x1000 ----
chk(beat_address(64'h1000, 8'd3, 3'd2, 2'b01, 0), 64'h1000, "INCR beat0");
chk(beat_address(64'h1000, 8'd3, 3'd2, 2'b01, 3), 64'h100C, "INCR beat3");
// ---- INCR from an UNALIGNED start: beat 0 keeps the odd address,
// later beats step from the aligned base 0x1000.
chk(beat_address(64'h1002, 8'd3, 3'd2, 2'b01, 0), 64'h1002, "INCR unaligned beat0");
chk(beat_address(64'h1002, 8'd3, 3'd2, 2'b01, 1), 64'h1004, "INCR unaligned beat1");
// ---- FIXED: every beat reuses the start address ----
chk(beat_address(64'h2000, 8'd3, 3'd2, 2'b00, 2), 64'h2000, "FIXED beat2");
// ---- WRAP: 4 beats x 4 bytes = 16-byte container based at 0x1000.
// Starting at 0x1008, beats run 1008, 100C, then WRAP to 1000, 1004.
chk(beat_address(64'h1008, 8'd3, 3'd2, 2'b10, 0), 64'h1008, "WRAP beat0");
chk(beat_address(64'h1008, 8'd3, 3'd2, 2'b10, 1), 64'h100C, "WRAP beat1");
chk(beat_address(64'h1008, 8'd3, 3'd2, 2'b10, 2), 64'h1000, "WRAP beat2 (wrapped)");
chk(beat_address(64'h1008, 8'd3, 3'd2, 2'b10, 3), 64'h1004, "WRAP beat3");
// ---- the quantities themselves ----
chk(beats_in_burst(8'd0), 1, "AxLEN=0 is ONE beat");
chk(beats_in_burst(8'd255), 256,"AxLEN=255 is 256 beats");
chk(bytes_per_beat(3'd3), 8, "AxSIZE=3 is 8 bytes");
if (errors == 0) $display("PASS - burst arithmetic matches the AMBA definition");
else $display("FAIL - %0d check(s) failed", errors);
$finish;
end
endmoduleThe WRAP case is the one worth reading twice. A 4-beat, 4-byte WRAP burst starting at 0x1008 does not run 1008, 100C, 1010, 1014 — it runs 1008, 100C, 1000, 1004, because the 16-byte container based at 0x1000 is the whole address space this burst may touch. That is the entire point of WRAP: a cache line fills starting at the critical word and wraps to collect the rest, never leaving the line. Get the container wrong and the burst silently reads the wrong memory, which no handshake check would ever notice.
9. Common Misconceptions
10. Debugging Insight
11. Verification Insight
12. Interview Questions
13. Summary
Every AXI burst is built from three quantities. A beat is a single VALID/READY data transfer — AXI's unit of data. The burst length is AxLEN + 1 beats (the +1 offset so 1 beat = AxLEN 0; mind the off-by-one). The transfer size is 2^AxSIZE bytes per beat, constant across the burst and never exceeding the bus width. Together they move (AxLEN+1) × 2^AxSIZE bytes from a single address transaction — and that amortization of address/arbitration overhead over many beats is the entire reason AXI is burst-based and efficient for memory and DMA. The limits differ by version: AXI3 caps every type at 16 beats; AXI4 raises INCR to 256 while FIXED/WRAP stay at 16 (WRAP ∈ 16).
These definitions are the arithmetic foundation for the rest of Module 7: the burst types (FIXED/INCR/WRAP), per-beat address calculation, the 4 KB boundary rule, and narrow/unaligned transfers are all computations on beats, length, and size. Debug and verify them by converting any symptom back to (AxLEN+1) beats and 2^AxSIZE bytes. Next: the first burst type, FIXED — where every beat reuses the same address.
14. What Comes Next
You've got the burst foundation; next, the three burst types, starting with FIXED:
- 7.2 — FIXED Bursts (coming next) — the burst where every beat reuses the same address, and its FIFO/peripheral use case.
- 7.3 — INCR Bursts (coming soon) — the incrementing workhorse for memory access.
Where these are specified. The burst quantities, the AxLEN+1 encoding, the per-beat address definitions for FIXED/INCR/WRAP and the version-dependent length limits are all defined in Arm's AMBA AXI Protocol Specification (IHI 0022). The address-progression definition in §6 is worth checking against the original once, because it is stated there more compactly than any tutorial can afford.
Previous: 6.8 — RESP & LAST Signals. Related: 6.1 — AxADDR, AxLEN & AxSIZE for the signals, and 6.2 — AxBURST for the burst-type selector. For the broader protocol catalog, see the AMBA family overview doc.