The Beginner’s Guide to State Machines - VHDL

The creation of state machines is a mixture of art and science. A well-crafted state machine will possess a sense of elegance; it will be appealing, both functionally and visually.
Here, a very simple example is presented as an illustration of state machine design. The state diagram for the Flintstones State Machine is shown in Figure1.

State_Machine_VHDL Figure1: The Flintstone State Machine

The Flintstones State Machine operates as follows:

1. The State Machine has two states, State Bed and State Rock.
2. There is one output, Fred, which takes the value 0 in State Bed and 1 in State Rock.
3. A reset, caused by a low level on Reset_n, puts the State Machine into State Bed.
4. The State Machine waits in State Bed while Barney is low, and enters State Rock when Barney goes high.
5. The State Machine then waits in State Rock while Wilma is low, and returns to State Bed when Wilma goes high.

An example implementation of the Flintstones State Machine is shown below:


 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Flintstones_SM_Proc: process(Sync_Reset_n, Clock_In)
-- Enumerate state types:
type Flintstones_Statetype is (
Bed, Rock
);
-- define the state variable:
variable Flint_State: Flintstones_Statetype;
-- Here’s the state machine:
begin
-- Define the asynchronously set reset states...
if (Sync_Reset_n = 0) then
Fred <= 0 after 1 ns;
Flint_State := Bed
-- Default conditions for each output, in this case identical to the
-- reset state:
elsif (Clock_Inevent and Clock_In = 1) then
Fred <= 0 after 1 ns;

-- Here are the state transitions:
case Flint_State is
when Bed =>
-- Transition from Bed to Rock:
if (Barney = 1) then
Fred <= 1 after 1 ns;
Flint_State := Rock;
-- Holding term in Bed:
else
Flint_State := Bed;
end if;
when Rock =>
-- Transition from Rock to Bed:
if (Wilma = 1) then
Fred <= 0 after 1 ns;
Flint_State := Bed;
-- Holding term in Rock:
else
Fred <= 1 after 1 ns;
Flint_State := Rock;
end if;
-- Default term for dead states:
when others =>
Flint_State := Bed;
end case;
end if;
end process Flintstones_SM_Proc;


For the most part, the Flintstones State Machine’s operation should be clear. A few points are worth noting, however:

1. The reset signal (Sync_Reset_n) is synchronized with Clock_In before being sent to the State Machine.
2. Barney and Wilma must also be synchronous to Clock_In; at the very least, there must be an assurance that the State Machine’s state and output register’s setup and hold times are not violated.
3. This design assigns a default value to each output and to the state variable before entering the case statement. This ensures that only those signals that are not taking default (usually inactive) values need be listed in the case statement. This is optional; it is entirely reasonable to list every signal under each transition term, including inactive signals.
4. Note that the output signal Fred comes directly from a D-type flip-flop: it is not a decode of the state variable. This ensures Fred’s cleanliness (so to speak).
5. The “when others” in the case statement handles the possibility that the State Machine might end up in a dead state.