State machine design techniques for Verilog and VHDL
Page 4 © Steve Golson 1994
For both the Verilog and VHDL one-hot machines,
the behavioral simulation will exactly agree with
the post-synthesis gate-level simulation.
4.3 Almost one-hot machine
The only difference from the pure one-hot machine
is that you may look at more than one state bit to
determine the current state:
case (1'b1)
// synopsys parallel_case full_case
state[START] && state[RW]:
if (in == 8'h3c)
next_state[SA] = 1'b1 ;
else
next_state[START] = 1'b1 ;
5.0 Outputs
Outputs are coded in a manner similar to the next
state value. A case statement (or the equivalent) is
used, and the output is assigned the appropriate
value depending on the particular state transition or
state value.
If the output is a don’t care for some conditions
then it should be driven unknown (x). Design
Compiler will use this don’t care information when
optimizing the logic.
Assigning the output to a default value prior to the
case statement will ensure that the output is
specified for all possible state and input
combinations. This will avoid unexpected latch
inference on the output. Also the code is simplified
by specifying a default value which may be
overridden only when necessary. The default value
may be 1, 0 or x.
It is best to have a default of 0 and occasionally set
it to 1 rather than the reverse (even if this requires
an external inverter). Consider an output that is 1 in
a single state, and 0 otherwise. Design Compiler
will make the output equal to the one-hot state bit
for that state. Now consider an output that is 0 in
only one state, and 1 otherwise. The output will be
driven by an OR of all the other state bits! Using
set_flatten -phase true will not help.
For a one-hot machine you can use the state bits
directly to create outputs which are active in those
states:
myout = state[IDLE] || state[FOO] ;
Sometimes it is easier to specify an output value as
a function of the next state rather than of the current
state.
5.1 Registered outputs
Outputs can be registered. A simple D flop may be
used, but a JK functionality can be implemented as
well. The output of the flop is fed back as an input
to the machine. The default next output value is the
current flop output:
next_myout = myout ; /* default */
With no further assignment the value will hold, or
we can set, clear, and toggle:
next_myout = 1’b1 ; /* set */
next_myout = 1’b0 ; /* clear */
next_myout = !myout ; /* toggle */
This JK type output is especially useful for pseudo-
state flag bits (see Section 3.3).
6.0 Inputs
6.1 Asynchronous inputs
Sometimes a state machine will have an input
which may change asynchronously with respect to
the clock. Such an input must be synchronized, and
there must be one and only one synchronizer flop.
The easiest way to accomplish this is to have the
sync flop external to the state machine module, and
place a large
4
set_input_delay on that input to
allow time for the sync flop to settle.
If the sync flop is included in the same module as
the FSM then you can place an input delay on the
internal flop output pin. Unfortunately this requires
the flop to be mapped prior to compiling the rest of
the machine.
Rather than hand-instantiating the flop we can use
register inference as usual and simply map that one
flop before compiling. The following script will
map the flop:
4. “Large” means a large fraction of your clock period.
Extra credit: ask your ASIC vendor about the metastabil-
ity characteristics of their flops. Try not to laugh.