Alternative way to implement state machines in VHDL - vhdl

I have seen many state machines implemented like this one from Altera:
ARCHITECTURE a OF state_machine IS
TYPE STATE_TYPE IS (s0, s1, s2);
SIGNAL state : STATE_TYPE;
BEGIN
PROCESS (clk, reset)
BEGIN
IF reset = '1' THEN
state <= s0;
ELSIF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN ...
An alterantive to that would be this:
ARCHITECTURE a OF state_machine IS
TYPE STATE_TYPE IS (s0, s1, s2);
BEGIN
PROCESS (clk, reset)
VARIABLE state : STATE_TYPE := s0;
BEGIN
IF reset = '1' THEN
state <= s0;
ELSIF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN ...
What are the pros (if any) and cons of doing it the alternative way? I have only seen the alternative in one place and I'm guessing there must be some good reason for that.

I like to keep local things local, so if the state information is needed only within the process, I use a variable. In that case, I also like to declare the state type inside the process:
ARCHITECTURE a OF state_machine IS
BEGIN
PROCESS (clk, reset)
TYPE STATE_TYPE IS (s0, s1, s2);
VARIABLE state : STATE_TYPE := s0;
BEGIN
...
In the rare cases where I need to access the state of an FSM from another process (e.g. interactive state machines), I'll use a signal for storing the state.
The signal vs. variable decision if often a matter of taste. Some developers think that variables are evil and will never use them. Others (like me) use them whenever they can to keep local things local. As a bonus, since variables are more lightweight objects than signals, they also simulate faster.

Using a variable to hold state would mean you couldn't look at state with a waveform viewer.
There might be some synchronization issues with signal inputs used for branching, delta cycle mismatch in zero time models.
Any state machine outputs derived from state would require signals in any event - every concurrent statement has a process equivalent, a VHDL simulator executes processes, processes communicate via signals.
The only pluses that come to mind is that it would be a more compact model (code size) and execute a bit faster.

I often use a variable called state. It keeps the definition hidden, private to just the process that is using it. If you have 2 communicating state machines in one process, they can both have a variable called state local to themselves. Sometimes that works well. Other times it's confusing!
As with many code-style issues, you have to decide on the most readable way to do things. There's no functional reason not to use variables (of any sort, not just state variables).
One other thing you can do with a variable is read the intended next state at the end of the process, which can be useful when you need to reduce latency of outputs. Again, care is needed as you can create long chains of logic inadvertently which can slow the design down.

Variables are great if you are determining a partial sum or intermediate product that is to be used further down in your process in the same clock cycle. However if a variable is not driven every clock cycle then a latch will be inferred. Since you will want the state to be 'remembered' for the next clock cycle then you will get a latch if you use a variable without an assistant register signal. To clarify...
signal state_sig : state_type;
begin
process(clk, rst)
variable state : state_type := s0;
begin
if rst = '1' then
state_sig <= s0;
elsif rising_edge(clk) then
state := state_sig
case state is
when s0 =>
if blah = '0' then
state := s1;
end if;
....
....
end case;
if state = s1 then state := s2; end if;
state_sig <= state;
end if;
end process;
In the above example you are able to avoid going in the state s1 by modifying the state variable before it gets registered. A quick and dirty way of changing the state machine behaviour. However the state_sig signal must be used to 'remember' the state to avoid latch inferral.

Related

Is this a valid way to code a VHDL async reset?

I have picked up some VHDL code to maintain that has a reset written in a way I'm not familiar with. I'm not sure if it's valid, and my simulator (Modelsim) is giving warnings that I wouldn't expect. Example of the pattern:
process(clk, reset_n)
begin
if reset_n = '0' then
counter <= (others=>'0');
end if;
if rising_edge(clk) then
case state is
when IDLE =>
if signal_a = signal_b then
state <= DATA;
end if;
when DATA =>
state <= IDLE;
when others =>
end case;
if state = DATA then
counter <= counter + 1;
else
counter <= (others => '0');
end if;
end if;
end process;
Modelsim warns that state, signal_a and signal_b are "read in the process but is not in the sensitivity list". I would not expect that as they are in a clocked block and the process is sensitive to the clock.
Is this a valid coding style for an async reset? I would expect to see elsif rising_edge(clk) instead, but understand this would cause problems here with the mix of other non-reset signals (state).
This pattern likely wont behave as you expect, and also likely wont synthesise (and if it does, it wont match the code).
This code has the clock overriding the reset. If reset is asserted ('0') then the counter will be reset, but if clk is running it will the run as if reset_n is '1'. This is because processes are only triggered by a 'event' on a signal in the sensitivity list, so the reset will only occur when reset_n changes to '0'. This doesnt usually matter in VHDL as the reset branch will have higher priority than the clock. So if it is clocked, the reset branch is taken. But here, because the reset has lower priority, it is as if reset_n is a negitive edge clock.
On the actual hardware, this is different. Sensitivity lists are normally ignored and the hardware is built from the code in the process. I would expect that this will fail to build either because it will complain about no logic matching the template, or dual edge flops are not allowed.
To fix this, either make the clock branch an elsif as you suggested, and you would also need to add state to the reset to avoid an accidental clock enable on state, or move the reset to the bottom of the process, where it will override the clock assignment properly, and allow you to have a mix of reset and non-reset registers in the same process.

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!

VHDL FSM multi-driven net Q is connected to constant driver, other driver is ignored, what's wrong with my code?

This code is a FSM which is a Moore Machine
Alyssa P. Hacker has a snail
that crawls down a paper tape
with 1’s and 0’s on it. The snail
smiles whenever the last two
digits it has crawled over are
01. Design Moore and Mealy
FSMs of the snail’s brain.
And the code is shown below
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity simpfsm is
Port ( A : in STD_LOGIC;
clk : in STD_LOGIC;
r : in STD_LOGIC;
Y : out STD_LOGIC);
end simpfsm;
architecture Behavioral of simpfsm is
type state_type is (SA,SB,SC);
signal state,next_state:state_type;
begin
SYNC_PROC:process(clk)
begin
if(clk'event and clk='1') then
if(r='1') then
next_state <= SA; -- removed trailing grave accent
else
state <= next_state;
end if;
end if;
end process;
OUTPUT_DECODE:process(state)
begin
case (state) is
when SA =>
Y <= '0';
when SB =>
Y <= '0';
when SC =>
Y <= '1';
when others =>
Y <= '0';
end case;
end process;
NEXT_STATE_DECODE:process(state,A)
begin
next_state <= state;
case (state) is
when SA =>
if(A='0') then
next_state <= SB;
end if;
when SB =>
if(A='1') then
next_state <= SC;
end if;
when SC =>
if(A='0') then
next_state <= SB;
elsif(A='1') then
next_state <= SA;
end if;
when others =>
next_state <= SA; --"if not state then begin with SA"
end case;
end process;
end Behavioral; -- removed trailing grave accent
The error is [XSIM 43-3249] File D:/Users/93443/project_4/project_4.srcs/sources_1/new/A_11_fsm.vhd, line 22. Unresolved signal "next_state" is multiply driven.
state_type is not a resolved subtype. Multiple drivers are detected during loading prior to model execution after being identified during elaboration.
IEEE Std 1076-2008
14.5 Elaboration of a statement part
14.5.5 Other concurrent statements
All other concurrent statements are either process statements or are statements for which there is an equivalent process statement.
Elaboration of a process statement proceeds as follows:
a) The process declarative part is elaborated.
b) The drivers required by the process statement are identified.
6.4.2.3 Signal declarations
... It is an error if, after the elaboration of a description, a signal has multiple sources and it is not a resolved signal. ...
There are drivers for next_state in processes SYNC_PROC and NEXT_STATE_DECODE
14.7 Execution of a model
14.7.2 Drivers
Every signal assignment statement in a process statement defines a set of drivers for certain scalar signals. There is a single driver for a given scalar signal S in a process statement, provided that there is at least one signal assignment statement in that process statement and that the longest static prefix of the target signal of that signal assignment statement denotes S or denotes a composite signal of which S is a subelement. Each such signal assignment statement is said to be associated with that driver. Execution of a signal assignment statement affects only the associated driver(s).
state_type an enumerated type and is a scalar type:
5.2 Scalar types
5.2.1 General
Scalar types consist of enumeration types, integer types, physical types, and floating-point types. ...
The solution would appear to be to reset state in SYNC_PROC instead of next_state.
If you remove the two extraneous grave accents ('`', 15.2 Character set) your code would be a Minimal, Complete, and Verifiable example despite Tricky's expression of suspicion. I removed them from your code example, after which your code analyzes and elaborates following the change to process SYNC_PROC:
if(r='1') then
state <= SA; -- WAS next_state
(Note the parentheses around a condition (here r='1') are redundant. In VHDL a condition is known to be an expression with a BOOLEAN value.)
If your simulator allows execution with top level ports it would report the multiple drivers. For those simulators that don't you'd require a testbench instantiating simpfsm:
14.2 Elaboration of a design hierarchy
An implementation may allow, but is not required to allow, a design entity at the root of a design hierarchy to have generics and ports. If an implementation allows these top-level interface objects, it may restrict their allowed forms (that is, whether they are allowed to be interface types, subprograms, packages, or objects), and, in the case of interface objects, their allowed types and modes in an implementation-defined manner.
As you might gather this represents a portability issue for detecting the error without a testbench or depending on an interactive of script driven simulator. The error can demonstrated with ghdl prior to the signal assignment target change:
ghdl -r simpfsm
for signal: .simpfsm(behavioral).next_state
./simpfsm:error: several sources for unresolved signal
./simpfsm:error: error during elaboration
Loading an elaborated design specification into memory is deferred to 'program' execution in compiler based VHDL simulators:
14.2 Elaboration of a design hierarchy
Elaboration of a design hierarchy is completed as follows:
— The drivers identified during elaboration of process statements (see 14.5.5) are created.
— The initial transaction defined by the default value associated with each scalar signal driven by a process statement is inserted into the corresponding driver.
next_state and state both have default values of state_type'LEFT (SA).
6.4.2.3 Signal declarations
In the absence of an explicit default expression, an implicit default value is assumed for a signal of a scalar subtype or for each scalar subelement of a composite signal, each of which is itself a signal of a scalar subtype. The implicit default value for a signal of a scalar subtype T is defined to be that given by T'LEFT.
And this implies detecting multiple drivers occurs during the loading portion of elaboration when each net is identified:
14.7.3.4 Signal update
A net is a collection of drivers, signals (including ports and implicit signals), conversion functions, and resolution functions that, taken together, determine the effective and driving values of every signal on the net.
We see in that part of elaboration (loading here) occurs during execution (ghdl's -r command):
14.2 Elaboration of a design hierarchy
The elaboration of a design hierarchy creates a collection of processes interconnected by nets; this collection of processes and nets can then be executed to simulate the behavior of the design.
Tricky's suspicion is somewhat valid, the grave accents would cause errors during analysis, while the error you provide occurs during elaboration. They can be assumed to be transcription errors here by investigating your reported error first.
Next_stat is driven in the reset of the SYNC_PROC
next_state <= SA;
and also in the NEXT_STATE_DECODE process.
You cannot drive it from two processes.
You also have an extra ` for no good reason. Is this the real code?

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.

VHDL - why do we need to declare signals for processes?

Just revisiting some VHDL and I was wondering inside processes for example, why do we need to declare a signal for a clock for example? Then later on in the code assign it to the port from the entity...
EXAMPLE VHDL:
signal clk_int: std_logic := '1';
BEGIN
clkgen: process(clk_int)
begin
clk_int <= not clk_int after 50ns
end process ckgen
ck_l <= clk_int;
In this example ck_l is a physcial port from the d flip flop yet we create and mess around with clk int then return the value to ck
The reason is that the port ck_l in this case is probably declared with direction out, so It cannot be read from. If you want to read it, like you would need to if you want to have a process that is sensitive to it, you need to use a signal or declare the port as inout or buffer.

Resources