There is a problem with assigning to state as a signal directly:
- you see a change only in the next clock cycle
Exactly as it should be, the clock causes state transitions, flip
flops to update, etc.
but as signal transition
depends on that value you can't debug you state machine easily
You only have difficulty if you compute other signals based on
'next_state', rather than 'state'. Personally I haven't had any
difficulty debugging without the 'next_state' signal.
Typically other signals/variable that are a function of the state
machine's state I compute based on the current state (i.e. the signal
'state' in this example) not on what the next state is going to be.
Typically this leads to higher clock cycle performance of the design
since the combinatorial logic that is needed to compute 'next_state'
does not roll into the logic needed to compute the output (or other
signal).
Readability would not necessarily be a function of whether there was
an explicit 'next_state' signal/variable or not. Either form can be
just as readable. For those cases, where duplication of code would
have to take place, I would have a variable 'next_state' for assigning
to those signals that would benefit from it. That's why I said "Most
times the only time..." 'most times' does not mean 'all times', it
means 'usually the case'.
Where do you modify state?
I modify state in the state machine. There is no need to have an
intermediate signal/variable to compute the 'next_state', just so that
it can be synchronously assigned to a signal called 'state'. There is
one clocked process of the following general form:
process(clk)
begin
if rising_edge(clk) then
if (reset = '1') then
current_state <= idle;
else
case current_state is
when idle => current_state <= Michigan;
when Michigan => current_state <= California;
when California => current_state <= Hawaii;
end case;
end if;
end if;
end process;
Easy by looking for next_state.
Just as easy looking for 'current_state'.
- Of course in some situations a counter can be a typing lazy
alternative BUT don't do that, you will not understand what you were
thinking a month after, and for a code review you have to talk your
mouth fuzzy that other designers will understand your work, more worse
you will have to document where plain code could be documentation
enough...
Actually you'll likely have more trouble explaining the state machine
then the counter. For example, let's say this design is for some form
of memory controller. Let's say that after issuing a read command to
the memory device you need to wait 40 ns for the data to be valid,
let's also assume that the clock period is 10 ns. One might be
tempted to make a state machine that has the proper number of states
so that 4 clock cycles after the read command is issued that data gets
sampled. Your design will be very fragile (in my opinion) because of
the implicit constants (i.e. the number of states) that are really a
function of the following parameters:
- Clock period
- Memory access time
Using a counter approach, one would have constants (actually I'd use
generic inputs on the entity) for both of these and they would be
defined in units of time and I'd define the upper end of the counter
to be the ceil() of the ratio of memory access time divided by clock
period. So it would be painfully clear where the design error is that
needs fixing when I find that the board was built with 60ns access
time parts instead of 40ns, the 'fix' would be to simply change the
generic parameter input to the entiy from 40ns to 60ns and rebuild.
With the state machine approach you'd have to modify a bunch more than
that and have a much higher risk of getting it wrong the first time.
Linking parameters that you have no control over in your design (in
this case the memory access time) so that they properly parameterize
the design will naturally lead to using counters. Hard coding in a
calculated number of states that depends on this uncontrolled
parameter (or pulse time requirement) in the form of states in a state
machine is a mistake. Although both designs will work, one will be
much more fragile and less likely to be able to be modified correctly
in the future...but that's just my 2 cents.
- The way I showed worked perfectly for designing complex state
machines in some very large ASICS, including debug and verification.
And my method has worked just as perfectly.
=> Lazy is not always best IMO.
You're the one who brought up lazy, not me.
KJ