Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] FSM in VHDL transitioning to wrong state for no reason

Status
Not open for further replies.

GuiRitter

Junior Member level 1
Joined
Oct 19, 2011
Messages
17
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,560
Hi everyone.

As per college assignment, I was tasked to implement a system to control a four floors elevator using state machine(s). I've decided to use Moore FSMs. In one of them, in the test bench, initially, the next state is one that doesn't even have a transition from the previous state. But, as soon as the reset signal is lifted, the current state becomes that state.

I'll post the FSM's graph and the VHDL module and test bench. I translated the VHDLs for easier comprehension, but that would be too much work for the graph, so I added the corresponding names in the VHDL's commentaries.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    23:20:40 05/17/2014 
-- Design Name: 
-- Module Name:    stateMachineMain - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
 
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity stateMachineMain is
    port (clock, reset,
        floorButtons,-- BA
        countingEnd,-- FC
        openDoorSensor,-- SPA
        closedDoorSensor-- SPF
            : in std_logic;
        destinationFloor-- AD
            : in std_logic_vector(1 downto 0);
        floorSensor-- SAx
            : in std_logic_vector(3 downto 0);
        enableDestinationFloor-- EAD
            : out std_logic;
        elevatorMotor,-- ME
        elevatorMotorDirection,-- MED
        openSignal,-- SA
        countingSignal,-- SC
        closeSignal-- SF
            : out std_logic);
end stateMachineMain;
 
architecture Behavioral of stateMachineMain is
    type states is (
        Floor1Above,-- A1C
        Floor1EntranceOpen,-- A1EA
        Floor1EntranceWait,-- A1EE
        Floor1Close,-- A1F
        Floor1ExitOpen,-- A1SA
        Floor1ExitWait,-- A1SE
        Floor1ExitClose,-- A1SF
        Floor2Below,-- A2B
        Floor2Above,-- A2C
        Floor2EntranceOpen,-- A2EA
        Floor2EntranceWait,-- A2EE
        Floor2Close,-- A2F
        Floor2ExitOpen,-- A2SA
        Floor2ExitWait,-- A2SE
        Floor2ExitClose,-- A2SF
        Floor3Below,-- A3B
        Floor3Above,-- A3C
        Floor3EntranceOpen,-- A3EA
        Floor3EntranceWait,-- A3EE
        Floor3Close,-- A3F
        Floor3ExitOpen,-- A3SA
        Floor3ExitWait,-- A3SE
        Floor3ExitClose,-- A3SF
        Floor4Below,-- A4B
        Floor4EntranceOpen,-- A4EA
        Floor4EntranceWait,-- A4EE
        Floor4Close,-- A4F
        Floor4ExitOpen,-- A4SA
        Floor4ExitWait,-- A4SE
        Floor4ExitClose);-- A4SF
    signal stateCurrent, stateNext : states;
begin
    process (clock, reset) begin
        if (reset = '1') then
            stateCurrent <= Floor1Close;
        elsif ((clock'event) and (clock = '1')) then
            stateCurrent <= stateNext;
        end if;
    end process;
    process (stateCurrent, destinationFloor, floorButtons, countingEnd, floorSensor, openDoorSensor, closedDoorSensor) begin
        case stateCurrent is
            when Floor1Above =>
                closeSignal <= '0';
                elevatorMotor <= '1';-- this line is not reached
                elevatorMotorDirection <= '0';
                if (floorSensor(0) = '1') then
                    stateNext <= Floor1EntranceOpen;-- this line is reached
                end if;
            when Floor1EntranceOpen =>
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                elevatorMotor <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor1EntranceWait;
                end if;
            when Floor1EntranceWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor1Close;
                end if;
            when Floor1Close =>
                enableDestinationFloor <= '1';
                closeSignal <= '1';
                if (floorButtons = '1') then
                    stateNext <= Floor1ExitOpen;
                end if;
            when Floor1ExitOpen =>
                enableDestinationFloor <= '0';
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor1ExitWait;
                end if;
            when Floor1ExitWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor1ExitClose;
                end if;
            when Floor1ExitClose =>
                closeSignal <= '1';
                if (closedDoorSensor = '1') then
                    if (destinationFloor = "00") then
                        stateNext <= Floor1EntranceOpen;
                    elsif (destinationFloor = "01") then
                        stateNext <= Floor2Below;
                    elsif (destinationFloor = "10") then
                        stateNext <= Floor3Below;
                    else
                        stateNext <= Floor4Below;
                    end if;
                end if;
            when Floor2Below =>--
                closeSignal <= '0';
                elevatorMotor <= '1';
                elevatorMotorDirection <= '1';
                if (floorSensor(1) = '1') then
                    stateNext <= Floor2EntranceOpen;
                end if;
            when Floor2Above =>
                closeSignal <= '0';
                elevatorMotor <= '1';
                elevatorMotorDirection <= '0';
                if (floorSensor(1) = '1') then
                    stateNext <= Floor2EntranceOpen;
                end if;
            when Floor2EntranceOpen =>
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                elevatorMotor <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor2EntranceWait;
                end if;
            when Floor2EntranceWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor2Close;
                end if;
            when Floor2Close =>
                enableDestinationFloor <= '1';
                closeSignal <= '1';
                if (floorButtons = '1') then
                    stateNext <= Floor2ExitOpen;
                end if;
            when Floor2ExitOpen =>
                enableDestinationFloor <= '0';
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor2ExitWait;
                end if;
            when Floor2ExitWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor2ExitClose;
                end if;
            when Floor2ExitClose =>
                closeSignal <= '1';
                if (closedDoorSensor = '1') then
                    if (destinationFloor = "00") then
                        stateNext <= Floor1Above;
                    elsif (destinationFloor = "01") then
                        stateNext <= Floor2EntranceOpen;
                    elsif (destinationFloor = "10") then
                        stateNext <= Floor3Below;
                    else
                        stateNext <= Floor4Below;
                    end if;
                end if;
            when Floor3Below =>--
                closeSignal <= '0';
                elevatorMotor <= '1';
                elevatorMotorDirection <= '1';
                if (floorSensor(2) = '1') then
                    stateNext <= Floor3EntranceOpen;
                end if;
            when Floor3Above =>
                closeSignal <= '0';
                elevatorMotor <= '1';
                elevatorMotorDirection <= '0';
                if (floorSensor(2) = '1') then
                    stateNext <= Floor3EntranceOpen;
                end if;
            when Floor3EntranceOpen =>
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                elevatorMotor <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor3EntranceWait;
                end if;
            when Floor3EntranceWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor3Close;
                end if;
            when Floor3Close =>
                enableDestinationFloor <= '1';
                closeSignal <= '1';
                if (floorButtons = '1') then
                    stateNext <= Floor3ExitOpen;
                end if;
            when Floor3ExitOpen =>
                enableDestinationFloor <= '0';
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor3ExitWait;
                end if;
            when Floor3ExitWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor3ExitClose;
                end if;
            when Floor3ExitClose =>
                closeSignal <= '1';
                if (closedDoorSensor = '1') then
                    if (destinationFloor = "00") then
                        stateNext <= Floor1Above;
                    elsif (destinationFloor = "01") then
                        stateNext <= Floor2Above;
                    elsif (destinationFloor = "10") then
                        stateNext <= Floor3EntranceOpen;
                    else
                        stateNext <= Floor4Below;
                    end if;
                end if;
            when Floor4Below =>--
                closeSignal <= '0';
                elevatorMotor <= '1';
                elevatorMotorDirection <= '1';
                if (floorSensor(3) = '1') then
                    stateNext <= Floor4EntranceOpen;
                end if;
            when Floor4EntranceOpen =>
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                elevatorMotor <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor4EntranceWait;
                end if;
            when Floor4EntranceWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor4Close;
                end if;
            when Floor4Close =>
                enableDestinationFloor <= '1';
                closeSignal <= '1';
                if (floorButtons = '1') then
                    stateNext <= Floor4ExitOpen;
                end if;
            when Floor4ExitOpen =>
                enableDestinationFloor <= '0';
                openSignal <= '1';
                countingSignal <= '1';
                closeSignal <= '0';
                if (openDoorSensor = '1') then
                    stateNext <= Floor4ExitWait;
                end if;
            when Floor4ExitWait =>
                openSignal <= '0';
                countingSignal <= '0';
                if (countingEnd = '1') then
                    stateNext <= Floor4ExitClose;
                end if;
            when Floor4ExitClose =>
                closeSignal <= '1';
                if (closedDoorSensor = '1') then
                    if (destinationFloor = "00") then
                        stateNext <= Floor1Above;
                    elsif (destinationFloor = "01") then
                        stateNext <= Floor2Above;
                    elsif (destinationFloor = "10") then
                        stateNext <= Floor3Above;
                    else
                        stateNext <= Floor4EntranceOpen;
                    end if;
                end if;
        end case;
    end process;
end Behavioral;




Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   13:42:15 05/18/2014
-- Design Name:   
-- Module Name:   C:/Xilinx/projects/TestBenchHDL/testStateMachineMain.vhd
-- Project Name:  TestBenchHDL
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
-- VHDL Test Bench Created by ISE for module: stateMachineMain
-- 
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes: 
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test.  Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation 
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY testStateMachineMain IS
END testStateMachineMain;
 
ARCHITECTURE behavior OF testStateMachineMain IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT stateMachineMain
    PORT(
         clock : IN  std_logic;
         reset : IN  std_logic;
         floorButtons : IN  std_logic;
         countingEnd : IN  std_logic;
         openDoorSensor : IN  std_logic;
         closedDoorSensor : IN  std_logic;
         destinationFloor : IN  std_logic_vector(1 downto 0);
         floorSensor : IN  std_logic_vector(3 downto 0);
         enableDestinationFloor : OUT  std_logic;
         elevatorMotor : OUT  std_logic;
         elevatorMotorDirection : OUT  std_logic;
         openSignal : OUT  std_logic;
         countingSignal : OUT  std_logic;
         closeSignal : OUT  std_logic
        );
    END COMPONENT;
    
 
   --Inputs
   signal clock : std_logic := '1';
   signal reset : std_logic := '1';
   signal floorButtons : std_logic := '0';
   signal countingEnd : std_logic := '1';
   signal openDoorSensor : std_logic := '0';
   signal closedDoorSensor : std_logic := '1';
   signal destinationFloor : std_logic_vector(1 downto 0) := (others => '0');
   signal floorSensor : std_logic_vector(3 downto 0) := "0001";
 
    --Outputs
   signal enableDestinationFloor : std_logic;
   signal elevatorMotor : std_logic;
   signal elevatorMotorDirection : std_logic;
   signal openSignal : std_logic;
   signal countingSignal : std_logic;
   signal closeSignal : std_logic;
 
   -- Clock period definitions
   constant clock_period : time := 20 ns;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: stateMachineMain PORT MAP (
          clock => clock,
          reset => reset,
          floorButtons => floorButtons,
          countingEnd => countingEnd,
          openDoorSensor => openDoorSensor,
          closedDoorSensor => closedDoorSensor,
          destinationFloor => destinationFloor,
          floorSensor => floorSensor,
          enableDestinationFloor => enableDestinationFloor,
          elevatorMotor => elevatorMotor,
          elevatorMotorDirection => elevatorMotorDirection,
          openSignal => openSignal,
          countingSignal => countingSignal,
          closeSignal => closeSignal
        );
 
   -- Clock process definitions
   clock_process :process
   begin
        clock <= '0';
        wait for clock_period/2;
        clock <= '1';
        wait for clock_period/2;
   end process;
 
 
   -- Stimulus process
   stim_proc: process
   begin        
      -- hold reset state for 100 ns.
--      wait for 100 ns;    
 
--      wait for clock_period*10;
 
      -- insert stimulus here 
        wait for 20 ns;
        reset <= '0';
      wait;
   end process;
 
END;



So, after 20 ns, the state changes from Floor1Close to Floor1EntranceOpen, even though that transition doesn't exist. I even tried to initialize the next state, but that didn't made a difference in the test bench. Also, after a reply I came back and edited this post. There are two lines with comments close to the beginning of the second process. I used a test signal to see which line was being executed, and the line that comes later is executed, while the line that comes before is not.

I'm using Xilinx ISE 13.1 x64 WebPack license.

Thanks in advance.
 

Attachments

  • stateMachineMain.png
    stateMachineMain.png
    130.5 KB · Views: 56
Last edited:

At least In real hardware, timing violations can easily cause "illegal" state transistions. Popular candidates for timing violations are:
- asynchronously released reset
- external inputs (buttons and sensors) that are used in the state machine without previous synchronization to the FSM clock.
 

At least In real hardware, timing violations can easily cause "illegal" state transistions. Popular candidates for timing violations are:
- asynchronously released reset
- external inputs (buttons and sensors) that are used in the state machine without previous synchronization to the FSM clock.

Yeah, I read about that while I was Googling for this problem. Too bad it doesn't apply. Just in case, I ran the test bench releasing the reset signal at different intervals. No change. And the inputs remain stable for the whole duration of the test.
 


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
process (stateCurrent, destinationFloor, floorButtons, countingEnd, floorSensor, openDoorSensor, closedDoorSensor) begin
        case stateCurrent is
            when Floor1Above =>
                closeSignal <= '0';
                elevatorMotor <= '1';
                elevatorMotorDirection <= '0';
                if (floorSensor(0) = '1') then
                    stateNext <= Floor1EntranceOpen;
                end if;


You don't define what state to go to if floorSensor(0) is not equal to '1'.

Regards
 
  • Like
Reactions: FvM

    FvM

    Points: 2
    Helpful Answer Positive Rating
You don't define what state to go to if floorSensor(0) is not equal to '1'.

Regards

It goes nowhere from that state. I've used this approach on other FSMs and it worked.

Besides, I added a test signal and verified some weird behaviour:

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
process (stateCurrent, destinationFloor, floorButtons, countingEnd, floorSensor, openDoorSensor, closedDoorSensor) begin
        case stateCurrent is
            when Floor1Above =>
                closeSignal <= '0';
                elevatorMotor <= '1';-- this line is not reached
                elevatorMotorDirection <= '0';
                if (floorSensor(0) = '1') then
                    stateNext <= Floor1EntranceOpen;-- this line is reached
                end if;



I've edited the first post to show this.
 
Last edited:

It would work in a fsm in a clocked process, but your using a combinational process.
 

ads-ee is right, I didn't notice the rather trivial issue.
Because stateNext isn't assigned in every case statement branch, you need a default assignment before the case statement:
Code:
stateNext <= stateCurrent;

The asynchronous inputs issue must be fixed for a real hardware design nevertheless.
 
ads-ee is right, I didn't notice the rather trivial issue.
Because stateNext isn't assigned in every case statement branch, you need a default assignment before the case statement:
Code:
stateNext <= stateCurrent;

The asynchronous inputs issue must be fixed for a real hardware design nevertheless.

I filled the code with

Code VHDL - [expand]
1
2
else
    stateNext <= stateCurrent;


and it worked! Thanks!

But I still don't understand why. Testing manually, there's no reason for that line to be executed. Must be one of those weird things about VHDL.
 

But I still don't understand why. Testing manually, there's no reason for that line to be executed. Must be one of those weird things about VHDL.

It has nothing to do with a 'weird things about VHDL', it is a design problem on your part. By not assigning a next state for every possible path through the FSM, your code describes a latch. Latches in programmable logic are destined to fail, that's what you're seeing. You will not be able to debug this on a simulator either because the timing problems that are the root cause of why a latch in programmable logic will eventually fail do not show up in a simulator.

Also, async inputs or other clock domain crossings that enter into a state machine that were mentioned earlier will not show up as a failure in simulation either. Simulation will always work as expected, real world hardware will always eventually fail.

In both cases, the reason the simulator works and does not match reality is simply due to the fact that simulator cannot detect timing problems. Static timing analysis and simply perusing the synthesis report for things like 'combinatorial loop detected' (or something like that) are the proper tools for that analysis.

Kevin Jennings
 
Avoiding latches is a sufficient reason to use a default assignment for next_state. It's also true that latches often involve code failure. The problem that causes "unexpected" behaviour of the originally posted code is more trivial, in fact the failure is well expectable. next_state is simply uninitialized.
 

It has nothing to do with a 'weird things about VHDL', it is a design problem on your part. By not assigning a next state for every possible path through the FSM, your code describes a latch. Latches in programmable logic are destined to fail, that's what you're seeing. You will not be able to debug this on a simulator either because the timing problems that are the root cause of why a latch in programmable logic will eventually fail do not show up in a simulator.

Also, async inputs or other clock domain crossings that enter into a state machine that were mentioned earlier will not show up as a failure in simulation either. Simulation will always work as expected, real world hardware will always eventually fail.

In both cases, the reason the simulator works and does not match reality is simply due to the fact that simulator cannot detect timing problems. Static timing analysis and simply perusing the synthesis report for things like 'combinatorial loop detected' (or something like that) are the proper tools for that analysis.

Kevin Jennings

Avoiding latches is a sufficient reason to use a default assignment for next_state. It's also true that latches often involve code failure. The problem that causes "unexpected" behaviour of the originally posted code is more trivial, in fact the failure is well expectable. next_state is simply uninitialized.

Ah, much better. I understand now. Thanks!

Edit: I just realized something. I thought that initializing the state variables was not necessary, as that would be done by reset. But I initialized them and removed all the

Code VHDL - [expand]
1
2
else
    stateNext <= stateCurrent;

and it worked too...
 
Last edited:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top