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
Output
  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_induct flow.
  • Align outputs in time when one version has more latency.
Did you find what you were looking for?

Quiz

No quiz questions available for this article.