VHDL 状态机卡在不可能的状态
VHDL State machine stucks in an impossible state
我写了一个VHDL状态机。它会工作一段时间,直到卡在不可能的状态。
总共有7个州,但我们只对其中两个感兴趣。状态图很简单:
IDLE2
<=> IDLE
<=> 其他州
换句话说就是初始状态为IDLE
。所有其他状态都可以通过 IDLE
状态到达。状态IDLE2
只能跳转到IDLE
状态。
代码片段:
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.
您可能会注意到,IDLE
状态不是 'stable'。每个周期机器都必须离开 IDLE
状态,即使什么都没有发生:IDLE
跳到 IDLE2
,从 IDLE2
到 returns 到 IDLE
下一个时钟周期。而且效果很好!
您可能还注意到我输出 STATE
到 STS
独立于状态。在 Altera SignalTap 中,我看到正常操作:状态来回跳转,并在适当的输入事件时进入其他状态。
问题
突然在许多正常操作周期之后我看到(在 SignalTap 中)STS = 0
并且没有及时改变。这意味着 STATE = IDLE
,机器不会跳转到 IDLE2
(STS = 6
)。而且它不会通过任何输入事件跳转到任何状态,它只是停留在状态 IDLE
。根据输出(PLD_WR = 1
和 PLD_RD = 0
)判断,代码卡在上面代码中的注释 <!> stuck
附近,但 STATE <= SEND1
不会出现。
这怎么可能??
免责声明:状态 IDLE2
和输出 STS
是为调试此特定问题而实现的。
令人惊讶的是,我在发布这个问题后就设法解决了自己的问题,尽管我为此苦苦挣扎了好几天!
答案:我将 switch-enum 块更改为 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
此外,我删除了调试 STS 输出和 IDLE2 状态,因为不再需要它们。幸运的是,它仍然有效!
但我仍然想知道为什么 switch-enum 不能正常工作。
可能是编译器错误,我使用 "good old" Quartus II 8.1 Web
我写了一个VHDL状态机。它会工作一段时间,直到卡在不可能的状态。
总共有7个州,但我们只对其中两个感兴趣。状态图很简单:
IDLE2
<=> IDLE
<=> 其他州
换句话说就是初始状态为IDLE
。所有其他状态都可以通过 IDLE
状态到达。状态IDLE2
只能跳转到IDLE
状态。
代码片段:
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.
您可能会注意到,IDLE
状态不是 'stable'。每个周期机器都必须离开 IDLE
状态,即使什么都没有发生:IDLE
跳到 IDLE2
,从 IDLE2
到 returns 到 IDLE
下一个时钟周期。而且效果很好!
您可能还注意到我输出 STATE
到 STS
独立于状态。在 Altera SignalTap 中,我看到正常操作:状态来回跳转,并在适当的输入事件时进入其他状态。
问题
突然在许多正常操作周期之后我看到(在 SignalTap 中)STS = 0
并且没有及时改变。这意味着 STATE = IDLE
,机器不会跳转到 IDLE2
(STS = 6
)。而且它不会通过任何输入事件跳转到任何状态,它只是停留在状态 IDLE
。根据输出(PLD_WR = 1
和 PLD_RD = 0
)判断,代码卡在上面代码中的注释 <!> stuck
附近,但 STATE <= SEND1
不会出现。
这怎么可能??
免责声明:状态 IDLE2
和输出 STS
是为调试此特定问题而实现的。
令人惊讶的是,我在发布这个问题后就设法解决了自己的问题,尽管我为此苦苦挣扎了好几天!
答案:我将 switch-enum 块更改为 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
此外,我删除了调试 STS 输出和 IDLE2 状态,因为不再需要它们。幸运的是,它仍然有效!
但我仍然想知道为什么 switch-enum 不能正常工作。 可能是编译器错误,我使用 "good old" Quartus II 8.1 Web