Question

A lot of the FSMs I see in VHDL work by setting a variable "next_state" in the FSM logic and then assign this seperately to the state variable outside of the process.

If there anything wrong with simply writing "state <= state_five;" to set the next state instead? I'm presuming there is a reason that so many people use a separate next state variable instead of directly assigning to the state as I see it all the time, but as far as I can tell there is no difference except that it makes the code longer and more complicated looking.

Have I missed something? Or is it just a question of style? And if so why is that style better, it seems unnecessary to me.

Was it helpful?

Solution

"Is there anything wrong with simply writing state <= state_five;?"

Nothing whatsoever - PROVIDED the state assignment is done in a clocked process.

This leads to the neat simple reliable "single process state machine" style, instead of the unreliable (because it's easy to get the sensitivity lists wrong) two-process style that is taught in WAY too many textbooks and online tutorials.

Search for "single process state machine" and you should be able to find good example material and further discussion.

Historical note : there may have been some synthesis tools in the previous century that had problems with the single-process style; but that's no reason to avoid it now.

OTHER TIPS

The reason why some people always write two-process state machines (that is, one synchronous process and one concurrent process) is probably mostly because they learned to do it that way in school, like others have said.

However, in some cases this coding style can actually be better than having a single synchronous process. In short it allows you to mix synchronous and concurrent assignments in the same context. Consider the following two pieces of code, both accomplishing the same thing:

Two-process state machine:

process (clk)
begin
  if rising_edge(clk) then
    state <= state_next;
  end if;
end process;  

process (all)
begin 
  state_next <= state;
  case state is 
    when s_idle => 
      if req_i = '1' then 
        fifo_read <= '1'; -- Concurrent assignment
        state_next <= s_check_data; -- "Synchronous" assignment 
      end if; 
    when s_check_data =>
      if fifo_out = x"1234" then
        (...)
      end if;
    (...) 
  end case; 
end process;

One-process state machine:

process (clk)
begin 
  if rising_edge(clk) then
    case state is 
      when s_idle => 
        if req_i = '1' then 
          fifo_read <= '1';
          state <= s_wait_for_data;
        end if;
      when s_wait_for_data =>
        state <= s_check_data;
      when s_check_data =>
        -- Data word from FIFO now available.
        if fifo_out = x"1234" then
          (...)
        end if;
      (...) 
    end case;
  end if;
end process;

Notice the extra state in the second example. Because there is no way to make concurrent assignments in synchronous processes in VHDL (I wish there was!), a register will be added to the fifo_read signal, delaying it by one cycle. While this example is simple enough, always sticking to one-process state machines can sometimes cause the code to become quite confusing and hard to follow for this reason. It can also cause your state machine to spend more resources in hardware and even make the code longer. Neither style is always the right choice, but I usually prefer the one-process variant.

Or even use a variable:

state := state_five

Using a variable to store the state means that it remains completely local to the process and doesn't pollute the namespace of the whole architecture.

It also means that if you are in the habit of using printf (sorry report) to track the progress of state machines when debugging (which is sometimes preferable to a waveform viewer), you can report the intended next state at the end of the state machine process, which can be handy.

Added: As noted in the comments, the variable assignment occurs "instantly" (to be clear - this doesn't cause the case statement to immediately switch to the next state though!)

This effect can be used to advantage (occasionally) if you need an output a cycle early - by assigning to said signal based on the next state at the end of the process. If I end up needing to do that I tend to have an explicit next_state variable which I use for everything except the case statement and the state := next_state; (which is right at the end of the clocked process). It demonstrates to the code reviewers that you intended to do it this way!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top