Skip to content
VLSI Mentor

Wishbone · Module 25

DMA Master

Wishbone B3 contains no DMA, so every decision an engine makes is local policy. Three invariants make it correct — and the defect that breaks the worst of them passes every conformance check ever written.

Every master this curriculum has built so far did what it was told, one transfer at a time. Chapter 23.1's wb_master_fsm takes a request, issues it, reports the answer, and stops. A DMA engine is the first master that is handed a description of work and then goes away and does it.

A DMA engine converts a transfer description into a sequence of independently completed bus operations, while preserving source and destination progress, transfer count, data integrity and error state across stalls and arbitration.

Start with what it is not:

it is calledwhy that is wrong
"memcpy in hardware"memcpy handles overlap; this engine explicitly does not
"a burst generator"a Wishbone BLOCK cycle has no length field — see §7
"a second CPU"it has no instructions, no branches, one job
"just a master FSM"a master FSM has no descriptor, no count, no held data
"one big bus transaction"it is 2N ordinary transactions for N items

1. Wishbone B3 Contains No DMA

Search B3 for DMA and you will find nothing. There is no DMA rule, no DMA chapter, no descriptor, no transfer count. That is not an omission — B3 specifies an interface, and a DMA engine is a client of that interface like any other master.

So the honest framing for the whole module:

Everything this engine decides is LOCAL DMA POLICY — NOT A WISHBONE REQUIREMENT. What B3 supplies is the set of obligations the engine must meet while it decides.

Three of those obligations shape the architecture:

RULE 3.25"MASTER interfaces MUST assert [CYC_O] for the duration of SINGLE READ / WRITE, BLOCK and RMW cycles. [CYC_O] MUST be asserted no later than the rising [CLK_I] edge that qualifies the assertion of [STB_O]."

RULE 3.35"The cycle termination signals [ACK_O], [ERR_O], and [RTY_O] must be generated in response to the logical AND of [CYC_I] and [STB_I]."

RULE 3.60"MASTER interfaces MUST qualify the following signals with [STB_O]: [ADR_O], [DAT_O()], [SEL_O()], [WE_O], and [TAGN_O]."

RULE 3.35 is why this engine has exactly one bus operation in flight, ever. One outstanding phase, no tags, no reordering. A deeper DMA pipeline is not a design option in Classic Wishbone — the protocol forbids the thing it would need.

RULE 3.60 is why a DMA can stall for an arbitrary number of clocks and stay correct. The whole request is held still while unanswered, so the engine can wait out a slow endpoint, a full FIFO, or a lost arbitration round and return to a question that has not moved.

2. Two Planes, Two Wishbone Ports, Opposite Directions

A DMA engine has two Wishbone interfaces, and confusing them is the most common misunderstanding about DMA.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//   CONTROL PLANE   this module. A SLAVE. The CPU writes SRC, DST,
//                   LENGTH and CTRL here. Small, register-mapped,
//                   Module 24's subject.
//   DATA PLANE      wb_dma. A MASTER. It moves the actual bytes and the
//                   CPU never touches it.

"The DMA is a peripheral" and "the DMA is a bus master" are both true, of different ports. The control plane is a Module 24 slave — a register map with an access policy and a termination scheme. The data plane is a master that the CPU never addresses at all.

A DMA subsystem's two Wishbone planes. On the control plane the CPU acts as master and writes source address, destination address, length and a control register into the DMA's register block, which is a Wishbone slave. On START that register block copies the programmed fields into a separate active descriptor. The active descriptor drives the DMA engine, which is a Wishbone master on the data plane, issuing a source read followed by a destination write for each item, through the interconnect to memory or a peripheral. The CPU never touches the data plane and the engine never consults the programming registers once a transfer is running.CPUmaster, control planewb_dma_regsSLAVE — SRC/DST/LEN/CTRLactive descriptorsnapshotted at STARTwb_dmaMASTER — data planeinterconnectChapters 23.5 / 23.6memoryaddresses increment12

3. The Three Invariants

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//   1. SOURCE PROGRESS ONLY ON SOURCE READ SUCCESS
//   2. DESTINATION PROGRESS ONLY ON DESTINATION WRITE SUCCESS
//   3. THE ITEM COUNT ADVANCES EXACTLY ONCE PER COMMITTED ITEM -
//      not on presentation, not on grant, not on RTY.

Each has a named defect in the RTL below, and five of the six defects in this module are PERFECTLY LEGAL WISHBONE. That is the module's central point, and Chapter 25.4 publishes the matrix that proves it.

4. The State Machine

The DMA engine's five states. IDLE waits for a start pulse; on start it captures the descriptor, and if the length is zero it completes immediately without issuing any bus operation. Otherwise it enters RD, the source read, where CYC and STB are asserted at the source address and held still until a termination arrives. A successful acknowledge captures the read data into the holding register, advances the source address, and moves to WR. WR is the destination write, driving the held data at the destination address, again held still until answered. A successful acknowledge advances the destination address and decrements the remaining count, returning to RD if items remain or completing if this was the last. A retry termination in either state re-presents the same operation without advancing anything, up to a retry limit; an error termination in either state goes to ERR and terminates the descriptor.IDLERDWRERRstart, LEN > 0 — capturestart, LEN >0 — captureRTY — re-present, advance nothingRTY — re-present, advance nothingRTY —re-present,…ACK — capture data, advance sourceACK — capture data, advance sourceACK — capturedata, advance…RTY — re-presentRTY — re-presentACK — dest++, count--ACK — dest++, count--ACK on the last item — doneACK on the last item — doneACK on thelast item —…ERRERRterminate, status setterminate, status set

Two states drive the bus and they differ only in direction:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  assign cyc_o = (st_q == S_RD) || (st_q == S_WR);
  assign stb_o = (st_q == S_RD) || (st_q == S_WR);
  assign we_o  = (st_q == S_WR);

  // RULE 3.60: the context is driven from registers and cannot move while
  // the phase is unanswered, because nothing but a successful termination
  // changes src_q / dst_q / hold_q.
  assign adr_o = (st_q == S_WR) ? eff_dst : eff_src;

Which clock owns which change is the whole of the design, so it is worth tabulating:

what changeson which clocknever on
held dataa successful source readpresentation, a write ACK
source addressa successful source readpresentation, RTY
destination addressa successful destination writepresentation, RTY
remaining counta successful destination writea source read, RTY, ERR
donethe final successful destination writeissuing the final write
[CYC_O], [STB_O]state entry and exit

5. The Holding Register

A source read and a destination write are two separate bus operations. Whatever the source returned has to survive the gap — and the gap can be arbitrarily long.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  // A source read and a destination write are TWO SEPARATE BUS
  // OPERATIONS. Whatever the source returned must survive the gap, which
  // may be arbitrarily long: destination wait states, arbitration loss,
  // retries. RULE 3.65 makes the slave's [DAT_O()] valid only on ITS
  // termination clock, so by the time the destination write happens the
  // source's data is long gone from the wire.
  assign dat_o = LIVE_READ_DATA ? dat_i : hold_q;

Chapter 24.2's RULE 3.65 is what makes the holding register mandatory rather than convenient. A slave's [DAT_O()] is qualified by its termination. Once that phase ends the data is not merely stale — it is not required to be anything at all.

LIVE_READ_DATA is the defect that ignores this, and Chapter 25.2 measures what it costs.

6. Progress Is Commit Accounting

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  logic term, ok, present;
  assign present = cyc_o && stb_o;
  assign term    = ack_i || err_i || rty_i;   // RULE 3.45 makes OR safe
  assign ok      = present && ack_i;

present is a request on the wire. ok is an answer. Every progress decision keys off ok:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  logic advance_rd, advance_wr;
  assign advance_rd = ADVANCE_ON_PRESENT ? (present && (st_q == S_RD))
                                         : (ok      && (st_q == S_RD));
  assign advance_wr = ADVANCE_ON_PRESENT ? (present && (st_q == S_WR))
                                         : (ok      && (st_q == S_WR));

Against a zero-wait slave the two coincide and the defect is invisible — the recurring shape of every commit-timing bug in this curriculum, from Chapter 23.3's FIRE_ON_STB to Chapter 24.2's SIDE_ON_STB.

ADVANCE_ON_PRESENT is the one defect in this module that also breaks a Wishbone rule, and it is worth being precise about why: advancing on presentation moves [ADR_O] while the phase is still open, which is RULE 3.60. The protocol does not know what a transfer count is; it happens to constrain a signal this particular bug disturbs.

7. RTY Is Not "Keep Waiting"

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
          end else if (present && rty_i) begin
            // RTY TERMINATES THIS ATTEMPT. The retry is a NEW transfer,
            // later. Nothing about the descriptor moves.
            nrty_q <= nrty_q + 16'd1;

B3's own description:

[RTY_I]"indicates that the interface is not ready to accept or send data, and that the cycle should be retried. When and how the cycle is retried is defined by the IP core supplier."

And for errors:

[ERR_I]"indicates an abnormal cycle termination. The source of the error, and the response generated by the MASTER is defined by the IP core supplier."

"Defined by the IP core supplier" is B3 naming us as the authority and declining to be one. So this engine's policy, stated in its datasheet header:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//   4  response to [ERR_I]   : TERMINATE the descriptor, set ERROR, stop.
//   5  response to [RTY_I]   : RETRY the same bus operation, up to
//                              MAX_RETRIES, ADVANCING NOTHING. On
//                              exhaustion, terminate with ERROR.

Chapter 25.3 measures both, and the COUNT_ON_RTY defect that treats "ask again" as "done".

8. Length Is In Items, And Zero Is Defined

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── LENGTH IS MEASURED IN ITEMS, NOT BYTES ──────────────────────────────
// One convention, stated once, at the register boundary and here. LENGTH
// counts 32-bit items. A 4-item transfer moves 16 bytes and performs 4
// source reads and 4 destination writes. Mixing the two conventions is
// the classic DMA off-by-four and this module refuses to offer the
// choice.

The addresses are byte addresses and the count is an item count. That asymmetry is deliberate and documented rather than discovered: a 4-item transfer from 0x100 touches 0x100, 0x104, 0x108, 0x10C.

And the case nobody decides until it bites:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── ZERO LENGTH IS DEFINED, NOT ACCIDENTAL ──────────────────────────────
// LENGTH = 0 completes immediately: no bus operation, no data moved, DONE
// asserted, ERROR clear. The alternative - underflowing the counter and
// transferring 2^N items - is what happens if nobody decides. LOCAL POLICY.

Measured — both deltas zero, and one completion:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      N=0   src_ok delta=0 dst_ok delta=0 remaining=0 done delta=1
      -> N=0 MOVED NOTHING AND COMPLETED. Both deltas are
         zero - not one bus operation was issued - and
         done was asserted. LOCAL POLICY: the engine
         checks for zero at START rather than entering
         the loop and underflowing to 65536 items.

And the off-by-one case, N=1:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      N=1   src_ok=1 dst_ok=1 remaining=0 done=1
            0x4800 = 0xc0de0000 (expected 0xc0de0000)
            0x4804 = 0x22222222 (expected 0x22222222, untouched)
            final src=0x0704 dst=0x4804
      -> ONE source read, ONE destination write, ONE done.
         Addresses advanced by exactly one ITEM_BYTES and
         the neighbouring word was not touched.

9. Configuration State Is Not Active Transfer State

The register block copies the programmed fields into a separate active descriptor when START is written:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── THE SNAPSHOT, WHICH IS THE POINT OF THIS MODULE ─────────────────────
//   CONFIGURATION STATE IS NOT ACTIVE TRANSFER STATE.
//
// START copies SRC/DST/LENGTH/INC into a separate ACTIVE descriptor. From
// that clock on, the engine reads only the active copy, and software may
// write the programming registers freely - preparing the next descriptor
// while the current one runs - without touching the transfer in flight.

The experiment: program a 4-item transfer, start it, then rewrite SRC, DST and LENGTH while it runs.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      rig            dst_ok  remaining  done  0x4400 holds
      correct             4          0     1  0xa0000000
      NO_SNAPSHOT        99          0     1  0xa0000000

      -> THE CORRECT RIG IGNORED THE REPROGRAMMING.

The defective engine moved 99 items instead of 4, because software's mid-flight LENGTH write extended the transfer that was already running.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      EVERY BUS TRANSACTION IN BOTH RIGS WAS LEGAL:
        protocol violations  correct 0   NO_SNAPSHOT 0

A defect that could not arm

The first version of this experiment reported both rigs identical. The register block's snapshot had been removed — and the engine latched the descriptor at START anyway, so nothing changed:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  // NO_SNAPSHOT is the architecture in which there is NO active
  // descriptor at all: the engine keeps only an item index and derives
  // every address from the LIVE programming inputs. Removing the
  // snapshot from the register block alone is not enough - this engine
  // would still have latched the values at START - and SIM A caught
  // exactly that: the defect was configured, compiled, and inert.

A defect parameter that cannot arm is not evidence of a correct design. Chapter 24.4 lost a gate to the same shape, and it is now a standing check: every negative control in this module must be shown firing.

START while BUSY is the other policy this raises, and it is stated rather than discovered:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      START WHILE BUSY - LOCAL POLICY: IGNORED
        starts accepted 3   starts ignored 1

10. What This Engine Does Not Do

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//   no scatter-gather, no descriptor rings, no linked lists
//   no overlapping source/destination support - NOT memmove, and 25.2
//     states it rather than leaving it to be discovered
//   no burst or [CTI_O()] - Classic phases only
//   no coherence, no IOMMU, no translation
//   no channel arbitration - ONE channel

And one more, which belongs to the bus rather than the engine: a DMA does not make anything atomic. RMW is B3's named indivisible construct — "used for indivisible semaphore operations" — and [CYC_O] merely stays asserted across it. Holding [CYC_O] across a descriptor locks nothing, which Chapter 25.4 takes up.


Next: Chapter 25.2 — Memory Transfers puts the engine to work moving a block of memory, gives each endpoint its own latency, and measures what happens to the data when the holding register is taken away.

Continue learning

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.