Skip to content
VLSI Mentor

Wishbone · Module 5

CYC — Cycle

CYC frames the bus cycle a transfer lives inside. It must be asserted no later than the edge qualifying STB and must outlast the transfer — and a master that drops it early destroys a transaction every other signal says is fine.

Chapter 4.9 established what CYC_O means: a claim on the bus, and the thing that makes a read-modify-write atomic. Chapter 5.1 drove it from the same register as STB_O and cited the permission that allows it.

This chapter is about its timing — where the cycle begins and ends relative to the transfer inside it.

When does a basic bus cycle begin and end, relative to the transfer it contains?

1. Cycle and Transfer Are Different Durations

Chapter 5.1 §1 argued that a transfer is an interval. A cycle is also an interval, and it is a different one.

The transfer is the interval during which STB_O presents a specific request: this address, this direction, this data.

The cycle is the interval during which the master holds the bus. It contains one or more transfers.

For a single read or write they coincide exactly, which is why wb_hs_master could drive both from one register under PERMISSION 3.40. For everything else they do not:

Cycle typeTransfers insideCYC_OSTB_O
SINGLE READ/WRITE1one transfer longidentical to CYC_O
BLOCKmanyspans all of themone assertion per transfer
RMW2 (a read then a write)spans bothone assertion each

RULE 3.25 names all three, which is the specification telling you directly that CYC_O's job is to be the outer interval. Module 8 owns block and read-modify-write cycles in full; this chapter needs only the fact that they exist, because it is what makes the two signals non-redundant.

2. Dropping CYC Early

This is the failure this chapter exists for, and it is unusually nasty because every other signal looks correct.

Suppose a master negates CYC_O while its transfer is still outstanding, but keeps STB_O, the address and the direction asserted.

What the slave does: nothing. RULE 3.30"SLAVE interfaces MAY NOT respond to any SLAVE signals when [CYC_I] is negated." The strobe, the address, the write data are all present and all forbidden to act on. OBSERVATION 3.25 puts it plainly: STB_I is only valid when CYC_I is valid.

What the master sees: no termination, ever. It waits.

What a waveform shows: a strobe held forever with no acknowledge — the signature Chapter 4.8 identified as an unanswered transfer. But the slave is not at fault, and a debugger who follows the usual instinct will spend the afternoon in the slave's RTL.

3. Holding CYC Too Long

The opposite error is legal, and the specification is unusually candid about it.

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

A permission and a recommendation against using it, side by side. That pairing is worth reading carefully, because it is a precise statement of a design boundary.

Why it is permitted: CYC_O is a claim about this master's interface. Nothing about holding it violates the handshake, and a master that genuinely needs a long tenure — an atomic sequence, a block — must hold it.

Why it is inadvisable: in a shared system, CYC_O is the bus request an arbiter watches. A master holding it with no transfers presented occupies the bus and starves everyone else. Chapter 4.12 showed the sharp form of this: a master holding CYC_O across a retry backoff prevents the very drain that would let its retry succeed.

The distinction to carry away. "Legal" and "correct in a system" are different claims. RULE 3.25 tells you what you must do; RECOMMENDATION 3.05 tells you what a system integrator will hold you to. Wishbone deliberately does not define arbitration policyChapter 4.9 §8 covered why — so the recommendation is as far as the specification can go.

4. RTL — Separating the Two Signals

wb_hs_master drove both from active_q. This master separates them, which is the minimum change that makes the distinction visible.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_cyc_frame_master — CYC_O and STB_O driven from DIFFERENT state.
//
// PURPOSE. Chapter 5.1's master satisfied RULE 3.25 trivially, by driving
// both qualifiers from one register under PERMISSION 3.40. This one opens
// its cycle a cycle EARLY — a bus request ahead of a presented transfer —
// which is the legal shape PERMISSION 3.40 does NOT cover and which makes
// "no later than" mean something.
//
// It is deliberately NOT a block master: one transfer per cycle still.
// Multi-transfer tenures belong to Module 8. What changes here is only
// WHERE the cycle boundary sits relative to the transfer.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00, 3.20).
// ─────────────────────────────────────────────────────────────────────────
module wb_cyc_frame_master #(
  parameter int unsigned AW = 30,
  parameter int unsigned DW = 32
) (
  input  logic            clk_i,
  input  logic            rst_i,

  input  logic            req_i,
  input  logic            req_we_i,
  input  logic [AW-1:0]   req_adr_i,
  input  logic [DW-1:0]   req_dat_i,
  input  logic [DW/8-1:0] req_sel_i,
  output logic            busy_o,
  output logic            done_o,
  output logic [DW-1:0]   done_dat_o,

  output logic            cyc_o,
  output logic            stb_o,
  output logic            we_o,
  output logic [AW-1:0]   adr_o,
  output logic [DW-1:0]   dat_o,
  output logic [DW/8-1:0] sel_o,
  input  logic [DW-1:0]   dat_i,
  input  logic            ack_i,
  input  logic            err_i,
  input  logic            rty_i
);
  // ── STATE ─────────────────────────────────────────────────────────────
  // S_CLAIM is the state that could not exist in Chapter 5.1's master: the
  // cycle is OPEN and no transfer is presented. In a shared system this is
  // the bus request sitting with the arbiter.
  typedef enum logic [1:0] { S_IDLE, S_CLAIM, S_XFER } state_e;
  state_e state_q;

  logic            we_q;
  logic [AW-1:0]   adr_q;
  logic [DW-1:0]   dat_q;
  logic [DW/8-1:0] sel_q;

  // ── THE SEPARATION ────────────────────────────────────────────────────
  // cyc_o covers S_CLAIM and S_XFER. stb_o covers S_XFER only.
  //
  // RULE 3.25 start boundary: CYC_O is asserted in S_CLAIM, one edge BEFORE
  // STB_O can be. "No later than" is satisfied with a cycle to spare.
  //
  // RULE 3.25 duration: cyc_o stays asserted for every cycle stb_o is, and
  // is negated only when the transfer terminates. There is no reachable
  // state with stb_o asserted and cyc_o negated — which is the structural
  // form of Chapter 5.1's property P1.
  assign cyc_o  = (state_q == S_CLAIM) || (state_q == S_XFER);
  assign stb_o  = (state_q == S_XFER);
  assign we_o   = we_q;
  assign adr_o  = adr_q;
  assign dat_o  = dat_q;
  assign sel_o  = sel_q;
  assign busy_o = (state_q != S_IDLE);

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

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      state_q    <= S_IDLE;              // RULE 3.20: both qualifiers low
      we_q       <= 1'b0;
      adr_q      <= '0;
      dat_q      <= '0;
      sel_q      <= '0;
      done_o     <= 1'b0;
      done_dat_o <= '0;
    end else begin
      done_o <= 1'b0;

      unique case (state_q)
        S_IDLE: begin
          if (req_i) begin
            // Latch the request and OPEN THE CYCLE, but do not present the
            // transfer yet. One cycle of separation is enough to show the
            // shape; a real arbitrated master would wait here for a grant.
            state_q <= S_CLAIM;
            we_q    <= req_we_i;
            adr_q   <= req_adr_i;
            dat_q   <= req_dat_i;
            sel_q   <= req_sel_i;
          end
        end

        S_CLAIM: begin
          // Cycle open, nothing presented. A slave sees CYC_I asserted and
          // STB_I negated: RULE 3.30 permits it to respond to nothing, and
          // RULE 3.35 forbids it to terminate. It waits. That is correct
          // and complete behaviour.
          state_q <= S_XFER;
        end

        S_XFER: begin
          if (terminated) begin
            // Both signals drop together here, because the cycle contains
            // exactly one transfer. In a block master the cycle would
            // survive and only stb_o would drop — Module 8's subject.
            state_q <= S_IDLE;
            done_o  <= 1'b1;
            if (ack_i && !we_q) done_dat_o <= dat_i;
          end
        end

        default: state_q <= S_IDLE;
      endcase
    end
  end
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_cyc_broken_master — the EARLY-DROP BUG, isolated.
//
// NOT A REFERENCE DESIGN. This module exists to be simulated against a
// slave that waits, so the failure in Section 2 can be observed rather
// than described. It is identical to wb_cyc_frame_master except that
// cyc_o is negated one cycle after the transfer is presented.
//
// The bug is ONE LINE, and every other signal it drives stays correct.
// ─────────────────────────────────────────────────────────────────────────
module wb_cyc_broken_master #(
  parameter int unsigned AW = 30,
  parameter int unsigned DW = 32
) (
  input  logic            clk_i,
  input  logic            rst_i,
  input  logic            req_i,
  input  logic [AW-1:0]   req_adr_i,
  output logic            busy_o,
  output logic            done_o,

  output logic            cyc_o,
  output logic            stb_o,
  output logic            we_o,
  output logic [AW-1:0]   adr_o,
  output logic [DW-1:0]   dat_o,
  output logic [DW/8-1:0] sel_o,
  input  logic            ack_i,
  input  logic            err_i,
  input  logic            rty_i
);
  logic          active_q;
  logic          waited_q;              // one cycle after presentation
  logic [AW-1:0] adr_q;

  // ── THE BUG ───────────────────────────────────────────────────────────
  // cyc_o is dropped once waited_q sets, while stb_o, adr_o, we_o and sel_o
  // all remain perfectly correct. RULE 3.25's DURATION half is violated;
  // the start half is fine. A slave obeying RULE 3.30 now responds to
  // nothing, so no termination ever arrives and this master waits forever.
  assign cyc_o  = active_q & ~waited_q;
  assign stb_o  = active_q;
  assign we_o   = 1'b0;
  assign adr_o  = adr_q;
  assign dat_o  = '0;
  assign sel_o  = '1;
  assign busy_o = active_q;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      active_q <= 1'b0;
      waited_q <= 1'b0;
      adr_q    <= '0;
      done_o   <= 1'b0;
    end else begin
      done_o <= 1'b0;
      if (!active_q) begin
        if (req_i) begin
          active_q <= 1'b1;
          waited_q <= 1'b0;
          adr_q    <= req_adr_i;
        end
      end else begin
        waited_q <= 1'b1;                        // drops cyc_o next cycle
        if (ack_i || err_i || rty_i) begin
          active_q <= 1'b0;
          waited_q <= 1'b0;
          done_o   <= 1'b1;
        end
      end
    end
  end
endmodule

Reading the pair

Purpose. The first master shows a cycle that legally outlives its transfer at the start. The second isolates the duration violation so it can be simulated.

Interface. Identical client contract to Chapter 5.1's master, so the two are drop-in comparable.

State. wb_cyc_frame_master uses a three-state machine whose middle state is the whole point. The broken master adds one flag.

Combinational behaviour. The two qualifier expressions differ — in the good master by which states they cover, in the broken one by a spurious ~waited_q term.

Sequential behaviour. Metadata latched once at req_i; state advances on termination.

Request start. CYC_O rises one edge before STB_O. RULE 3.25's "no later than" is met with margin.

Waiting. All metadata is register-held and untouched while S_XFER persists.

Termination. Sampled as a level in S_XFER; both qualifiers drop together because the cycle holds one transfer.

Read data. Captured on ack_i && !we_q only.

Reset. Synchronous, active high; S_IDLE negates both qualifiers, satisfying RULE 3.20 through the state encoding — a reviewer checking that rule must trace the encoding rather than find a direct assignment.

Failure modes. The broken master is the failure mode; Section 7 covers the rest.

Simplifications. S_CLAIM is one cycle long and unconditional. A real arbitrated master would remain there until granted, which is Chapter 2.6's territory and Module 8's.

CYC opens early: the bus request precedes the transfer

7 cycles
Seven clock cycles. In cycle two the master asserts the cycle signal alone, with the strobe still negated; this is the bus request being made before any transfer is presented. In cycle three the strobe joins it and the address becomes meaningful, so the transfer is now presented. The slave acknowledges in cycle four. In cycle five both the cycle and strobe signals are negated together. The point of the figure is cycle two, where the cycle signal is asserted with no transfer presented, which rule three point two five permits because it requires the cycle to be asserted no later than the edge qualifying the strobe rather than at the same time.cycle open, nothing presentedcycle open, nothingpresentedtransfer presentedtransfer presentedterminatedterminatedCLK_ICYC_OSTB_OADR_O--------0x4000x400------------ACK_It0t1t2t3t4t5t6
Figure 1 — CYC asserted one cycle before STB. Legal: RULE 3.25 sets a deadline, not a coincidence.

Cycle 2 is the legal state Chapter 5.1's master could not reach. CYC_O asserted, STB_O negated. The slave sees a cycle in progress and no transfer; RULE 3.35 forbids it to terminate and RULE 3.30 permits it to do nothing. It waits.

In an arbitrated system this cycle is the bus request. The master is asking; the arbiter has not yet granted. Forcing the two signals to rise together would mean a master could not ask for the bus until its transfer was fully assembled.

CYC dropped early: a RULE 3.25 duration violation

7 cycles
Seven clock cycles showing the failure. In cycle two the master asserts both the cycle and strobe signals with a valid address, correctly presenting a transfer. In cycle three the master negates the cycle signal while leaving the strobe, address and direction perfectly correct. From cycle three onward the slave is forbidden by rule three point three zero from responding to any slave signal while the cycle input is negated, so its acknowledge stays low indefinitely. The strobe remains asserted through cycles three to seven with no acknowledge ever arriving. The waveform at the master is indistinguishable from a slave that failed to answer, even though the slave is behaving correctly.presented correctlypresented correctlyCYC dropped: transfer is deadCYC dropped: transfer isdeadACK will never comeACK will never comeCLK_ICYC_OSTB_OADR_O----0x4000x4000x4000x4000x4000x400ACK_It0t1t2t3t4t5t6
Figure 2 — the same transfer with CYC dropped early. Every other signal is correct and the transfer is dead.

Compare the two STB_O traces. In Figure 2 it is asserted longer, the address is stable, the direction is right. Every signal a reviewer would check is correct. The only wrong thing is a signal that went away, and absences are harder to see on a waveform than presences.

This is why P1 is the first probe. One glance at CYC_O distinguishes Figure 2 from a genuine slave failure, and nothing else does.

6. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_cyc_frame_checker — cycle-framing properties.
//
// P1 and P2 are SPECIFICATION (RULE 3.25). P3 is LOCAL POLICY, and is the
// one that would be wrong for a different master — deliberately so, to
// make the labelling matter rather than be decoration.
// ─────────────────────────────────────────────────────────────────────────
module wb_cyc_frame_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). A strobe never exists
  //      outside a cycle. Checked as a plain implication EVERY cycle, not
  //      on the rising edge: $rose(stb_o) |-> $rose(cyc_o) would forbid the
  //      legal early-claim shape in Figure 1, which is the over-strong
  //      property trap Chapter 4.6 Section 10 described.
  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). While a transfer is presented
  //      and unterminated, the cycle survives to the next edge. This is the
  //      property that catches Figure 2, and it catches it on the FIRST
  //      cycle of the violation rather than when the master eventually
  //      appears to hang.
  property p_cyc_outlives_outstanding;
    @(posedge clk_i) (cyc_o && stb_o && !terminated) |=> cyc_o;
  endproperty
  a_cyc_outlives_outstanding : assert property (p_cyc_outlives_outstanding)
    else $error("RULE 3.25: CYC_O negated with a transfer outstanding");

  // P3 — LOCAL POLICY for a SINGLE-transfer master. The cycle does not
  //      survive its transfer: both qualifiers drop together.
  //
  //      This property is CORRECT HERE AND WRONG FOR A BLOCK MASTER, which
  //      legitimately holds cyc_o across several transfers. It is included
  //      precisely because it must be deleted when this master grows — a
  //      policy property that fails after a deliberate design change is
  //      doing its job (Chapter 4.11 Section 8).
  property p_single_transfer_cycle;
    @(posedge clk_i) (cyc_o && stb_o && terminated) |=> !cyc_o;
  endproperty
  a_single_transfer_cycle : assert property (p_single_transfer_cycle)
    else $error("LOCAL: cycle outlived its transfer in a single-transfer master");
endmodule

P2 is the property worth having. The failure it catches produces a symptom — a hang — that is many cycles removed from its cause and identical to three other causes. P2 fires on the edge the violation occurs, with the rule number in the message.

P3 is included to be deleted. It encodes "this master performs one transfer per cycle", which is true today and will stop being true when block support arrives. Labelling it LOCAL POLICY means the engineer who deletes it knows they are relaxing a design decision rather than defeating a conformance check.

Tooling limitation. Icarus Verilog cannot parse SVA. These are reviewed by inspection; the two masters above are elaborated and simulated in Section 7.

7. Failure Modes and Discriminating Evidence

Symptom: the master hangs; STB_O, ADR_O and WE_O all look correct.

Candidate causes. CYC_O negated while the transfer is outstanding — a RULE 3.25 duration violation.

Discriminating evidence. Probe CYC_O at the master (P1). Negated while STB_O is asserted is conclusive, and it is the only cause of a hang where the slave is provably innocent. Every other hang cause leaves CYC_O correctly asserted.

Likely RTL location. The cyc_o assignment — a term that clears it independently of the transfer's lifetime.

Property. P2.

Symptom: a slave never responds, and CYC_I at the slave is low while STB_I is high.

Candidate causes. Either the master violated RULE 3.25, or the interconnect routes STB but not CYC.

Discriminating evidence. Compare CYC_O at the master with CYC_I at the slave in the same cycle. Asserted at the master and negated at the slave isolates the interconnect; negated at both isolates the master. Chapter 3.5 noted that CYC is broadcast rather than decoded, so a fabric that drops it is a wiring error rather than a decode error.

Symptom: one master starves the others; the bus is idle but unavailable.

Candidate causes. A master holding CYC_O with no transfers presented — legal under PERMISSION 3.05, inadvisable under RECOMMENDATION 3.05.

Discriminating evidence. CYC_O asserted continuously with STB_O idle. The absence of strobes is what distinguishes this from a slave that will not terminate, where the strobe stays high too.

Likely RTL location. The master's state machine exit conditions — not the arbiter.

Symptom: transfers to one slave work; the same transfers through an arbiter intermittently fail.

Candidate causes. A slave gated on stb_i alone, so it acts on a strobe whose cycle belongs to a different master.

Discriminating evidence. Check cyc_i at the slave when it misbehaves. Low while stb_i is high is a direct RULE 3.30 violation in the slave.

Likely RTL location. The slave's xfer term. This is the bug PERMISSION 3.40's single-register master teaches by accident, as Chapter 5.1 §10 warned.

8. Common Mistakes

"CYC_O and STB_O must rise together."

Wrong mental model: reading RULE 3.25's "no later than" as "at the same time".

Concrete bug: no functional bug — but a master built this way cannot request the bus before its transfer is ready, and an assertion written this way ($rose(stb_o) |-> $rose(cyc_o)) fails on the perfectly legal design in Figure 1.

Observable evidence: an assertion firing on a correct master, which invites someone to "fix" the design to satisfy it.

Correct model: RULE 3.25 sets a deadline. Earlier is legal and useful; later is not.

"If the transfer is taking too long, drop CYC_O and retry."

Wrong mental model: the master can withdraw a transfer.

Concrete bug: the slave stops responding under RULE 3.30 and the transfer is dead, with no termination ever. If the slave had already begun a side effect, nobody knows whether it completed.

Observable evidence: a hang whose cause is upstream of every signal a debugger normally checks.

Correct model: there is no protocol-level abandon. A system that needs one puts a watchdog in the interconnect, which RECOMMENDATION 3.10 suggests explicitly, so the transfer is terminated rather than orphaned.

"Holding CYC_O is harmless if I'm not transferring anything."

Wrong mental model: the cycle signal only matters when a transfer is present.

Concrete bug: a master parking CYC_O high between operations. Legal under PERMISSION 3.05 and fatal to throughput in a shared system.

Observable evidence: other masters starved; latency that scales with the number of masters rather than with traffic.

Correct model: CYC_O is the arbiter's input. RECOMMENDATION 3.05 says so directly, and it is the specification's way of noting that a permission is not an endorsement.

9. Interview Reasoning

At CYC_O — the one signal the question does not mention, which is usually deliberate.

Why it is the first candidate. RULE 3.30 forbids a slave from responding to any slave signal while CYC_I is negated. So a master that drops CYC_O while holding everything else correct has produced a transfer that no conformant slave may answer. The strobe is present, the address is right, and the slave is required to ignore all of it.

Why the waveform misleads. At the master, this is indistinguishable from "the slave never answered" — strobe held, no termination. Three other causes produce the same picture: no slave decoded the address, the slave has an unhandled decode path, or the return path is broken. Nothing in the master-side view separates them, which is why Chapter 5.1 §5's four-probe sequence exists and why CYC_O is P1.

What confirms it in one observation. CYC_O low with STB_O high, at the master. That is a RULE 3.25 duration violation and it is conclusive — no other fault produces it.

Where the bug is in RTL. The cyc_o expression will have a term that clears it on something other than the transfer's lifetime — a counter, a timeout, a "done" flag that sets early. In wb_cyc_broken_master it is a single & ~waited_q.

The follow-up I would expect, and the answer. Why would anyone write that? Usually an attempted timeout: the master decided the transfer was taking too long and tried to withdraw it. Wishbone has no withdraw. The transfer is now orphaned — and if the slave had started a side effect, the master cannot even learn whether it happened. The system-level answer is RECOMMENDATION 3.10's watchdog in the interconnect, which terminates the transfer properly instead of abandoning it.

10. Understanding Check

11. What's Next

The cycle's boundaries are settled: no later than the strobe at the start, outlasting it at the end, and — for a single transfer — dropping with it.

Inside that frame sits the signal that actually presents the request. Chapter 5.1's slave answered in the cycle it was asked; a slave that needs longer changes what the strobe has to do.

When is a transfer actually being presented, and what must remain true for as long as it is?

Chapter 5.3 — STB — Strobe 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.