Skip to content

AMBA CHI · Module 7 · CHI Transaction Model

The Transaction State Machine

The clean four-phase lifecycle is an abstraction; the real hardware runs two state machines, one on the requester and one on the home, and they must agree. The home's machine is the richer one, because the home is the point of serialization — it orders every access to a line and holds that ordering until the requester's CompAck. That hold is what makes conflicting transactions to one address safe: a second request is ordered strictly behind the first. Release the ordering too early — when the completion is sent, not acknowledged — and two transactions to a line can interleave and break coherence. Learn both sides' states and why the home holds serialization until CompAck. Representative model, not the specification.

Advanced17 min readAMBA CHITransaction FSMPoint of SerializationOrderingHome Node

Module 7 · Chapter 7.6 · CHI Transaction Model

Project thread — 7.5 gave the lifecycle as one clean loop. This chapter opens the two real FSMs — requester and home — that implement it, and closes Module 7. Module 8 walks concrete request flows.

1. Learning Outcomes

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

  • Explain that the lifecycle is implemented as two FSMs — requester-side and home-side — kept consistent.
  • Describe the home as the point of serialization (POS) for a line.
  • Trace the home FSM's two paths — snoop and memory — to completion.
  • State why the home must hold a line's ordering until CompAck.
  • Diagnose how releasing ordering early lets conflicting transactions interleave.
  • Implement a representative home-side transaction FSM in SystemVerilog, Verilog-2001, and VHDL.

2. Why Should I Learn This?

The lifecycle in Chapter 7.5 was a clean loop because it described one transaction in isolation. Real hardware runs two machines per transaction — the requester's and the home's — and they must stay in step across a fabric that reorders packets. More importantly, the home runs many such machines at once for different transactions, some to the same line, and it is the home's job to keep those from stepping on each other.

That is the heart of coherence ordering. The home is where a line's accesses are serialized, and the exact moment it considers one transaction "done enough" to let the next proceed decides whether two writers to a line are correctly ordered or silently interleaved. This chapter is where the abstract "the home orders things" becomes a concrete state machine with a specific, load-bearing rule about when ordering is released.

3. Key Terms

4. Previous Chapter Connection

Chapter 7.5 drew the lifecycle as a single loop: dispatch, in-flight, response, retirement, owned by a tracker slot. It deliberately showed one side and one transaction.

This chapter splits that loop into the two machines that really run it. The requester's is close to the 7.1 read FSM — issue, wait, CompAck. The home's is new and richer: it orders the request at the POS, drives the snoop or memory path, returns the completion, and — critically — holds the line's ordering until CompAck. The tracker pool of 7.5 lives on both sides; here we watch what each slot's FSM actually does, and why the home's retirement timing is the linchpin of coherence ordering.

5. Core Concept — two machines, and the home orders the line

Each transaction is driven by two cooperating state machines, and the home's carries the ordering responsibility.

  • Requester-side FSM. The RN issues the REQ, waits through the in-flight phase (grants, snoop of its request, data), and closes with CompAck — essentially the 7.1 machine, generalized across read, write, atomic.
  • Home-side FSM. The HN accepts and orders the request at the POS, then takes one of two paths: snoop holders (SnpShared/SnpUnique, Chapter 7.4) and collect their responses, or go straight to memory. It assembles the completion, sends CompData / Comp, and waits for CompAck.
  • The ordering hold. From the moment it orders the request until it receives CompAck, the home keeps the line's serialization owned. A conflicting request — another transaction to the same line — is ordered strictly behind, not allowed to race.
  • Consistency. The two FSMs advance on shared events: the home's snoop is the requester-of-the-snoop's input; the requester's CompAck is the home's retirement trigger. Neither side is "done" until both agree — and the binding event is CompAck.

The synthesis:

The lifecycle is two FSMs — requester and home — advancing in lockstep across the fabric. The home is the point of serialization: it orders each request to a line and holds that ordering until CompAck, so conflicting transactions queue behind rather than interleave. CompAck is the hinge: it closes the requester's transaction and releases the home's ordering. Retire the home's ordering on anything earlier and two transactions to one line can overlap.

6. Engineering Mental Model — two clerks with a shared ledger

A records office where two clerks handle one filing, and a master ledger orders all changes to a file.

  • The front clerk (requester) takes your request, waits while it is processed, and signs off when the work is confirmed.
  • The records clerk (home) owns the master ledger for each file. When your request comes in, the records clerk claims the file's next slot in the ledger — fixing your change's order — then does the work: either asking whoever currently holds the file to hand it over (snoop) or pulling it from the archive (memory).
  • Crucially, the records clerk keeps the file's slot locked in the ledger until you sign off (CompAck). Anyone else wanting that file is queued after you.

If the records clerk releases the file's ledger slot the moment the work is sent — before you sign — the next person's change can be recorded against a file you have not finished with, and the ledger's order no longer matches reality. The lock has to hold until the signature.

7. Engineering Diagram — the home-side transaction FSM

A home-side transaction state machine with four states. Idle, the start state, means no transaction owns this tracker. From Idle, an ordered request on the snoop path moves to Snoop; on the memory path it moves directly to Data. Snoop has a self-loop for snooping additional holders and moves to Data once all snoop responses are in. Data sends the completion and moves to Wait-ack. Wait-ack returns to Idle, releasing the line's ordering, only when CompAck is received.IdleSnoopDataWait-ackorder + snooporder + snoopsnoop resp insnoop resp inmemory pathmemory pathsend Compsend CompCompAck: releaseCompAck: releasemore holdersmore holders
Figure 1 — the home-side transaction state machine. From Idle, an ordered request either enters the Snoop path (holders must be snooped) or, on the memory path, goes straight to Data. Snoop stays until every holder has responded, then moves to Data. Data sends the completion and enters Wait-ack, which returns to Idle — releasing the line's ordering — only on CompAck. The line's serialization is held for the entire loop, from ordering to CompAck.

Read it as a loop with a shortcut: the snoop path (Idle → Snoop → Data) when holders must be snooped, or the memory path (Idle → Data) when none do. Either way the machine returns to Idle — releasing the line's ordering — only on CompAck.

8. The Requester-Side and Home-Side States

The two machines, side by side.

PhaseRequester-side (RN)Home-side (HN)
Dispatchissue REQ, reserve TxnIDorder request at POS, allocate tracker
In-flightawait grant / snoop / datasnoop holders or fetch memory
Responsereceive CompData / Compassemble and send completion
Retirementsend CompAck, free slotreceive CompAck, release ordering

The rule to carry: the two FSMs mirror the 7.5 lifecycle but with different jobs — the requester waits and acknowledges; the home orders, resolves, and holds serialization. They meet at two events: the snoop (home drives, a holder responds) and the CompAck (requester drives, home retires). CompAck is the shared closing event — it must mean the same "done" to both sides.

9. Serialization at the Home — conflicts ordered by the POS

The home's extra responsibility, made explicit.

  • One order per line. Every access to a line passes through its home (Chapter 4.7), which places them in a single order. That order is the coherence order for the line.
  • In-flight means owned. While a transaction to a line is in-flight at the home — its FSM not yet back to Idle — the home owns that line's ordering. It will not start a conflicting transaction ahead of it.
  • Conflicts queue. A second request to the same line is held (ordered behind) until the first releases. This is how two writers to one line are strictly ordered rather than raced.
  • Release at CompAck. The home releases the ordering only when the first transaction retires on CompAck — because until the requester acknowledges, the transaction is not fully installed, and letting the next one proceed could interleave with the first's completion.

The point to carry:

The home is not just a router to memory; it is the serializer of a line. Its FSM does not return to Idle when the data is sent — it returns when the transaction is acknowledged, because that ordering hold is the mechanism that keeps conflicting transactions from overlapping. The requester's CompAck and the home's ordering release are the same event for a reason: coherence ordering is defined at the point where the home lets the next conflicting transaction begin.

10. Transaction Walkthrough — a read through both FSMs

RN0 reads a line homed at HN; RN1 holds it dirty. Watch both machines.

  1. RN dispatch / HN order. RN0's FSM issues ReadShared (→ its in-flight state). HN's FSM orders the request at the POS and, seeing RN1 as a holder, takes the snoop path (→ Snoop). The line's ordering is now owned by this transaction.
  2. Snoop. HN snoops RN1 (SnpShared); RN1 responds with data. HN's FSM moves Snoop → Data. (A second request to this line arriving now is queued behind.)
  3. Complete. HN's FSM sends CompData to RN0 and moves Data → Wait-ack. RN0's FSM receives the data (→ its response state) and installs the line.
  4. Acknowledge. RN0 sends CompAck (retiring its slot). HN receives it, moves Wait-ack → Idle, and releases the line's ordering.
  5. Next conflict proceeds. Only now does HN begin the queued conflicting transaction — strictly after the first, correctly ordered.

The two machines met at the snoop (step 2) and the CompAck (step 4). Note step 4: the home released ordering on CompAck, not on sending CompData in step 3 — the DebugLab shows why that gap matters.

11. RTL / Hardware View — a home-side transaction FSM

The home's machine orders a request, chooses the snoop or memory path, completes, and holds ordering until CompAck. pos_busy marks the ordering hold. Representative and sequential.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative home-side transaction FSM (educational).
// Order the request, take the SNOOP path (need_snoop) or the MEMORY path, send
// the completion, then release ordering ONLY on CompAck. pos_busy marks the
// serialization hold: while asserted, a conflicting request to this line waits.
module chi_hn_txn (
  input  logic clk, rst_n,
  input  logic req,          // an ordered request enters this tracker
  input  logic need_snoop,   // holders must be snooped
  input  logic snoop_done,   // all snoop responses collected
  input  logic data_ready,   // data available to complete
  input  logic comp_ack,     // requester's CompAck received
  output logic issue_snoop,  // drive snoops
  output logic send_comp,    // drive CompData / Comp
  output logic pos_busy      // line ordering owned (conflicts wait) until CompAck
);
  typedef enum logic [1:0] { IDLE, SNOOP, DATA, WACK } state_t;
  state_t state, next;
 
  always_comb begin
    next = state;
    case (state)
      IDLE:  if (req) next = need_snoop ? SNOOP : DATA;  // two paths
      SNOOP: if (snoop_done) next = DATA;                // self-loop: more holders
      DATA:  if (data_ready) next = WACK;                // completion sent
      WACK:  if (comp_ack)   next = IDLE;                // release ordering on ACK
    endcase
  end
 
  assign issue_snoop = (state == SNOOP);
  assign send_comp   = (state == DATA) && data_ready;
  assign pos_busy    = (state != IDLE);   // held from order to CompAck
 
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) state <= IDLE;
    else        state <= next;
endmodule

The same behavior in Verilog-2001:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Representative home-side transaction FSM (Verilog-2001).
module chi_hn_txn (
  input clk, rst_n, req, need_snoop, snoop_done, data_ready, comp_ack,
  output issue_snoop, send_comp, pos_busy
);
  localparam IDLE = 2'd0, SNOOP = 2'd1, DATA = 2'd2, WACK = 2'd3;
  reg [1:0] state, next;
 
  always @* begin
    next = state;
    case (state)
      IDLE:  if (req) next = need_snoop ? SNOOP : DATA;
      SNOOP: if (snoop_done) next = DATA;
      DATA:  if (data_ready) next = WACK;
      WACK:  if (comp_ack)   next = IDLE;
      default:               next = IDLE;
    endcase
  end
 
  assign issue_snoop = (state == SNOOP);
  assign send_comp   = (state == DATA) && data_ready;
  assign pos_busy    = (state != IDLE);
 
  always @(posedge clk or negedge rst_n)
    if (!rst_n) state <= IDLE;
    else        state <= next;
endmodule

And in VHDL:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- Representative home-side transaction FSM (VHDL).
library ieee;
use ieee.std_logic_1164.all;
 
entity chi_hn_txn is
  port (
    clk, rst_n  : in  std_logic;
    req         : in  std_logic;
    need_snoop  : in  std_logic;
    snoop_done  : in  std_logic;
    data_ready  : in  std_logic;
    comp_ack    : in  std_logic;
    issue_snoop : out std_logic;
    send_comp   : out std_logic;
    pos_busy    : out std_logic
  );
end entity;
 
architecture rtl of chi_hn_txn is
  type state_t is (IDLE, SNOOP, DATA, WACK);
  signal state : state_t := IDLE;
begin
  process (clk, rst_n)
  begin
    if rst_n = '0' then
      state <= IDLE;
    elsif rising_edge(clk) then
      case state is
        when IDLE  => if req = '1' then
                        if need_snoop = '1' then state <= SNOOP; else state <= DATA; end if;
                      end if;
        when SNOOP => if snoop_done = '1' then state <= DATA; end if;
        when DATA  => if data_ready = '1' then state <= WACK; end if;
        when WACK  => if comp_ack = '1'   then state <= IDLE; end if;
      end case;
    end if;
  end process;
 
  issue_snoop <= '1' when state = SNOOP else '0';
  send_comp   <= '1' when (state = DATA and data_ready = '1') else '0';
  pos_busy    <= '0' when state = IDLE else '1';
end architecture;

All three keep pos_busy asserted from the ordered request until CompAck — so the line's ordering is owned for the whole transaction, and a conflict cannot slip in. The DebugLab shows the coherence hazard of releasing it at send_comp instead.

12. Verification View — the home holds ordering until CompAck

The property that protects coherence ordering: the home owns the line (pos_busy) from the request until CompAck, and releases only on the ack.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind to chi_hn_txn.
// 1. Ordering is held (pos_busy) continuously until CompAck — it does not drop at
//    send_comp. pos_busy may fall only in the cycle after comp_ack.
property p_hold_until_ack;
  @(posedge clk) disable iff (!rst_n)
    ($fell(pos_busy)) |-> $past(comp_ack);
endproperty
 
// 2. The completion is sent (send_comp) while still holding ordering — sending
//    Comp must NOT itself release the line.
property p_comp_does_not_release;
  @(posedge clk) disable iff (!rst_n)
    send_comp |-> pos_busy;
endproperty

The system point, beyond the checks:

Two transaction FSMs make one transaction, but the coherence guarantee lives in when the home lets go. Sending the completion is not the same as finishing the transaction — the requester has not yet acknowledged, so the line's new state is not yet settled everywhere. If the home released ordering at send_comp, a conflicting transaction could be ordered against a line whose previous transaction is still landing, and the two would interleave. Holding until CompAck closes that gap: the requester's acknowledgement and the home's release are the same instant, so there is never a moment when a line's ordering is ambiguous. That single alignment is what makes the two-FSM system coherent.

  • What it proves: ordering is held to CompAck, and sending Comp does not release it.
  • What it does not prove: the requester's own FSM correctness — that is the RN-side machine (Chapter 7.1).
  • Bug signature: pos_busy falling at send_comp — a line released for conflicts before its transaction retired.

13. Testbench — the home holds ordering to CompAck

Runs the snoop path and checks pos_busy stays asserted through send_comp, dropping only after CompAck.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module tb_chi_hn_txn;
  logic clk = 0, rst_n = 0;
  logic req = 0, need_snoop = 0, snoop_done = 0, data_ready = 0, comp_ack = 0;
  logic issue_snoop, send_comp, pos_busy;
  int errors = 0;
 
  chi_hn_txn dut (.*);
  always #5 clk = ~clk;
 
  initial begin
    @(posedge clk) rst_n = 1;
 
    // Ordered request, snoop path.
    @(posedge clk) begin req = 1; need_snoop = 1; end
    @(posedge clk) begin req = 0; need_snoop = 0; end
    if (!pos_busy || !issue_snoop) begin errors++; $display("FAIL not snooping/owned after order"); end
    else $display("PASS ordering owned, snooping");
 
    // Snoops complete -> data.
    @(posedge clk) snoop_done = 1;
    @(posedge clk) snoop_done = 0;
 
    // Data ready -> send completion; ordering MUST still be held here.
    @(posedge clk) data_ready = 1;
    if (!send_comp) begin errors++; $display("FAIL no completion when data ready"); end
    else if (!pos_busy) begin errors++; $display("FAIL ordering released at send_comp"); end
    else $display("PASS completion sent, ordering still held");
    @(posedge clk) data_ready = 0;
 
    // CompAck -> release ordering.
    @(posedge clk) comp_ack = 1;
    @(posedge clk) comp_ack = 0;
    if (pos_busy) begin errors++; $display("FAIL ordering not released after CompAck"); end
    else $display("PASS ordering released on CompAck");
 
    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 ordering owned, snooping
PASS completion sent, ordering still held
PASS ordering released on CompAck
ALL TESTS PASSED

14. DebugLab — the home releases ordering when it sends the completion

1

The home releases ordering when it sends the completion

HOME RELEASES ORDERING AT SEND_COMP, BEFORE COMPACK -> CONFLICT INTERLEAVES
Symptom

Two cores hammering the same line occasionally observe a coherence violation — one reads a value inconsistent with the ordering both should have seen, or an update is lost. It only appears when transactions to one address overlap; spread-out access is clean.

Evidence

A conflicting transaction begins before the first is acknowledged:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
txn A (RN0 ReadUnique, line L):
  HN sends CompData to RN0, HN FSM -> IDLE (ordering RELEASED)  <-- too early
  RN0 has NOT yet sent CompAck; still installing L
txn B (RN1 ReadUnique, line L) arrives:
  HN, now IDLE for L, orders B and snoops -> races A's install
result: A and B interleave on L -> inconsistent ordering

The home let B proceed in the window between sending A's completion and receiving A's CompAck.

First Divergence

The home FSM's retirement was triggered by send_comp — sending the completion — rather than by comp_ack. From that point the line's ordering was released while transaction A was still landing, so a conflicting transaction B could be ordered into the gap.

Root Cause

The home is the point of serialization, and serialization must hold until the transaction retires. Sending the completion is not retirement; the requester's CompAck is. Between the two, transaction A's effect on the line is not yet settled everywhere, so releasing the ordering there lets a conflicting transaction interleave — exactly the overlap the POS exists to prevent. The requester-side early-retire bug of Chapter 7.1 aliased one requester's TxnID; this is its home-side twin, and it mis-orders two different transactions to one line.

Fix

Release the line's ordering only on CompAck: gate the home FSM's return to Idle on comp_ack, never on send_comp. The pos_busy signal must stay asserted through the completion and drop only at retirement, so a conflicting request is held behind the in-flight transaction until it is truly done. Send the completion when the data is ready, but hold serialization until the acknowledgement.

15. Common Mistakes

  • Releasing ordering at send_comp. Assumption: completion sent means done. Bug: conflict interleave (the DebugLab). Prevention: hold ordering to CompAck.
  • Modeling only one FSM. Assumption: one machine per transaction. Bug: requester/home views diverge. Prevention: model both, meeting at snoop and CompAck.
  • Letting conflicts race. Assumption: independent trackers are independent. Bug: two writers to a line overlap. Prevention: order same-line conflicts behind the in-flight one.
  • Skipping the memory path. Assumption: every request snoops. Bug: needless snoops / mis-modeled latency. Prevention: two paths — snoop or memory.
  • Treating CompAck as optional at the home. Assumption: the home retires on its own. Bug: ordering released early or never. Prevention: CompAck retires the home FSM.
  • Inconsistent shared events. Assumption: snoop/ack timing is loose. Bug: FSMs desynchronize. Prevention: advance both sides on the shared events.

16. Engineering Checklist

  • Model a transaction as two FSMs — requester-side and home-side — kept consistent.
  • Treat the home as the POS; it orders every access to a line.
  • Support both paths in the home FSM — snoop and memory.
  • Hold the line's ordering (pos_busy) from order to CompAck.
  • Release serialization only on CompAck — never at send_comp.
  • Order same-line conflicts strictly behind the in-flight transaction.

17. Key Takeaways

  • The lifecycle is implemented as two FSMs — requester-side and home-side — that must stay consistent.
  • The home is the point of serialization: it orders every access to a line into one coherence order.
  • The home FSM has two paths — snoop holders or fetch memory — before completing.
  • It holds a line's ordering until CompAck, so conflicting transactions queue behind, never interleave.
  • Releasing ordering at send_comp instead of CompAck lets two transactions to one line overlap — a coherence hazard.
  • Model both sides, hold serialization to CompAck, order conflicts behind; the model here is representative.

18. Quick Revision

The transaction state machine. The clean lifecycle is implemented as two FSMs: a requester-side machine (issue REQ, wait, send CompAck — the 7.1 machine generalized) and a richer home-side machine. The home is the point of serialization for a line: it orders each request, takes the snoop path (snoop holders, collect responses) or the memory path (fetch from the SN), sends the completion, and waits for CompAck. The load-bearing rule: the home holds the line's ordering until CompAck, not until it sends the completion — so a conflicting transaction to the same line is ordered strictly behind the in-flight one, never raced against it. Release the ordering at send_comp and the two interleave against a line still landing — a coherence hazard, the home-side twin of Chapter 7.1's early-retire. The two FSMs meet at the snoop and at CompAck; CompAck closes the requester and releases the home. Model both sides, hold serialization to CompAck. Representative model; Module 8 walks concrete request flows, starting with ReadShared.

Coming Next

Chapter 8.1 — ReadShared Flow. Module 7 built the transaction model — the four kinds, the lifecycle, and the two FSMs that run it. Module 8 puts it to work on concrete, named flows. Chapter 8.1 walks the ReadShared flow in full detail — every packet, state transition, and decision as a core fetches a line into Shared state — turning the general read of Chapter 7.1 into the specific, traceable sequence you will recognize on a waveform and in a coherence log.