Wishbone · Module 25
Arbitration Impact
B3 permits a master to hold CYC_O indefinitely and recommends against it in the same chapter. Measured: a lightly loaded CPU cost the DMA more than a saturated one did.
A DMA engine is the second master on a bus that already had one. Modules 16 through 18 built arbitration and interconnect; this chapter does not rebuild them. It asks one question:
What does arbitration do to a DMA, and what does a DMA do to everyone else?
The system is two independent masters and one fabric:
1. CYC Is An Arbitration Request, Not A Lock
B3's own description of the signal:
[CYC_O]— "indicates that a valid bus cycle is in progress... The[CYC_O]signal is useful for interfaces with multi-port interfaces (such as dual port memories). In these cases, the[CYC_O]signal requests use of a common bus from an arbiter."
It requests. It does not seize. And B3 then does something unusual — it permits a behaviour and advises against it, within the same chapter:
PERMISSION 3.05 — "MASTER interfaces MAY assert
[CYC_O]indefinitely."RECOMMENDATION 3.05 — "Arbitration logic often uses
[CYC_I]to select between MASTER interfaces. Keeping[CYC_O]asserted may lead to arbitration problems. It is therefore recommended that[CYC_O]is not indefinitely asserted."
A DMA holding [CYC_O] across an entire descriptor is legal and antisocial. This engine releases it between bus operations, and says so:
// The engine releases both between bus operations rather than holding
// [CYC_O] across the descriptor. PERMISSION 3.05 would allow holding it
// ("MASTER interfaces MAY assert [CYC_O] indefinitely") and
// RECOMMENDATION 3.05 advises against it ("Keeping [CYC_O] asserted may
// lead to arbitration problems"). Chapter 25.4 measures the difference.And CYC is not an atomicity lock either
RMW is B3's named indivisible construct:
"The RMW (read-modify-write) cycle is used for indivisible semaphore operations. During the first half of the cycle a single read data transfer is performed. During the second half of the cycle a write data transfer is performed. The
[CYC_O]signal remains asserted during both halves of the cycle."
[CYC_O] staying asserted is a consequence of the RMW cycle, not the mechanism that makes it indivisible. Holding [CYC_O] across a DMA descriptor locks no slave, blocks no other master from a different target, and confers no atomicity. A DMA that assumes otherwise has invented a guarantee the specification never offered.
2. A Wishbone BLOCK Cycle Is Not An AXI Burst
Since a DMA is where people reach for "bursts", the distinction matters here more than anywhere:
"During BLOCK cycles, the interface basically performs SINGLE READ/WRITE cycles as described above. However, the BLOCK cycles are modified somewhat so that these individual cycles (called phases) are combined together to form a single BLOCK cycle. This function is most useful when multiple MASTERs are used on the interconnect. For example, if the SLAVE is a shared (dual port) memory, then an arbiter for that memory can determine when one MASTER is done with it so that another can gain access."
No length field. No burst type. No address-increment mode. A BLOCK cycle is a grouping of ordinary phases under one [CYC_O], for the arbiter's benefit. It tells the arbiter "I am not finished" — which is the same lever RECOMMENDATION 3.05 warns about, pointed at a bounded group instead of forever.
3. A Grant Is Not A Completed Transfer
This is the invariant that makes a DMA survivable on a shared bus:
| event | what it means | what it must NOT do |
|---|---|---|
| the arbiter grants the DMA | its request reaches a slave | advance anything |
the slave asserts [ACK_I] | the transfer happened | — |
| the DMA loses arbitration | some clock was not answered | advance anything, set an error |
Losing arbitration is not an error and not a failure. It is a clock on which the request was not answered, indistinguishable from a wait state, and RULE 3.60 obliges the master to hold the request still either way. A DMA that keys its progress to [ACK_I] needs no arbitration-specific logic at all.
A DMA that advanced on a grant would corrupt under contention, which is precisely the ADVANCE_ON_PRESENT defect from Chapter 25.1.
4. The Experiment
Eight items, same descriptor, three CPU loads. The CPU reads inside the DMA's source region — same-target contention on purpose.
CPU load DMA clocks DMA items DMA stall clks CPU done
idle 41 8 25 0
light 43 8 27 6
sustained 41 8 25 9First, the result that is not in doubt:
-> ALL THREE MOVED EXACTLY 8 ITEMS. Contention
changed WHEN, never WHAT. Losing arbitration is
not a failure and not an error - it is simply a
clock on which the request was not answered, and
RULE 3.60 obliges the master to hold it still. data integrity under sustained load: 0 mismatch(es)
-> THE BYTES ARE RIGHT. A DMA that advanced on a
GRANT rather than on a COMPLETION would not be
able to say that, because a grant it lost would
still have moved its pointers.5. The Result That Contradicts The Obvious Guess
READ THE MIDDLE ROW. The WORST case for the DMA is
not the sustained CPU load - it is the LIGHT one.
idle 41 clocks, 25 stall
light 43 clocks, 27 stall
sustained 41 clocks, 25 stallA heavily loaded CPU cost the DMA nothing. A lightly loaded one cost it two clocks.
A CPU THAT ASKS OCCASIONALLY ARRIVES AT AWKWARD
MOMENTS. The shared-bus arbiter hands ownership over
only when the current owner has no cycle open, so
each sporadic CPU request costs a handover the DMA
then has to win back.
A CPU THAT ASKS CONSTANTLY SETTLES INTO A PATTERN.
Ownership alternates predictably and the DMA takes
its turn inside the wait states the CPU is already
paying for. Module 23 found the same shape from the
other side: a second competing master made each
transfer cheaper, because the first was leaving the
target idle half the time anyway.Chapter 23.6 found the same shape from the other side: a second competing master made each transfer cheaper, because the first was leaving the target idle half the time anyway.
THE DIFFERENCE HERE IS 2 CLOCKS ON 41 - small, and
pointing the opposite way to the obvious guess. That
is the reason to measure rather than assert.Two clocks is not a large effect and the direction is the finding. A module that reported "sustained load slowed the DMA by X%" would have been telling a story the measurement does not support.
And it runs both ways
AND THE COST RUNS BOTH WAYS. The light-load CPU
completed 6 reads and the sustained one 9, both
while competing with the same DMA. Neither master
owns the fabric; each lengthens the other."DMA offloads the CPU" is a statement about instruction counts, not about bus latency. The CPU is not executing copy instructions — and its memory accesses now queue behind somebody else's.
6. What This Experiment Does Not Show
WHAT THIS EXPERIMENT DOES NOT SHOW: that DMA is
faster than software, or slower. It moved 8 items
at THIS arbitration policy, against THESE endpoints,
with THIS CPU pattern. Fairness belongs to the
arbiter and Module 17 owns it.Worth stating what would have to change to change the answer: the arbitration policy, the endpoint latencies, the CPU's access pattern, the address map, whether the two masters share a target at all. Chapter 22 owns throughput analysis; this chapter owns what this architecture cost under these conditions.
Fairness is the arbiter's, not the DMA's. An engine that tried to be polite by inserting idle clocks would be solving a problem it cannot see, in a place that cannot observe the outcome.
7. The Full Negative-Control Matrix
Four checkers, seven rigs, one workload, both endpoints slow so that presentation and completion are different clocks:
rig PROTOCOL LOCAL ACCOUNT SCORE
correct 0 0 ok 0
ADVANCE_ON_PRESENT 11 6 ok 6
LIVE_READ_DATA 0 0 ok 6
NO_SNAPSHOT 0 0 ok 0
INC_FIXED_ENDPOINT 0 0 ok 0
COUNT_ON_RTY 0 10 ok 3
DONE_EARLY 0 2 WRONG 0And which local invariant each one actually trips:
rig srcmv dstmv hold rem_e rty err done ovr lead
correct 0 0 0 0 0 0 0 0 0
ADVANCE_ON_PRESENT 0 0 0 6 0 0 0 0 0
LIVE_READ_DATA 0 0 0 0 0 0 0 0 0
NO_SNAPSHOT 0 0 0 0 0 0 0 0 0
INC_FIXED_ENDPOINT 0 0 0 0 0 0 0 0 0
COUNT_ON_RTY 0 0 0 0 1 0 0 0 9
DONE_EARLY 0 0 0 0 0 0 2 0 0Each defect trips a different invariant, and the zeros are the measurement.
Six of seven are protocol-clean
SIX OF THE SEVEN RIGS SCORED ZERO PROTOCOL
VIOLATIONS, INCLUDING FIVE BROKEN ONES. Wishbone B3
contains no DMA, so there is no rule for a DMA bug
to break - a conformance suite passes almost this
whole table.The exception earns its violations:
THE EXCEPTION IS INSTRUCTIVE. ADVANCE_ON_PRESENT
scored 11 protocol violations, and it earned them:
advancing the address on presentation MOVES [ADR_O]
while the phase is still unanswered, and RULE 3.60
requires it to be held still. wb_conformance's
ctx-moved check is watching for exactly that. So one DMA accounting bug happens to also be a
Wishbone violation - NOT because the protocol knows
about transfer counts, but because this particular
way of getting them wrong also disturbs a signal
the protocol does constrain.The one nothing catches
LIVE_READ_DATA trips 0 local invariants and
corrupts 6 of 6 items. NO CHECKER IN THIS
MODULE CATCHES IT. It holds every address still, it
counts every commit exactly once, its accounting is
ok - and it moves the wrong bytes. Only the
reference model knows.And the off-diagonal that is supposed to be zero
INC_FIXED_ENDPOINT trips 0 local invariants in a
memory-to-memory rig, because BOTH endpoints are
supposed to increment here. Its damage is visible
only against a fixed endpoint, which is SIM G.A defect can be harmless in one scenario and destructive in another, and a matrix that ran only one scenario would have declared it benign. Chapter 25.3 is where it delivers 1 item of 6.
8. The Checkers Prove Their Own Inputs
-> EVERY CHECKER PROVED ITS OWN INPUTS KNOWN.
Module 24 lost a gate to an undriven counter:
the value went X, `if (x == 0)` was neither
true nor false, the check was SKIPPED, and the
run reported a pass it had not earned. // ── X-SAFETY. Case equality, so an X is DETECTED rather than
// silently making every comparison unknown. ──
if ((^remaining_i === 1'bx) || (^src_ok_i === 1'bx) ||
(^dst_ok_i === 1'bx) || (^requested_i === 1'bx) ||
(done_i === 1'bx) || (cyc_i === 1'bx) ||
(stb_i === 1'bx))
unk_q <= 1'b1;A checker with X outputs is a failed checker, not a passing design.
9. The Integrated Audit
THE CORRECT RIG, ITEM BY ITEM
requested items 6
source successes 6
destination successes 6
retries 1
errors 0
remaining 0
done events 1
final source address 0x0118
final destination addr 0x4418
source wait clocks 14
destination wait clocks 12
scoreboard mismatches 0
protocol violations 0
local-policy violations 0
checker inputs unknown 0Six requested, six read, six written, one retry that advanced nothing, addresses exactly six items on, one completion, and zero mismatches against a model built independently of the engine.
10. Misconceptions, Against The Evidence
| claim | the measurement |
|---|---|
| "once the DMA is granted, the transfer happened" | ADVANCE_ON_PRESENT: 6 items corrupted, 11 RULE 3.60 violations |
| "CYC gives the DMA ownership of the system" | CYC requests a bus; RMW is the indivisible construct |
| "a DMA may hold the bus because its work is useful" | PERMISSION 3.05 permits it, RECOMMENDATION 3.05 advises against |
| "DMA always improves performance" | light CPU load cost 2 clocks; sustained cost 0 |
| "DMA means the CPU is uninvolved" | CPU completions fell from 9 to 6 across loads |
| "protocol conformance proves the data is right" | LIVE_READ_DATA: clean on every checker, every byte wrong |
| "one descriptor is one Wishbone transaction" | six items = twelve phases |
11. Where Module 25 Ends
Four chapters built a DMA engine, a control plane with a snapshotted descriptor, two endpoint shapes, a checker with nine local invariants and an X-safety output — 1,101 lines of design RTL, ten simulations, six named defects, and a reference model that is the only thing standing between a clean checker report and corrupt memory.
The single most transferable result: LIVE_READ_DATA passed the Wishbone conformance monitor, passed all nine DMA invariants, produced perfect accounting, and moved the wrong bytes in every item. Everything this module builds to check how a transfer was conducted is silent about what was moved.
Module 26 takes up verification of exactly that gap.
Continue learning
Related tutorials
- Related topic
Shared Resources
Two initiators wired to one target is not a wiring problem with a wiring solution. A single-port target has one address input and one completion output, so access must be serialised — and the rule that matters most is not who goes first but that ownership cannot change while a transaction is in flight.
- Related topic
CPU + DMA Systems
Two initiators in contention, with the clocks counted in four columns: holding work, asking for the bus, owning it, and being answered. Contention cost two clocks out of twenty-one.
- Related topic
"Wishbone Cannot Support DMA"
A category error, measured: eight items moved correctly with zero protocol violations, then the same engine delivering every one to the wrong region.
- Related topic
CYC_O
STB_O presents one transfer; CYC_O frames the tenure it belongs to. Holding it across transfers is what makes a read-modify-write atomic — and what atomicity still does not guarantee.
Standards & specifications
- Governing standard
- Wishbone SoC Interconnection Architecture (OpenCores)(opens OpenCores in a new tab)
Defines the Wishbone signal set, the bus cycles built from it and the interface rules a portable IP core must follow. It deliberately leaves interconnect topology, address map and arbitration policy to the integrator, so those are system decisions rather than requirements of the specification.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the Wishbone curriculum.
