Skip to content

AMBA AHB · Module 16

Memory Slave

Designing an AHB SRAM/memory slave — the same capture-then-act structure, but the storage is a large SRAM array (a compiled macro, not flops) and the new element is wait-state generation. When the memory isn't single-cycle (multi-cycle SRAM/flash, single-ported conflict, or registered read output), the slave drives HREADYOUT low until the memory is ready, then high; a fast single-cycle SRAM needs no waits. The bus interface to bulk storage, where memory timing becomes bus timing.

Chapters 16.1 and 16.2 built slaves whose storage was a handful of registers, then a parameterised register array — and both were zero-wait: they responded in a single cycle, so HREADYOUT stayed high. This chapter builds a memory slave — an AHB-Lite slave backed by a large SRAM array rather than registers — and with it introduces the first slave that cannot always answer in one cycle. The structure is still the same capture-then-act backbone (16.1): capture the address-phase context (sel_q, write_q, addr_q), then act in the data phase. The storage changes — a parameterised SRAM (often a compiled macro) instead of flops — and the access changes accordingly (drive addr/wdata/we into the SRAM on a write; drive addr and return rdata on a read). But the genuinely new element is wait-state generation: real memories are sometimes not single-cycle — a multi-cycle SRAM/flash needs several cycles, a single-ported SRAM shared with another path can conflict, a registered read output adds a cycle of latency. When the memory isn't ready, the slave drives HREADYOUT low (insert wait states — chapter 6.2), holding the master, then drives it high when the data is available. (A fast single-cycle SRAM needs no wait states — HREADYOUT stays high, exactly like the simple slave.) This chapter builds the memory slave and its wait-state logic — the slave side of slave-inserted wait states.

1. What Is It?

A memory slave is an AHB-Lite slave whose storage is a large SRAM/memory array (not individual registers), with wait-state generation for when the memory isn't single-cycle. Its parts:

  • Same capture-then-act — capture the address-phase context (sel_q, write_q, addr_q), act in the data phase (16.1's structure).
  • SRAM array — the storage is a parameterised memory (a compiled SRAM macro or inferred array), not flops; accessed by addr, wdata, we, returning rdata.
  • Wait-state generation — when the memory isn't ready (multi-cycle, single-ported conflict, registered read), drive HREADYOUT low; drive it high when the data is available.
  • Zero-wait when fast — a single-cycle SRAM needs no wait states (HREADYOUT stays high, like the simple slave).
A memory slave: capture → SRAM array (addr/wdata/we/rdata) → HRDATA, plus wait-state logic driving HREADYOUT low until the SRAM is ready.
Figure 1 — a memory slave: SRAM access + wait-state generation. The same capture-then-act forms addr_q, write_q, sel_q. The SRAM array is accessed in the data phase — a write drives addr/wdata/we in; a read drives addr and returns rdata onto HRDATA. The new piece is wait-state logic: if the SRAM is not ready (multi-cycle or single-ported conflict), the slave drives HREADYOUT low (wait), then high (done). A zero-wait SRAM needs no waits; a multi-cycle or single-ported one drives HREADYOUT low until ready.

So a memory slave is the simple slave (16.1) with SRAM storage and wait-state generation: the structure (capture-then-act, qualified select, registered context) is identical, but the storage becomes a large SRAM array (a compiled macro, not flops — because thousands/millions of locations can't be flops), and — crucially — the slave gains the ability to insert wait states when the memory can't answer in one cycle. The write path drives the SRAM's addr/wdata/we; the read path drives addr and muxes rdata onto HRDATA. The wait-state logic drives HREADYOUT low while the memory is busy and high when it's ready. So a memory slave is the standard memory-backed slave — the simple slave with bulk storage and the ability to stall the bus when the storage is slow. So it's the first non-trivially-timed slave.

2. Why Does It Exist?

The memory slave exists because systems need bulk storage (RAM, ROM, flash) on the bus — far more than registers can hold — and that storage is backed by memory arrays that aren't always single-cycle, so the slave must be able to insert wait states to match the memory's real timing.

The bulk storage need is the root: a system needs memory — instruction/data RAM, ROM/flash for code, framebuffers, scratchpads — often kilobytes to megabytes. That's far more than a register bank (dozens of registers) can hold, and it can't be built from individual flops (a megabyte of flops is absurd in area). So bulk storage uses dense memory arraysSRAM (compiled macros), flash, DRAM — and those need a slave to put them on the bus. So the memory slave exists to expose bulk memory over AHB. So it's the bus interface to RAM/ROM/flash. So systems need memory slaves.

The memory isn't always single-cycle drives the wait states: dense memories aren't always able to respond in one cycle. A small, fast SRAM might be single-cycle. But a larger or slower SRAM, a flash (slow), a single-ported SRAM shared between two access paths (one must wait), or a memory with a registered read output (pipelined for timing) needs more than one cycle — or needs to stall a conflicting access. The bus, though, expects a response — and AHB's mechanism for "not ready yet" is wait states (HREADYOUT low — chapter 6.2). So the memory slave must generate wait states to match the memory's real timing — holding the master while the memory works, then completing. So wait-state generation exists because memories aren't always single-cycle. So the slave must manage timing. So the slave inserts waits.

The bus-timing decoupling is the deeper why: wait states decouple the bus protocol (which is fixed) from the memory's timing (which varies by memory type/speed). The master doesn't need to know how fast the memory is — it just waits when HREADYOUT is low and proceeds when it's high. So the same master works with a fast SRAM (zero waits) or a slow flash (many waits) — the slave absorbs the difference by inserting the right number of waits. So wait states are how the bus adapts to any memory speed without changing the master. So the memory slave's wait-state generation is the adaptation layer between the fixed bus and the variable memory. So the memory slave exists because: systems need bulk storage (RAM/ROM/flash — far beyond registers, backed by dense memory arrays, not flops — the why); those memories aren't always single-cycle (multi-cycle, single-ported conflict, registered read — driving wait-state generation); and wait states decouple the fixed bus from the variable memory timing (the same master works with any memory speed — the adaptation). So the memory slave is the bus interface to bulk memory, and its wait-state generation is what lets a fixed bus protocol serve memories of any speed — the slave absorbing the timing difference. So it's the bulk-storage slave that adapts the bus to the memory. So this chapter builds the first slave that manages bus timing.

3. Mental Model

Model the memory slave as a librarian at a counter (the bus interface) backed by a vast archive (the SRAM). For a book on the front shelf, the librarian hands it over instantly (zero wait — HREADYOUT high). But for a book in deep storage — or when someone else is already at the only retrieval cart (single-ported conflict) — the librarian says "one moment" and holds up a wait sign (HREADYOUT low) until the book arrives, then hands it over (HREADYOUT high).

A librarian at a counter (the bus interface) backed by a vast archive (the SRAM array — far bigger than a desk of forms, which was the register bank). You hand the librarian a call number (the captured address) and either a book to file (a write) or a request to fetch (a read). For a book on the front shelf — a fast, single-cycle SRAM — the librarian files it or hands it over instantly: no waiting, the counter is immediately free for the next person (HREADYOUT stays high — zero wait, exactly like the register desk). But the archive is vast, and not every book is on the front shelf. A book in deep storage — a multi-cycle memory — takes several minutes to retrieve: the librarian says "one moment" and holds up a wait sign (HREADYOUT low), making you wait at the counter, then hands it over when it arrives (HREADYOUT high). Or the archive has only one retrieval cart (a single-ported SRAM) and someone else is already using it (a conflicting access) — again the librarian holds up the wait sign until the cart is free, then serves you. Or the librarian double-checks every book at a side desk before handing it over (a registered read output) — adding one fixed extra moment each time. In every case, the wait sign (HREADYOUT low) means "not ready — hold on", and taking it down (HREADYOUT high) means "here it is — done". You, at the counter, just wait when the sign is up — you don't need to know why it's slow. So the librarian absorbs the archive's slowness by holding you at the counter exactly as long as needed.

This captures the memory slave: the librarian at the counter = the bus interface (capture-then-act); the vast archive = the SRAM array; the call number = the captured address (addr_q); front-shelf instant service = a fast single-cycle SRAM (HREADYOUT stays high, zero wait); deep-storage "one moment" with the wait sign up = a multi-cycle memory (HREADYOUT low for the wait cycles); the single retrieval cart in use = a single-ported SRAM conflict (wait until free); double-checking at the side desk = a registered read output (+1 cycle latency); taking the wait sign down = HREADYOUT high (data ready, transfer completes); you just waiting without knowing why = the master simply holding while HREADYOUT is low. The slave absorbs the memory's slowness by holding the bus exactly as long as needed.

Watch a zero-wait write followed by a read that needs one wait state:

Zero-wait write, then a read with one wait state

5 cycles
Cycles 0-1: write D to A, HREADYOUT high (zero wait). Cycles 2-4: read B, HREADYOUT low in cycle 3 (one wait state), then high in cycle 4 with HRDATA=Q. HREADYOUT low means not ready; high means data available.Write D to A — SRAM single-cycle, HREADYOUT high (zero wait)Write D to A — SRAM si…Read B — SRAM not ready, HREADYOUT LOW (wait state)Read B — SRAM not read…HREADYOUT HIGH, HRDATA=Q valid — read completesHREADYOUT HIGH, HRDATA…HCLKHADDRABBBBHWRITEWRRRRHWDATA0DDDDHRDATA0000QHREADYOUTt0t1t2t3t4
Figure 2 — a zero-wait write, then a read with one wait state. Cycles 0-1: write to address A — address phase (cycle 0), then data phase (cycle 1) with HWDATA=D; the SRAM is single-cycle for the write, so HREADYOUT stays high and the write completes in one data cycle. Cycles 2-4: read from address B — address phase (cycle 2), then the data phase needs an extra cycle (the SRAM read is multi-cycle here), so the slave drives HREADYOUT LOW in cycle 3 (wait state — master holds), then HIGH in cycle 4 with HRDATA=Q valid (data ready, transfer completes). HREADYOUT low = 'not ready'; high = 'here it is'.

The model's lesson: the slave absorbs the memory's slowness by holding the bus exactly as long as needed. In the waveform, the single-cycle write completes with HREADYOUT high (zero wait), while the multi-cycle read drives HREADYOUT low for one wait cycle — holding the master — then high with the data valid.

4. Real Hardware Perspective

In hardware, the memory slave is a compiled SRAM macro (or inferred array), an address/write-data/write-enable path into it, a read-data mux onto HRDATA, and wait-state logic driving HREADYOUT — the timing of which depends on the SRAM's latency.

The SRAM macro: bulk storage isn't flops — it's a compiled SRAM macro (a dense, custom-laid-out memory block from a memory compiler) or, for small/FPGA memories, an inferred array (reg [W-1:0] mem [0:DEPTH-1]) that the tool maps to block RAM. The macro has ports: an addr, a wdata, a write-enable (we), and a rdata output. So in hardware, the storage is a memory macro with those ports. So the slave drives the ports from the captured AHB context. So it's a macro, not flops.

Three wait-state sources: multi-cycle memory, single-ported conflict, and registered read — each driving HREADYOUT low until ready.
Figure 3 — why a memory slave inserts wait states. Multi-cycle memory: flash or a slow SRAM needs N cycles to return data → HREADYOUT low for N-1 cycles. Single-ported conflict: a memory shared with another access path means a conflicting access waits its turn → HREADYOUT low until its turn. Registered read: a read output registered for timing adds +1 cycle of latency → HREADYOUT low 1 cycle. In each case, drive HREADYOUT low while not ready, high when data is available. A fast single-cycle SRAM needs no wait states — like the simple slave.

The access path: on a write (sel_q && write_q in the data phase), the slave drives the SRAM's addr = addr_q, wdata = HWDATA, we = 1 — writing HWDATA to location addr_q. On a read (sel_q && !write_q), it drives addr = addr_q, we = 0, and the SRAM's rdata is muxed onto HRDATA. (A subtlety: SRAMs are usually synchronousaddr is presented one cycle, rdata comes the next — which itself can mean a registered-read latency to manage. The address-phase/data-phase pipelining of AHB aligns well here: the address is available in the address phase, so a synchronous SRAM read launched then can have rdata ready in the data phase.) So in hardware, the access path drives the SRAM ports from the captured context and muxes rdata to HRDATA. So it's port-driving. So the path is straightforward.

The wait-state logic: this is the new piece. HREADYOUT reflects whether the memory is ready. For a single-cycle SRAM (read launched in the address phase, rdata ready in the data phase), HREADYOUT stays high — zero wait. For a multi-cycle memory, the slave needs a small counter/FSM: when an access starts, drive HREADYOUT low and count the memory's latency; when the count expires (data ready), drive HREADYOUT high and complete. For a single-ported SRAM with a conflict (e.g. a second access path also using the SRAM), the slave drives HREADYOUT low until the conflict clears (its turn comes). For a registered read output, there's a fixed one-cycle stall on reads. So in hardware, the wait-state logic is a counter/FSM (or simple combinational condition) that drives HREADYOUT low while the memory is busy, high when ready. Crucially, HREADYOUT must follow the wait-state rules (chapter 6.2): once a wait is being inserted, the slave holds HREADYOUT low for the needed cycles and the control/data stay stable; the master is held automatically. So in hardware, the memory slave is a compiled SRAM macro + an access path (drive addr/wdata/we, mux rdata) + wait-state logic (a counter/FSM driving HREADYOUT to match the memory's latency). The timing details (synchronous SRAM, registered reads) make this the first slave where getting the cycle-by-cycle HREADYOUT timing right is the core challenge. So in hardware, it's a macro plus timing-matched wait-state control. So the timing is the hard part.

5. System Architecture Perspective

At the system level, the memory slave is the bus interface to bulk storage, and its wait-state generation is the mechanism that lets a single, fixed bus serve memories of wildly different speeds — from fast on-chip SRAM to slow flash — without the master ever knowing the difference.

The bulk-storage interface: the memory slave is how the system's bulk memory (instruction/data RAM, ROM, flash, scratchpads) sits on the bus. The CPU fetches code from a ROM/flash memory slave, reads/writes data in a RAM memory slave, accesses framebuffers and scratchpads — all through memory slaves. So at the system level, memory slaves are the storage tier on the bus — the largest, most-accessed slaves. So they're foundational to the system's operation (no code/data without them). So memory slaves are the storage backbone.

The speed-adaptation via wait states: different memories have wildly different speeds — a tightly-coupled SRAM might be single-cycle, an on-chip flash might need many cycles, an external memory (through a controller) many more. Yet they all connect to the same bus with the same protocol. The wait-state mechanism is what makes this work: each memory slave inserts as many waits as its memory needs — zero for fast SRAM, several for flash, many for external — and the master simply waits (HREADYOUT low) without knowing or caring why. So at the system level, wait states adapt the one bus to many memory speeds — the slave absorbs the speed difference. So the system can mix fast and slow memories transparently. So wait states are the speed-adaptation layer. So memories of any speed coexist.

The performance consequence: because memory slaves can insert waits, memory speed directly affects system performance (chapter 14.4 — the wait-state penalty). A slow memory (many waits) stalls the CPU on every access — a bottleneck (chapter 14.8). So system architects care about memory slave timing: they put hot code/data in fast (zero/low-wait) memory, use caches to hide slow-memory latency, and budget the wait states. So the memory slave's wait-state behavior is a first-order performance factor — not just a correctness detail. So at the system level, the memory slave is the bus interface to bulk storage (the storage tier — RAM/ROM/flash, the most-accessed slaves), its wait-state generation adapts the fixed bus to any memory speed (the slave absorbing the difference — fast SRAM to slow flash, transparently to the master), and its timing is a first-order performance factor (the wait-state penalty — chapter 14.4 — driving memory hierarchy, caching, and placement decisions). So the memory slave is where storage meets the bus, and where memory speed becomes bus timing — making it both a foundational slave and a performance-critical one. So get the wait-state timing right, and place memories by speed.

6. Engineering Tradeoffs

The memory slave embodies the SRAM-backed, wait-state-generating, timing-matched design.

  • SRAM macro vs flops. A compiled SRAM macro is dense (the only feasible way to build bulk memory) at the cost of fixed ports and timing; flops are flexible but absurd in area beyond a few registers. Use a macro for bulk storage.
  • Zero-wait vs multi-cycle memory. A fast single-cycle SRAM gives zero-wait access (best performance) but may be small/costly; a slower/larger/cheaper memory needs wait states (lower performance). Trade speed for capacity/cost; place hot data in fast memory.
  • Single-ported vs dual-ported SRAM. A single-ported SRAM is smaller/cheaper but forces conflicting accesses to wait (wait states on conflict); a dual-ported SRAM avoids the conflict at higher area. Choose by access pattern.
  • Registered read output vs combinational. Registering the read output helps timing closure (higher clock) at the cost of +1 cycle read latency (a wait state); a combinational read avoids the latency but may limit frequency. Trade frequency for latency.

The throughline: a memory slave is the simple slave (16.1) backed by a large SRAM array (a compiled macro, not flops) instead of registers — the same capture-then-act structure (capture sel_q, write_q, addr_q; act in the data phase), driving the SRAM's addr/wdata/we on a write and muxing rdata to HRDATA on a read. The new element is wait-state generation: when the memory isn't single-cycle (multi-cycle SRAM/flash, single-ported conflict, or registered read output), the slave drives HREADYOUT low (inserting wait states — chapter 6.2) until the memory is ready, then high. A fast single-cycle SRAM needs no waits (HREADYOUT stays high). It's the bus interface to bulk storage, and its wait-state timing is a first-order performance factor (the wait-state penalty — chapter 14.4).

7. Industry Example

Build a memory slave for an on-chip instruction SRAM, then contrast with a flash.

A CPU fetches instructions from an on-chip SRAM (fast) and from on-chip flash (slow) — both memory slaves on the bus.

  • The SRAM (single-cycle, zero wait). The instruction SRAM is a fast, single-ported, synchronous SRAM. The slave captures addr_q in the address phase and launches the SRAM read then; the synchronous SRAM presents rdata in the next cycle — which is the AHB data phase. So rdata is ready in the data phase, HREADYOUT stays high, and the read completes zero-wait. The address-phase/data-phase pipelining of AHB aligns perfectly with the synchronous SRAM's one-cycle read latency. So a well-matched SRAM gives zero-wait access — the best case.
  • The flash (multi-cycle, several waits). The on-chip flash is slow — say it needs 4 cycles to return data. The flash memory slave, on a read, drives HREADYOUT low and starts a 4-cycle counter; for cycles 1-3 it holds HREADYOUT low (3 wait states), keeping the master waiting and the access in progress; in cycle 4, when the flash data is ready, it muxes rdata onto HRDATA and drives HREADYOUT high — completing the read. So every flash fetch costs 4 cycles (3 waits) — slow, but correct.
  • The performance contrast. Fetching from SRAM is zero-wait (1 cycle/access); fetching from flash is 4 cycles/access. So code in SRAM runs 4× faster (per fetch) than code in flash. This is exactly why systems copy hot code from flash to SRAM at boot, or use an instruction cache to hide flash latency — the wait-state penalty (chapter 14.4) of the flash is a real performance cost the architecture works around.
  • Single-ported conflict (if shared). If the SRAM were shared (e.g. CPU instruction fetch and a DMA both accessing it through one port), a conflict would force one to wait — the slave drives HREADYOUT low on the loser until the port is free. (A dual-ported SRAM would avoid this, at higher area.)

The example shows the memory slave across the speed spectrum: a fast SRAM (zero-wait, AHB pipelining aligned with the synchronous read), a slow flash (multi-cycle, several wait states via a counter), the performance contrast (driving SRAM-copy/caching decisions), and the single-ported conflict (waits on contention). The same slave structure (capture-then-act + SRAM access) serves both, differing only in the wait-state timing matched to each memory. This is how bulk storage sits on the bus. This is the storage-tier slave.

8. Common Mistakes

9. Interview Insight

Memory slave design is a practical RTL interview topic — the SRAM-vs-flops point, the wait-state generation, and the HREADYOUT-timing discipline are the signals.

A summary card on the memory slave: SRAM array storage, wait-state generation, and HREADYOUT timing.
Figure 4 — a strong answer in one card: same capture-then-act, but the storage is an SRAM array (addr/wdata/we in, rdata out); the new element is wait states — HREADYOUT low while the memory is not ready (multi-cycle / single-ported / registered read), then high; a fast single-cycle SRAM needs no waits, like the simple slave; present rdata when HREADYOUT goes high. The senior point: capture, access the SRAM, and generate wait states by holding HREADYOUT low until the memory is ready.

The answer that lands gives the structure and the wait-state timing: "A memory slave is the simple slave backed by a large SRAM array instead of registers. It keeps the same capture-then-act structure — capture the qualified select, the write flag, and the address in the address phase, then act in the data phase — but the storage is a compiled SRAM macro, not flops, because you can't build kilobytes or megabytes from individual registers. On a write, it drives the SRAM's address, write data, and write enable; on a read, it drives the address and muxes the SRAM's read data onto HRDATA. The genuinely new element compared to a register slave is wait-state generation. Real memories aren't always single-cycle. A fast SRAM might be, and there AHB's address-phase/data-phase pipelining aligns nicely with a synchronous SRAM — you launch the read in the address phase and the data's ready in the data phase, so HREADYOUT stays high, zero-wait. But a multi-cycle memory like flash, or a single-ported SRAM with a conflicting access, or a registered read output, can't answer in one cycle. In those cases the slave drives HREADYOUT low to insert wait states, holding the master, then drives it high when the data is actually ready. The critical discipline is the HREADYOUT timing: you drive it low for exactly the memory's latency — if you drive it high before the data's ready, the master samples garbage, a data-corruption bug; during the wait you hold the captured address and the access stable; and you present valid HRDATA in the cycle HREADYOUT goes high. That's usually a small FSM or counter that models the memory's latency. And the wait states matter for performance — a slow memory stalls the CPU on every access, which is why systems put hot code in fast SRAM or use caches." The SRAM-vs-flops point, the wait-state generation, and the precise HREADYOUT-timing discipline are the senior signals.

10. Practice Challenge

Build and reason from the memory slave.

  1. The structure. Describe the memory slave: SRAM array storage (not flops), capture-then-act access (drive addr/wdata/we, mux rdata).
  2. Wait-state sources. List the reasons a memory slave inserts wait states (multi-cycle, single-ported conflict, registered read) and what HREADYOUT does in each.
  3. Read the waveform. From Figure 2, explain the zero-wait write and the one-wait-state read (what HREADYOUT does and when HRDATA is valid).
  4. HREADYOUT timing. Explain why driving HREADYOUT high too early corrupts data and too late wastes cycles — and what must stay stable during the wait.
  5. Synchronous SRAM. Explain how AHB's address-phase/data-phase pipelining lets a fast synchronous SRAM be zero-wait, and when you still need waits.

11. Key Takeaways

  • A memory slave is the simple slave backed by a large SRAM array (a compiled macro, not flops) instead of registers — same capture-then-act, driving the SRAM's addr/wdata/we on a write and muxing rdata to HRDATA on a read.
  • The new element is wait-state generation — real memories aren't always single-cycle (multi-cycle SRAM/flash, single-ported conflict, registered read), so the slave drives HREADYOUT low until the memory is ready, then high (chapter 6.2).
  • A fast single-cycle SRAM needs no wait statesHREADYOUT stays high; AHB's address-phase/data-phase pipelining aligns with a synchronous SRAM's one-cycle read for zero-wait access.
  • HREADYOUT timing must be exact — drive it high in the cycle the data is valid: too early → the master samples garbage (corruption); too late → wasted cycles. Usually a small FSM/counter models the memory latency.
  • Hold during the wait — while HREADYOUT is low, the captured addr_q/write data and the access must stay stable (else wrong location); HRDATA need only be valid when HREADYOUT is high.
  • It's the bus interface to bulk storage — the storage tier (RAM/ROM/flash), and its wait-state timing is a first-order performance factor (the wait-state penalty — chapter 14.4 — driving caching/placement).

12. What Comes Next

You now can build a memory slave with wait-state generation. The next chapters drill into the slave's output-generation logic in detail:

  • HREADYOUT Generation (next) — implement correct per-slave HREADYOUT timing in full.
  • HRDATA Muxing, HRESP Generation, and the rest — the richer slave RTL output paths.

To revisit the simple slave this extends, see A Simple AHB-Lite Slave; for the wait-state mechanism itself, see Slave-Inserted Wait States and What HREADY Means.