State management in VHDL FSMs - vhdl

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.

"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.

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!

Related

In VHDL, Can I use signal'event if signal is not a clock?

I am trying to clean up my VHDL code. I have a signal that is NOT a clk.
Can I write an event change monitor like the following and how do I get it to compile so it can be synthesized? (see code) I have tried several permutations but I cannot get it to compile. Will signal'event compile if signal is not a CLK and if so, how is it done? I see on the web and other literature that it can be done but all examples I see show CLK'event.
signal cntr: unsigned(15 downto 0) := (others => '0');
...
process(CLK):
begin
IF rising_edge(CLK) THEN
if (cntr'event) then
do something;
end if;
or...
if(cntr(0)'event) then
do something;
end if;
END IF;
end process;
I get the following and others
: can't synthesize condition that contains an isolated 'EVENT predefined attribute
rising_edge(CLK) is already an event, making your design synchronous, which is good. As said in comments, only clock signals should use that.
Looking at another even at that time doesn't make sense in synchronous designs, as the 2 signals won't change exactly at the same time, creating a race condition. Or actually a clock within a clock, and the synthesis error...
It may work in simulation, but don't rely on that fact.
The normal way to program in HDL languages is to save the previous value of the signal, on the same clock (for example cntr_d <= cntr) and to compare with that previous value. That allows to find if the signal went up (previously at 0, currently at 1), went down, changed (is different)...
And that method is perfectly fine for synthesis!

Is there any difference in these codes?

I am trying to make a new design. I design it with two processes which are synchronous and asynchronous. I generally give reset in the asynchronous process which is shown first code snippet. However, someone just told me that is a mistake. In her knowledge, I should give the reset statement in the synchronous process. I also checked the schematic for the first one and saw it is connected correctly to flip-flop's resets.
sync_proc : process(clk_i)
begin
if(rising_edge(clk_i)) then
do smt..
end if;
end process sync_proc;
async_proc : process(some signals)
begin
if(reset_i = '1') then
reset smt..
else
do smt..
end if;
end process sync_proc;
Above is my code and below is what she suggested.
sync_proc : process(clk_i)
begin
if(reset_i = '1') then
reset smt..
else(rising_edge(clk_i)) then
do smt..
end if;
end process sync_proc;
I am wondering that, is there any differences between these states? If so, what are they?
Think of a VHDL process as a little bit of software that models a little bit of hardware. With your approach, you have two little bits of hardware driving the same signal, ie a short circuit. With her (correct) approach, you have one little bit of hardware (a flip-flop) driving one signal.

Using clock and enable

I was given a code for a D Flip-Flop with enable.
process(clk, en)
begin
if rising_edge(clk) then
if en = ‘1’ then
Q <= D;
end if;
end if;
end process;
I was told that I should not use if rising_edge(clk) and en = ‘1’ then .... Why?
Why isn't the if for the en = '1' before the if for clock since the clock is changing more often?
And is it necessary to specify that en in the process parenthesis process(clk, en)?
Some people believe that the VHDL compilers and synthesizers are not able to figure out that it's the same thing as you've shown here. I've never directly compared the output, but I'd be pretty sad if it mattered.
Changing more often doesn't really matter in hardware. In theory, it shouldn't matter. In practice, the compiler will probably incorrectly warn about your sensitivity list if you changed the order of the conditionals.
It is not.
Here is the answer to all 3 of your questions:
If you're coding sequential logic, it is wise to stick to a template. Here is one such template for sequential logic with no asynchronous reset, which all synthesis tools should understand:
process(clock) -- nothing else should go in the sensitivity list
begin
-- never put anything here
if rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
So en should not be in the senstivity list and it should not be tested in the same if statement as the clock is tested.
If you think about it, there is another good reason why en should not be in the sensitivity list: the output of a flip-flop with no asyncrhonous reset only changes when the clock changes; it does not change when the D input changes.

What is the difference between "wait until rising_edge(clk)" vs "if rising_edge(clk)"?

I came across two styles of process statements in VHDL.
process(clk)
begin
if rising_edge(clk)
...do something...
The other one is
process
begin
wait until rising_edge(clk)
...do something...
What are the pros and cons of each method?
Assuming the ... part of the second example does not have any wait statement, the two forms are semantically equivalent.
They will behave identically in simulation.
However, the first form is the recommended style for synthesis and will be deemed more readable by many.
Both forms are equivalent for synthesis in Vivado. The second wait form can be considered more compact as it "saves" an indentation level.
I generally agree with wap26's answer, with one addition.
I sometimes like to write a top-level architecture which acts as both the synthesisable top-level design and as the simulation test bench - typically for smaller designs.
Within such designs, you often drive the clock yourself during simulation, using wait statements, like:
if IS_SIMULATION then
wait for SIM_CLK_PERIOD / 2;
clk <= '0';
wait for SIM_CLK_PERIOD / 2;
clk <= '1';
else
clk <= external_clk;
end if;
The issue now is that you still need to handle the initial/reset state for the synthesisable section. This requires an assertion that the entity's signals have been initialised before the first (or some) rising edge of the external clock.
But we can't use if rising_edge(external_clk), because this process cannot have a sensitivity list (it uses wait statements in the simulation section). Therefore, in this case, using wait until rising_edge(external_clk) is required.
A if [conditions].... :
continuously execute the acts. The process will go on regardless of whether the conditions is met or not, only skipping the statement in the "if" when not meeting the conditions, and will execute the afterwards statements, in all weather!
B wait until [conditions]... :
only execute the acts at the conditions met! If the conditions are not met, the process will hang (or be blocked/suspended) here, and can't go on, even there have many statements afterwards.
In most cases, expecially in simulations, B is better than A. In some cases, only B can be done, rather than A.
Here's an example:
A
for i in 0 to 10 loop;
if rising_edge(clk) then
..acts..
end if;
end loop;
B
for i in 0 to 10 loop;
wait until rising_edge(clk);
...acts....
end loop;
A can't work, but B can!
Essentially, the second type is only useful in simulation. The wait statement requires time to flow between separate statements within a process, which is unlike the hardware synthesis process. It will typically appear within a simulation stimulus or diagnostic process.
In the first form, the process is triggered by the clock event and runs in a single step, representing synchronous logic.

difference between using reset logic vs initial values on signals

Let's say I have a signal, I can either assign a initial value of zero OR I can set it to zero upon RESET. I've seen my co-workers using the two method interchangeably. I just want to see others opinion on this.
Example (using initial value):
architecture arch of xxx is
signal flag : STD_LOGIC := 0;
begin
process (clk) begin
if rising_edge(clk) then
-- do something
end if;
end process;
end arch;
Example (using reset value):
architecture arch of xxx is
signal flag : STD_LOGIC;
begin
process (clk,rst) begin
if (rst = '1') then
flag <= '0';
elsif rising_edge(clk) then
-- do something
end if;
end process;
end arch;
If possible, use a dedicated reset signal, for several reasons:
Designs using complex clock generation may require that a module is held idle
(reset) until the clock is stable. Using initial values with an unstable but
running clock may change the initial value from the expected.
A module that interfaces to other or external modules may get protocol
violations on an interface during startup, and to avoid wrong operation or
hangup due to protocol violations, it may be required to hold the module in
reset until the protocol operation is well defined in the interface.
Restart of the entire system, or part of the system, is possible by asserting
reset, instead of having to reload the entire FPGA, which takes much longer
time, and may be more complicated if it requires CPU interaction.
Some FPGA technologies, for example Altera partial reconfiguration, does not
support initial values for the modules used in partial reconfiguration.
Reuse of modules is therefore easier if only reset is used.
Simulation of different start/restart conditions is easier when it is
possible to apply reset, and continue the same simulation sequence. If
initial value is used, then the entire simulation must be restarted.
Apply reset to as few flip-flops as possible, for the resource reasons that Russell
points out. Also, applying it to only the required flip-flop, makes it easier
to catch bugs and oversights in the design during simulation, since unknown X
values may then appear. The reset should be asynchronous, since most FPGA and
ASIC technologies have flip-flops with dedicated reset input, and the reset
will then not slow down the timing of the synchronous design part, by insertion of logic to apply a reset value. The slow down can be seen in for example Altera Cyclone V, where logic is inserted in the data path due to the synchronous reset through a MLABCELL, as shown in the data path timing report here:
A flip-flop using asynchronous reset does not have this extra delay in the data path, as can be seen in figure through this link.
The process for flip-flops with reset should be written with the reset part as:
process (clk, rst) begin
if rising_edge(clk) then
-- Flip-flops updated at clock
end if;
if (rst = '1') then
-- Flip-flops reset
end if;
end process;
This coding style makes it possible to apply reset to only some of the
flip-flops updated at the rising clock, while the remaining flip-flops are
implemented without reset.
The combined if-then-elsif-end if in question code, actually specified that
the state is held during reset for flip-flops that are not reset, since the
rising_edge(clk) part of the if does then not take effect. This is
probably not the intended implementation.
For proper timing, the reset signal (rst) should be synchronized to the clock
(clk), at least for deassertion (1 to 0), so recovery and removal time are not violated.
'Value after FPGA configuration' vs 'Value after reset'
The initial value will be the value the signal will get after the FPGA configuration.
The value affected in case of a reset will be... the value the signal will get in case the reset signal is asserted :-)
About the signal value after FPGA configuration
From Xilinx "Large FPGA Methodology Guide" page 31 :
FPGA devices have dedicated global set/reset signals (GSR). At the end of device
configuration, the GSR is automatically asserted to initialize all registers to the initial state specified in the HDL code.
Every register is at a known state at the end of configuration. You do not need to code a global reset for the sole purpose of initializing the device.
Of course, you need to trust the FPGA you use about this initial value. People often prefer to have a reset on control signals to ensure this out of configuration initial value, even if this is normaly not required...
To reset or not to reset
Maybe you need a reset for specific other reasons :
coding rules that enforce this
the necessity to set this signal back to a known value without having to reconfigure the FPGA
If you need this reset, it will probably be asserted when the FPGA go out of configuration, and the initial value will then be useless, so it is probably better to not use it.
Hope this helps.
I'm of the opinion that you should not reset any signals that do not need it. Only things like state machines or counters should be reset. Adding resets to everything means that the tools will have to add routing resources to hook up all of these resets. So for example I almost never reset any signal that just holds data, or some enable signal that will only be active for one clock cycle anyway.
Regarding initialization, I initialize every register that I infer. This can be easily checked by looking at a modelsim waveform. Red = Bad. This takes no additional resources to achieve, but it ensures that the FPGA starts up in a known-condition.

Resources