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 type | Transfers inside | CYC_O | STB_O |
|---|---|---|---|
| SINGLE READ/WRITE | 1 | one transfer long | identical to CYC_O |
| BLOCK | many | spans all of them | one assertion per transfer |
| RMW | 2 (a read then a write) | spans both | one 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 policy — Chapter 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.
// ─────────────────────────────────────────────────────────────────────────
// 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// ─────────────────────────────────────────────────────────────────────────
// 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
endmoduleReading 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.
5. Waveforms — Legal Early, Illegal Short
CYC opens early: the bus request precedes the transfer
7 cyclesCycle 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 cyclesCompare 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
// ─────────────────────────────────────────────────────────────────────────
// 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");
endmoduleP2 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
Related tutorials
- Related topic
STB_O
Bus wires always carry values; STB_O is what turns a set of values into a request. Qualification, the termination every strobe is owed, and why silence is the one response a slave may never give.
- Related topic
Control Signals
Address and data are payload; they say what values are involved and nothing about what should happen to them. Control information is what makes a bus interpretable: a qualifier that says a request is real, a direction, lane enables, a completion and an error — each derived from a failure that occurs without it.
- Related topic
Data Flow
One Wishbone access, followed through every block in both directions: what the master drives, where the address changes form, which signals are broadcast and which are decoded, and how read data and termination find their way back to exactly one requester.
- Related topic
DAT_O
Both masters and slaves have a DAT_O, and they mean opposite things. What each must drive, when it must be valid, and why a master may legally leave stale write data on the bus during a read.
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.
