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 下一个时钟周期。而且效果很好!

您可能还注意到我输出 STATESTS 独立于状态。在 Altera SignalTap 中,我看到正常操作:状态来回跳转,并在适当的输入事件时进入其他状态。

问题

突然在许多正常操作周期之后我看到(在 SignalTap 中)STS = 0 并且没有及时改变。这意味着 STATE = IDLE,机器不会跳转到 IDLE2 (STS = 6)。而且它不会通过任何输入事件跳转到任何状态,它只是停留在状态 IDLE。根据输出(PLD_WR = 1PLD_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