Use AHB when you need burst bandwidth but only one or two masters. Use APB for every register-mapped peripheral. Use AXI when you cross into a high-performance, high-latency, out-of-order world.
// Address phase (driven by master)
HCLK // single clock
HRESETn // active-low reset
HADDR [31:0]
HTRANS[1:0] // 00 IDLE, 01 BUSY,
// 10 NONSEQ, 11 SEQ
HWRITE
HSIZE [2:0] // 001 halfword, 010 word, 011 dword…
HBURST[2:0] // SINGLE, INCR, WRAP4/8/16, INCR4/8/16
HPROT [3:0] // cacheable, bufferable, privileged, D/I
HMASTLOCK
// Data phase (driven by master/slave)
HWDATA[31:0] // master → slave
HRDATA[31:0] // slave → master
HREADY // slave: xfer complete
HRESP [1:0] // OKAY, ERROR, RETRY, SPLIT
HSEL_x // per-slave, decoded from HADDR
HREADY is low.HREADY low to extend the current data phase — and by the pipelining rule, that also extends the address phase of the next transfer.HREADYOUT; a global mux ORs all slaves and the bus's overall HREADY comes back to every master.HREADYOUT = 1; only the addressed slave may pull it low.HREADY = HREADYOUT of the selected slave (no arbitration).If a slave can always complete a data phase in one cycle, it simply ties HREADYOUT high — and the pipelined bus runs at peak.
Flash or external RAM drops HREADYOUT until its own timing is met. The master sees the whole bus stall — an intentional design point for MCU-class systems where worst-case stalls are rare.
| HBURST | Name | Length | Address step |
|---|---|---|---|
| 000 | SINGLE | 1 | — |
| 001 | INCR | undefined | by HSIZE |
| 010 | WRAP4 | 4 | wraps at 4·HSIZE |
| 011 | INCR4 | 4 | by HSIZE |
| 100 | WRAP8 | 8 | wraps at 8·HSIZE |
| 101 | INCR8 | 8 | by HSIZE |
| 110 | WRAP16 | 16 | wraps at 16·HSIZE |
| 111 | INCR16 | 16 | by HSIZE |
Cache line fills. A cache-line miss wants the critical word first, then the remaining words in wrap-around order — so the CPU gets data it can use on the first beat.
WRAP4 at address 0x08 with HSIZE=word gives 0x08 → 0x0C → 0x00 → 0x04.
INCR is useful when the master doesn't know in advance how long the burst will be (e.g. DMA serving a FIFO) — it simply starts with NONSEQ, continues with SEQ, and ends by issuing IDLE or a new NONSEQ on a different address.
| HRESP[1:0] | Name | Meaning |
|---|---|---|
| 00 | OKAY | Normal success |
| 01 | ERROR | Transfer failed (bus error) |
| 10 | RETRY | Master must retry later (AHB only) |
| 11 | SPLIT | Slave will release bus & raise HSPLITx(n) when ready |
AHB-Lite has only OKAY and ERROR — the RETRY / SPLIT machinery was removed as part of the simplification.
A slow slave (e.g. a memory controller waiting on an off-chip burst) could respond SPLIT. The arbiter would remove that master from arbitration until the slave asserted HSPLITx[n] for that master number — like a credit-return.
This let other masters continue using the bus during the long latency. Conceptually close to AXI's out-of-order IDs — the same idea, older implementation.
HBUSREQx, HLOCKx (atomic lock), HGRANTx.HMASTER[3:0] so slaves can identify who's talking (important for SPLIT).For multi-master MCU designs, Arm published multi-layer AHB (2002) — a simple interconnect of AHB-Lite masters crossbarred onto AHB slaves. No shared single-master view; each master has its own port into the fabric.
When TrustZone for Armv8-M arrived in 2016 (Cortex-M23, M33), the core internally produced Secure/Non-Secure transactions — and that security attribute had to propagate through the AHB fabric to the MPU / bus matrix / APB bridge.
PCLK // single clock
PRESETn // active-low reset
PADDR [31:0]
PSEL_x // per-slave select
PENABLE // two-phase indicator
PWRITE
PWDATA[31:0]
PRDATA[31:0]
PREADY // (APB3+) slave ack
PSLVERR // (APB3+) error
PPROT [2:0] // (APB4+) secure/priv/data
PSTRB [3:0] // (APB4+) byte strobes
PNSE / PWAKEUP // (APB5) security / wake
| Version | Year | Added signals / features |
|---|---|---|
| APB2 | 1996 | Baseline. PSEL/PENABLE/PWRITE/PADDR/P{W,R}DATA. Slaves had to complete in 1 cycle. |
| APB3 | 2003 | PREADY (wait states), PSLVERR (error response). |
| APB4 | 2010 | PPROT[2:0] (data/inst, privileged, secure). PSTRB[3:0] (byte strobes). |
| APB5 | 2015 | PWAKEUP (low-power wake), PNSE (RME Non-secure-extended), user signals, PPROT[2]=NS harmonised. |
A UART with 8 registers at 100 kHz doesn't need burst transfers, out-of-order IDs, or cache coherency. It needs a clocked 32-bit interface with byte-strobed writes and an ack.
APB4 gives you exactly that in ~10 signals. It's the reason every SoC has at most one APB master (an AHB-to-APB bridge) but can have hundreds of APB slaves.
Many bridges also perform a clock-domain crossing — AHB at CPU speed (e.g. 200 MHz), APB at a slow peripheral clock (e.g. 25 MHz).
The bridge buffers one AHB request at a time, synchronises it across to PCLK, runs the APB transaction, and synchronises the result back. No address pipelining across the bridge.
module ahb_lite_sram #(parameter ADDR_W = 12) (
input logic HCLK,
input logic HRESETn,
input logic HSEL,
input logic [31:0] HADDR,
input logic [1:0] HTRANS,
input logic HWRITE,
input logic [2:0] HSIZE,
input logic [31:0] HWDATA,
output logic [31:0] HRDATA,
output logic HREADYOUT,
output logic [1:0] HRESP
);
logic [31:0] mem [0:(1<<ADDR_W)-1];
logic [ADDR_W-1:0] addr_q;
logic write_q, sel_q;
// Sample address phase
always_ff @(posedge HCLK or negedge HRESETn)
if (!HRESETn) {sel_q, write_q, addr_q} <= '0;
else if (HREADYOUT) begin
sel_q <= HSEL && HTRANS[1]; // NONSEQ or SEQ
write_q <= HWRITE;
addr_q <= HADDR[ADDR_W+1:2]; // word addr
end
// Data phase
always_ff @(posedge HCLK)
if (sel_q && write_q) mem[addr_q] <= HWDATA;
assign HRDATA = sel_q && !write_q ? mem[addr_q] : '0;
assign HREADYOUT = 1'b1; // zero-wait-state slave
assign HRESP = 2'b00; // OKAY
endmodule
Single-port SRAM, zero wait states, OKAY only. Real peripherals add HSIZE handling, PROT checks, and byte strobes.
A slave that latches HADDR unconditionally will misfire on IDLE / BUSY cycles. Always gate on HSEL && HTRANS[1] && HREADY.
Idle slaves must drive HREADYOUT = 1; if a slave tristates or drives 0, the whole bus hangs.
AHB mandates a two-cycle ERROR: in the first data cycle drive HRESP=ERROR with HREADY=0, and in the second drive HRESP=ERROR with HREADY=1. Miss this and the master's fault-handler behaves incorrectly.
If an APB slave misbehaves and never asserts PREADY, the bridge — and thus the whole AHB above it — stalls indefinitely. Most bridges implement a watchdog that forces PSLVERR on timeout.
All beats in an AHB burst must share HSIZE. A half-word + word burst is protocol-illegal — split into two bursts instead.
AHB forbids a burst from crossing a 1 KB boundary. Masters must split longer transfers. Slaves should assert ERROR if they see one anyway.
| Dimension | AHB-Lite | AXI4 |
|---|---|---|
| Channels | 1 (address+data shared phases) | 5 independent |
| Out-of-order | No | Yes, via AxID |
| Outstanding transactions | 1 | Many (implementation limit) |
| Burst length | ≤16 | ≤256 |
| Typical area | Very small | Larger |
| Power | Easy to clock-gate | Needs more care |
| Good for | MCUs, register mgmt | High-BW masters |
Use AHB-Lite where the source traffic is bursty but low-latency (MCU CPU misses to TCM). Use AXI where the source is high-throughput and latency-tolerant (DMA, GPU, NIC, NPU).
module apb_loopback_reg (
input logic PCLK, PRESETn,
input logic PSEL, PENABLE, PWRITE,
input logic [31:0] PADDR, PWDATA,
output logic [31:0] PRDATA,
output logic PREADY, PSLVERR
);
logic [31:0] r_q;
always_ff @(posedge PCLK or negedge PRESETn)
if (!PRESETn) r_q <= 32'h0;
else if (PSEL && PENABLE && PWRITE) r_q <= PWDATA;
assign PRDATA = r_q;
assign PREADY = 1'b1; // always ready (zero wait states)
assign PSLVERR = 1'b0;
endmodule
This really is the minimum: one flop, three combinational outputs. PREADY tied high makes every access a two-cycle SETUP/ACCESS round-trip.
module apb_status_ro #(parameter W = 32) (
input logic PCLK, PRESETn,
input logic PSEL, PENABLE,
input logic [W-1:0] status_i, // external live signal
output logic [31:0] PRDATA,
output logic PREADY, PSLVERR
);
assign PRDATA = {{(32-W){1'b0}}, status_i}; // pure wires
assign PREADY = 1'b1;
assign PSLVERR = 1'b0;
endmodule
For HW bring-up silicon: a mask-ROM'd APB slave often returns a fixed "MAGIC" word so the first boot-check is just if (*APB_BASE == 0xDEADBEEF) go;
Arm Ltd. — AMBA AHB Protocol Specification (IHI 0033) — includes AHB, AHB-Lite, and AHB5
Arm Ltd. — AMBA APB Protocol Specification (IHI 0024) — APB, APB3, APB4, APB5
Arm Ltd. — AMBA Multi-Layer AHB Overview (ARM IHI 0048)
Arm Ltd. — Cortex-M3 Technical Reference Manual — how the CPU presents its AHB-Lite ports
Yiu, J. — The Definitive Guide to ARM Cortex-M3/M4 Processors — chapters on bus interface and memory system
Flynn, D. & Luke, S. — AMBA AHB — enabling bus-based SoC design (IEEE Micro, 1997)
Ashenden, P. — The Designer's Guide to VHDL & Digital Design Using VHDL — example AHB-Lite / APB slave implementations
STMicroelectronics — STM32F4 Reference Manual (RM0090) — canonical example of AHB / APB1 / APB2 hierarchy
ARM DUI 0552A — Cortex-M MCU system-bus design guide — multi-layer AHB examples
Presentation built with Reveal.js 4.6 · Playfair Display + DM Sans + JetBrains Mono
Educational use.