The Finite State Machine (FSM) are one of the basic building blocks every FPGA designer should know and deploy often. However, over the years when implementing state machines in many different solution spaces (defense, aerospace, automotive etc) I have learnt a few tips and recommendations which I thought I would share. Following these have provided me with a better quality of results and helped me deliver working systems to my customers faster.
Develop the state machine as a single clocked process.
Perhaps the most controversial point is always using a single process state machine. Of course, this is different to the state machine architecture we are taught when we first learn about them. Many, if not most universities teach state machine implementation using two processes, one combinatorial and another sequential.
With a two-process state machine implementation the main functionality will be contained in a combinatorial process. If we fail to fully define all the combinatorial conditions within this process we will implement latches during synthesis. The combinatorial process may also generate glitches on its outputs as the state and inputs change.
Debugging can also be harder as the sensitivity list needs to be complete, including all of the signals used in the combinatoral process. Failure to include a signal in the sensitivity list will result in different behaviour between RTL simulation and the implementation which can take a little time to find. This is alleviated somewhat if we are using VHDL 2008, where we can use the “all” statement in the process declaration. Of course to take advantage of this your tool chain needs to support VHDL 2008.
By contrast a one process state machine enables much easier use of conditional definition and removes the ability for latches to be created. While preventing glitches as all outputs signals are registered.
Personally I also find them a little easier to debug as all the functionality is within one process.
Decouple functionality, only allow single bit input and outputs to your state machine.
We are often tempted to take into our state machine large buses and decode these within the main body. This is especially true when counters are used for the timing of events within the state machine. For example, as shown in the code snippet below
when wait_cnt =>
if cnt >= std_logic_vector(to_unsigned(128,16)) then
current_state <= read_fifo;
cnt <= (others =>’0’);
cnt <= cnt + 1;
Implementing the state machine in this manner includes additional logic within the state machine for both the comparator and the counter. This will impact the performance of the state machine within the implemented FPGA as it requires more resources and consequently more routing.
A better method is to use an external process for the counter or other external functions which pass in a single control signal. This leaves the bulk of the logic decoupled from the state machine. Taking the counter example, we can use an external counter process to generate a single pulse once the terminal count is achieved as shown below.
when wait_cnt =>
if cnt_terminal = ‘1’ then
current_state <= read_fifo;
cnt_reset <= ‘1’;
In the above code the single bit input provided from the counter process to indicate the terminal count has been reached. While the state machine asserts a single bit output to reset the counter when this occurs. This uses less logic within the state machine, enabling better performance.
As shown in this example only a single bit should also only leave the state machine as well.
Address any unmapped states
Many times, when we develop a state machine, the implementation does not use a power of two states leaving several unmapped states. If the state machine enters an unmapped state the state machine will stall and become unresponsive as there is no recovery mechanism. Depending upon the application this can be merely inconvenient or lead to catastrophic consequences.
Transitions to unmapped states can occur for a variety of reasons, from a single event effect to an electrically noisy environment or even vibration effecting device bond wires (before you ask yes, I have seen this). It is therefore good practice to ensure there is a path back from an unmapped state back into the main flow of the design. One of the simplest mechanisms to do this is to cycle through the unused states following the reset or power up before the state machine enters its idle state. This prevents the unmapped states from being optimised out during synthesis, while providing a simple recovery mechanism.
Consider the unexpected, what happens if control signals arrive late or early
When considering the control flow of a state machine it is important to consider what happens if an expected signal does not arrive when expected. While in an ideal world we would have defined interface definitions for each module in our design sadly this is not always the case. As such we need to make sure the state machine does not hang in a state waiting for a signal which has already occurred and as such has been missed.
Considering this ensures the state machine can handle the worse case conditions in operation.
This is incredibly important if your state machine contains structures like below, where a late signal can easily lead to the system becoming unresponsive.
when <state> =>
if input_one = ‘1’ then
if input_two = ‘1’ then
current_state <= wait_fifo;
elsif input_three = ‘1’ then
current_state <= idle;
Should input one not be asserted when inputs two or three occur then the state machine will hang and become un-responsive. If such a structure is unavoidable and I am sure you can avoid it with a little thought, a timer or other recovery function should be added to prevent the state machine locking up, allowing a graceful recovery.
- For more on high reliability state machines read USING FPGA’S IN MISSION CRITICAL SYSTEMS
For more on the basics of state machines read How to implement a state machine in your FPGA
MicroZed Chronicles on GitHub
Want a Book