Yann pointed out in a comment that a Johnson counter may be a good way to save some gates in the logic implementation of the dice. Currently a simple binary counter is used.
To be honest, it seems that I mistakenly thought of Johnson counters being simple ring counter with one flipflop per state, when in fact they are a nice concept to reduce the number of flipflops needed for a counter by two compary to a ring counter. Even the Wikipedia entry throws Johnson counter and ring counters into one category, which is a bit confusing.
A fairly nice property of a Johnson counter implementation is that it is possible to implement a counter that comes with a natural sequence length of 6, exactly what we need for the dice. So, in contrast to the binary counter, no additional logic is needed to limit the sequence length.
- The sequence is not in order, since it does not follow binary encoding
- The sequence contains "000", which is currently not decoded as a valid face figure on the die.
- There are illegal states of the counter, so it has to be initialized
1) is not really an issue, since we want to randmize the die anyways. So we just accept that the sequence is different. 2) can be solved by inverting the middle bit. See below. 3) requires is to add a reset input. But the NE555 comes with a reset input anyways, so that is almost for free.
Sequence johnson counter middle bit inverted dice pattern Seq1 000 010 2 Seq2 001 011 3 Seq3 011 001 1 Seq4 111 101 5 Seq5 110 100 4 Seq6 100 110 6
Here comes the VHDL implementation of the modified dice:
architecture main of dice555johnson is signal cnt: unsigned(2 downto 0); begin process (clk,n_clk,nreset) begin if nreset = '0' then cnt <= "000"; elsif rising_edge(clk) then cnt <= cnt(1 downto 0) & NOT cnt(2); end if; end process; -- 1 2 -- 3 0 3 -- 2 1 -- Encoding: -- 011 0 -- 000 1 -- 001 0,1 -- 110 1,2 -- 111 0,1,2 -- 100 1,2,3 -- drive inverted LEDs dice(0) <= NOT cnt(0); dice(1) <= '1' when (cnt = "011") else '0'; dice(2) <= NOT cnt(2); dice(3) <= '0' when (cnt = "100") else '1'; end;
And here are the design stats after synthesis:
Number of cells: 9 ne_DFF_clear 3 ne_NAND3 2 ne_NOT 4 Chip area for module '\main': 23.000000
.SUBCKT main clk n_clk nrst dice.0 dice.1 dice.2 dice.3 X0 cnt.1 1 ne_NOT X1 cnt.2 dice.2 ne_NOT X2 cnt.0 dice.0 ne_NOT X3 1 cnt.2 dice.0 dice.3 ne_NAND3 X4 cnt.1 dice.2 cnt.0 2 ne_NAND3 X5 2 dice.1 ne_NOT X6 clk nrst dice.2 cnt.0 ne_DFF_clear X7 clk nrst cnt.0 cnt.1 ne_DFF_clear X8 clk nrst cnt.1 cnt.2 ne_DFF_clear .ENDS main
Compared to the stats of the original implementation with binary counter:
Number of cells: 18 ne_DFF 3 ne_NAND2 7 ne_NAND3 2 ne_NOT 6 Chip area for module '\main': 39.000000
Quite impressive! Thanks for the tip, Yann. Will I build this? Probably not, I trust that it would work and I think owning one NE555 based electronic dice is already enough :)
Edit: Digital simulation output is shown below. Please note, that the dice output is inverted since the LEDs are active low. I found a tiny bug, which is fixed above.