Written by Ray Salemi
State machines are a foundation of digital design. Eventually we all reach the point where we need to control our digital algorithm, and we almost always turn to a state machine to do the job.
Because of this, many EDA tools recognize when the RTL designer is creating a state machine and use this information to improve their simulation and synthesis results. Once a tool recognizes a state machine in your design, it can deliver a list of features that are not available for generic logic. For example, synthesis tools can change the state machine encoding to improve synthesis results, while simulators can render the state machine and provide debugging and coverage information. Tools such as Mentor’s Precision High-Reliability synthesis engine can even add error correcting information to allow the state machine to power through single-event upsets and jump to the next correct state.
However, none of these features will work if the software can’t recognize the state machine. While EDA tool manufactures support a wide variety of state machine coding styles, it’s still possible to write code that can’t be recognized as a state machine, either by software tools or by humans.
This is the first of a series of articles that will talk about state machine today. We’re going to start with the most basic topic, naming our states and identifying the state variable.
Every state machine has a register that holds the state. This register feeds the logic that creates the state machine output. The register also combines with input signals to figure out the next state. In this article, we’ll examine techniques for coding a state machine to make it easy to debug and reuse. As an example, we’ll use a simple traffic light state machine:
The first thing you’ll notice about this state machine is that the states have descriptive names. The machine sits in the cars_go state until someone presses the walk_request button. Then it slows the cars, stops them, and lets the pedestrians walk. It then warns the people that the light is about to go back to green, and then goes back to green. This is a simple illustrative state machine. In a real-world state machine we’d need to use a counter to keep the states in each state long enough to be useful.
We want to capture the readability of the state names in our code. This will make it easier to debug, and we’ll be able to put the state variables into the waveform viewers of some simulators to see the current state on a wave form. We can create this name-to-state mapping in VHDL and in Verilog (SystemVerilog’s approach is similar to VHDLs).
In VHDL we create a state type that lists the names of the states. Then we declare our state variables to be of the state type. The code looks like this:
Lines 45-50 specify a VHDL type called “state_type” and create values that can be placed in that type. This serves two purposes: it makes the state machine easy to read, and it lets the compiler catch cases where you mistyped the value. This is more difficult to do if you were using raw numbers for your state types.
Notice that this code doesn’t specify the coding for the state machine; it leaves the coding up to the synthesis tool, or up to the needs of the designer. A designer could tell the synthesis tool to code this state machine as a one-hot if it was necessary to catch single event upsets or allow for error-correcting codes. Or the designer could have the synthesis tool use a binary encoding for a more compact solution.
We can do a similar thing with Verilog:
This code uses Verilog parameters to attach names to numbers, and then later code can use the names to put the numbers into the state diagram. The numbers in this example are suggested encodings for the states. Most synthesis tools can override these state encodings to create whichever encoding the designer wants to see.
For completeness, here is the same thing in SystemVerilog. Notice that SystemVerilog has adopted VHDL’s numberless approach:
All of these ways of writing the state machine make it much easier to write the next-state logic and the output logic. Here is the next state logic for this state machine written in Verilog and VHDL:
This is very easy to read—much easier than if we hand named the states “s0,” and “s1” as I have seen in some code. Now, when you come back to this state machine in six months, you’ll remember what you were doing when you designed it.
Today we looked at ways to create synthesis-friendly state machines that are easy to understand and reuse. In the next article, we will look at coding Mealy and Moore state machines and our options for dividing next-state logic and output logic.