Skip to content
VLSI Mentor

Wishbone · Module 16

Resource Sharing

A word that changed between two correct reads with nothing on the bus to say so, a private resource that acquired ownership zero times, and a master given no service for sixty clocks without a rule being broken.

Chapter 16.3 made ownership correct in both directions and proved it against three defects built to break it. Correct ownership turns out to buy less than it looks like it buys.

Once ownership is right, what may a master assume about the state it shares?

1. Simulation — SIM H: A Word That Moved

The CPU reads a shared location, releases the bus, and reads it again later. Both reads are ordinary, both are answered ACK, and nothing goes wrong.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM H - the shared word changes between two correct reads ===
    clock 21   CPU reads 0x030            -> 0xaaaa0030
              CPU releases the bus; the read was answered ACK
              DMA writes 0x030           -> 0xaaaa0010
    clock 37   CPU reads 0x030 again      -> 0xaaaa0010

    clocks between the two reads                 16
    terminations either read received            ACK
    bus events telling the CPU the word moved    0
    shared RAM writes performed by the DMA       1
    a master saw a termination it did not own    0

Reading it

Two correct reads, sixteen clocks apart, returning different values.

0xAAAA0030 then 0xAAAA0010. Between them the DMA wrote 0x030 once — a legal write, by a legal master, through a correct interconnect, answered ACK.

The line that matters is the one that reports nothing: bus events telling the CPU the word moved — 0.

There is no such event to report. Wishbone has no invalidation, no snoop, no notification and no version counter. The CPU's first read was correct when it was answered and it stayed correct about that instant forever. What it stopped being was current, and nothing in the protocol distinguishes those two states.

Say it as a rule of reading rather than a rule of the bus. "My previous read was answered correctly" and "the value is still what I read" are different claims, and only the first is supported by anything. In a single-master system they coincide. They stop coinciding the moment a second initiator exists, which is the same clock the system became a multi-master system — usually an integration event rather than a code change in either device.

2. When Ownership of Two Cycles Is Not Enough

This is where Module 15 reconnects, and the connection is precise rather than general.

Suppose the CPU's two accesses are not two unrelated reads but a read and a write that depend on each other — read a counter, add one, write it back. Chapter 15.1 measured exactly that and lost the update.

Correct ownership does not help. The CPU owned the bus for its read. It owned the bus for its write. Both tenures were correct, both transfers were conformant, and the interconnect did nothing wrong. What was not owned is the interval between them, and ownership of two separate cycles says nothing about it.

So the decision rule is about the operation, not about the bus. If a compound operation requires shared state not to change between its parts, ordinary ownership of each part is insufficient and the interval must be held — which is what Chapter 15.2 established LOCK_O is for, and Chapter 15.3 bounded to bus masters only.

If it does not require that, this is not a problem at all. A DMA copying a buffer nobody else is writing shares the path with the CPU and shares no state with it. Confusing the two is the most common over-reaction to this chapter — systems get locks they do not need because "the bus is shared" was heard as "the data is shared".

3. RTL — The Same Splitter, in a Second Place

Which brings the argument to its sharpest form: contention is a property of a path. The module below is the one Chapter 16.2 already used below the interconnect. Here it is used above one.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_split2 — one Wishbone path in, two out, selected by one address bit.
//
// This is Module 12's decoder reduced to the smallest form that still
// works, and it follows Chapter 12.4's convention exactly: a target's
// CYC_I and STB_I are the incoming ones ANDed with its select, so an
// unselected target sees a negated CYC_I and RULE 3.30 keeps it silent.
//
// It appears TWICE in Module 16's system, which is the point:
//
//   * below the interconnect, splitting the shared path into the shared
//     RAM and the DMA's configuration registers;
//   * on the CPU's own port, splitting its accesses into the ones that
//     reach the shared path and the ones that never leave the CPU.
//
// The second placement is what Chapter 16.4 measures: contention is a
// property of a shared path, not of having two masters.
//
// The address bit is decoded combinationally from ADR_I, which is valid
// only while the master is presenting - "When [CYC_O] is negated, all
// other MASTER signals are invalid." Both masters here hold ADR stable for
// the whole of a transfer, so the select is stable for the whole of it.
// ─────────────────────────────────────────────────────────────────────────
module wb_split2 #(
  parameter int unsigned AW      = 12,
  parameter int unsigned DW      = 32,
  parameter int unsigned SW      = DW/8,
  parameter int unsigned SEL_BIT = 11      // 0 -> leg A, 1 -> leg B
) (
  // -- upstream master port --
  input  logic          m_cyc_i,
  input  logic          m_stb_i,
  input  logic          m_lock_i,
  input  logic          m_we_i,
  input  logic [AW-1:0] m_adr_i,
  input  logic [DW-1:0] m_dat_i,
  input  logic [SW-1:0] m_sel_i,
  output logic [DW-1:0] m_dat_o,
  output logic          m_ack_o,
  output logic          m_err_o,
  output logic          m_rty_o,
  // -- leg A (address bit clear) --
  output logic          a_cyc_o,
  output logic          a_stb_o,
  output logic          a_lock_o,
  output logic          a_we_o,
  output logic [AW-1:0] a_adr_o,
  output logic [DW-1:0] a_dat_o,
  output logic [SW-1:0] a_sel_o,
  input  logic [DW-1:0] a_dat_i,
  input  logic          a_ack_i,
  input  logic          a_err_i,
  input  logic          a_rty_i,
  // -- leg B (address bit set) --
  output logic          b_cyc_o,
  output logic          b_stb_o,
  output logic          b_lock_o,
  output logic          b_we_o,
  output logic [AW-1:0] b_adr_o,
  output logic [DW-1:0] b_dat_o,
  output logic [SW-1:0] b_sel_o,
  input  logic [DW-1:0] b_dat_i,
  input  logic          b_ack_i,
  input  logic          b_err_i,
  input  logic          b_rty_i,
  // -- observation --
  output logic          hit_b_o
);
  logic hit_b;
  assign hit_b   = m_adr_i[SEL_BIT];
  assign hit_b_o = hit_b;

  assign a_cyc_o  = m_cyc_i  && !hit_b;
  assign a_stb_o  = m_stb_i  && !hit_b;
  assign a_lock_o = m_lock_i && !hit_b;
  assign b_cyc_o  = m_cyc_i  &&  hit_b;
  assign b_stb_o  = m_stb_i  &&  hit_b;
  assign b_lock_o = m_lock_i &&  hit_b;

  // The payload fields fan out unchanged. They are qualified by STB_O at
  // the target (RULE 3.60), and only one target ever has STB_I asserted.
  assign a_we_o = m_we_i;  assign a_adr_o = m_adr_i;
  assign a_dat_o = m_dat_i; assign a_sel_o = m_sel_i;
  assign b_we_o = m_we_i;  assign b_adr_o = m_adr_i;
  assign b_dat_o = m_dat_i; assign b_sel_o = m_sel_i;

  assign m_ack_o = hit_b ? b_ack_i : a_ack_i;
  assign m_err_o = hit_b ? b_err_i : a_err_i;
  assign m_rty_o = hit_b ? b_rty_i : a_rty_i;
  assign m_dat_o = hit_b ? b_dat_i : a_dat_i;
endmodule

Reading it

It is thirty lines of combinational logic and it decides the entire question of what is shared.

hit_b = m_adr_i[SEL_BIT], and the two legs get m_cyc_i && !hit_b and m_cyc_i && hit_b. That is Chapter 12.4's convention unchanged — a target's CYC_I is the incoming one ANDed with its select, so an unselected target sees CYC_I negated and RULE 3.30 keeps it silent.

The payload fields fan out to both legs unchanged. They are qualified by STB_O at the target (RULE 3.60), and only one target ever has STB_I asserted, so there is nothing to gate and nothing to mux on the way down. The return direction is a two-way select on the same bit.

Now the placement, which is what this section is actually about.

Below the interconnect, this module splits the shared path into the shared RAM and the DMA's configuration registers. Both legs are downstream of ownership; both are shared.

Above the interconnect, on the CPU's own port, it splits the CPU's accesses into the ones that go to the interconnect and the ones that do not. The second leg never reaches the interconnect at all — no ownership is requested, no ownership is granted, and the DMA is not involved in any way.

Same module, same thirty lines, and the difference in what it means is total.

A diagram showing which accesses contend and which do not. The CPU master's port goes first into its own address splitter. One leg of that splitter goes to a private RAM that no other master can reach, bypassing the interconnect entirely. The other leg goes into the interconnect, where it meets the DMA master's port. The interconnect selects one of the two and drives a second splitter, which fans out to the shared RAM and to the DMA's configuration registers. Only accesses that cross the interconnect can contend.CPU masterone portwb_split2adr[10]private RAMnever contendsinterconnectownershipDMA masterthe competitorshared RAMcontendslocal legshared leg12

The private leg leaves the diagram before it reaches anything the DMA can see. That is the whole architecture of a scratchpad, a local register file, a tightly-coupled memory — and it is why "multi-master SoC" does not mean "every access is serialised".

4. Simulation — SIM I: Private and Shared, Under Identical Traffic

Eight CPU writes: four to 0x4000x403, which the splitter keeps local, and four to 0x0000x003, which cross the interconnect. The DMA is copying six words throughout both groups.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM I - a private resource and a shared one, same traffic ===
    the CPU performs four writes to 0x400..0x403, which its own
    splitter keeps local, and four to 0x000..0x003, which cross
    the interconnect. The DMA is copying throughout.

    four PRIVATE writes  (0x400..0x403)
      ownership acquisitions              0
      clocks requesting the interconnect  0
      terminations from the interconnect  0
      words written to the private RAM    4
    four SHARED writes   (0x000..0x003)
      ownership acquisitions              4
      clocks requesting the interconnect  5
      terminations from the interconnect  4

    DMA words copied throughout         6
    DMA failed                          0
    violations: no-owner 0  non-owner term 0  context 0  mid-transfer 0

Reading it

Four private writes: zero acquisitions, zero clocks requesting the interconnect, zero terminations from it — and four words written.

The work happened. Nothing contended. The CPU asserted CYC_O on its own port for each of those four transfers; the splitter routed them to the local leg; the interconnect never saw a request. That is why the probe is wired to cpu_icyc_o — the CPU's CYC_O as the interconnect sees it — rather than to the master's own pins.

That wiring detail is worth a sentence, because getting it wrong produces a specific false report. An instrument attached to the master's pins counts every private access as a clock spent requesting the bus, and every private ACK as a termination received while another master owned the path. This module made that mistake and the probe reported four non-owner terminations that had never happened. The masters were right; the instrument was in the wrong place.

Four shared writes: four acquisitions, five clocks requesting, four terminations.

Five against four is the whole cost of contention in this group — one extra clock, because Chapter 16.2 established that every acquisition costs one clock structurally, so four acquisitions cost four. One clock of the five is the DMA.

And the DMA copied all six words through both groups, with zero violations. The two workloads coexisted. What separates them is not priority or fairness — it is whether the address crossed the interconnect.

The design lesson is a question to ask early rather than a technique. Which of this device's accesses actually need to reach shared state? Everything else can be local, and every access made local is an access that cannot contend, cannot be delayed by another master, and cannot be affected by any defect in Chapter 16.3.

5. One Shared Bus Is One Choice Out of Five

Module 16 has used a shared bus throughout because it is the smallest topology that creates the problem. It is not the only one, and the specification is explicit about that.

Supports various IP core interconnection means, including: Point-to-point / Shared bus / Crossbar switch / Data flow interconnection / Off chip

And the glossary says exactly why a shared bus behaves as it does:

The shared bus interconnection is a system where a MASTER initiates addressable bus cycles to a target SLAVE. Traditional buses such as VMEbus and PCI bus use this type of interconnection. As a consequence of this architecture, only one MASTER at a time can use the interconnection resource (i.e. bus).

Read the causation in that last sentence. "As a consequence of this architecture"the one-at-a-time restriction comes from choosing a shared bus, not from Wishbone. There is no rule anywhere in B3 that says one master at a time. A crossbar carries several transfers concurrently and is equally conformant:

Each connection channel can be operated in parallel to other connection channels. This increases the data transfer rate of the entire system by employing parallelism.

So "multi-master" implies exactly nothing about topology. It does not imply a crossbar, and this chapter's private leg shows it does not even imply that all of one master's traffic reaches the shared fabric. Module 18 is where topology is designed; what belongs here is knowing that the serialisation measured in SIM D and SIM I is a consequence of one choice among five.

6. RTL — The Shared Resource Itself

The memory both masters want. Two of its features are load-bearing and neither is decoration.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_shared_ram — the resource both masters want.
//
// A word-addressed RAM with byte selects, an optional fixed wait-state
// count, and one input that is not decoration:
//
//   busy_i   while asserted, every presented phase is terminated with
//            RTY_O instead of ACK_O and nothing is read or written.
//
// That input exists because the specification describes this exact use:
// "This signal is generally used for shared memory and bus bridges. In
// these cases SLAVE circuitry asserts [RTY_I] if the local resource is
// busy." A shared memory answering RTY is the specification's own example,
// not an invention of this module.
//
// The wait-state counter counts clocks the phase has been HELD, and is
// cleared by the answer rather than loaded at the start. Module 14 shipped
// the other shape and it acknowledged before its latency had loaded.
// ─────────────────────────────────────────────────────────────────────────
module wb_shared_ram #(
  parameter int unsigned AW    = 12,
  parameter int unsigned DW    = 32,
  parameter int unsigned SW    = DW/8,
  parameter int unsigned WORDS = 256,
  parameter int unsigned WAITS = 0
) (
  input  logic          clk_i,
  input  logic          rst_i,
  input  logic          cyc_i,
  input  logic          stb_i,
  input  logic          we_i,
  input  logic [AW-1:0] adr_i,
  input  logic [DW-1:0] dat_i,
  input  logic [SW-1:0] sel_i,
  input  logic          busy_i,
  output logic [DW-1:0] dat_o,
  output logic          ack_o,
  output logic          err_o,
  output logic          rty_o,
  // -- observation: how many times this memory actually changed --
  output logic [15:0]   writes_o
);
  logic [DW-1:0] mem [0:WORDS-1];
  logic [15:0]   nwr_q;
  logic [7:0]    held_q;

  logic xfer, ready;
  assign xfer  = cyc_i && stb_i;
  assign ready = xfer && (held_q >= WAITS[7:0]);

  assign ack_o    = ready && !busy_i;
  assign rty_o    = xfer  &&  busy_i;
  assign err_o    = 1'b0;
  assign writes_o = nwr_q;

  logic [$clog2(WORDS)-1:0] widx;
  assign widx = adr_i[$clog2(WORDS)-1:0];
  assign dat_o = mem[widx];

  integer i, b;
  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      held_q <= 8'd0;
      nwr_q  <= 16'd0;
      // Init pattern assumes DW = 32, which is this module's only
      // instantiation in Module 16. Every word is recognisable on sight:
      // mem[k] reads 0xAAAA_00kk.
      for (i = 0; i < WORDS; i = i + 1)
        mem[i] <= 32'hAAAA_0000 + i[15:0];
    end else begin
      // Held for this phase, cleared by the answer - never preloaded.
      if (!xfer || ack_o || rty_o) held_q <= 8'd0;
      else                         held_q <= held_q + 8'd1;

      if (ack_o && we_i) begin
        nwr_q <= nwr_q + 16'd1;
        for (b = 0; b < SW; b = b + 1)
          if (sel_i[b]) mem[widx][b*8 +: 8] <= dat_i[b*8 +: 8];
      end
    end
  end
endmodule

Reading it

busy_i is the specification's own example, not an invention. While it is asserted, every presented phase is terminated with RTY_O and nothing is read or written. B3 describes precisely this use:

This signal is generally used for shared memory and bus bridges. In these cases SLAVE circuitry asserts [RTY_I] if the local resource is busy.

A shared memory answering RTY is what the signal is for, and Chapter 16.3's isolation table used it to show that RTY routes to the owner like every other termination.

writes_o counts the memory's own updates, not bus acknowledgements, and the distinction is the one Chapter 15.4 had to learn twice. A slave that commits more than once per phase still acknowledges once. The resource's counter and the bus's counter measure different things, and in SIM F they disagreed — 8 write phases against 4 words changed, in a rig where 7 phases changed 3 words.

The wait-state counter counts clocks the phase has been HELD, and is cleared by the answer rather than loaded at the start. Module 14 shipped the other shape and it acknowledged before its latency had loaded. held_q >= WAITS with held_q cleared on ack_o || rty_o is the form that survives a sweep.

And the byte selects are honoured on every write, per byte lane, which is Chapter 13.2's contract and the reason a partial write from either master does what it says.

7. Simulation — SIM J: A Master That Never Lets Go

The CPU has permanent work and is observed for sixty clocks, twice. In the first window it holds CYC_O across its requests; in the second it negates it between them. Everything else is identical, including the DMA's workload.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM J - a master that never releases the bus ===
    the CPU has permanent work and is observed for 60 clocks,
    twice: once holding CYC_O across its requests, once not.

    CPU policy     bus terms  DMA acq.  DMA phases  waiting  copied
    holds CYC_O        21         1         1           59       0
    negates CYC_O      23         8         8           15       4

    In the holding window the DMA completed its READ phase and
    then never got the bus again: it is holding a word it cannot
    write. Its copy is half done and it is not stuck on a rule.

    Both CPUs are conformant. PERMISSION 3.05: "MASTER interfaces
    MAY assert [CYC_O] indefinitely." Every transfer in both rows
    completed correctly; the difference is which master ran.

    violations in the holding window: no-owner 0  non-owner term 0
    after the CPU stops requesting, DMA words copied: 4

Reading it

Read the two rows against each other and then read the sentence underneath them.

Holding CYC_O: 21 bus terminations, 1 DMA acquisition, 1 DMA phase completed, 59 clocks of the DMA waiting, 0 words copied.

Negating CYC_O: 23 bus terminations, 8 DMA acquisitions, 8 phases, 15 clocks waiting, 4 words copied.

The DMA's single acquisition in the first window is the detail that makes this concrete. It got the bus once, completed its read, and never got it again. It is holding a word it read and cannot write. Its copy is exactly half of one word done, and it will stay there for as long as the CPU keeps CYC_O asserted.

Now the part that has to be said without flinching. Both CPUs are conformant.

PERMISSION 3.05 — MASTER interfaces MAY assert [CYC_O] indefinitely.

Every transfer in both windows completed correctly. No rule was broken, no violation was recorded — no-owner 0, non-owner term 0 — and the interconnect behaved exactly as designed: it retains an owner while that owner's CYC_O is asserted, and this owner's never dropped.

The specification anticipates this and does not call it an error. RECOMMENDATION 3.05:

Keeping [CYC_O] asserted may lead to arbitration problems. It is therefore recommended that [CYC_O] is not indefinitely asserted.

"May lead to arbitration problems." A recommendation, naming a consequence, about a permission it does not withdraw. That pairing — PERMISSION 3.05 granting the behaviour and RECOMMENDATION 3.05 warning about it — is the specification telling you where its own authority ends.

And the last line closes the loop honestly: after the CPU stops requesting, DMA words copied: 4. The DMA was never broken. It resumed the moment the path was free, finished its copy, and reported success. Nothing needed fixing in either master.

8. The Question This Module Cannot Answer

So: two conformant masters, one correct interconnect, one workload in which one of them receives no service at all.

The system's behaviour was determined entirely by the ownership policy, and every ownership policy in this module was chosen for being the smallest thing that executes:

  • the CPU wins a tie on an idle bus — a tie-break, chosen arbitrarily;
  • an owner is retained while its CYC_O is asserted — one of at least two reasonable rules, and the one that cost the DMA a tenure every time it paused;
  • a waiting master is granted on release — with nothing said about what to do when two are waiting.

Each of those had a measurable consequence in this module, and none of them was derived from anything. They are the smallest choices that make a system run, and a real system has to make them deliberately.

How should a system choose among competing requesters over time, so that goals like priority and forward progress are met?

That question is not answered here, and it is not answered in B3 either. "Arbitration methodology is defined by the end user (priority arbiter, round-robin arbiter, etc.)." Module 17 is where the choosing becomes the subject — what the policies are, what each one costs, and what it means for a requester to be guaranteed service rather than merely permitted it.

What Module 16 contributes to that question is the vocabulary to ask it precisely. A requester, an owner, a transfer, an effect; a path that is shared and a path that is not; a delay that is contention and a delay that is structural. Without those distinctions, "the arbiter is unfair" is not yet a bug report.

9. Failure Modes and Discriminating Evidence

SYMPTOM — a master reads a value that was correct a moment ago and acts on stale data.

Candidates. Another master legitimately wrote it. The reader cached it. The operation needed an interval it did not hold.

Discriminating evidence. The resource's own write counter against the reader's expectations. If the location changed and every transfer was conformant, this is sharing working as specified — and the fix is in the algorithm, not the bus. Chapter 15.2 is the fix when the operation is compound; nothing is the fix when it is not.

SYMPTOM — one master gets no service while another is active.

Candidates. The other master holds CYC_O across its idle clocks. The release policy retains longer than the transfer. The selection policy never reaches the waiting requester.

Discriminating evidence. The busy master's CYC_O duty cycle against its STB_O duty cycle. If CYC_O is asserted far more than STB_O, it is holding the bus while doing nothing — PERMISSION 3.05 territory, and the thing RECOMMENDATION 3.05 warns about. Not a protocol violation, and not something the starved master can fix.

SYMPTOM — a device is slow only after an unrelated master is added to the design.

Candidates. Its accesses cross the interconnect and now contend.

Discriminating evidence. Acquisitions against clocks spent requesting. The difference is contention; acquisitions alone are structural. Then ask the design question: do those accesses need to reach shared state at all? SIM I's private group acquired ownership zero times.

SYMPTOM — adding a lock did not fix a lost update.

Candidates. The writer is not a bus master. The lock covers one cycle and the interval spans two. The interconnect's release policy makes the lock irrelevant — or makes it essential and it was not honoured.

Discriminating evidence. The resource's update count against the bus's commit count. More updates than commits means a non-bus writer, which Chapter 15.3 measured with one master and which no amount of ownership evidence will explain.

10. Common Mistakes

"Once the CPU has read a shared register, that value is valid until the CPU writes it."

Why it is wrong: SIM H. Another legitimate master may modify it, with no bus event of any kind to say so. The read was correct about an instant, not about a duration.

"A value changing between my two reads means something is broken."

Why it is wrong: nothing was broken in SIM H. Both reads were answered ACK, the write was conformant, the interconnect recorded zero violations. Sharing means shared.

"The bus is shared, so I need a lock."

Why it is wrong: sharing a path and sharing state are different. A DMA copying a buffer nobody else touches shares the path and shares no data. A lock costs the other master its tenure and buys nothing. Ask what state the operation depends on, not what wire it travels over.

"Multi-master means a crossbar."

Why it is wrong: five interconnection means are named in the specification and a shared bus is the first of them. The one-master-at-a-time behaviour in this module is a consequence of choosing a shared bus — the glossary says so in those words — not a property of Wishbone.

"In a multi-master SoC, every access is serialised against every other."

Why it is wrong: SIM I's four private writes acquired ownership zero times and requested the interconnect on zero clocks. Only accesses that cross a shared path contend on it.

"Starvation is a Wishbone protocol error."

Why it is wrong: no rule in B3 promises a pending master will ever own the bus. The starving window in SIM J recorded zero violations, and the master doing the starving is exercising PERMISSION 3.05. It is an arbitration problem — the specification's own phrase — and arbitration is the end user's.

"The starved master should time out and report an error."

Why it is a trap: it can, and Chapter 10.4's watchdog is the mechanism. But the DMA in SIM J was not failing — it finished correctly the moment the path was free. A timeout would have converted a delay into a spurious failure. Whether a bounded wait is a failure is a system decision, and it needs a number nobody has supplied.

11. Interview Reasoning

"Can shared state change between two of my accesses even if both of my accesses are correct?"

Yes, and it is not a fault. Another master may write between them, and Wishbone has no invalidation, no snoop and no notification. The bus tells you nothing. If your operation depends on the state not changing, hold the interval — Chapter 15.2.

"Does multi-master imply a crossbar?"

No. Five interconnection means are named in B3 — point-to-point, shared bus, crossbar, data flow and off chip. A shared bus serialises because it is a shared bus; the glossary attributes the restriction to the architecture, not the protocol.

"Why can a pending master starve even though every completed transfer is protocol-correct?"

Because nothing in the protocol is about selection over time. PERMISSION 3.05 lets a master hold CYC_O indefinitely; RECOMMENDATION 3.05 advises against it and calls the consequence an arbitration problem. Forward progress is an arbitration property and B3 delegates arbitration entirely.

"A DMA transfer is slow only when a driver is polling a status register. What are you looking at?"

Contention, most likely — measure it before assuming a bug. Acquisitions minus waiting clocks separates structural cost from competition. Then ask whether the polled register is on the shared path at all: if it can be made local, the contention disappears without touching the arbiter. If the delay is unbounded rather than merely large, that is Module 17.

"You are asked to add a lock because a shared buffer is 'sometimes corrupted'. What do you establish first?"

What writes that buffer, and whether the operation is compound. If a second master writes it and the reader's operation spans two cycles, a lock is the right answer. If the corrupting writer is not a bus master, a lock buys nothingChapter 15.3 measured exactly that with a perfect lock and a lost update.

12. Understanding Check

In SIM H, which of the two CPU reads was wrong?

Neither. Both were answered ACK and both returned the memory's contents at the clock they were answered. What changed is the memory, legitimately, between them.

The CPU's four private writes produced zero ownership acquisitions. Where did the transfers go?

Down the local leg of the CPU's own splitter, to a RAM the interconnect cannot reach. They were ordinary Wishbone transfers with ordinary handshakes — they simply never crossed a shared path.

The probe was moved from the CPU's own pins to the interconnect-side port. What did it report before the move?

Four non-owner terminations that never happened — the private RAM's acknowledgements, counted as though they had arrived while another master owned the bus. The design was right and the instrument was in the wrong place, which is worth remembering the next time a checker fires on correct hardware.

In SIM J's first window the DMA acquired the bus once and copied zero words. Why zero rather than one?

Because a word takes two phases. It completed its read and never got the bus back for the write. It is holding the word, and it wrote it as soon as the CPU stopped.

Would raising the DMA's priority fix SIM J?

It would change who starves, which is not the same as fixing it — and it is a Module 17 question rather than a Module 16 one. What this chapter can say is that the outcome was determined by the policy and not by either master, and that both masters were conformant throughout.

13. What Module 16 Established

16.1 — why there is a second initiator. The same four-word copy, performed twice, with the same eight transfers both times. What changed is which device holds the state of the operation — and a DMA engine is a master because it generates bus cycles, which is the specification's definition, not because of who configured it.

16.2 — four layers that stop being one event. A local request, ownership, a transfer, an effect. Measured: five clocks holding work with CYC_O negated, six clocks asserting CYC_O without owning, two clocks of actual contention out of twenty-one terminations. Request is not CYC_O; CYC_O is not ownership.

16.3 — ownership has two directions. A forward mux and a return demux, and three defects that break one or the other. The result that matters is the conformance monitor: all four interconnects satisfy every checkable rule in B3, including the one that turns a read into a write. Rule conformance is necessary and it is not sufficient.

16.4 — what sharing costs. A word that moved between two correct reads with zero bus events. A private resource that acquired ownership zero times under identical traffic. And one master receiving no service for sixty clocks with no rule broken by anybody.

The through-line is one distinction applied four times. What the protocol guarantees against what your architecture must decide. The protocol guarantees the shape of a transfer. It decides nothing about who gets to make one.

14. What's Next

Every ownership policy in this module was chosen for being the smallest thing that runs, and every one of them had a measurable consequence.

How should a system choose among competing requesters — and what does it mean to guarantee that a requester is served?

Module 17 — Arbitration takes up the question this module could only pose: fixed priority and what it costs, round robin and what it does not solve, what fairness means precisely enough to verify, how starvation is detected and avoided, and the arbiter RTL itself. The full path is on the Wishbone curriculum index.

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.