Reputation: 168
I wrote a VHDL State Machine. It works some time until it gets stuck on an impossible state.
There are 7 states in total, but only two of them interesting for us. The state graph is simple:
IDLE2
<=> IDLE
<=> Other states
In words, it means that initial state is IDLE
. All other states can be reached through IDLE
state. State IDLE2
can only jump to the IDLE
state.
Fragment of the code:
ENTITY MC_PLD_vhd IS
PORT
(
--INPUTS
MC_WR: IN STD_LOGIC;
MC_RD: IN STD_LOGIC;
Tstart: IN STD_LOGIC;
CLK: IN STD_LOGIC;
--OUTPUTS
PLD_WR: OUT STD_LOGIC;
PLD_RD: OUT STD_LOGIC;
STS: OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END MC_PLD_vhd;
ARCHITECTURE MC_PLD_vhd_dff OF MC_PLD_vhd IS
TYPE tSTATE is
(
IDLE --0
,REC1 --1
,SEND1 --2
--I omit some not significant states
,IDLE2 --6
);
SIGNAL STATE :tSTATE := IDLE;
BEGIN
PROCESS(CLK) IS
BEGIN
IF RISING_EDGE(CLK) THEN
STS <= std_logic_vector(to_unsigned(tSTATE'pos(STATE), 8));
CASE STATE IS
WHEN IDLE =>
IF Tstart = '1' THEN
PLD_WR <= '1';
PLD_RD <= '0';
STATE <= SEND1; -- <!> stuck
ELSE
IF MC_WR = '1' THEN
PLD_RD <= '1';
PLD_WR <= '0';
STATE <= REC1;
ELSE
PLD_WR <= '0';
PLD_RD <= '0';
STATE <= IDLE2;
END IF;
END IF;
WHEN IDLE2 =>
PLD_WR <= '0';
PLD_RD <= '0';
STATE <= IDLE;
WHEN IsReceiving_wait_RD_rise_1 => <...>
-- Other left away, as they don't add any information to my question.
As you may notice, the IDLE
state is not 'stable'. Every cycle the machine must leave the IDLE
state, even if nothing is happening: IDLE
jumps to IDLE2
, and from IDLE2
it returns to IDLE
the next clock cycle. And it works pretty well!
Also you may notice that I output STATE
through STS
independently from state. In Altera SignalTap I see normal operation: states jumps back and forth, and enters to other states at appropriate input events.
Suddenly after many cycles of normal operation I see (in SignalTap) that STS = 0
and doesn't change in time. This means that STATE = IDLE
, and the machine does NOT jump to IDLE2
(STS = 6
). And it does NOT jump to any state by any input event, it's just stuck in state IDLE
. Judging by outputs (PLD_WR = 1
and PLD_RD = 0
) the code is stuck near the comment <!> stuck
in the code above, but STATE <= SEND1
doesn't occur.
Disclaimer: The state IDLE2
and the output STS
were implemented for debugging this particular problem.
Upvotes: 2
Views: 1317
Reputation: 168
Surprisingly, I managed to solve my own problem just after I posted this question, despite the fact that I struggled with it a several days!
ANSWER: I change switch-enum block to if-integer.
PROCESS(CLK) IS
CONSTANT STATE_IDLE :INTEGER := 0;
CONSTANT STATE_RECEIVE :INTEGER := 1;
--I omit other states
CONSTANT STATE_IDLE2 :INTEGER := 6;
VARIABLE STATE :INTEGER := 0;
BEGIN
IF RISING_EDGE(CLK) THEN
STS <= std_logic_vector(to_unsigned(STATE, 8));
IF STATE = STATE_IDLE THEN
IF Tstart = '1' THEN
PLD_WR <= '1';
PLD_RD <= '0';
STATE := STATE_SEND_wait_RD;
ELSE
IF MC_WR = '1' THEN
PLD_RD <= '1';
PLD_WR <= '0';
STATE := STATE_RECEIVE;
ELSE
PLD_WR <= '0';
PLD_RD <= '0';
STATE := STATE_IDLE2;
END IF;
END IF;
ELSIF STATE = STATE_IDLE2 THEN
PLD_WR <= '0';
PLD_RD <= '0';
STATE := STATE_IDLE;
ELSIF STATE = STATE_RECEIVE THEN
--Unsignificant states omitted
Further, I cut out debugging STS output and IDLE2 state because they are no longer needed. And it still works, fortunately!
But I'm still wondering why switch-enum does not properly work. May be it's compiler fault, I use "good old" Quartus II 8.1 Web
Upvotes: 0