Skip to content

AMBA AXI · Module 8

Same-ID Ordering Rules

AXI's same-ID ordering guarantee — transactions sharing an AxID complete in issue order — what it does and does not cover (different IDs, read-vs-write), and why same-ID across multiple slaves can serialize and hurt performance.

Chapter 8.2 leaned on a guarantee repeatedly: same ID means in order. Now we state it precisely, because it's the rule that makes outstanding transactions predictable — and the boundaries of what it does and doesn't promise are exactly where ordering bugs and performance traps live. The rule is narrow on purpose: it orders transactions sharing an ID, and nothing else. It says nothing about different IDs (they may reorder — Chapter 8.4) and nothing about reads versus writes (a separate concern). And it has a sharp performance edge: same-ID transactions spread across multiple slaves can force the interconnect to serialize. This chapter pins down the guarantee and its limits.

1. The Rule

The same-ID ordering rule, stated for each direction:

  • Reads: read transactions issued with the same ARID return their data in the order the addresses were issued. Read data for an earlier same-ID read arrives before a later same-ID read's data.
  • Writes: write transactions issued with the same AWID complete — their B responses return — in the order the addresses were issued.

That's the whole guarantee: for a given ID, completion order equals issue order. A subordinate or interconnect may have the later transaction's result ready first, but it must hold it back and deliver the earlier same-ID one first. This is what lets a manager that needs ordering simply reuse one ID and trust the sequence.

Manager issues three reads with ARID=3; the subordinate returns their data in issue order despite any internal readiness.ManagerSubordinateAR — ARID=3 (read 0)AR — ARID=3 (read 1)AR — ARID=3 (read 2)R — RID=3 (read 0first)R — RID=3 (read 1)R — RID=3 (read 2last)
Figure 1 — same-ID ordering. The manager issues three reads all tagged ARID=3. Even if the subordinate could produce the third read's data first, it must return RID=3 data in issue order — read 0, then read 1, then read 2. For a given ID, completion order equals issue order.

2. A Same-ID Read Stream on the Wire

Three same-ID reads return their data strictly in issue order, regardless of which the subordinate finished first:

same-id-order — three ARID=3 reads return in issue order

7 cycles
Three reads tagged ARID 3 return read-data D0, D1, D2 in the order issued, RID equal to 3 on each, RLAST on each single-beat response.RID=3 data in issue order: D0, D1, D2RID=3 data in issue order: D0, D1, D2read 0 data firstread 0 data firstread 2 data lastread 2 data lastaclkrvalidridX333333rdataXD0D0D1D1D2D2rlastt0t1t2t3t4t5t6
Figure 2 — same-id-order: three reads all with ARID=3. The RID on the read-data channel returns data D0, D1, D2 in issue order — read 0's data, then read 1's, then read 2's. The subordinate must not let a later same-ID read's data overtake an earlier one's; for the same ID, the data sequence mirrors the issue sequence.

3. What the Rule Does Not Cover

The guarantee is deliberately narrow. Two things it explicitly does not promise:

  • Different IDs are not ordered. Transactions with different AxIDs have no ordering relationship — the system may complete them in any order (Chapter 8.4). The rule only orders within one ID.
  • Reads and writes are not ordered relative to each other. ARID and AWID live in separate ID spaces; a read and a write — even with the same numeric ID value — have no ordering guarantee between them. If a manager needs a write to land before a dependent read (or vice versa), it must enforce that itself, typically by waiting for the first transaction's response before issuing the second. AXI's IDs order reads among reads and writes among writes, never reads against writes.

Missing either limit is a classic bug source: assuming different-ID transactions stay ordered, or assuming a same-valued read and write are ordered. Neither holds.

Guaranteed: same-ID reads ordered, same-ID writes ordered. Not guaranteed: different-ID ordering, read-versus-write ordering.Same-ID reads✓ ordered (issue order)Same-ID writes✓ ordered (issue order)Different IDs✗ no order — may reorderRead vs write✗ no order — enforce manually12
Figure 3 — the rule's scope. Guaranteed: same-ARID reads in order, same-AWID writes in order. NOT guaranteed: ordering between different IDs (may reorder), and ordering between reads and writes (separate ID spaces — must be enforced by the manager). The guarantee is strictly within one ID and one direction.

4. Same ID Across Multiple Slaves — The Serialization Trap

Here's the performance edge. The interconnect must preserve same-ID ordering even when same-ID transactions target different slaves. But different slaves have different latencies and respond independently — so to guarantee that same-ID response 0 (from a slow slave) precedes same-ID response 1 (from a fast slave), the interconnect must hold back the fast slave's response until the slow one is done. Effectively, same-ID traffic to multiple slaves serializes at the rate of the slowest, and the interconnect needs buffering/blocking to enforce it.

The consequence: reusing one ID across transactions that hit different slaves can badly hurt throughput (head-of-line blocking across slaves). Many systems therefore follow a guideline — keep one ID to one slave, or use distinct IDs for transactions that can target different slaves — so the ordering constraint never forces cross-slave serialization. This is the practical reason ID assignment must consider not just ordering need but where transactions go.

Same-ID transactions to a slow and a fast slave force the interconnect to hold the fast response until the slow one completes, serializing them.resp 1 firstmust waitresultTwo same-ID txns→ differentslavesFast slave: resp 1ready earlyInterconnect holdsresp 1 for orderSerialized atslow-slave rate
Figure 4 — same-ID across slaves serializes. Two same-ID transactions go to a slow slave (resp 0) and a fast slave (resp 1). To preserve issue order, the interconnect must hold the fast slave's resp 1 until the slow slave's resp 0 returns — serializing at the slow slave's rate. Distinct IDs (or one-ID-per-slave) avoid this.

5. The Write-Data Ordering Rule AXI4 Added

There is a third ordering constraint that belongs on this page and is routinely missed, because it is not an ID rule at all — it is a rule about the W channel that AXI4 introduced by deleting something.

AXI3 had a WID signal. Write data beats carried their own ID, which meant a manager could interleave the data of two different write transactions on the W channel and the subordinate would sort them out by WID.

AXI4 removed WID entirely and removed write-data interleaving with it. The consequence is a hard ordering requirement:

A manager must send write data in the same order as it issued the write addresses. Not per-ID — globally, across every outstanding write. The Nth AW handshake owns the Nth write-data burst on the W channel.

The read side has the symmetric story — AXI4 also dropped read-data interleaving, so all beats of one read burst return contiguously. That is developed in read data interleaving; the executable check for it appears in §6 below, because "beats of one burst arrive contiguously" is an ordering property this page can assert directly.

6. The Rules as an Executable Checker

Section 7 below describes a per-ID scoreboard in prose. Here it is as code — because "completion order equals issue order" is a claim a checker can actually enforce, and a page that only describes the scoreboard leaves the reader to invent the hard part.

The design is a per-ID FIFO. Every accepted address pushes; every accepted completion pops. Ordering violations then surface two ways: a completion for an ID with nothing outstanding, and — the real detector — a completion whose payload does not correspond to the transaction at the head of that ID's queue.

axi_same_id_order_checker.sv — per-ID ordering, bindable to any AXI4 port
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────────
//  Same-ID ordering checker (AMBA AXI4 §A5.3).
//
//  Bind to a manager, subordinate, or interconnect port:
//     bind axi_slave axi_same_id_order_checker #(.ID_W(4)) u_ord (.*);
//
//  WHAT MAKES THE ORDER CHECK REAL: a FIFO pop alone cannot detect reordering —
//  pop the head and any arriving response "looks" in order. Detection needs the
//  payload to identify WHICH transaction completed. This checker uses the
//  address-as-data convention (the memory model returns rdata == araddr), which
//  costs nothing in a testbench and makes a swapped pair of same-ID reads show
//  up immediately as a data mismatch. Drive it against a real memory model and
//  set CHECK_DATA=0; you keep the outstanding checks and lose only the
//  reordering detector, which the scoreboard then owns instead.
// ─────────────────────────────────────────────────────────────────────────────
module axi_same_id_order_checker #(
  parameter int ID_W       = 4,
  parameter int ADDR_W     = 32,
  parameter int DATA_W     = 32,
  parameter bit CHECK_DATA = 1        // 0 when a real memory model owns data checking
) (
  input logic              aclk,
  input logic              aresetn,
  // Read address / read data
  input logic              arvalid, arready,
  input logic [ID_W-1:0]   arid,
  input logic [ADDR_W-1:0] araddr,
  input logic              rvalid,  rready, rlast,
  input logic [ID_W-1:0]   rid,
  input logic [DATA_W-1:0] rdata,
  // Write address / write response
  input logic              awvalid, awready,
  input logic [ID_W-1:0]   awid,
  input logic [ADDR_W-1:0] awaddr,
  input logic              bvalid,  bready,
  input logic [ID_W-1:0]   bid
);
 
  localparam int N_ID = 1 << ID_W;
 
  typedef logic [ADDR_W-1:0] addr_t;
 
  // One issue-order queue per ID. This IS the same-ID rule: the guarantee is
  // that each queue drains front-first, so the head is the only transaction
  // allowed to complete next for that ID.
  addr_t rd_pending [N_ID][$];
  addr_t wr_pending [N_ID][$];
 
  int unsigned rd_checked, wr_checked, rd_errors, wr_errors;
 
  // ── Issue side ────────────────────────────────────────────────────────────
  always_ff @(posedge aclk) begin
    if (!aresetn) begin
      for (int i = 0; i < N_ID; i++) begin
        rd_pending[i].delete();
        wr_pending[i].delete();
      end
      rd_checked = 0; wr_checked = 0; rd_errors = 0; wr_errors = 0;
    end else begin
      if (arvalid && arready) rd_pending[arid].push_back(araddr);
      if (awvalid && awready) wr_pending[awid].push_back(awaddr);
 
      // ── Read completion ────────────────────────────────────────────────
      if (rvalid && rready && rlast) begin
        if (rd_pending[rid].size() == 0) begin
          rd_errors++;
          $error("[%0t] RLAST for ARID=%0h with no outstanding read", $time, rid);
        end else begin
          addr_t expect_addr = rd_pending[rid].pop_front();
          rd_checked++;
          // The reordering detector. Under address-as-data, the head of this
          // ID's queue predicts the payload exactly; a swap shows up here.
          if (CHECK_DATA && rdata !== DATA_W'(expect_addr)) begin
            rd_errors++;
            $error("[%0t] SAME-ID ORDER VIOLATION, ARID=%0h: expected data for addr %0h, got %0h",
                   $time, rid, expect_addr, rdata);
          end
        end
      end
 
      // ── Write completion ───────────────────────────────────────────────
      if (bvalid && bready) begin
        if (wr_pending[bid].size() == 0) begin
          wr_errors++;
          $error("[%0t] B response for AWID=%0h with no outstanding write", $time, bid);
        end else begin
          void'(wr_pending[bid].pop_front());
          wr_checked++;
        end
      end
    end
  end
 
  // ── AXI4 has no read-data interleaving: once a burst starts, every beat
  //    until RLAST carries the same RID. This is a pure-protocol ordering
  //    property, checkable with no model at all.
  logic            burst_active;
  logic [ID_W-1:0] active_id;
 
  always_ff @(posedge aclk or negedge aresetn) begin
    if (!aresetn) burst_active <= 1'b0;
    else if (rvalid && rready) begin
      if (rlast)             burst_active <= 1'b0;
      else if (!burst_active) begin
        burst_active <= 1'b1;
        active_id    <= rid;
      end
    end
  end
 
  a_no_read_interleaving:
  assert property (@(posedge aclk) disable iff (!aresetn)
      (rvalid && rready && burst_active) |-> (rid == active_id))
    else $error("[%0t] read data interleaved: RID=%0h arrived mid-burst of RID=%0h",
                $time, rid, active_id);
 
  // ── Covers. Every check above is conditional, so a quiet bus passes them
  //    all while proving nothing. These say the scenarios actually happened.
  c_same_id_depth_2: cover property (@(posedge aclk) disable iff (!aresetn)
      (arvalid && arready) ##0 (rd_pending[arid].size() >= 1));
  c_multi_beat_read: cover property (@(posedge aclk) disable iff (!aresetn)
      (rvalid && rready && !rlast));
  c_write_outstanding: cover property (@(posedge aclk) disable iff (!aresetn)
      (awvalid && awready) ##0 (wr_pending[awid].size() >= 1));
 
  final begin
    $display("[same-id checker] reads checked=%0d writes checked=%0d errors=%0d",
             rd_checked, wr_checked, rd_errors + wr_errors);
  end
 
endmodule

What each check means, and what a failure tells you.

CheckThe claimA failure tells you
SAME-ID ORDER VIOLATIONThe head of an ID's queue is the next transaction that may completeA subordinate or interconnect let a ready-early same-ID transaction overtake an earlier one — the exact violation §1 forbids
no outstanding read/writeA completion exists only for an accepted addressA response was manufactured, replayed, or tagged with the wrong ID. Often an interconnect ID-remap bug
a_no_read_interleavingAll beats of one read burst are contiguousAXI3-era interleaving behaviour on an AXI4 port
c_same_id_depth_2 etc.The scenarios ran at allIf these sit at zero, every check above passed vacuously and the run is not evidence

The last row is the one to internalise. Each ordering check is an implication over a condition that a lightly-loaded bus never creates. A same-ID checker that never saw two outstanding same-ID transactions has proven nothing, and the cover is the only artifact that distinguishes "ordering held" from "ordering was never tested."

7. Common Misconceptions

8. Debugging Lab — Throughput Halved After an "Unrelated" ID Change

1

A one-line ID assignment change halves DMA throughput with no functional failure

SAME-ID-CROSS-SLAVE-SERIALIZATION
Observed Symptom

A DMA engine streaming to two memories drops from ~1.9 GB/s to ~0.95 GB/s. Every test passes. No assertion fires, no scoreboard mismatch, no protocol violation. The only change in the commit was ID assignment: a cleanup that consolidated several AWID/ARID values onto one ID "for simpler tracking."

Expected vs Actual

Expected. Two independent memories, each capable of ~1 GB/s, accessed concurrently → roughly additive throughput.

Actual. Aggregate throughput equals what the slower memory alone can sustain. Waveforms show the DMA issuing addresses at full rate and the fast memory producing responses promptly — but those responses sitting in the interconnect, not reaching the manager.

Diagnostic

The signature that separates this from ordinary backpressure: the fast slave's response is complete and the interconnect is not forwarding it. Ordinary backpressure would show the manager withholding RREADY; here RREADY is high and the data still does not arrive.

Three questions localise it:

  1. Are the stalled transactions sharing an ID? Check ARID/AWID on the delayed pair. If they differ, this is not the trap — go look at arbitration.
  2. Do they target different slaves? Same ID to one slave is ordinary head-of-line blocking; same ID across different slaves is the serialization case (§4).
  3. Does the delay track the slow slave's latency? Measure the fast response's held time. If it consistently equals the slow slave's outstanding latency, the interconnect is holding it to preserve issue order — which is the interconnect being correct.
Root Cause

The same-ID rule requires completion in issue order, and the interconnect must honour it even across slaves it does not control the latency of. With both memories' traffic on one ID, a response from the fast memory that is ready first cannot be delivered first — the interconnect must buffer it until the earlier same-ID response returns from the slow memory.

The consolidation "for simpler tracking" imposed a total order on transactions that had no ordering requirement. Nothing is broken: the manager asked for ordering, and it got it, at the cost of the concurrency the two independent memories existed to provide.

Fix

Give traffic to different slaves different IDs, so no cross-slave ordering constraint exists:

the ID assignment, before and after
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  before:  memory A traffic → AWID/ARID = 0
           memory B traffic → AWID/ARID = 0      ← one ID spanning two slaves
 
  after:   memory A traffic → AWID/ARID = 0
           memory B traffic → AWID/ARID = 1      ← ordering only where it is needed

The rule of thumb §4 gives — one ID per slave, or distinct IDs for traffic that can target different slaves — exists precisely to make this unrepresentable. Note what the fix does not do: it does not relax any ordering the design actually depended on, because the two streams were independent to begin with.

Prevention

Treat ID assignment as an architectural decision, not bookkeeping. Reusing an ID is a request for serialization, and it is free only when the transactions genuinely must be ordered and reach the same slave.

Two practical guards. Add a throughput regression to CI — a functional suite cannot catch this, because nothing functional is wrong; only a performance metric can. And add a cover for same-ID transactions in flight to different slaves: if it fires, either the ordering is intentional and documented, or it is this bug waiting for a latency asymmetry to expose it.

9. Debugging Insight

10. Verification Insight

11. Interview Questions

12. Summary

The same-ID ordering rule is AXI's core ordering guarantee, and it's narrow by design: for a given AxID, completion order equals issue order — same-ARID reads return data in issue order, same-AWID writes return B responses in issue order, with the system holding back any ready-early later transaction to preserve it. The limits are as important as the rule: different IDs are not ordered (they may reorder — 8.4), and reads and writes are not ordered relative to each other (separate ID spaces — the manager must enforce any read/write dependency by waiting on responses). And there's a performance edge: same-ID transactions across multiple slaves force the interconnect to serialize (holding fast responses behind slow ones), so one-ID-per-slave or distinct IDs avoid cross-slave head-of-line blocking.

The discipline this yields: use one ID to order same-direction accesses (accepting in-order, possibly serialized completion), distinct IDs for independent accesses (throughput via reordering), and explicit response-waits for read/write dependencies (which IDs can't express). Bugs are either assumed ordering that wasn't guaranteed (data hazards) or over-imposed ordering that wasn't needed (lost throughput). Next: the flip side — different-ID and out-of-order completion — the reordering this rule deliberately permits, and the hazards it introduces.

13. Where This Is Specified

The same-ID ordering guarantee is normative text in the Arm AMBA AXI Protocol Specification — transaction ordering in §A5 (Transaction identifiers), with the write-response ordering rule in §A5.3 and the ID rules themselves in §A5.1. Arm publishes it on the AMBA AXI documentation page.

Two things are worth reading in the specification rather than taking from any tutorial, because both are commonly reconstructed wrongly from memory. First, that ARID and AWID are separate ID spaces with no ordering between them — the source of the stale-read-after-write bug in §8. Second, the AXI4 change list, where WID and write-data interleaving were removed: that deletion is what turns "send write data in address order" into a protocol requirement (§5), and it is invisible to anyone who learned ordering from AXI3 material.

The SVA used in §6 is IEEE Std 1800 (SystemVerilog) clause 16 — see concurrent assertions for the sampling and implication semantics, and for why every check there is paired with a cover.

Related lessons. ID mechanics are in AxID and transaction IDs; the concurrency this rule constrains is in why outstanding transactions exist; the reordering it permits is different-ID ordering. For the channel-level detail behind §5–§6, see read data interleaving, write ordering and WLAST, and the B response. For the verification build-out, AXI scoreboards and AXI assertions.

14. What Comes Next

You've got the ordering guarantee; next, the reordering it permits:

Previous: 8.2 — Transaction IDs. Related: 6.3 — AxID for ID mechanics, and 8.1 — Why Outstanding Transactions Exist for the concurrency this orders. For the broader protocol catalog, see the AMBA family overview doc.