AMBA CHI · Module 12 · Ordering and Consistency
DSB Semantics
The DMB ordered without waiting; the DSB waits. A DSB blocks execution until all the accesses issued before it have actually completed — landed in memory or a device — before any instruction after it proceeds. That is the completion guarantee the DMB withholds — not just observed-ahead, but done. It is what buffer-then-doorbell needs — the buffer written before the device reads it — and what cache and TLB maintenance and MMIO rely on. The cost is that a DSB stalls: it holds the pipeline until completion, so use it only where completion is genuinely required. Its mirror misuse: a DSB where only ordering is needed turns every lightweight synchronization into a stall. Representative model, not the specification.
Advanced15 min readAMBA CHIDSBBarrierCompletionSynchronization
Module 12 · Chapter 12.5 · Ordering and Consistency
Project thread — 12.4 was the DMB (ordering). This chapter is the DSB (completion). 12.6 catalogues the ordering rules.
1. Learning Outcomes
By the end of this chapter you should be able to:
- Define the DSB as a completion barrier — it waits for prior accesses to finish.
- Contrast the DSB (waits for completion) with the DMB (orders observation, no wait).
- Identify when completion is required — buffer-then-doorbell, maintenance, MMIO.
- State the cost of a DSB — it stalls until completion.
- Diagnose the performance loss of using a DSB where only ordering is needed.
- Implement a representative DSB model in SystemVerilog, Verilog-2001, and VHDL.
2. Why Should I Learn This?
The DSB is the barrier you reach for when ordering is not enough — when a subsequent action depends on prior accesses having actually happened, not merely been observed in order. Kicking off a DMA that reads a buffer, completing a cache or TLB maintenance operation, ensuring a device register write has taken effect before the next step — all need completion, and the DSB is how a program demands it. It is the barrier that makes "the writes are done" a guarantee, not a hope.
Its power is a wait, and that wait is its cost. A DSB stalls until completion, which is far more expensive than the DMB's stall-free ordering. So the DSB is a precise tool for a specific need, and its misuse is the exact mirror of the DMB's: where the DMB is too weak when completion is needed (Chapter 12.4), the DSB is too strong when only ordering is needed — every unnecessary DSB is a pipeline stall for a guarantee the code did not require. Knowing when completion is truly needed is knowing when to pay for a DSB.
3. Key Terms
4. Previous Chapter Connection
Chapter 12.4 defined the DMB — an ordering barrier that makes before-accesses observed ahead of after-accesses without waiting for them to complete. It ended by naming the case the DMB cannot handle: when a subsequent action depends on the before-accesses having landed.
This chapter is that case's answer — the DSB. Where the DMB ordered, the DSB waits: it blocks until the before-accesses are complete before letting anything after it proceed. It is the strict superset of the DMB's guarantee (it also orders), plus the completion the DMB withholds. The two together span the module's barrier needs: DMB for ordering, DSB for completion. 12.4 showed the DMB's limit; 12.5 provides what fills it — at the cost of a stall.
5. Core Concept — waits for completion, at the cost of a stall
A DSB blocks until all prior accesses have completed, before any subsequent instruction proceeds.
- Waits for completion. A DSB does not proceed past itself until every before-access has completed — reached its endpoint and taken effect (landed in memory or a device). Not observed-ahead: done.
- Also orders. Because the before-accesses are complete before anything after, they are trivially observed ahead too — a DSB provides the DMB's ordering plus completion.
- The cost is a stall. Waiting for completion holds the pipeline; no later instruction runs until the before-accesses finish. This is expensive relative to the DMB's stall-free ordering.
- Use where completion is required. Buffer-then-doorbell (the buffer must be written before the device reads it), cache/TLB maintenance completion, MMIO ordering-with-effect — cases where the effect must have happened.
The synthesis:
A DSB is a completion barrier: it blocks until all before-accesses have completed before any after-instruction proceeds. It is stronger than a DMB — completion implies the ordering a DMB gives, plus the guarantee the accesses are done. Its cost is a stall, so it is for cases that genuinely need completion (buffer-then-doorbell, maintenance, MMIO). Use a DMB where only ordering is needed.
6. Engineering Mental Model — wait for the delivery confirmation
If the DMB was "postmarked in order," the DSB is "wait for delivery confirmation."
- You send the package (the data write), then a DSB. The DSB holds you — you do not take the next step — until you receive confirmation the package has arrived.
- Only once delivery is confirmed do you make the phone call that says "act on it now — it's there." Because you waited, the recipient really can act; the package is delivered, not just posted.
- This is what a buffer-then-doorbell handoff needs: the buffer must be delivered (written) before the doorbell tells the device to read it — a delivery confirmation, not a postmark.
- The cost is the wait. You stood idle until confirmation arrived — time you would not spend if you only needed the packages sequenced (a DMB). So you wait for delivery only when arrival actually matters.
Delivery confirmation (DSB) is what you need when the next step depends on the package being there; a postmark (DMB) is enough when you only need an order.
7. Engineering Diagram — blocking until completion
Read the order: the agent waits for the completion of @A before issuing the doorbell — so the device is signalled only after the buffer has actually landed. The DSB inserted a genuine wait; the doorbell fires on a completed buffer, not an in-flight one.
8. DSB versus DMB
The two barriers, by what they guarantee.
| Guarantee | DMB (ordering) | DSB (completion) |
|---|---|---|
| Before observed before after? | yes | yes |
| Waits for before to complete? | no | yes |
| Blocks the pipeline? | no | yes (stall) |
| Enough for message passing / locks? | yes | yes (overkill) |
| Enough for "writes are done"? | no | yes |
| Cost | cheap (no stall) | expensive (stall) |
The rule to carry: a DMB orders, a DSB completes. The DSB is the strict superset — it also orders — but it waits, so it stalls. Reach for a DSB only when a subsequent action depends on the before-accesses having finished (a device will act on the data, a maintenance op must be complete). Where only a relative order matters, a DMB is correct and far cheaper. Match the barrier to the requirement, and no stronger.
9. When Completion Is Required — and the Cost of Overkill
The two sides of the DSB — where it is needed and where it is waste — deserve their own statement.
- A dependent effect needs completion. When the next step acts on the result of the before-accesses — a DMA reads the buffer, a device processes the write, a TLB flush must be finished — the accesses must be complete, and only a DSB guarantees it.
- Maintenance needs completion. Cache and TLB maintenance operations are only safe to build on once finished; a DSB waits for that finish.
- Overkill stalls. A DSB where only ordering was needed inserts an unnecessary completion wait — the pipeline stalls for a guarantee the code did not require. On a hot synchronization path, this is a large, avoidable performance loss.
- The mirror of the DMB's misuse. A DMB where completion is needed is a correctness bug (Chapter 12.4); a DSB where only ordering is needed is a performance bug. Both come from mismatching the barrier to the requirement.
The point to carry:
The DMB and DSB are two prices for two guarantees, and the discipline is to pay the price that matches the need — no more, no less. Under-buy (DMB for completion) and you get a correctness bug; over-buy (DSB for ordering) and you get a performance bug. The completion the DSB provides is genuinely necessary only when a later action depends on the effect of earlier accesses having materialized — a narrower set than synchronization in general. So the DSB should be rare and deliberate: a barrier you place because you can point to the specific dependent effect that requires the writes to be done. Everywhere else, the DMB's stall-free ordering is both sufficient and correct.
10. Reading the Semantics — buffer-then-doorbell done right
Trace the buffer-then-doorbell handoff, where a DSB is exactly right.
- Write the buffer. The driver writes the data buffer at A — potentially many writes, some still in flight.
- DSB. A DSB blocks until all the buffer writes have completed — landed in memory.
- Wait resolves. The DSB does not proceed until completion is confirmed; the buffer is now fully written.
- Doorbell. Only now does the driver write the doorbell register at the device, telling it the buffer is ready.
- Device reads a complete buffer. The DMA engine, seeing the doorbell, reads a buffer that is fully landed — no partial or stale data.
The DSB was correct because the doorbell's effect (the DMA reading the buffer) depended on the buffer being complete. A DMB here would only have ordered the writes ahead of the doorbell without waiting — the Chapter 12.4 bug. And using a DSB for a plain lock release, where only ordering is needed, would stall pointlessly — the DebugLab.
11. RTL / Hardware View — a DSB model
A DSB blocks until completion. Its model gates the after-instruction on all before-accesses being complete, and exposes the stall. Representative.
// Representative DSB (Data Synchronization Barrier) model (educational).
// A DSB BLOCKS until all before-accesses have COMPLETED before any after-instruction
// proceeds. It provides ordering AND completion, at the cost of a stall. after_may_
// proceed is gated on all_before_complete; while waiting, the pipeline is stalled.
module chi_dsb (
input logic dsb_issued, // a DSB was executed
input logic all_before_complete, // every before-access has completed
output logic after_may_proceed, // an after-instruction may proceed
output logic provides_completion, // a DSB guarantees completion
output logic provides_ordering, // completion implies ordering too
output logic stalling // the DSB is holding the pipeline (waiting)
);
// A DSB provides both completion and (implied) ordering.
assign provides_completion = dsb_issued;
assign provides_ordering = dsb_issued;
// After-instructions proceed only once every before-access has completed.
assign after_may_proceed = dsb_issued ? all_before_complete : 1'b1;
// While a DSB waits for completion, the pipeline stalls.
assign stalling = dsb_issued && !all_before_complete;
endmoduleThe same behavior in Verilog-2001:
// Representative DSB model (Verilog-2001).
module chi_dsb (
input dsb_issued, all_before_complete,
output after_may_proceed, provides_completion, provides_ordering, stalling
);
assign provides_completion = dsb_issued;
assign provides_ordering = dsb_issued;
assign after_may_proceed = dsb_issued ? all_before_complete : 1'b1;
assign stalling = dsb_issued && !all_before_complete;
endmoduleAnd in VHDL:
-- Representative DSB model (VHDL).
library ieee;
use ieee.std_logic_1164.all;
entity chi_dsb is
port (
dsb_issued : in std_logic;
all_before_complete : in std_logic;
after_may_proceed : out std_logic;
provides_completion : out std_logic;
provides_ordering : out std_logic;
stalling : out std_logic
);
end entity;
architecture rtl of chi_dsb is
begin
provides_completion <= dsb_issued;
provides_ordering <= dsb_issued;
after_may_proceed <= all_before_complete when dsb_issued = '1' else '1';
stalling <= dsb_issued and (not all_before_complete);
end architecture;All three gate after_may_proceed on all_before_complete when a DSB is issued — a genuine completion wait — and expose stalling while it waits. That wait is the completion guarantee (and the cost); the DebugLab is paying it when only ordering was needed.
12. Verification View — completion gates the after-instruction
The properties that pin the DSB: it waits for completion and provides both guarantees.
// Bind to chi_dsb.
// 1. After a DSB, an after-instruction proceeds only once all before-accesses complete.
property p_waits_for_completion;
@(*) dsb_issued |-> (after_may_proceed == all_before_complete);
endproperty
// 2. A DSB provides completion (and, implied, ordering).
property p_provides_both;
@(*) dsb_issued |-> (provides_completion && provides_ordering);
endproperty
// 3. A DSB stalls while any before-access is incomplete.
property p_stalls_until_complete;
@(*) (dsb_issued && !all_before_complete) |-> stalling;
endpropertyThe system point, beyond the checks:
The DSB makes time part of the barrier: it does not just constrain the order accesses are observed in, it constrains when the program may continue, holding until the physical effects have settled. That is a genuinely stronger and costlier thing than ordering, because ordering can be achieved with clever buffering and reordering that never stalls, while completion demands the program actually wait for the world to catch up. So the DSB should be read as a synchronization with the outside — memory, a device — rather than merely between agents. The engineering lesson is that this synchronization has a real latency cost, so it belongs only where the program's next action truly cannot begin until the prior effects exist. Everywhere else, ordering without waiting is both correct and free of the stall.
- What it proves: a DSB gates the after-instruction on completion and stalls until then.
- What it does not prove: that completion was actually required — that is the programmer's judgment.
- Bug signature: a DSB on a path that needed only ordering — an avoidable stall (the DebugLab).
13. Testbench — the DSB waits, then proceeds
Drives the DSB model and checks it stalls until completion, then proceeds.
module tb_chi_dsb;
logic dsb_issued, all_before_complete;
logic after_may_proceed, provides_completion, provides_ordering, stalling;
int errors = 0;
chi_dsb dut (.*);
task automatic check(input logic di, abc,
input logic exp_proceed, exp_stall, input string name);
dsb_issued = di; all_before_complete = abc; #1;
if (after_may_proceed !== exp_proceed || stalling !== exp_stall) begin
errors++; $display("FAIL %s: proceed=%0b stall=%0b", name, after_may_proceed, stalling);
end else $display("PASS %s: proceed=%0b stall=%0b", name, after_may_proceed, stalling);
endtask
initial begin
check(1'b1, 1'b0, 1'b0, 1'b1, "DSB, before NOT complete -> stall, no proceed");
check(1'b1, 1'b1, 1'b1, 1'b0, "DSB, before complete -> proceed");
check(1'b0, 1'b0, 1'b1, 1'b0, "no DSB -> proceed freely (no wait)");
if (errors == 0) $display("ALL TESTS PASSED");
else $display("%0d FAILURE(S)", errors);
$finish;
end
endmoduleExpected output:
PASS DSB, before NOT complete -> stall, no proceed: proceed=0 stall=1
PASS DSB, before complete -> proceed: proceed=1 stall=0
PASS no DSB -> proceed freely (no wait): proceed=1 stall=0
ALL TESTS PASSED14. DebugLab — using a DSB where only ordering is needed
Using a DSB where only ordering is needed
DSB WHERE ONLY ORDERING NEEDED -> UNNECESSARY COMPLETION STALLS -> PERFORMANCE LOSSSynchronization-heavy code is much slower than expected — locks and handoffs cost far more than the work they protect — with the pipeline frequently stalled at barriers, even though correctness is fine.
Every barrier was a completion stall:
lock release: write data @A; DSB; write lock @B
message pass: write data @A; DSB; write flag @B
each DSB WAITS for @A to COMPLETE before proceeding -> pipeline stall
but these only needed ORDERING (observed-ahead), not completion
a DMB would order without waiting -> no stall
result: hot paths pay a completion wait they never required -> slowThe barriers were correct but too strong — completion waits where ordering sufficed.
The code used a DSB — a completion barrier that stalls — for synchronization that needed only ordering. From that point every such barrier paid a completion wait the situation did not require.
A DSB waits for completion and stalls, so using it where only ordering is needed pays for a guarantee the code did not require. Message passing and lock release need only a relative order (observed-ahead), which a DMB provides without waiting. A DSB also orders, but its completion wait is pure overhead on these paths. This is the mirror of the DMB misuse (Chapter 12.4): there a too-weak barrier caused a correctness bug; here a too-strong barrier causes a performance bug. Both stem from mismatching the barrier to the requirement.
Use a DMB where only ordering is needed — message passing, locks — and reserve the DSB for genuine completion requirements (buffer-then-doorbell, maintenance, MMIO). Match the barrier's strength to what the situation demands; do not default to the strongest. Ordering with a DMB is correct and stall-free where completion is not required.
15. Common Mistakes
- DSB where ordering suffices. Assumption: strongest is safest. Bug: needless stalls (the DebugLab). Prevention: a DMB where only order matters.
- DMB where completion is needed. Assumption: a DMB waits. Bug: acting on in-flight data (Chapter 12.4). Prevention: a DSB for completion.
- Barrier by default, not by need. Assumption: pick one and use it everywhere. Bug: wrong strength. Prevention: match the barrier to the requirement.
- Missing the DSB before a doorbell. Assumption: ordering is enough. Bug: device reads partial data. Prevention: a DSB before signalling a device that acts on the data.
- DSB not covering all prior accesses. Assumption: it waits for some. Bug: an incomplete access proceeds. Prevention: a DSB waits for all before-accesses.
- Ignoring the stall cost. Assumption: DSBs are free. Bug: performance loss. Prevention: use them sparingly.
16. Engineering Checklist
- Use a DSB where a subsequent action needs the before-accesses completed.
- Apply it to buffer-then-doorbell, cache/TLB maintenance, and MMIO completion.
- Understand a DSB stalls until completion — it is expensive.
- Use a DMB (not a DSB) where only ordering is needed.
- Match the barrier's strength to the requirement — no stronger.
- Ensure the DSB covers all relevant prior accesses.
17. Key Takeaways
- A DSB is a completion barrier: it waits until all before-accesses have completed.
- It is stronger than a DMB — it provides completion (and, implied, ordering).
- Its cost is a stall — it holds the pipeline until completion.
- Use a DSB where a subsequent action depends on the writes having landed — doorbell, maintenance, MMIO.
- Using a DSB where only ordering is needed causes unnecessary stalls — a performance bug.
- Complete with a DSB, order with a DMB, match strength to need; the model here is representative.
18. Quick Revision
DSB semantics. The Data Synchronization Barrier is a completion barrier: it blocks until all the accesses issued before it have completed — reached their endpoint and taken effect (landed in memory or a device) — before any instruction after it proceeds. It is stronger than a DMB: completion implies the DMB's ordering plus the guarantee the accesses are done. That is what completion-dependent patterns need — buffer-then-doorbell (the buffer must be written before the device reads it), cache and TLB maintenance completion, and MMIO. The cost is a stall: the DSB holds the pipeline until completion, which is expensive. So a DSB is for cases that genuinely need completion; where only a relative order matters (message passing, locks), a DMB is correct and stall-free. The mirror of the DMB's misuse: a DMB where completion is needed is a correctness bug; a DSB where only ordering is needed is a performance bug — an avoidable completion stall on every lightweight synchronization. Complete with a DSB, order with a DMB, and match strength to need. Representative model; 12.6 catalogues the CHI ordering rules.
Coming Next
Chapter 12.6 — CHI Ordering Rules. You have the barriers; the next chapter is the specification's own catalogue of ordering guarantees. Chapter 12.6 covers the CHI ordering rules — the specific, itemized guarantees the spec makes about request order, observation order, and completion, including ordered versus unordered request streams — so you can look up exactly what CHI promises rather than assume, closing the ordering material before consistency models.