Eight states need three binary bits, eight one-hot bits, or four Johnson bits. The table lists every code.
State | Binary | Gray | One-hot | Johnson (4-bit) |
|---|---|---|---|---|
S0 | 000 | 000 | 00000001 | 0000 |
S1 | 001 | 001 | 00000010 | 0001 |
S2 | 010 | 011 | 00000100 | 0011 |
S3 | 011 | 010 | 00001000 | 0111 |
S4 | 100 | 110 | 00010000 | 1111 |
S5 | 101 | 111 | 00100000 | 1110 |
S6 | 110 | 101 | 01000000 | 1100 |
S7 | 111 | 100 | 10000000 | 1000 |
Property | Binary | Gray | One-hot | Johnson |
|---|---|---|---|---|
Bits changing per step | 1 to 3 (e.g. 011→100 flips all three) | Always 1 | Always 2 (one falls, one rises) | Always 1 |
Decode one state | n-input AND | n-input AND | Read one bit | 2-input AND |
Flops for N states | ⌈log₂ N⌉ | ⌈log₂ N⌉ | N | N/2 |
Can express any N? | Yes | Any N as an open sequence; a closed one-bit ring must have even length and its wrap must be checked | Yes | Only even N |
The transition counts describe the eight-state rings shown above, including wraparound. Binary is the smallest code, one-hot is the easiest to decode, and these Gray and Johnson rings change one bit per step. Truncating a Gray sequence can break its wrap: 00 → 01 → 11 → 00 changes one bit on the first two transitions but two bits on the last. An odd-length closed ring with exactly one changing bit per transition is impossible: each bit flip toggles the parity of the number of ones, so an odd number of flips cannot return to the starting code. Branches, aborts and resets need their own transition audit.
One bit changing per step matters when the state is sampled asynchronously or drives glitch-sensitive outputs. With several bits changing, a receiver can briefly see a code that is neither the old nor the new state.
Each slot is half a nanosecond, and the skews are illustrative numbers. The two bus lanes show the code the receiver sees, in hex, and the decode lanes are a combinational test for the code 111 (state S7 in binary).
Binary, slots 0 and 1: the code is 3 (011), state S3.
Binary, slot 2: bit 2 has risen but bits 1 and 0 have not yet fallen, so the receiver sees 7 (111). The decode pulses high for one slot although the FSM never visits S7.
Binary, slots 3 and 4: the code passes through 5 (101) and settles at 4 (100), state S4.
Gray: S3 to S4 is 2 (010) to 6 (110). Only one bit changes, so there is no intermediate code and the decode stays low.
Gray limits adjacent ring steps to one changing bit. This FSM's abort can jump from S4 (110) to S0 (000), changing two bits; S5 (111) to S0 changes three. Reset can make the same jumps. Do not use this raw Gray FSM state for CDC. Transfer a stable status snapshot with a handshake. Gray FIFO pointers use a constrained sequence plus synchronization and physical timing constraints; see the CDC section.
Three bits change at once and not at exactly the same instant. For a short time the code can be any mix (for example 111 or 000), which a combinational decode may interpret as a different state, producing a glitch.
No. The wrap 11 → 00 flips two bits. Changing the codes or adding bits cannot make an odd-length closed ring one-bit throughout: each one-bit transition toggles ones parity, and returning to the original code requires an even number of toggles.
The listing checks the eight-state code sequences and their wrap transitions, then checks the two-bit wrap of a truncated three-state Gray sequence.
module code_check;
// Generate the codes from the state number and verify the properties in the table above.
function automatic logic [2:0] to_gray(logic [2:0] b); return b ^ (b >> 1); endfunction
function automatic logic [7:0] to_onehot(logic [2:0] b); return 8'b1 << b; endfunction
function automatic logic [3:0] to_johnson(logic [2:0] b);
// 4-bit Johnson counter value after b steps: shift in the inverted MSB
logic [3:0] j = 4'b0000;
for (int i = 0; i < b; i++) j = {j[2:0], ~j[3]};
return j;
endfunction
int errors = 0, nx, flips_g, flips_j, flips_h, ones_h, flips_bin;
logic [2:0] g0, g1, dg;
logic [3:0] j0, j1, dj;
logic [7:0] h0, h1, dh;
initial begin
for (int i = 0; i < 8; i++) begin
nx = (i + 1) % 8; // next state (wraps 7 -> 0)
g0 = to_gray(i); g1 = to_gray(nx);
j0 = to_johnson(i); j1 = to_johnson(nx);
h0 = to_onehot(i); h1 = to_onehot(nx);
dg = g0 ^ g1; flips_g = $countones(dg); if (flips_g != 1) errors++; // Gray: exactly one bit changes
dj = j0 ^ j1; flips_j = $countones(dj); if (flips_j != 1) errors++; // Johnson: exactly one bit changes
dh = h0 ^ h1; flips_h = $countones(dh); if (flips_h != 2) errors++; // one-hot: one falls, one rises
ones_h = $countones(h0); if (ones_h != 1) errors++; // exactly one bit set
end
// Truncating to three states preserves the open sequence, but not a one-bit wrap.
for (int i = 0; i < 3; i++) begin
nx = (i + 1) % 3;
g0 = to_gray(3'(i)); g1 = to_gray(3'(nx));
dg = g0 ^ g1;
flips_g = $countones(dg);
if (flips_g != ((i == 2) ? 2 : 1)) errors++;
end
// binary is not one bit at a time: 3 -> 4 flips all three bits
g0 = 3'd3 ^ 3'd4; flips_bin = $countones(g0);
if (flips_bin != 3) errors++;
// the table: spot-check a few entries
if (to_gray(3'd2) !== 3'b011) errors++;
if (to_gray(3'd4) !== 3'b110) errors++;
if (to_johnson(3'd3) !== 4'b0111) errors++;
if (to_johnson(3'd7) !== 4'b1000) errors++;
if (to_onehot(3'd5) !== 8'b00100000) errors++;
if (errors != 0) $fatal(1, "FAIL: encoding property errors=%0d", errors);
$display("PASS: eight-state Gray/Johnson rings change one bit per step; three-state Gray wrap flips two; one-hot and binary checks pass");
$finish;
end
endmodule