Skip to content

AMBA CHI · Module 5 · CHI System Components

RN-D (IO-Coherent Request Node)

The IO-coherent Request Node is the first subtraction from RN-F. Like RN-F it issues coherent transactions, so it sees current data and its writes are made coherent — no software flushes. Unlike RN-F, it hosts no coherent cache, so it holds no cache-line state and is never snooped. It reads with ReadOnce, a coherent snapshot it does not retain, and writes with WriteUnique, never caching the line. DMA engines, NICs, and accelerators that share data with CPUs but need no coherent cache are its natural home. This chapter details what it keeps from RN-F and what it drops — the requester half without the cache half. Representative model, not the specification.

Intermediate14 min readAMBA CHIIO-CoherentReadOnceWriteUniqueDMA

Module 5 · Chapter 5.2 · CHI System Components

Project thread — 5.1 detailed RN-F, the complete participant. This chapter takes the first subtraction: a coherent requester with no cache. 5.3 turns to the Home Node.

1. Learning Outcomes

By the end of this chapter you should be able to:

  • Define the IO-coherent Request Node: a coherent requester with no coherent cache.
  • Explain why it is never snooped — it holds no snoopable cache state.
  • Distinguish what it keeps from RN-F (coherent requests) and drops (cache states, snoop response).
  • Match its accesses to ReadOnce and WriteUnique for coherent regions.
  • See why a cacheless node must use ReadOnce, not a retaining request like ReadShared.
  • Implement a representative IO-coherent request selector in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

Most real SoCs have far more IO-coherent requesters than CPUs — every DMA engine, network controller, and accelerator that touches CPU-shared data is one. Getting them right is what lets an accelerator read a buffer a CPU just wrote without a software cache flush, which is a large performance and simplicity win.

It is also the cleanest lesson in the taxonomy: the IO-coherent node is RN-F minus the cache. Seeing exactly which behaviors that removes — and which it keeps — sharpens your understanding of both nodes, and of why the request a node issues must match the state it is willing to hold.

3. Key Terms

4. Previous Chapter Connection

Chapter 5.1 made RN-F the archetype: full cache states, full request repertoire, full snoop response. This chapter subtracts the middle pillar — the coherent cache — and watches what falls away with it.

Removing the cache removes two RN-F behaviors at once: there is no cache-line state to maintain, and therefore no snoop to answer (the Home Node never records this node as a holder, so it never snoops it). What remains is RN-F's initiator half: it still issues coherent requests, tracks them by TxnID, and receives data and responses. The IO-coherent node is that half, standing alone.

5. Core Concept — a requester without a cache

The IO-coherent node keeps coherent requesting and drops coherent caching.

  • It requests coherently. Its reads and writes go through the coherence protocol, so a read returns the current value — even if that value is dirty in a CPU's cache — and a write is made coherent (other copies invalidated). This is the whole point: it sees and produces coherent data without software managing caches.
  • It holds no coherent cache. It keeps no line in a CHI state (I/UC/UD/SC/SD). Whatever it reads, it consumes and does not retain as a coherent copy. It may have a local buffer, but that buffer is not part of the coherence domain.
  • It is never snooped. Because it holds no snoopable state, the Home Node's directory never lists it as a holder, and it receives no SNP packets. It has no snoop-response logic at all.
  • It uses non-retaining requests. For coherent regions it uses ReadOnce (a coherent snapshot it does not keep) and WriteUnique (a coherent write without caching). For non-coherent regions it uses ReadNoSnp / WriteNoSnp.

The synthesis:

An IO-coherent node is the requester half of RN-F: it initiates coherent transactions to see and produce current data, but hosts no coherent cache, so it holds no line state and is never snooped. Its request set is chosen to match: non-retaining transactions like ReadOnce and WriteUnique, never a request that would leave it holding a snoopable copy it cannot service.

6. Engineering Mental Model — a courier, not a resident

Return to the co-op of shared tools. RN-F was a full member who borrows, holds, and lends tools.

The IO-coherent node is a courier who runs errands for outside clients.

  • The courier can fetch the current version of a tool (ReadOnce) — the desk makes sure it hands over the up-to-date one, even pulling it from a member who has it marked up — and deliver a new version (WriteUnique) that supersedes others' copies.
  • But the courier does not keep tools at home. There is no shelf at the courier's place for the co-op to reclaim from, so the desk never calls the courier to ask "do you still have this?" (never snooped).
  • Crucially, the courier must not check a tool out as if to keep it (a retaining request). If they did, the desk would list them as a holder and later call to reclaim it — and the courier, having no shelf and no way to answer, would leave the desk waiting forever.

A courier who fetches and delivers but never stocks a shelf — that is the IO-coherent node.

7. Engineering Diagram — the IO-coherent node

An IO-coherent Request Node. An IO device such as a DMA engine, network controller, or accelerator connects to a request engine that issues coherent REQ packets and tracks transactions by TxnID but has no coherent cache and no snoop-response logic. It connects to the interconnect on REQ, RSP, and DAT channels, but receives no SNP because it is never snooped.IO deviceDMA / NIC / acceleratorRequest enginecoherent REQ · TxnID · nocache · not snoopedInterconnect → HNREQ / RSP / DAT — no SNP in12
Figure 1 — an IO-coherent Request Node. An IO device (DMA, NIC, accelerator) drives a request engine that issues coherent transactions and tracks them by TxnID, but hosts no coherent cache and has no snoop-response logic. Its interconnect interface carries REQ, RSP, and DAT — but no incoming SNP, because a cacheless node is never snooped.

Compare the RN-F diagram of Chapter 5.1: same requester structure, but the coherent cache is gone and the interconnect interface has no SNP channel inbound. That absence is the whole node.

8. What It Keeps and Drops

The IO-coherent node is RN-F with one pillar removed. The consequences:

RN-F behaviorIO-coherent nodeWhy
issues coherent requestskeptit must see/produce coherent data
tracks transactions by TxnIDkeptit still has outstanding transactions
holds cache-line statesdroppedno coherent cache
answers snoopsdroppednever snooped (no snoopable state)
full request repertoirereduceduses non-retaining ReadOnce / WriteUnique

Two facts to carry: everything that depends on holding a cached line is gone (states, snoop response), and everything that is pure initiation remains (requests, TxnID, receiving data). The node is coherent as a requester, not as a cache.

9. The IO-Coherent Request Set

Its transactions are chosen so it never ends up holding a snoopable copy.

AccessRegionTransactionEffect
readcoherentReadOncecurrent snapshot; requester does not retain it
writecoherentWriteUniqueinvalidates other copies; writer does not cache
readnon-coherentReadNoSnpplain read, no snoop
writenon-coherentWriteNoSnpplain write, no snoop

Two facts to carry: ReadOnce is the coherent read for a cacheless node — it gets the current value (the Home Node snoops holders as needed) but leaves the requester unlisted in the directory — and WriteUnique lets it write coherently without caching. It never issues ReadShared or ReadUnique, because those would leave it holding a line the Home Node expects to snoop.

10. Transaction Walkthrough — a DMA reads CPU-produced data

A CPU writes a buffer; a DMA engine (IO-coherent) then reads it — with no software flush.

  1. CPU produces. CPU0's RN-F writes the buffer; the line is now UD (dirty) in CPU0's cache — not yet in memory.
  2. DMA reads. The DMA's IO-coherent node issues ReadOnce for the buffer line to the Home Node.
  3. Home resolves. The Home Node's directory shows CPU0 holds the line dirty. It snoops CPU0, which supplies the current (dirty) data.
  4. DMA receives. The Home Node returns the current data to the DMA on DAT. The DMA gets exactly what CPU0 wrote — no stale memory, no flush.
  5. No retention. The DMA does not cache the line, and the directory does not list it as a holder. Nothing to snoop later; the DMA consumed a coherent snapshot and moved on.

Hardware coherency did the work software used to do with cache flushes. And because the DMA used ReadOnce, step 5 leaves no loose end — the opposite of what the DebugLab shows.

11. RTL / Hardware View — an IO-coherent request selector

The IO-coherent node's defining logic is choosing a non-retaining transaction for each access. Here is that selector. Representative and combinational.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative IO-coherent request-type selector (educational).
// A cacheless coherent requester uses ReadOnce / WriteUnique for coherent
// regions (see/produce current data without retaining a snoopable copy) and
// NoSnp variants for non-coherent regions. It never issues a retaining request.
module iocoherent_reqsel (
  input  logic       is_write,       // 1 = write, 0 = read
  input  logic       coherent,       // 1 = coherent region, 0 = non-coherent
  output logic [1:0] opcode          // 0 ReadOnce, 1 WriteUnique, 2 ReadNoSnp, 3 WriteNoSnp
);
  localparam logic [1:0] READONCE=2'd0, WRITEUNIQUE=2'd1, READNOSNP=2'd2, WRITENOSNP=2'd3;
  always_comb begin
    if (coherent)
      opcode = is_write ? WRITEUNIQUE : READONCE;   // coherent: snoop others, do not cache
    else
      opcode = is_write ? WRITENOSNP : READNOSNP;   // non-coherent: bypass coherency
  end
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative IO-coherent request-type selector (Verilog-2001).
module iocoherent_reqsel (
  input        is_write,
  input        coherent,
  output reg [1:0] opcode
);
  localparam READONCE=2'd0, WRITEUNIQUE=2'd1, READNOSNP=2'd2, WRITENOSNP=2'd3;
  always @* begin
    if (coherent) opcode = is_write ? WRITEUNIQUE : READONCE;
    else          opcode = is_write ? WRITENOSNP  : READNOSNP;
  end
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative IO-coherent request-type selector (VHDL).
library ieee;
use ieee.std_logic_1164.all;
 
entity iocoherent_reqsel is
  port (
    is_write : in  std_logic;
    coherent : in  std_logic;
    opcode   : out std_logic_vector(1 downto 0)   -- 0 RdOnce,1 WrUnique,2 RdNoSnp,3 WrNoSnp
  );
end entity;
 
architecture rtl of iocoherent_reqsel is
begin
  process(is_write, coherent)
  begin
    if coherent = '1' then
      if is_write = '1' then opcode <= "01"; else opcode <= "00"; end if;   -- WrUnique / RdOnce
    else
      if is_write = '1' then opcode <= "11"; else opcode <= "10"; end if;   -- WrNoSnp / RdNoSnp
    end if;
  end process;
end architecture;

All three pick a non-retaining coherent transaction (ReadOnce / WriteUnique) or a non-coherent one — never ReadShared or ReadUnique. That the retaining requests are simply absent from the selector is the point: a cacheless node must not issue them.

12. Verification View — coherent reads never retain

Two properties: a coherent read is always ReadOnce, and a non-coherent access always bypasses snooping.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to iocoherent_reqsel.
localparam logic [1:0] READONCE=2'd0, WRITEUNIQUE=2'd1, READNOSNP=2'd2, WRITENOSNP=2'd3;
 
// 1. A coherent read is ReadOnce — never a retaining ReadShared/ReadUnique.
always_comb if (coherent && !is_write) assert (opcode == READONCE);
 
// 2. A non-coherent access always uses a NoSnp variant.
always_comb if (!coherent) assert (opcode == READNOSNP || opcode == WRITENOSNP);

The system point, beyond the two checks:

The node's whole safety rests on never issuing a retaining request. A retaining request (ReadShared, ReadUnique) tells the Home Node "I will hold this line — snoop me about it later." A cacheless node cannot answer such a snoop, so it must never make that promise. ReadOnce is the coherent read that makes no such promise: the Home Node gathers the current value and returns it, but records no holder. The request set is not an arbitrary subset — it is exactly the transactions a node with no snoopable state can safely issue.

  • What it proves: coherent reads are non-retaining; non-coherent accesses bypass snooping.
  • What it does not prove: the rest of the transaction flow (the selector is only the opcode choice).
  • Bug signature: a retaining request issued by a cacheless node → an unanswerable snoop later (the DebugLab).

13. Testbench — select a transaction for each access

Checks the opcode for the four (read/write × coherent/non-coherent) cases.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_iocoherent_reqsel;
  logic is_write, coherent;
  logic [1:0] opcode;
  int errors = 0;
  localparam logic [1:0] READONCE=2'd0, WRITEUNIQUE=2'd1, READNOSNP=2'd2, WRITENOSNP=2'd3;
 
  iocoherent_reqsel dut (.*);
 
  task automatic check(input logic w, input logic co, input logic [1:0] exp, input string tag);
    is_write = w; coherent = co; #1;
    if (opcode !== exp) begin errors++; $display("FAIL [%s] opcode=%0d exp=%0d", tag, opcode, exp); end
    else $display("PASS [%s] opcode=%0d", tag, opcode);
  endtask
 
  initial begin
    check(1'b0, 1'b1, READONCE,    "coherent read -> ReadOnce");
    check(1'b1, 1'b1, WRITEUNIQUE, "coherent write -> WriteUnique");
    check(1'b0, 1'b0, READNOSNP,   "non-coherent read -> ReadNoSnp");
    check(1'b1, 1'b0, WRITENOSNP,  "non-coherent write -> WriteNoSnp");
 
    if (errors == 0) $display("ALL TESTS PASSED");
    else             $display("%0d FAILURE(S)", errors);
    $finish;
  end
endmodule

Expected output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
PASS [coherent read -> ReadOnce] opcode=0
PASS [coherent write -> WriteUnique] opcode=1
PASS [non-coherent read -> ReadNoSnp] opcode=2
PASS [non-coherent write -> WriteNoSnp] opcode=3

14. DebugLab — a cacheless node issues a retaining read

1

A cacheless node issues a retaining read

RETAINING READ FROM CACHELESS NODE -> UNANSWERABLE SNOOP -> HANG
Symptom

An accelerator or DMA runs fine in isolation, but the system hangs when a CPU later accesses a line the IO device read — a coherent transaction never completes and a watchdog fires. It only happens on lines the IO device touched with a read.

Evidence

The Home Node snooping the IO node, which never responds:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
step  event                                  note
 1    IO node issues ReadShared (line A)      registered as a HOLDER in the directory
 2    CPU0 issues ReadUnique (line A)         needs exclusive
 3    HN sends SnpUnique to the IO node       expecting a snoop response
 4    IO node: no cache, no snoop logic       -> no response ever
 5    HN waits for the response               -> transaction hangs

The directory lists the IO node as a holder (step 1), so the Home Node snoops it (step 3) — but it cannot answer.

First Divergence

Step 1: the IO node issued ReadShared — a retaining request — instead of ReadOnce. That registered it as a directory holder, creating a future snoop it has no way to service.

Root Cause

A retaining request is a promise to hold the line and answer snoops about it. A cacheless node cannot keep that promise: it has no line state and no snoop-response path. When the Home Node later snoops it (as the directory says it should), the snoop goes unanswered and the dependent transaction stalls. The bug is issuing a request whose obligations the node cannot meet.

Fix

A cacheless IO-coherent node must issue ReadOnce for coherent reads (and WriteUnique for writes). ReadOnce returns the current value — the Home Node snoops real holders to get it — but leaves the IO node out of the directory, so it is never snooped and nothing can hang. Match the request to the state you can hold: no snoopable cache means only non-retaining requests.

15. Common Mistakes

  • Issuing retaining reads from a cacheless node. Assumption: any coherent read works. Bug: unanswerable snoop, hang (the DebugLab). Prevention: use ReadOnce, never ReadShared/ReadUnique.
  • Expecting the IO node to be snooped. Assumption: every requester is snoopable. Bug: waiting for a response it cannot give. Prevention: a cacheless node is never snooped.
  • Thinking IO-coherent means non-coherent. Assumption: no cache means no coherency. Bug: stale reads, missing flushes. Prevention: its accesses are coherent; it just does not cache.
  • Confusing its buffer with a coherent cache. Assumption: a local buffer joins the coherence domain. Bug: expecting snoops of the buffer. Prevention: the buffer is outside coherency; nothing there is snooped.
  • Using coherent ops on non-coherent regions. Assumption: always snoop. Bug: needless snoop traffic. Prevention: use NoSnp variants off the coherent map.
  • Naming confusion (RN-D vs RN-I). Assumption: the label pins the behavior. Bug: expecting DVM or a cache. Prevention: focus on the behavior — coherent requester, no cache.

16. Engineering Checklist

  • Confirm the node hosts no coherent cache and needs none.
  • Use ReadOnce for coherent reads, WriteUnique for coherent writes.
  • Use ReadNoSnp / WriteNoSnp for non-coherent regions.
  • Never issue a retaining request (ReadShared / ReadUnique) from a cacheless node.
  • Expect no inbound SNP — provide no snoop-response logic.
  • Still track transactions by TxnID; it is a full initiator.

17. Key Takeaways

  • The IO-coherent Request Node is RN-F minus the cache: a coherent requester that holds no snoopable state.
  • It issues coherent transactions (so it sees/produces current data) but is never snooped.
  • It uses non-retaining requests — ReadOnce (coherent snapshot) and WriteUnique (coherent write) — plus NoSnp for non-coherent regions.
  • It must never issue a retaining request (ReadShared/ReadUnique); doing so registers it as a holder it cannot service — an unanswerable snoop and a hang.
  • It gives DMA, NICs, and accelerators coherent data with no software flushes — a major simplification.
  • Its label varies (RN-D here, RN-I in the strict spec); the behavior is the point. The model here is representative.

18. Quick Revision

IO-coherent Request Node (RN-D here; RN-I in the strict spec). RN-F minus the coherent cache: a coherent requester with no snoopable state. It issues coherent transactions so it sees the current value (the Home Node snoops real holders on its behalf) and its writes are made coherent — no software flushes — but it holds no cache-line state and is never snooped. Request set: ReadOnce (coherent read, not retained) and WriteUnique (coherent write, not cached) for coherent regions; ReadNoSnp / WriteNoSnp for non-coherent. It must never issue a retaining request (ReadShared/ReadUnique): that registers it as a directory holder, and the later snoop it cannot answer hangs the fabric. Natural home: DMA, NICs, accelerators. Keeps RN-F's initiator half; drops the cache half. Representative model.

Coming Next

Chapter 5.3 — HN-F (Fully Coherent Home Node). With both request-node kinds in hand, the taxonomy turns to the home. The next chapter details the fully coherent Home Node — the node that holds the directory / snoop filter, serializes access, and drives the targeted snoops the request nodes receive. Where Chapter 4.3 introduced the Home Node's role, 5.3 gives HN-F its depth: the directory structure, the coherence state machine it runs per line, and how it turns a request into the right snoops and response.