Skip to content
VLSI Mentor

Wishbone · Module 15

Shared Resources

A perfect lock, an arbiter that honours it, and no second master at all — and one update is still lost, because the competitor was inside the slave.

Chapter 15.2 found the interval and measured three ways of covering it wrongly. Every experiment so far assumed the only thing that could change the counter was another bus master.

What exactly is the resource, and who else can reach it?

1. Naming the Competitors

For any resource worth protecting, the list is longer than "the other CPU".

Another bus master — a second processor, a DMA engine, a test interface. This is the one LOCK_O covers, and Modules 15.1 and 15.2 measured it in both directions.

The peripheral's own hardware. A counter that increments on an event. A status register whose bits are set by the condition they report. A FIFO level that changes because data arrived. None of these is a bus master and none is excluded by anything on the bus.

Another port of the same memory. A dual-port RAM has a second interface by definition. A lock on one port says nothing about the other.

Anything outside this bus entirely. A second interconnect reaching the same device, a processor's own cache holding a stale copy, a debugger writing through a back door.

The useful discipline is to ask the question in the other direction. Not "did I lock the bus" but "what is the complete list of things that can write this location, and which of them does my mechanism exclude". For most of the list, the answer is none of them.

A diagram of what a bus lock excludes and what it does not. On the left, two bus masters reach the interconnect, and the interconnect reaches the shared counter register. A lock held by one master stops the interconnect granting the bus to the other, so that path is blocked. On the right, three other writers reach the same register without passing through the interconnect at all: the peripheral's own event logic inside the slave, a second port of a dual-port memory, and an agent on another interconnect. None of them is a bus master and none of them is affected by the lock.master Aholds LOCK_Omaster Bexcludedinterconnecthonours LOCK_Ithe counterthe protected stateevent logicinside the slavesecond portdual-port memoryanother fabricnever on this busgrantedblocked12

One dashed edge on the left is everything a bus lock excludes. Three solid edges on the right reach the same register without passing through the thing holding the lock.

Section 4 measures the top one — and it does so with master B removed entirely, so the only path into the register besides the master's own is the event logic.

2. Scope Is a Property of the System, Not the Signal

LOCK_O requests complete ownership of the bus. Its description is explicit: "Lock is asserted to request complete ownership of the bus. Once the transfer has started, the INTERCON does not grant the bus to any other MASTER."

It is not a statement about an address. Section 3 measures the consequence: a master locking one slave delays a master that was going somewhere else entirely, because in this interconnect there is one path and holding it holds everything.

A different fabric could route them concurrently and would be equally conformant, because arbitration methodology is "defined by the end user". Neither behaviour is required and neither is forbidden — which means the scope of a lock is a property of the interconnect you happen to have, not of the signal.

That cuts both ways and the second way is the dangerous one. A wide lock costs throughput. A narrow lock — one that protects only the addressed slave — protects only the addressed slave, and a system relying on it to serialise two resources has a race it cannot see.

3. Simulation — SIM E: What the Lock Excludes

Master A locks and increments the counter at word 0. Master B targets a different slave entirely — a second counter at word 16. The two operations share no state whatsoever.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM E - what the lock excludes ===
    A locks and increments the counter at word 0.
    B targets a DIFFERENT slave, the counter at word 16.
    The two operations share no state whatsoever.

    slave at word 0    10 -> 11
    slave at word 16   100 -> 101
    both completed     1
    clocks B requested without being granted   5

    Both results are correct, and B waited anyway.

    LOCK_O's description is about the BUS: 'Lock is asserted
    to request complete ownership of the bus... the INTERCON
    does not grant the bus to any other MASTER'. It is not a
    statement about an address.

    So in THIS interconnect - a single shared path, LOCAL
    POLICY - a lock taken for one resource delays every other
    master regardless of where it was going. A different
    fabric could route them concurrently. Neither behaviour
    is required by the specification.

Reading it

Both results are correct and B waited anyway.

Five clocks of requesting without being granted, for an operation that could not possibly have interfered with A's. The two counters are separate registers in separate slaves.

This is LOCAL INTERCONNECT POLICY and it is worth saying which part is which. That B waited is a consequence of one shared path and a lock over it. That the lock is over the bus rather than the address is LOCK_O's definition. That the specification permits both this fabric and one that would route the two concurrently is the part people assume away.

The design consequence is a real trade. A lock held for an RMW is a lock held against every other master regardless of destination, so the cost of atomicity here is measured in other masters' latency, not in the locking master's. Module 17 is where that becomes a design subject; what belongs here is knowing the cost exists and where to look for it.

4. Simulation — SIM F: An Updater That Is Not a Bus Master

One master. It asserts LOCK_O and holds it across both halves. The arbiter honours it. There is no second master in this rig at all.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM F - an updater that is not a bus master ===
    One master. It asserts LOCK_O and holds it across both
    halves. There is no second master in this rig at all.

    counter before          10
    master read             10
    hardware events fired   1
    master wrote            11
    write commits           1
    counter after           11
    expected: one increment + one event = 12
    result                  ONE UPDATE LOST

    The bus lock did exactly what it promises. No other
    MASTER touched the resource, because there was no other
    master. The competitor was inside the slave.

    LOCK_I's description bounds the claim precisely: a slave
    receiving it 'is accessed by a single MASTER only'. That
    is a statement about masters. A peripheral's own hardware
    is not a master and is not excluded by anything on the bus.

Reading it

The bus lock did exactly what it promises, and one update was lost.

Trace the arithmetic. The counter holds 10. The master reads 10. In the one clock between the read being answered and the write being presented, the hardware event fires and the counter becomes 11. The master then writes the value it derived — 11 — and the counter is 11.

One increment from the master, one from the event, and the counter moved by one.

Nothing on the bus went wrong and nothing could have. There was no second master to exclude. LOCK_O was asserted for the whole interval. The arbiter honoured it. The competitor was inside the slave, and no bus signal reaches inside a slave.

And the slave's priority here is a choice, which the measurement depends on. wb_counter_slave applies a bus write and a simultaneous event together — the event adds to the written value — so an event landing on the commit clock survives. An event landing strictly inside the gap does not, because the master's write replaces the register with a value computed before it.

A different slave could resolve it differently and would be equally conformant, because Wishbone does not reach inside a target. What is not a choice is that something must resolve it, and a design that leaves the collision undefined has a worse problem than a lost update.

5. Where the Guarantee Actually Has to Come From

For a resource with a non-bus updater, the options are all inside the slave.

Make the operation a single transfer. A slave that increments on a write to a command offset has no interval to protect — the read-modify-write happens in the slave, in one clock, with the event logic on the same side of the boundary. This is why "add one" peripherals exist.

Have the slave arbitrate internally. Give the event path and the bus write path a defined priority and make the loser retry or accumulate. That is what this module's slave does for the coincident case, and it is a slave design decision rather than a bus one.

Suppress the updater for the interval. Some peripherals allow their event logic to be masked. This works and it changes the meaning of the operation — events during the window are lost or deferred rather than counted.

None of these is a Wishbone mechanism, and that is the point. Module 24 is where slave-side design of this kind belongs. What belongs here is knowing that the bus cannot solve it and which layer can.

6. Failure Modes and Discriminating Evidence

Symptom: a locked RMW loses updates with only one master in the system.

Candidate causes. A non-bus updater — event logic, a second port, an external agent.

Discriminating evidence. The resource's own update count against the number of bus commits. More state changes than bus writes means something else is writing. This is conclusive and it does not require finding the culprit first.

Likely location: inside the slave, not on the bus.

Symptom: a lock protects one operation and an unrelated master stalls.

Candidate causes. Bus-wide locking, which is what LOCK_O requests.

Discriminating evidence. The waiting master's destination against the locking master's. Different slaves and still waiting means the fabric serialises everything. That is a throughput property of the interconnect, not a defect.

Symptom: two resources that must agree are observed inconsistent.

Candidate causes. Two separate RMW operations assumed to compose.

Discriminating evidence. Whether any single cycle covered both. An RMW cycle addresses one location. Two operations are two operations, and no Wishbone mechanism makes them one.

Symptom: a dual-port memory shows a lost update despite a locked access.

Candidate causes. The other port.

Discriminating evidence. Whether the competing write appeared on this bus at all. If it did not, no bus-level mechanism could have prevented it — the access never passed through the thing holding the lock.

7. Verification

The counter slave's two properties are the resource's own guarantees, and both are local.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_counter_props — the resource's own guarantees. LOCAL: Wishbone does
// not reach inside a target.
// ─────────────────────────────────────────────────────────────────────────
module wb_counter_props #(
  parameter int unsigned DW = 32
) (
  input logic          clk_i,
  input logic          rst_i,
  input logic          cyc_i,
  input logic          stb_i,
  input logic          we_i,
  input logic          ack_i,
  input logic          err_i,
  input logic          event_i,
  input logic [DW-1:0] count_i
);
  default disable iff (rst_i);

  // P11 — LOCAL SLAVE POLICY, and the one that makes every other
  // measurement in this module meaningful. The register changes only on an
  // acknowledged write or a hardware event. A phase held across several
  // clocks commits once; a phase answered with ERR commits nothing.
  property p_commit_only_on_ack_or_event;
    @(posedge clk_i) (!$stable(count_i)) |->
      $past(event_i) || $past(cyc_i && stb_i && we_i && ack_i);
  endproperty
  a_commit_only_on_ack_or_event: assert property (p_commit_only_on_ack_or_event);

  // P12 — LOCAL SLAVE POLICY. A refused write leaves the register alone.
  // This is why Chapter 15.4 can say the counter is unchanged after an
  // error WITHOUT appealing to the specification - which provides no
  // rollback of any kind.
  property p_err_commits_nothing;
    @(posedge clk_i) (cyc_i && stb_i && we_i && err_i && !event_i) |=>
      $stable(count_i);
  endproperty
  a_err_commits_nothing: assert property (p_err_commits_nothing);
endmodule

P11 names the event path explicitly, which is the honest way to write it. A property asserting that the register changes only on an acknowledged write would be false of this slave by design — and the temptation would then be to weaken it rather than to notice that the event is a legitimate second writer.

P12 is what lets Chapter 15.4 say the counter is unchanged after an error without appealing to the specification. It is a statement about this slave, verifiable in its source, and Wishbone provides no rollback of any kind — so the guarantee has to come from somewhere and this is where.

8. Common Mistakes

"Atomic means nobody anywhere can change the value."

Wrong mental model: the word has a single scope.

What is true: it has whatever scope the mechanism has. LOCK_I excludes other masters — "accessed by a single MASTER only". Measured: perfect bus exclusion, no second master, one update lost.

"A locked bus prevents the peripheral's own hardware from updating a register."

Wrong mental model: the lock reaches inside the slave.

What is true: no bus signal reaches inside a slave. The event logic is on the other side of the interface and is not making a bus access.

"An RMW makes a dual-port RAM atomic across both ports."

Wrong mental model: the resource is the thing locked.

What is true: the bus is the thing locked. A write through the second port never passes through the interconnect holding the lock, so nothing about it can be prevented from this side.

"Locking protects the address I named."

Wrong mental model: the lock has address scope.

What is true: LOCK_O requests ownership of the bus. SIM E measures an unrelated master delayed for five clocks. Whether a fabric narrows that is its own policy and is not required either way.

"Two locked operations on two registers give me a consistent view of both."

Wrong mental model: operations compose.

What is true: each RMW cycle addresses one location. Two operations can be interleaved with anything else between them, and no Wishbone mechanism joins them.

9. Interview Reasoning

Yes, and the specification's own wording is where the boundary is.

LOCK_I's description: a slave receiving it "is accessed by a single MASTER only, until either LOCK_I or CYC_I is negated."

"Accessed by a single MASTER" is the whole promise. It excludes other masters. It says nothing about anything that is not a master — the peripheral's own event logic, a second port of a dual-port memory, an agent on a different interconnect.

Measured: one master, LOCK_O asserted across the whole interval, an arbiter that honours it, no second master in the system — and one update lost, because a hardware event incremented the counter between the read and the write.

Which makes the right question architectural rather than protocol. List everything that can write the location; ask which of them passes through the thing holding the lock. For event logic inside the slave, the answer is none.

And the fix is not on the bus. Make the operation a single transfer, arbitrate inside the slave, or mask the updater — all slave-side, and all changing what the operation means.

10. Understanding Check

The slave's own hardware.

The counter has an event input — something inside the peripheral that also increments it, which is ordinary for a counter that reports a real condition.

The event fired in the one clock between the read being answered and the write being presented. The counter went from 10 to 11 on its own. The master then wrote 11, the value it had derived from reading 10.

Two increments, one increment of effect — the same arithmetic as Chapter 15.1's lost update, with no second master anywhere.

And the lock was doing its job the whole time. It excluded other masters, of which there were none. The competitor was never on the bus, so nothing on the bus could have prevented it.

11. What's Next

The resource is defined, the competitors are named, and the boundary of a bus mechanism is measured: perfect bus exclusion, no second master, one update lost.

Two chapters have used a two-master system as laboratory equipment without looking at it closely.

What does the interconnect actually have to do, and what happens when it does not?

Chapter 15.4 — Multi-Master Systems records the ownership timeline clock by clock, runs byte-identical masters against an interconnect that ignores their locks, and validates three checkers against the defects they claim to detect. 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.