AMBA AXI · Module 15
Reusable AXI RTL Templates
Assemble the Module 15 building blocks into a reusable, parameterised AXI RTL library — the primitive set (skid, FIFO, register bank, FSMs, adapters), the parameterisation and naming conventions that make blocks composable, how to build subsystems by wiring primitives, and the conventions that keep a library correct-by-construction.
This chapter closes Module 15 by stepping back from individual blocks to the library. Across the module we built a simple AXI4-Lite slave, a parameterised register bank, write and read FSMs, the skid buffer, ready/valid pipelining, and FIFOs. Individually they're useful; assembled into a consistent, parameterised, drop-in library they become the foundation every AXI design reuses. The leverage isn't any one block — it's the conventions that let blocks compose without rework: a uniform VALID/READY interface, consistent parameter and signal naming, sensible defaults, and a clear menu of when to reach for which primitive. This chapter catalogs the primitive set, states the parameterisation and naming conventions that make them composable, shows how to build subsystems by wiring primitives, and lists the conventions that keep a library correct-by-construction.
1. The Primitive Set
A practical AXI RTL library is a small, orthogonal set of primitives — each does one thing, all share the same handshake interface, and larger blocks are compositions of them.
The menu — which primitive solves which problem — is the library's real interface:
| Need | Primitive | From |
|---|---|---|
| Register a handshake for timing | Skid buffer | 15.5 |
| Decouple producer/consumer rates, absorb bursts | FIFO (sync) | 15.7 |
| Cross a clock domain | FIFO (async) | 15.7 / 14.2 |
| Multi-stage timing pipeline | Ready/valid pipeline (skid stages) | 15.6 |
| Sequence a write burst | Write FSM | 15.3 |
| Sequence a read burst | Read FSM | 15.4 |
| Memory-mapped control/status | Register bank | 15.2 |
| Minimal control slave | AXI4-Lite slave | 15.1 |
2. Parameterisation Conventions
Composability comes from uniform parameters. Every block in the library is parameterised on the same axes, with the same names, so instances line up and width/ID mismatches are caught at elaboration:
// Standard parameter set, shared by every AXI block in the library
parameter int ADDR_W = 32, // address width
parameter int DATA_W = 64, // data width (bytes = DATA_W/8 → WSTRB width)
parameter int ID_W = 4, // transaction ID width
parameter int USER_W = 0, // sideband width (0 = none)
parameter int LEN_W = 8, // AWLEN/ARLEN width (8 = AXI4 up to 256 beats)
parameter int DEPTH = 2 // buffer depth (2 = skid; larger = FIFO)The conventions that make this work: derive, don't duplicate (STRB_W = DATA_W/8 is computed, never passed separately, so it can't disagree); safe defaults (a block with default DEPTH=2 is a skid buffer; bump it for a FIFO); width-agnostic logic (loops and slices use the parameters, never hardcoded 32/8); and elaboration-time assertions (initial assert (DATA_W inside {32,64,128,...})) to reject illegal configurations at build time rather than failing in simulation.
3. Naming and Interface Conventions
The second half of composability is naming. If every block names its handshake ports the same way, wiring is mechanical and review is fast:
- Direction prefixes:
s_for the subordinate (slave) side that receives,m_for the manager (master) side that drives — so a block's input channel iss_*and its output channel ism_*, and connectingm_*of one block tos_*of the next is a one-to-one name match. - Channel suffixes: the AXI channel signal names verbatim (
awvalid,awready,awaddr,wdata,wstrb,wlast,bresp, …) so a full AXI port is a recognizable, complete set. - Active-low reset
aresetn, single clockaclkper domain, named consistently. - One handshake rule, everywhere:
*VALIDand payload driven independently of*READY; payload stable until accepted; exactly the contract every primitive already obeys.
// A library block's AXI write-channel ports — same names in every block
input logic [ID_W-1:0] s_awid,
input logic [ADDR_W-1:0] s_awaddr,
input logic [LEN_W-1:0] s_awlen,
input logic s_awvalid,
output logic s_awready,
// ... m_aw* on the output side, identical suffixes4. Building Subsystems by Composition
With a uniform interface and naming, subsystems are wiring diagrams. A registered, rate-decoupled AXI4-Lite peripheral, for example, is just primitives chained: a skid buffer at the port (timing), the Lite slave / register bank (function), and optionally a FIFO where buffering is needed — each m_* to the next s_*. Larger blocks (an interconnect port, a data mover, a width converter) are the same idea at larger scale.
5. Common Misconceptions
6. Debugging Insight
7. Verification Insight
8. Interview Questions
9. Summary
A reusable AXI RTL library is less about any single block than about the conventions that make blocks compose. The primitive set is small and orthogonal — flow control (skid buffer, FIFO, pipeline stage), protocol engines (write FSM, read FSM), storage (register bank), and adapters (width/protocol/CDC) — and a clear menu maps each design need to a primitive. Parameterisation conventions thread the same axes (ADDR_W, DATA_W, ID_W, USER_W, LEN_W, DEPTH) through every block, derive dependent values (STRB_W = DATA_W/8) instead of passing them, supply safe defaults, and assert legal configurations at elaboration. Naming conventions (s_/m_ direction prefixes + verbatim AXI channel suffixes) turn integration into a one-to-one name match, making wiring mechanical and connection errors obvious.
With a uniform interface and naming, subsystems are wiring diagrams — a port skid for timing, a register bank or FSM for function, a FIFO for rate decoupling, an async FIFO at clock crossings, each m_* to the next s_* — and they inherit correctness from their primitives. The discipline that keeps a library correct-by-construction: verify each primitive once, thoroughly, across its parameter range, then focus integration verification on seams, composition-level properties (deadlock, ordering, depth, timing), and configuration coverage — because local correctness is necessary but not sufficient for system correctness. This completes Module 15 (Building / Hands-On): from a single Lite slave to a composable library. Next, Module 16 builds the verification machinery — the checker mindset, SVA assertions, monitors, scoreboards, and coverage — that proves both the primitives and the systems built from them.
10. What Comes Next
You've built and packaged the RTL; Module 16 turns to proving it correct:
- 16.1 — The Protocol-Checker Mindset (coming next) — how to think about what could violate the AXI spec, the foundation for the assertions, monitors, scoreboards, and coverage that verify everything you've built.
Previous: 15.7 — FIFO-Based Buffering. Related: 15.1 — A Simple AXI4-Lite Slave and 15.5 — The Skid Buffer for the primitives this library assembles, and 10.5 — AXI4-Lite Verification Checklist for the per-block verification the library depends on.