Home
VHDL info
VHDL links
VHDL models

One Hot State Machine Design & VHDL Coding

This section gives an overview of how to describe one-hot state machines with VHDL, it assumes some prior knowledge of state machine design. Users should be familiar with the State Machine Design & VHDL Coding section before going ahead to this section.


What is a one-hot encoded state machine?

A one-hot encoded state machine is a state machine in which there is a bit in the state vector for every state in the state machine. (eg. a state machine with 17 states will have a 17-bit wide state vector). It is sometimes known as bit-per-state encoding.
The one-hot encoding technique was developed as a consequence of the typical FPGA architecture - rich in registers but with limited fan-in to each internal logic macrocell (a CLB in Xilinx-speak). Only one of the state vector registers is active ('hot') at any one time.

Example state machine - The state machine is clocked by a signal 'clk' which is not shown on the flow diagram.


Why use them?

To detect when the state machine is in a particular state only requires that a single bit is tested instead of the whole state vector as would be the case for a binary-coded state machine. Changing states is simply a case of changing the currently 'hot' register to 'cold' and setting the next state register to 'hot'. (Note that 2 bits in the state vector change for every state transition - so caution must be used if the state vector is decoded asynchronously to generate other outputs.) The logic required to detect the current state to generate outputs and next state logic is minimal, requiring less combinatorial logic - so allowing for higher clock frequencies. This is the main reason for using the one-hot structure. Our example state machine has 6 states, so 6 registers will be required - the disadvantage of one-hot encoding is the larger quantity of registers that are required.


Where should they be used?

One-hot state machines require more flip-flops than a binary-coded state machine, so use them in devices that are register-rich but have low fan-in to each logic macrocell (e.g. Xilinx FPGAs). They are generally not useful in CPLDs such as the Xilinx 9500 or CoolRunner families since these have a wide fan-in to each logic macrocell.


Writing the VHDL code

There are 2 coding styles - "hard encoding" and "soft coding".

Soft encoding

Soft encoding a state machine allows the state encoding to be quickly and easily changed. The basic technique is to declare an enumeration type which has the state names as the set of possible values, then declare the state vector(s) as signals of that type. The default encoding of the enumeration type is modified by the attribute "enum_encoding". The state assignments are made by positional association between the TYPE declaration and the ATTRIBUTE declaration. In our example listing below, idle takes the value "000001", state1 takes the value "000010" and so on. The rest of the state machine is coded as normal using a CASE construct. The following code snippet (Listing 1) shows our example state machine coded as a one-hot state machine using the two-process style:

IMPORTANT!
Not all synthesis tools support the enum_encoding attribute and some may use a different name for the attribute. Check your synthesis tool documentation.

ARCHITECTURE arc_softenc OF softenc IS

  -- declare the enumeration type
  TYPE states IS (idle,state1,state2,state3,state4,state5);
  
  -- assign the states
  ATTRIBUTE enum_encoding : string;
  ATTRIBUTE enum_encoding OF states: TYPE IS "000001 000010 000100
                                              001000 010000 100000";
  
  -- the state vectors
  SIGNAL present_state : states;
  SIGNAL next_state    : states;

BEGIN


  -- the combinatorial process
  comb_proc : PROCESS (present_state,start,branch,hold)
  BEGIN

    -- state transitions
    CASE present_state IS

      WHEN idle =>                      -- when in idle ..
        IF (start = '0') THEN           -- ..wait for start=0
          next_state <= state1;         -- ..then go to state1
        ELSE
          next_state <= idle;           -- ..else stay in idle
        END IF ;

      WHEN state1 =>                    -- in state 1..
        IF (branch = '1') THEN          -- ..if branch=1
          next_state <= state4;         -- ..then go to state4
        ELSE
          next_state <= state2;         -- ..else pass to state2
        END IF ;

      WHEN state2 =>
        next_state <= state3;           -- go to state3

      WHEN state3 =>
        IF (hold = '0') THEN            -- ..if hold=0
          next_state <= state4;         -- ..then go to state4
        ELSE
          next_state <= state3;         -- ..else stay in state3
        END IF ;

      WHEN state4 =>
        next_state <= state5;           -- go to state5

      WHEN state5 =>
        next_state <= idle;             -- go to idle

    END CASE;

  END PROCESS comb_proc;


  -- the synchronous process
  sync_proc : PROCESS (clk,reset)
  BEGIN
    IF (reset = '0') THEN                -- async active low reset
      present_state <= idle;             -- to idle state on reset
    ELSIF (clk'EVENT AND clk = '0') THEN -- sync to clk falling edge
      present_state <= next_state;       -- change state
    END IF ;
  END PROCESS sync_proc;

END ARCHITECTURE arc_softenc;

Listing 1 : soft encoded one-hot state machine

Note the lack of a WHEN OTHERS clause - this will be discussed further in Undefined States.

A further extension of this idea is to replace the state assignments string with a text string that directs the synthesis tool to produces the required state encoding. For example the Metamor synthesis tool can produce a one-hot state machine by changing the expression in the attribute specification line to "one hot". The attribute specification line:

ATTRIBUTE enum_encoding OF states: TYPE IS "000001 000010 000100
                                            001000 010000 100000";

then becomes:

ATTRIBUTE enum_encoding OF states: TYPE IS "one hot";
Hard encoding

Hard encoding ensures that a one-hot state machine is always generated, regardless of the synthesis tool that is being used. This makes it less portable to other targets which might not be register-rich.

The CASE construct can't be used as it will use the entire state vector to make the state-to-state transition equations, and we need to use only the inputs and the currently 'hot' state. Each state is considered in turn, using an IF...THEN ...END IF; structure which describes when the state becomes 'hot' or 'cold'. The VHDL code for the example state machine is:

ARCHITECTURE arc_hardenc OF hardenc IS

-- state vector, 6 bits for 6 states
SIGNAL state_vector : std_logic_vector(5 DOWNTO 0);
  
-- define hot & cold, must be defined before initial constant
CONSTANT hot        : std_logic := '1';
CONSTANT cold       : std_logic := '0';
  
-- these constants act as indices to the state vector signal
-- & must be defined before the initial state constant
CONSTANT idle       : integer   := 0;
CONSTANT state1     : integer   := 1;
CONSTANT state2     : integer   := 2;
CONSTANT state3     : integer   := 3;
CONSTANT state4     : integer   := 4;
CONSTANT state5     : integer   := 5;
  
-- initial state (idle is hot, all other states are cold)
CONSTANT initial:std_logic_vector(5 DOWNTO 0):=(idle=>hot,OTHERS=>cold);

BEGIN

 state_machine : PROCESS (clk,reset)

 BEGIN

 IF (reset='1') THEN                        -- async active hi reset
  state_vector <= initial;                  -- to idle state on reset

 ELSIF (clk'EVENT AND clk='1') THEN         -- sync to clk rising edge

  -- idle
  IF ((state_vector(idle) = hot AND start = '1') OR
       state_vector(state5) = hot)
  THEN
   state_vector(idle) <= hot;
  ELSE
   state_vector(idle) <= cold;
  END IF;

  -- state 1
  IF (state_vector(idle) = hot AND start = '0') THEN
   state_vector(state1) <= hot;
  ELSE
   state_vector(state1) <= cold;
  END IF;

  -- state 2
  IF (state_vector(state1) = hot AND branch = '0') THEN
   state_vector(state2) <= hot;
  ELSE
   state_vector(state2) <= cold;
  END IF;

  -- state 3
  IF (state_vector(state2) = hot OR
   (state_vector(state3) = hot AND hold = '1'))
  THEN
   state_vector(state3) <= hot;
  ELSE
   state_vector(state3) <= cold;
  END IF;

  -- state 4
  IF ((state_vector(state3) = hot AND hold = '0') OR
   (state_vector(state1) = hot AND branch = '1'))
  THEN
   state_vector(state4) <= hot;
  ELSE
   state_vector(state4) <= cold;
  END IF;

  -- state 5
  IF (state_vector(state4) = hot) THEN
   state_vector(state5) <= hot;
  ELSE
   state_vector(state5) <= cold;
  END IF;

 END IF;

END PROCESS state_machine;

END ARCHITECTURE arc_hardenc;

Listing 2 : hard encoded one-hot state machine


Generating outputs from the state bits

Note that 2 bits of the state vector change for each state transition: the present state goes cold, the next state goes hot, so be careful when asynchronously decoding the state vector to produce auxiliary outputs. It may be better to have synchronous outputs.

Because there is one flip-flop per state, some outputs may require a large number of product terms (fan-in) which defeats the purpose of one-hot encoding. Consider for example an output that is active in the first 8 states of a state machine with 16 states. With a one-hot coded state machine, this will require 8 product terms, but with a binary coded state machine it may require as little as 1 product term. However, an output which is valid in only one state may benefit from one-hot encoding as the output is just the state bit itself.


Undefined states

One concern that many designers have with one-hot state machines is the large number of undefined states. A binary-coded version of our example state machine requires a 3 bit state vector, and so the number of undefined states is:

23 - 6 = 2 undefined states.

The designer can take care of these undefined states using the WHEN OTHERS clause. See the State Machine Design & VHDL Coding section for more information.

A one-hot coded version of the example state machine however has many more undefined states because the state vector is 6 bits wide:

26 - 6 = 58 undefined states.

IMPORTANT!
A one-hot state machine is in an illegal state when more than one of the bits in the state vector is 'hot'.

Using the WHEN OTHERS clause to take care of undefined states may not feasible because of the large amount of wide fan-in logic that will be generated.

WHEN OTHERS =>
        next_state <= idle;             -- illegal state, go to idle

The designer must decide what action should be taken when the state machine finds itself in an illegal / undefined state - should it go to a particular state? (perhaps the initial state), should it be reset asynchronously or synchronously? The designer can also decide to take no action on reaching an undefined state, allowing maximum logic minimisation, but risking a locked-up state machine. The consequences of these decisions will have far reaching effects on the amount of logic produced.


Ensuring maximum speed

One-hot coding is used to increase the maximum clock frequency, so don't let the FPGA routing and layout cause any unnecessary loss due to excessive routing delays.

  • use a global clock buffer for the clock net to ensure low skew and maximum speed.
  • place the next state logic in the same CLB as the flip-flop that it feeds ensure low interconnection delays.
  • place the state vector flip-flops in adjacent CLBs with the floorplan tool or by using RLOC constraints to ensure low interconnection delays.

Automatic state encoding with FPGA Express

FPGA Express users have a further alternative to the hard and soft encoding styles described above. FPGA Express allows the designer to specify either one-hot or binary encoding as an synthesis option. The ENUM_ENCODING attribute must be left out to allow FPGA Express to choose the state encoding, just declare the enumeration type and the state vector(s):

ARCHITECTURE arc_fpgaexpenc OF fpgaexpenc IS

  -- declare the enumeration type
  TYPE states IS (idle,state1,state2,state3,state4,state5);
  
  -- DON'T USE THESE TWO LINES, ALLOW FPGA EXPRESS TO CHOOSE ENCODING!
  --ATTRIBUTE enum_encoding : string;
  --ATTRIBUTE enum_encoding OF states: TYPE IS "000001 000010 000100
  --                                            001000 010000 100000";
  
  -- the state vectors
  SIGNAL present_state : states;
  SIGNAL next_state    : states;

BEGIN
   .
   .            

Then in the Synopsys FPGA Express GUI (or the Xilinx Foundation GUI), choose Synthesis -> Options, and click on the Project Tab of the Options dialog box. Select the encoding style as required.
In the Xilinx Foundation GUI, just choose Synthesis -> Options to see the Options dialog box.


Maintained by Mark Harvey. Please email me with any comments.