Some design changes move or replace registers: a state machine re-encoded from binary to one-hot, logic retimed across a register, a pipeline stage added. The two versions no longer have matching registers, so their logic cannot be compared cone by cone. Sequential equivalence compares them over time instead: from reset, with the same inputs, do they produce the same outputs in every cycle? This article checks a traffic light controller against its one-hot re-encoding, finds a bug in the re-encoding, and proves the fixed version equivalent.
9 min read | Intermediate
What You'll Learn
- Explain when combinational equivalence no longer applies
- Build a sequential miter with a shared reset and shared inputs
- Find a difference between two encodings of a state machine
- Prove sequential equivalence with k-induction and with the Yosys equiv flow
When Registers Do Not Match
A binary state machine with three states uses two flip-flops; the same machine one-hot uses three. No register of one corresponds to a register of the other, so a combinational check has nothing to pair. Yet both machines should behave identically on their outputs. The comparison must run over time: start both from reset, apply the same input sequence, and compare outputs cycle by cycle.
That is a property check on a miter with state, exactly the kind of check this tutorial has run since Chapter 2. A bounded check finds differences; a proof needs induction, and often a helper that relates the two state encodings.
The Example: a Traffic Light
A side-road light stays green until a car waits, then goes yellow for one cycle, red for one cycle, and back to green:
module tl_bin (input clk, input rst, input car, output red, output yellow, output green);
localparam G = 2'd0, Y = 2'd1, R = 2'd2;
reg [1:0] st;
always @(posedge clk)
if (rst) st <= G;
else case (st)
G: if (car) st <= Y;
Y: st <= R;
R: st <= G;
default: st <= G;
endcase
assign green = (st == G);
assign yellow = (st == Y);
assign red = (st == R);
endmodule
The one-hot version writes the next-state logic per flip-flop, and gets the red one wrong:
module tl_onehot (input clk, input rst, input car, output red, output yellow, output green);
reg g, y, r;
always @(posedge clk)
if (rst) begin g <= 1'b1; y <= 1'b0; r <= 1'b0; end
else begin
g <= (g && !car) || r;
y <= g && car;
r <= y || (r && car); // bug: should be r <= y;
end
assign green = g; assign yellow = y; assign red = r;
endmodule
The Sequential Miter
module tl_miter (input clk, input rst, input car);
wire r1, y1, g1, r2, y2, g2;
tl_bin u_bin (.clk(clk), .rst(rst), .car(car), .red(r1), .yellow(y1), .green(g1));
tl_onehot u_one (.clk(clk), .rst(rst), .car(car), .red(r2), .yellow(y2), .green(g2));
`ifdef FORMAL
reg init = 1'b1;
always @(posedge clk) init <= 1'b0;
always @(*) if (init) assume (rst);
// both versions start from reset together and see the same inputs: outputs must match
always @(*) if (!init) assert (r1 == r2 && y1 == y2 && g1 == g2);
`endif
endmodule
The run fails at step 4:
A car arrives in step 1, both lights go yellow in step 2 and red in step 3. In step 3 another car waits. The binary version goes back to green, as specified. The one-hot version turns green too, but because of the extra term (r && car) it also keeps red on: two lights at once, and red stuck for as long as cars keep coming. Fix the line to r <= y; and the run passes.
Quick Check
Q: Why must both designs share the reset in the miter?
Show Answer
Sequential equivalence is about behavior from a known start. If the two designs started in unrelated states, they would produce different outputs even when the logic is correct, and the check would report false differences.
Proving Equivalence
A bounded run shows no difference within its depth. For a proof, SymbiYosys in prove mode tries k-induction on the miter. With k = 1 it returns UNKNOWN: the induction step starts from pairs of states that agree on their outputs in one cycle but are not a real pair, such as one-hot states that no reset can produce. With k = 2 the proof passes, because such state pairs cannot produce matching outputs for two cycles in a row and then diverge.
Yosys has a dedicated flow for the same question. equiv_make pairs the outputs, equiv_simple -seq checks them over a few cycles, and equiv_induct completes the proof by induction:
read_verilog tl_bin.v read_verilog tl_onehot.v proc equiv_make tl_bin tl_onehot equiv hierarchy -top equiv equiv_simple -seq 5 equiv_induct equiv_status
Of those cells 3 are proven and 0 are unproven. Equivalence successfully proven!
Commercial sequential equivalence tools add automatic state mapping for common transformations such as re-encoding and retiming, so that large designs can be proven.
Quick Check
Q: A pipelined version of a block produces the same results one cycle later than the original. How must the miter change?
Show Answer
The comparison must be aligned in time: compare the pipelined output with the original output delayed by one cycle, for example out_pipe == $past(out_orig), and skip the first cycle after reset.
Running It in ChipVerify Lab
The example contains both controllers and the miter, with the bug in the one-hot version. Set the top module to tl_miter and run.
Common Mistakes
Mistake #1: Comparing designs with different reset behavior
If one version resets to a different state, the miter fails at once. Both versions must start from equivalent reset states, and the miter must assume the shared reset.
Mistake #2: Forgetting latency differences
A retimed or pipelined design may produce the same values a cycle later. Align the comparison, or every cycle looks like a difference.
Mistake #3: Stopping at a bounded pass
For re-encoded state machines, a proof by induction is usually cheap, as here with k = 2. Get the proof.
Practice Exercise
Challenge: Repair the One-Hot Encoding
Open the example and run it. Use the counterexample to find the wrong next-state equation. Fix it and run again. Then explain why the original binary design never needs a term like (r && car).
Hint
Which states lead to RED in the binary state machine, and under which conditions?
Solution
The fix is r <= y;. In the binary design, the only way into RED is from YELLOW, unconditionally, and RED always leaves to GREEN after one cycle. A one-hot equation is the OR of all incoming transitions, so RED's flip-flop must be set exactly when YELLOW is active. With the fix the miter passes.
Open the ready-made example in the lab and run the formal check from the formal panel. The free tier allows a depth of up to 10 cycles, and PRO allows up to 100.
Summary
- When registers do not correspond, equivalence must be checked over time, from a shared reset with shared inputs.
- A sequential miter is a property check: outputs equal in every cycle.
- A one-hot re-encoding with an extra term kept the light red while cars kept coming, found at step 4.
- The fixed design was proven equivalent with k-induction at k = 2, and with the Yosys
equiv_inductflow. - Align outputs in time when one version has more latency.