How a high-speed AXI4-Lite master talks to simple APB peripherals — the full block diagram, bridge FSM, write & read timing, and synthesizable Verilog RTL.
The CPU and high-bandwidth masters drive an AXI4-Lite bus. Low-speed control peripherals — UART, GPIO, timers, register blocks — live on the much simpler APB bus. The bridge is the translator between the two domains.
Five independent channels, VALID/READY handshakes, outstanding transactions. Great for CPUs and DMA, but heavy: every peripheral would need address-decode, response logic and 5 channels of plumbing.
One address, one data path, a two-phase (setup → access) transfer, no bursts, no outstanding. Tiny gate count. Perfect for registers, GPIO, UART — anything low-bandwidth.
Putting one bridge between the two means dozens of simple peripherals share a single AXI port. You pay the AXI cost once, at the bridge, instead of in every peripheral.
The bridge handles one transaction at a time. It waits in IDLE, drives the APB setup and access phases in ACCESS, then issues the AXI response.
An AXI write is accepted, then translated into an APB setup cycle (PSEL=1, PENABLE=0) followed by the access cycle (PENABLE=1). When PREADY is high the bridge raises BVALID.
| Channel | Signals |
|---|---|
| Write addr | AWADDR, AWVALID, AWREADY |
| Write data | WDATA, WSTRB, WVALID, WREADY |
| Write resp | BRESP, BVALID, BREADY |
| Read addr | ARADDR, ARVALID, ARREADY |
| Read data | RDATA, RRESP, RVALID, RREADY |
| Signal | Meaning |
|---|---|
| PADDR | Address to peripheral |
| PSEL | Slave select (setup+access) |
| PENABLE | Access phase strobe |
| PWRITE | 1=write, 0=read |
| PWDATA | Write data |
| PRDATA | Read data back |
| PREADY | Slave ready / done |
| PSLVERR | Slave error → BRESP/RRESP |
A single synchronous always block with the 4-state FSM. Registered outputs, one outstanding transaction, and PSLVERR mapped to BRESP/RRESP. This is the exact bridge emitted by the register map generator in AXI4-Lite mode.
//==============================================================
// axil_to_apb — AXI4-Lite slave to APB3 master bridge
// Single outstanding transaction. PREADY-driven access phase.
//==============================================================
module axil_to_apb #(
parameter ADDR_WIDTH = 8,
parameter DATA_WIDTH = 32
)(
input ACLK,
input ARESETn,
// ---- AXI4-Lite slave ----
input [ADDR_WIDTH-1:0] S_AXI_AWADDR,
input S_AXI_AWVALID,
output reg S_AXI_AWREADY,
input [DATA_WIDTH-1:0] S_AXI_WDATA,
input [(DATA_WIDTH/8)-1:0] S_AXI_WSTRB,
input S_AXI_WVALID,
output reg S_AXI_WREADY,
output reg [1:0] S_AXI_BRESP,
output reg S_AXI_BVALID,
input S_AXI_BREADY,
input [ADDR_WIDTH-1:0] S_AXI_ARADDR,
input S_AXI_ARVALID,
output reg S_AXI_ARREADY,
output reg [DATA_WIDTH-1:0] S_AXI_RDATA,
output reg [1:0] S_AXI_RRESP,
output reg S_AXI_RVALID,
input S_AXI_RREADY,
// ---- APB3 master ----
output reg [ADDR_WIDTH-1:0] PADDR,
output reg PSEL,
output reg PENABLE,
output reg PWRITE,
output reg [DATA_WIDTH-1:0] PWDATA,
input [DATA_WIDTH-1:0] PRDATA,
input PREADY,
input PSLVERR
);
localparam IDLE=3'd0, ACCESS=3'd1, WRRESP=3'd2, RDRESP=3'd3;
reg [2:0] state;
reg is_write;
always @(posedge ACLK or negedge ARESETn) begin
if (!ARESETn) begin
state <= IDLE; is_write <= 1'b0;
PSEL <= 1'b0; PENABLE <= 1'b0; PWRITE <= 1'b0;
PADDR <= {ADDR_WIDTH{1'b0}}; PWDATA <= {DATA_WIDTH{1'b0}};
S_AXI_AWREADY <= 1'b0; S_AXI_WREADY <= 1'b0;
S_AXI_BVALID <= 1'b0; S_AXI_BRESP <= 2'b00;
S_AXI_ARREADY <= 1'b0; S_AXI_RVALID <= 1'b0;
S_AXI_RDATA <= {DATA_WIDTH{1'b0}}; S_AXI_RRESP <= 2'b00;
end else begin
S_AXI_AWREADY <= 1'b0; S_AXI_WREADY <= 1'b0; S_AXI_ARREADY <= 1'b0;
case (state)
IDLE: begin
PENABLE <= 1'b0;
if (S_AXI_AWVALID && S_AXI_WVALID) begin
is_write <= 1'b1;
PADDR <= S_AXI_AWADDR; PWDATA <= S_AXI_WDATA;
PWRITE <= 1'b1; PSEL <= 1'b1;
S_AXI_AWREADY <= 1'b1; S_AXI_WREADY <= 1'b1;
state <= ACCESS;
end else if (S_AXI_ARVALID) begin
is_write <= 1'b0;
PADDR <= S_AXI_ARADDR; PWRITE <= 1'b0; PSEL <= 1'b1;
S_AXI_ARREADY <= 1'b1;
state <= ACCESS;
end
end
ACCESS: begin
PENABLE <= 1'b1; // setup -> access phase
if (PENABLE && PREADY) begin
PSEL <= 1'b0; PENABLE <= 1'b0;
if (is_write) begin
S_AXI_BVALID <= 1'b1; S_AXI_BRESP <= PSLVERR ? 2'b10 : 2'b00;
state <= WRRESP;
end else begin
S_AXI_RVALID <= 1'b1; S_AXI_RDATA <= PRDATA;
S_AXI_RRESP <= PSLVERR ? 2'b10 : 2'b00;
state <= RDRESP;
end
end
end
WRRESP: if (S_AXI_BREADY) begin S_AXI_BVALID <= 1'b0; state <= IDLE; end
RDRESP: if (S_AXI_RREADY) begin S_AXI_RVALID <= 1'b0; state <= IDLE; end
default: state <= IDLE;
endcase
end
end
endmodule
Need this wired to real registers? The APB / AXI Register Map Generator emits this bridge plus a matching register block and top wrapper in one click.
SoC fabrics use AXI for the CPU and high-bandwidth masters, but simple peripherals use the lightweight APB bus. The bridge converts AXI4-Lite transactions into APB accesses so low-speed peripherals attach to an AXI system without each needing a full AXI interface.
AXI4-Lite has five independent channels with VALID/READY handshakes and outstanding support. APB is a single non-pipelined bus with a two-phase setup/access transfer and no bursts — far simpler and cheaper for control registers.
It idles until an AXI write (AWVALID & WVALID) or read (ARVALID), latches address/data, drives the APB setup then access phase, waits for PREADY, and returns BVALID (write) or RVALID + RDATA (read).
Yes — one synchronous always block, registered outputs, standard handshakes. BRESP/RRESP propagate APB PSLVERR as SLVERR. Works with Vivado, Quartus, Yosys and Synopsys DC.