Skip to content
VLSI Mentor

Wishbone · Module 8

Single Read Cycle

One transfer, one bus cycle — and a monitor that counts them separately. That the two numbers agree here is a property of this master, not a law of the protocol.

Module 6 followed a read from a client request to a captured value, and Module 7 followed a write to a committed register. Both worked at the level of one transfer.

Module 8 changes the unit of analysis.

What makes Module 6's read a complete Wishbone bus cycle, and not merely a read transaction?

1. What RULE 3.25 Actually Says

The cycle signal has one normative requirement, and it names three cycle types:

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]."

Read the list. SINGLE, BLOCK, RMW — three cycle shapes, one signal framing all of them. A rule that only ever had to cover single transfers would not need to say "for the duration of".

And the CYC_O signal description spells out why:

"The cycle output [CYC_O], when asserted, indicates that a valid bus cycle is in progress. The signal is asserted for the duration of all bus cycles. For example, during a BLOCK transfer cycle there can be multiple data transfers. The [CYC_O] signal is asserted during the first data transfer, and remains asserted until the last data transfer."

That sentence is the whole of Module 8 in miniature. One cycle, many transfers, CYC_O spanning from the first to the last.

What this chapter establishes is the degenerate case — the cycle that contains exactly one transfer — so that the general case has something to be measured against.

2. Counting a Trace

A single read cycle

7 cycles
Seven clock cycles showing one Wishbone read with two wait states. The cycle signal and the strobe signal both rise at the start of cycle two and both fall at the end of cycle four, so the bus cycle interval and the transfer interval are identical. Write enable is low throughout. The address holds word four for all three presented cycles. The acknowledge appears only in cycle four. Two annotation rows beneath show the bus cycle interval spanning cycles two to four and the transfer interval spanning the same cycles two to four.cycle starts AND transfer startscycle starts AND transferstartstransfer ends AND cycle endstransfer ends AND cycleendsCLK_ICYC_OSTB_OWE_OADR_O----0x40x40x4------------ACK_IDAT_I0x00x00x0574206010x00x00x0t0t1t2t3t4t5t6
Figure 1 — one bus cycle containing one transfer. The two intervals coincide, and that is a property of this master, not of the protocol.

Count it the way the rest of Module 8 will ask you to.

Bus cycles = 1. CYC_O rose once and fell once.

Transfers = 1. One termination arrived. The number of transfers is the number of terminations — not the number of cycles STB_O was asserted, which is three here. Chapter 6.5 made that point for waits; it is the same counting rule at cycle level.

Wait cycles = 2. Cycles 2 and 3: presented, not terminated.

The two markers land on the same edges, and that coincidence is the thing to notice rather than to assume.

3. Why the Earlier Masters Tied Them Together

Every master in Modules 5, 6 and 7 drove cyc_o and stb_o from a single active_q register. That was not a shortcut — it is explicitly permitted, and the permission states its own precondition:

PERMISSION 3.40"If a MASTER doesn't generate wait states, then [STB_O] and [CYC_O] MAY be assigned the same signal."

"If a master doesn't generate wait states." Those masters did not: each presented one transfer and held STB_O until it terminated.

OBSERVATION 3.55 says the same thing from the other direction: "[CYC_O] needs to be asserted during the entire transfer cycle. A MASTER that doesn't generate wait states doesn't negate [STB_O] during a transfer cycle."

4. RTL — Measuring a Cycle

Module 8 needs to count things Modules 6 and 7 never counted. One small simulation-only block does that for the whole module.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_cycle_monitor — SIMULATION-ONLY instrumentation.
//
// PURPOSE. Count the quantities Module 8 reasons about, from the bus alone,
// so that every claim in Chapters 8.1 to 8.6 is measured rather than
// asserted. It drives nothing and is not part of any design.
//
// THE COUNTING RULES, which are the chapter's content in executable form:
//   bus cycles  = rising edges of CYC_O
//   transfers   = cycles where a QUALIFIED transfer is TERMINATED
//                 (NOT cycles where STB_O is asserted — a waited transfer
//                  is presented for many cycles and is still one transfer)
//   waits       = qualified cycles with NO termination
//   idle-in-cycle = CYC_O asserted, STB_O negated
//                 (impossible in Modules 6/7; normal from Chapter 8.3 on)
//
// Reset: SYNCHRONOUS, ACTIVE HIGH, matching the rest of the course.
// ─────────────────────────────────────────────────────────────────────────
module wb_cycle_monitor (
  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 rty_i,

  output int unsigned cycles_o,      // bus cycles begun
  output int unsigned transfers_o,   // transfers COMPLETED
  output int unsigned reads_o,
  output int unsigned writes_o,
  output int unsigned waits_o,       // presented-but-unterminated cycles
  output int unsigned gaps_o,        // CYC asserted, STB negated
  output int unsigned busy_clks_o    // clocks with CYC asserted
);
  logic cyc_q;                       // for rising-edge detection

  logic xfer, term;
  assign xfer = cyc_i & stb_i;
  assign term = xfer & (ack_i | err_i | rty_i);

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      cyc_q       <= 1'b0;
      cycles_o    <= 0;
      transfers_o <= 0;
      reads_o     <= 0;
      writes_o    <= 0;
      waits_o     <= 0;
      gaps_o      <= 0;
      busy_clks_o <= 0;
    end else begin
      cyc_q <= cyc_i;

      // A new bus cycle begins on the RISING EDGE of CYC_O. Counting
      // assertions rather than clocks is what makes one long block cycle
      // count as one cycle rather than as its duration.
      if (cyc_i && !cyc_q) cycles_o <= cycles_o + 1;

      if (cyc_i) busy_clks_o <= busy_clks_o + 1;

      // A transfer is counted at its TERMINATION, never at its
      // presentation. Chapter 6.5 and Chapter 7.4 both measured bugs that
      // came from counting presentations instead.
      if (term) begin
        transfers_o <= transfers_o + 1;
        if (we_i) writes_o <= writes_o + 1;
        else      reads_o  <= reads_o  + 1;
      end

      if (xfer && !term) waits_o <= waits_o + 1;

      // The state Modules 6 and 7 never produced.
      if (cyc_i && !stb_i) gaps_o <= gaps_o + 1;
    end
  end
endmodule

Reading it

Purpose. Turn the counting rules of Section 2 into something a testbench can print, so Module 8's numbers are measurements.

Interface. Inputs only, plus counters. It is not synthesizable designint unsigned outputs are a simulation convenience, and the module is never instantiated inside anything that ships.

State. Seven counters plus one delayed copy of CYC_O for edge detection.

Combinational logic. xfer and term — the same two terms every slave in this course computes, here used to count rather than to respond.

Sequential logic. All counting, so every number is sampled at a clock edge and there is no race with the signals it observes.

Cycle start. The rising edge of CYC_O. Transfer start. Not counted — deliberately, because a transfer's start is not a well-defined single event when it can be presented for many cycles.

Termination. Counted, and split by direction using we_i sampled in the terminating cycle. That is safe because RULE 3.60 requires WE_O stable while the transfer is presented.

Cycle end. Implied by the next rising edge, or by the run ending.

Reset. Synchronous, active high.

Failure modes. Counting stb_i instead of term would over-count every waited transfer — which is exactly the class of bug Chapter 7.4 measured inside a slave.

Simplifications. No per-address tracking, no latency histogram. Chapter 8.6 adds only what it needs.

5. Simulation — One Cycle, One Transfer

wb_read_master from Chapter 6.1 was pointed at the running peripheral, reading ID at word 4, with the monitor attached.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM A - single read cycle ===
  zero wait states:
    bus cycles begun        1
    transfers completed     1
    reads / writes          1 / 0
    wait cycles             0
    gaps (CYC & !STB)       0
    clocks with CYC high    1
    value captured          0x57420601
  with 2 wait states:
    bus cycles begun        1
    transfers completed     1
    reads / writes          1 / 0
    wait cycles             2
    gaps (CYC & !STB)       0
    clocks with CYC high    3
    value captured          0x57420601

One cycle and one transfer in both runs, which is the chapter's claim in numeric form.

The wait states changed the cycle's duration and not its content. Three clocks of CYC_O instead of one; still one transfer. That separation — duration versus content — is what Chapter 8.3 exploits.

gaps = 0 in both. This master cannot produce a gap: cyc_o and stb_o come from the same register, so CYC_O asserted with STB_O negated is unreachable. That zero is the signature of a PERMISSION 3.40 master, and it is the number that changes first in Chapter 8.3.

6. Failure Modes and Discriminating Evidence

Symptom: the cycle never ends — CYC_O stays asserted indefinitely.

Candidate causes. No termination ever arrived, or the master's release logic never ran.

Discriminating evidence. Check STB_O alongside it. Asserted too means the transfer is unanswered — Chapter 6.1 §6's four-probe walk applies unchanged. Negated while CYC_O stays high means the transfer completed and the master did not release, which is a cycle-control bug and lives in different logic entirely.

Likely RTL location. The first case is downstream; the second is the master's own state machine.

Symptom: CYC_O negates while STB_O is still asserted.

Candidate causes. A master releasing the cycle before its transfer terminated.

Discriminating evidence. Conclusive on sight — it is a RULE 3.25 duration violation, and a conformant slave stops responding under RULE 3.30, so the transfer can never complete. Chapter 5.2 §2 measured the resulting hang.

Symptom: the transfer count is higher than the number of operations issued.

Candidate causes. Counting STB_O assertions rather than terminations.

Discriminating evidence. Compare the count against the wait length. If it scales with latency rather than with traffic, the counter is counting presentations. This is the measurement-side twin of the slave bug Chapter 7.4 §5 measured.

Likely RTL location. The counter's enable — in the monitor, or in whatever is reporting.

7. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_single_cycle_checker — cycle-shape properties for a SINGLE cycle.
//
// P1 and P2 are SPECIFICATION (RULE 3.25). P3 is LOCAL DESIGN POLICY — it
// describes a master that performs one transfer per cycle, which is a
// choice, and it must be DELETED for a block or RMW master. It is included
// precisely so that deletion is a deliberate act.
// ─────────────────────────────────────────────────────────────────────────
module wb_single_cycle_checker (
  input logic clk_i,
  input logic rst_i,
  input logic cyc_o,
  input logic stb_o,
  input logic ack_i,
  input logic err_i,
  input logic rty_i
);
  default disable iff (rst_i);

  logic terminated;
  assign terminated = ack_i | err_i | rty_i;

  // P1 — SPECIFICATION (RULE 3.25, start boundary). CYC_O is asserted no
  //      later than the edge qualifying STB_O, so a strobe outside a cycle
  //      is never legal. Checked every cycle as a plain implication:
  //      $rose(stb_o) |-> $rose(cyc_o) would wrongly forbid a master that
  //      opens its cycle early to request the bus.
  property p_stb_inside_cyc;
    @(posedge clk_i) stb_o |-> cyc_o;
  endproperty
  a_stb_inside_cyc : assert property (p_stb_inside_cyc)
    else $error("RULE 3.25: STB_O asserted outside a bus cycle");

  // P2 — SPECIFICATION (RULE 3.25, duration). The cycle outlives any
  //      transfer outstanding inside it.
  property p_cyc_spans_outstanding;
    @(posedge clk_i) (cyc_o && stb_o && !terminated) |=> cyc_o;
  endproperty
  a_cyc_spans_outstanding : assert property (p_cyc_spans_outstanding)
    else $error("RULE 3.25: CYC_O negated with a transfer outstanding");

  // P3 — LOCAL POLICY, TRUE ONLY FOR A SINGLE-TRANSFER MASTER. The cycle
  //      ends with its transfer. A BLOCK master (Chapter 8.3) and an RMW
  //      master (Chapter 8.4) both violate this legitimately, and this
  //      property must be removed when a master grows into either.
  property p_one_transfer_per_cycle;
    @(posedge clk_i) (cyc_o && stb_o && terminated) |=> !cyc_o;
  endproperty
  a_one_transfer_per_cycle : assert property (p_one_transfer_per_cycle)
    else $error("LOCAL: cycle outlived its transfer in a single-transfer master");
endmodule

P3 is the property this module will spend four chapters escaping. It encodes "this master performs one transfer per cycle" — invisible in the RTL as a statement, and exactly what changes in Chapter 8.3.

A policy property that must be deleted when a design grows is doing its job, provided it is labelled. Chapter 5.2 §6 made the same argument about the same property; Module 8 is where the deletion actually happens.

Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection; the monitor is elaborated and simulated.

8. Common Mistakes

"CYC_O and STB_O are the same signal."

Wrong mental model: generalising from single-transfer masters.

Concrete bug: a slave gated on stb_i alone — correct in a single-master system, a RULE 3.30 violation that fails under arbitration.

Observable evidence: a slave responding to a transfer belonging to another master, appearing as corruption under load.

Correct model: PERMISSION 3.40 permits tying them if the master never generates wait states. It is conditional, and Section 3's callout gives the condition.

"One CYC_O pulse means one transfer."

Wrong mental model: the cycle is the transfer.

Concrete bug: a cycle-level counter or a performance script that reports one transfer per cycle assertion, understating a block by a factor of four.

Observable evidence: measured throughput that contradicts the data actually moved.

Correct model: transfers are counted at terminations. CYC_O says how long the operation lasted, not how much it did.

"ACK ends the cycle."

Wrong mental model: the termination releases CYC_O.

Concrete bug: none in a single-transfer master, where they coincide — but the model predicts the wrong thing for every block and RMW cycle.

Observable evidence: a block trace that the reader cannot account for, because they expect CYC_O to fall at the first acknowledge.

Correct model: ACK terminates a transfer. The master's cycle-control logic decides when the cycle ends, per RULE 3.25's duration requirement.

9. Interview Reasoning

A transfer is one request-and-termination exchange. A bus cycle is the interval a master claims the bus for, and it may contain one transfer or several.

STB_O marks the transfer. It says a request is being presented right now, and the transfer ends when a termination arrives — ACK, ERR or RTY, exclusive under RULE 3.45.

CYC_O marks the cycle. RULE 3.25 requires it asserted for the duration of SINGLE, BLOCK and RMW cycles, and the signal description says it is asserted during the first data transfer and remains asserted until the last.

Why they look identical in most teaching examples. A master doing one transfer per cycle has two intervals that coincide, and PERMISSION 3.40 explicitly allows driving both from one signal if the master doesn't generate wait states. Every master in the earlier modules qualified.

Where the distinction becomes load-bearing. A block cycle holds CYC_O across several transfers, toggling STB_O per transfer. A read-modify-write holds it across a read and a write. And a master may pause mid-cycle — negating STB_O while keeping CYC_O asserted, which the block sections describe as master-inserted wait states.

The counting consequence, which is how I would check someone understood it. Ask how many transfers are in a trace. The answer is the number of terminations, never the number of cycles STB_O was high — a waited transfer is presented for many cycles and is still one transfer.

And the arbitration consequence. CYC_O is what an arbiter watches — RECOMMENDATION 3.05 notes arbitration logic often uses CYC_I to select between masters. So the cycle is also the unit of bus ownership, which is why Chapter 8.4 can build an indivisible sequence out of it.

10. Understanding Check

11. What's Next

One cycle, one transfer, and a clear statement of why those two numbers happened to match.

The write from Module 7 has the same shape. Before generalising to many transfers, it is worth seeing exactly how much of the cycle skeleton survives when the payload direction reverses — because what survives is the part Module 8 is actually about.

How does the same single-transfer cycle structure carry a write?

Chapter 8.2 — Single Write Cycle answers it. 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.