A one-hot register for 8 states holds 256 values, but only 8 are legal. A flipped bit, a reset glitch or a clock-domain slip can leave no bit set or two.
What happens next depends on the logic alone. The listing under Testbench shows an unprotected rotate that never recovers.
Illegal pattern | Example | What the unprotected rotate does |
|---|---|---|
All zeros |
| Rotates zeros forever: dead lock-up, no state is ever active |
Two bits set |
| Both bits rotate: two states are active at once, permanently |
Each slot is one clock cycle, sampled just after its rising edge, with step high throughout. The faults are forced into both registers just after the edges that open slots 2 and 5.
Slots 0 and 1: both rings hold one bit, 1 then 2 (S0, S1).
Slot 2: the code becomes 6 (0000_0110), two bits set. err goes high at once because s & (s − 1) is not zero.
Slots 3 and 4: the unsafe ring rotates both bits (c, 18). The safe ring has loaded S0 = 1 at the first edge and steps on normally.
Slots 5 to 8: an all-zero fault. The unsafe ring stays 0 for ever; the safe ring raises err and is back at 1 one edge later.
Strategy | Cost | Use when |
|---|---|---|
| Implementation-dependent; may be optimized outside reachable operation | Define RTL behavior; qualify mapped recovery separately |
One-hot validity check (below) | Zero/multiple-bit detection and recovery mux; area and delay depend on mapping | Fault model requires illegal-code detection/recovery |
Error output / sticky flag / counter | Detection logic plus storage/reporting resources as needed | When you must report or retain the event |
Do nothing | Zero | Never for production designs where a lock-up would hang the system |
This example models a persistent, known 8-bit register corruption between edges with the clock running and reset inactive. err detects an illegal code combinationally; the next unforced rising edge restores exactly S0, even with step=0. err then clears, so a system needing a persistent record must latch/count the event. X/Z, metastability, transient combinational faults and faults in the detector are outside this two-state corruption sweep.
Returning to a legal state does not undo an unintended write, request or result already emitted before recovery. Define a safe transaction policy: suppress side effects while invalid, invalidate outstanding results, and report or retry as required. For this known-code model, a write enable can be gated by !err, but detector propagation/hazards and the receiver's sampling window still need timing analysis. No physical containment claim is made by this RTL checker.
A legal-but-wrong state is invisible to an illegal-code detector: corrupting S0 into S5 leaves exactly one bit set. Redundancy, protocol checks or a stronger code/fault model may be needed. The directed legal-code injection below demonstrates this limitation.
The listing covers all 248 illegal known codes with step=0 and step=1 (496 cases), including all-zero and two-bit faults. Force/release occurs entirely between edges; variable state retains the injected value after release until the next procedural update. The first unforced edge is checked for exact S0 recovery and err clearing, alongside the unsafe machine's independently predicted hold/rotate result. A subsequent edge checks normal operation.
module onehot_unsafe (input logic clk, rst_n, step, output logic [7:0] s);
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) s <= 8'b0000_0001;
else if (step) s <= {s[6:0], s[7]}; // rotate; no check of the code
endmodule
module onehot_safe (input logic clk, rst_n, step, output logic [7:0] s, output logic err);
// legal means exactly one bit set
assign err = (s == 8'b0) || ((s & (s - 8'b1)) != 8'b0);
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) s <= 8'b0000_0001;
else if (err) s <= 8'b0000_0001; // recover to the reset state
else if (step) s <= {s[6:0], s[7]};
endmodule
Rotating moves each bit to its neighbour; with no bit set there is nothing to move, so the result is again zero. The machine has no active state and nothing inside it can re-create one, so it is permanently dead until reset.
The sweep covers the 248 illegal known codes with step low and high (496 cases), with force and release between clock edges. X and Z values, metastability, transient faults and faults in the detector are outside it, and it makes no physical containment claim.