AMBA Protocol

AHB – Advanced High-performance Bus

AHB (Advanced High-performance Bus) is the AMBA 2 pipelined on-chip bus that bridges the gap between the simple APB and the full AXI4. Its overlapping address-and-data pipeline, burst support, and multi-master arbitration make it the standard interconnect for mid-performance SoC subsystems — processor-to-memory paths, DMA controllers, and on-chip ROM/SRAM interfaces.

Standard — AMBA 2 AHB / AMBA 5 AHB5 (Arm)
Topology — Shared bus, multi-master
Pipeline — 2-stage (address + data)
Max Burst — 16 beats (INCR16 / WRAP16)
Flow Control — HREADY wait states

Overview & Pipeline

The key performance advantage of AHB over APB is its two-stage pipeline. While the data phase of one transfer is in progress, the address phase of the next transfer is already being presented. This keeps the bus active every cycle rather than spending idle cycles re-presenting addresses.

T1 T2 T3 T4 T5 Transfer A Transfer B Transfer C ADDR A DATA A ADDR B DATA B ADDR C DATA C ▲ overlap: ADDR B & DATA A same cycle

Because address and data overlap, a slave must register the address signals on the cycle they appear (the address phase) and use them during the following cycle (the data phase) when HWDATA or HRDATA is valid.

AHB vs APB vs AXI4: APB is non-pipelined (3-cycle minimum per transfer, no burst). AHB is pipelined with a central shared bus and burst up to 16. AXI4 uses 5 independent channels and supports bursts up to 256 — but at the cost of much greater complexity. AHB sits naturally between them in both bandwidth and complexity.

Signal Reference

SignalDirWidthPhaseDescription
HCLK1Bus clock. All signals sampled on rising edge.
HRESETn1Active-low bus reset.
HADDR[31:0]M→S32AddressTransfer address. Presented one cycle before data.
HTRANS[1:0]M→S2AddressTransfer type: IDLE, BUSY, NONSEQ, SEQ.
HWRITEM→S1Address1 = write, 0 = read.
HSIZE[2:0]M→S3AddressTransfer size: 0=byte, 1=halfword, 2=word, 3=doubleword …
HBURST[2:0]M→S3AddressBurst type: SINGLE, INCR, WRAP4/8/16, INCR4/8/16.
HPROT[3:0]M→S4AddressProtection: [0] privileged, [1] bufferable, [2] cacheable, [3] allocate.
HSELdecoder→S1AddressSlave select from address decoder. Indicates this slave is targeted.
HWDATA[31:0]M→S32+DataWrite data. Valid one cycle after address phase.
HRDATA[31:0]S→M32+DataRead data returned by slave during data phase.
HREADYmux→M/S1DataBus ready signal (multiplexed from all slaves). LOW extends the data phase.
HREADYOUTS→mux1DataSlave's own ready output, fed into the bus multiplexer.
HRESP[1:0]S→M1 or 2DataTransfer response: OKAY / ERROR (+ RETRY / SPLIT in full AHB).

HTRANS — Transfer Types

HTRANS tells the slave what kind of transfer is currently on the address bus.

HTRANS[1:0]NameMeaning
2'b00IDLENo transfer. Master has nothing to send. Slave must respond OKAY but ignore the access.
2'b01BUSYMaster is mid-burst but needs to insert a wait (e.g., waiting for data from cache). Slave ignores this beat but the burst continues.
2'b10NONSEQStart of a new burst, or a single transfer. Address and control signals are unrelated to any previous transfer.
2'b11SEQSubsequent beat of an ongoing burst. Address is derived from the previous beat's address + transfer size.

A slave only needs to act on NONSEQ and SEQ. IDLE and BUSY are informational — a well-designed slave ignores them and always returns OKAY with HREADYOUT=1 during those phases.

HBURST — Burst Types

HBURST[2:0]NameBeatsAddressUse Case
3'b000SINGLE1FixedSingle non-burst transfer
3'b001INCRUndefinedIncrementingUndefined-length incremental burst (master decides when to stop)
3'b010WRAP44Wrap at 4-beat boundaryCache-line fill (4-word cache)
3'b011INCR44Incrementing4-beat sequential burst
3'b100WRAP88Wrap at 8-beat boundaryCache-line fill (8-word cache)
3'b101INCR88Incrementing8-beat sequential burst
3'b110WRAP1616Wrap at 16-beat boundaryCache-line fill (16-word cache)
3'b111INCR1616Incrementing16-beat sequential burst

WRAP bursts are used for cache-line fills: the processor requests the critical word first, then the burst wraps around the cache-line boundary so all words are fetched in the minimum number of cycles. INCR bursts are general-purpose sequential accesses with no boundary constraint.

Write Transfer Timing

A 3-beat INCR3 write burst. The address of beat N+1 appears on the bus during the data phase of beat N.

HCLK HADDR HTRANS HWRITE HWDATA HREADY

Read Transfer Timing

For a read, the slave presents HRDATA during the data phase. The master samples HRDATA on the rising edge when HREADY is HIGH.

HCLK T1 T2 T3 T4 T5 HADDR prev A0 A1 next HTRANS IDLE NONSEQ SEQ IDLE HWRITE 0 (read) HRDATA D0 D1 HREADY 1 addr A0 D0 valid D1 valid

Wait States (HREADY)

A slave extends its data phase by driving HREADYOUT LOW. The bus multiplexer propagates this as HREADY LOW to the master. The master must hold all address-phase signals stable (HADDR, HTRANS, HWRITE, HSIZE, HBURST) and not advance to the next transfer until HREADY returns HIGH.

HCLK HADDR prev A0 (held stable) A1 HRDATA not ready D0 valid HREADY wait states (HREADY=0) HREADY=1 → transfer completes

Multiple wait states can be inserted by keeping HREADY LOW for additional cycles. There is no protocol-defined maximum, but practical designs limit wait states to avoid starving other masters.

HRESP — Response Codes

HRESPNameAvailabilityMeaning
1'b0 / 2'b00OKAYAHB & AHB-LiteTransfer completed successfully.
1'b1 / 2'b01ERRORAHB & AHB-LiteTransfer failed. Slave must drive HREADY LOW for one extra cycle before ERROR, giving the master time to sample it cleanly.
2'b10RETRYFull AHB onlySlave cannot complete the transfer now — master should retry. Typically used for split transactions while the slave fetches data.
2'b11SPLITFull AHB onlySlave releases the bus and will signal the arbiter when it is ready to resume. Allows other masters to use the bus during a long memory access.

ERROR response protocol: When a slave needs to signal ERROR, it first drives HREADY LOW and HRESP=ERROR for one cycle, then drives HREADY HIGH and HRESP=ERROR for the second cycle. The two-cycle sequence ensures the master has a full cycle to sample the response before the bus moves on.

AHB vs AHB-Lite

AHB-Lite (defined in AMBA 3) is a single-master subset of full AHB. It removes the arbiter, multi-master bus grant signals, and RETRY/SPLIT responses. It is the version used in the vast majority of modern Cortex-M based SoCs because most embedded designs have a single bus master (the CPU) plus a DMA controller that can be handled separately.

FeatureFull AHBAHB-Lite
MastersMultiple (arbiter required)Single
Arbiter signalsHBUSREQ, HGRANT, HLOCK, HMASTERNot present
HRESP width2-bit (OKAY/ERROR/RETRY/SPLIT)1-bit (OKAY=0 / ERROR=1)
SPLIT responseSupportedNot supported
RETRY responseSupportedNot supported
ComplexityHigherLower
Typical useHigh-end multi-master SoCsCortex-M microcontrollers, embedded SoCs

Verilog RTL — AHB-Lite Slave (Register File)

A minimal AHB-Lite slave with a 4×32-bit register file. The key detail is latching address-phase signals at the end of the address phase so they are available during the data phase.

Verilog ahb_lite_slave.v
module ahb_lite_slave (
  input  wire        HCLK,
  input  wire        HRESETn,

  // Address phase inputs (registered on rising edge when HREADY=1)
  input  wire        HSEL,
  input  wire [31:0] HADDR,
  input  wire        HWRITE,
  input  wire [1:0]  HTRANS,
  input  wire [2:0]  HSIZE,
  input  wire        HREADY,     // bus HREADY in

  // Data phase
  input  wire [31:0] HWDATA,
  output reg  [31:0] HRDATA,
  output wire        HREADYOUT,  // slave ready (1 = no wait)
  output wire        HRESP       // 0=OKAY 1=ERROR (AHB-Lite)
);

  // Always ready, always OKAY for this simple slave
  assign HREADYOUT = 1'b1;
  assign HRESP     = 1'b0;

  // Latch address-phase signals at end of address phase
  reg        lat_sel, lat_write;
  reg [31:0] lat_addr;
  reg [1:0]  lat_trans;

  always @(posedge HCLK) begin
    if (!HRESETn) begin
      lat_sel   <= 1'b0;
      lat_write <= 1'b0;
      lat_addr  <= 32'h0;
      lat_trans <= 2'b00;
    end else if (HREADY) begin   // sample only when bus is free
      lat_sel   <= HSEL;
      lat_write <= HWRITE;
      lat_addr  <= HADDR;
      lat_trans <= HTRANS;
    end
  end

  // 4-register file
  reg [31:0] regs [0:3];
  wire [1:0] reg_idx = lat_addr[3:2];
  wire       valid   = lat_sel && (lat_trans[1] == 1'b1); // NONSEQ or SEQ

  // Write — data phase
  integer i;
  always @(posedge HCLK) begin
    if (!HRESETn) begin
      for (i = 0; i < 4; i = i + 1) regs[i] <= 32'h0;
    end else if (valid && lat_write && HREADY)
      regs[reg_idx] <= HWDATA;
  end

  // Read — combinational
  always @(*) begin
    if (valid && !lat_write)
      HRDATA = regs[reg_idx];
    else
      HRDATA = 32'h0;
  end

endmodule

Critical design rule: Always latch HSEL, HADDR, HWRITE, and HTRANS at the end of the address phase (when HREADY is HIGH). These signals change to the next transfer's values in the following cycle, but HWDATA for the current write arrives later — so you must remember what the address was.

Interview Q&A

How does the AHB pipeline differ from APB?
APB is non-pipelined: it uses a dedicated setup cycle followed by an access cycle, so every transfer takes at least 2 cycles plus any PREADY wait states, and the next transfer cannot begin until the current one is fully complete. AHB is pipelined: the address of the next transfer is driven onto the bus during the data phase of the current one, so back-to-back transfers take just one cycle each (ignoring wait states). This makes AHB roughly 2× more efficient for sequential accesses.
Why must an AHB slave latch the address-phase signals?
Because AHB is pipelined, HADDR, HWRITE, HTRANS, and HSEL are already presenting the next transfer's information during the cycle when HWDATA is valid for the current write. If the slave reads HADDR directly during the data phase, it will see the wrong address. The slave must register the address-phase signals on the clock edge when HREADY is HIGH at the end of the address phase, and then use those registered values when processing HWDATA in the subsequent data phase.
What is the BUSY transfer type used for?
BUSY is inserted by a master that is mid-burst but temporarily cannot supply the next address — for example, a CPU whose pipeline has stalled waiting for data from a cache miss. The BUSY transfer holds the current burst open without advancing the address, so the slave knows the burst is not finished. The slave must ignore the BUSY beat (treat it like IDLE) and the burst resumes with SEQ when the master is ready again. BUSY can only appear inside a burst, never as the first beat.
What is the difference between WRAP and INCR bursts?
Both INCR and WRAP bursts increment the address by the transfer size each beat. The difference is address wrapping: INCR bursts increment without any boundary constraint (address simply keeps growing). WRAP bursts wrap the address back to the start of the aligned cache-line boundary when the address reaches the end of the line. For example, a WRAP4 burst starting at address 0x08 on a 32-bit bus wraps at 0x10 — so the sequence is 0x08 → 0x0C → 0x00 → 0x04, filling a 16-byte cache line with the critical word first.
How does AHB handle an ERROR response?
An AHB slave signals ERROR over two cycles. In the first cycle it drives HREADYOUT LOW and HRESP=ERROR — this inserts a wait state so the master has time to sample the error cleanly. In the second cycle it drives HREADYOUT HIGH and HRESP=ERROR, and the master samples the error on that rising edge. The two-cycle sequence is mandatory in the AHB specification; a single-cycle ERROR is not allowed. After an ERROR, the master must abort the current burst.
What signals does AHB-Lite remove compared to full AHB?
AHB-Lite removes all multi-master arbitration signals: HBUSREQ (master bus request), HGRANT (arbiter grant), HLOCK (locked transfer sequence), HMASTER (master ID tag), and HMASTLOCK. It also removes SPLIT and RETRY response codes, reducing HRESP to a single bit. The result is a much simpler interface suited to single-master designs such as Cortex-M microcontrollers where there is no need to arbitrate between competing masters.
Can a master terminate a burst early?
Yes, but only for undefined-length INCR bursts. A master can end an INCR burst at any point simply by driving HTRANS=IDLE (or NONSEQ for the next unrelated transfer) before completing all intended beats. Fixed-length bursts (INCR4, INCR8, INCR16, WRAPx) must be completed as specified — the master cannot stop early. If an interrupt or higher-priority event forces early termination of a fixed-length burst, the master must complete the remaining beats (optionally using BUSY to insert idle beats) before starting the new transaction.