VHDL中有限状态机的奇怪行为

时间:2014-06-10 14:42:08

标签: vhdl fsm

所以我最近开始学习VHDL作为大学实习的一部分。 这次,我们的任务是创建一个摩尔机器,您可以在该机器上以某种方式设置时间并将其用作倒计时,一旦达到0就触发警报。

启动状态为“空闲”,如果按“keySet_in”,可以通过按“keyUp_in”增加分钟来设置分钟,或者按“keyDown_in”减少分钟。 如果您按任何其他键,倒计时将转到“开始”并以默认值1分钟开始。还有LED可以控制时钟上的小数点和数字的高亮显示。那些并不重要,并且尽我所能地工作。

从分钟选择中,您可以通过按“keyRight_in”到达第二个计数器的第一个/第二个数字。您可以按照与分钟相同的方式增加/减少它。 一旦达到较小的数值,如果你再次“keyRight_in”,你就会开始。 除非你在几分钟内,否则你总是可以使用keyLeft_in返回,在这种情况下它什么都不做。

如果在倒计时期间按任意键,倒计时将取消并重置为前一个值的空闲状态。如果它达到0,警报将一直播放,直到您按下按钮然后您将返回空闲状态。

现在我们尝试在FPGA上实现我的代码,并且有一些非常奇怪的错误行为,即使我们重写了整个代码并检查了一点点,我和老师都无法解释。现在这些老师也只是学生,所以我想他们的知识并不完美,也许这里的人可能会知道更多:

我们所拥有的一种奇怪的行为是(例如,从我的记忆中,可能不是100%准确)大多数按钮都不起作用。当试图增加/减少分钟时,它只会在9和8之间切换。当试图增加/减少更高的数字秒时,它总是一次需要2步(从9到7到5,......)。大多数其他按钮甚至没有反应,例如你可以不使用leftKey_in。 初始值是1分钟。我们也尝试了3种不同的FPGA。

从那以后,我想到了解决这些问题的两种(不太可能的)选择: 1.为流程P1添加敏感列表 2.添加'state< = idle; '作为初始值(包含在代码中)

所以我知道这是一个很长的文本墙,所以如果任何人仍在阅读,那么代码是: pastebin link(使用stackoverflow的代码有问题,所以我使用了pastebin)

library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    use work.TIMER_PKG.ALL;

entity CONTROLLER is
    port (
        -- Clocks and Reset
        sysclk_in   : in std_logic;
        clk10hz_in  : in std_logic;
        reset_in    : in std_logic;




        -- Alu
        alu_instruction_out : out ALU_INSTRUCTION_TYPE;
        timer_is_zero_in : in std_logic;

        -- Key Controls
        keyUp_in    : in std_logic;
        keyDown_in  : in std_logic;
        keyLeft_in  : in std_logic;
        keyRight_in : in std_logic;
        keySet_in   : in std_logic;

        -- 7 Segment Display
        disp_highlight_out : out std_logic_vector(3 downto 0);
        disp_dots_out      : out std_logic_vector(3 downto 0);

        -- Alarm
        alarm_out   : out std_logic
    );
end CONTROLLER;

architecture Behavioral of CONTROLLER is

type fsm_type is ( IDLE, START, WAIT10HZ, CNTDWN, TIMER_END, RESTORE,
                                                SEL_MIN, INC_MIN, DEC_MIN,
                                                SEL_SEC10, INC_sec10, DEC_SEC10,
                                                SEL_SEC, INC_SEC, DEC_SEC);

signal state, next_state : fsm_type;
state <= idle;

begin

P1:process is begin
wait until rising_edge(sysclk_in);
state <= next_state;
end process;


P2:process(sysclk_in, reset_in, keyup_in, keydown_in, keyleft_in, keyright_in, keyset_in,
                                timer_is_zero_in) is begin
        next_state <= state;
        case state is
                when IDLE =>
                        if (keyright_in or keyup_in or keydown_in or keyleft_in) = '1' then
                                next_state <= start;
                        elsif keyset_in = '1' then
                                next_state <= sel_min;
                        end if;

                when Start =>
                        next_state <= wait10hz;

                when wait10hz =>
                        if clk10hz_in = '1' then
                        next_state <= cntdwn;
                        end if;

                when cntdwn =>
                        if timer_is_zero_in = '1' then
                        next_state <= timer_end;
                        elsif (keyright_in or keyup_in or keydown_in or keyleft_in or keyset_in) ='1' then
                        next_state <= restore;
                        end if;

                when restore =>
                        next_state <= start;

                when timer_end =>
                if (keyright_in or keyup_in or keydown_in or keyleft_in or keyset_in) ='1' then
                        next_state <= idle;
                        end if;

                when sel_min =>
                if keyup_in = '1' then
                        next_state <= inc_min;
                elsif keydown_in ='1' then
                        next_state <= dec_min;
                elsif keyright_in ='1' then
                        next_state <= sel_sec10;
                end if;

                when sel_sec10 =>
                        if keyleft_in = '1' then
                        next_state <= sel_min;
                        elsif keyright_in ='1' then
                        next_state <= sel_sec;
                        elsif keyup_in = '1' then
                        next_state <= inc_sec10;
                        elsif keydown_in = '1' then
                        next_state <= dec_sec10;
                        end if;

                when sel_sec=>
                        if keyleft_in ='1' then
                        next_state <= sel_sec10;
                        elsif keyright_in ='1' then
                        next_state <= start;
                        elsif keydown_in ='1' then
                        next_state <= dec_sec;
                        elsif keyup_in ='1' then
                        next_state <= inc_sec;
                        end if;

                when inc_min =>
                next_state <= sel_min;

                when dec_min =>
                next_state <= sel_min;

                when inc_sec10 =>
                next_state <= sel_sec10;

                when dec_sec10 =>
                next_state <= sel_sec10;

                when inc_sec =>
                next_state <= sel_sec;

                when dec_sec =>
                next_state <= sel_sec;

                when others => null;


        end case;

        if  reset_in = '1' then
        next_state <= idle;
        end if;

                        disp_highlight_out <= "1111";
                  disp_dots_out <= "0101";
                  alarm_out <= '0';
                  alu_instruction_out <= alu_none;



        case state is
                when start =>
                alu_instruction_out <= alu_store;
                disp_highlight_out <= "1111";
                disp_dots_out <= "0101";

                when idle =>
                alu_instruction_out <= alu_none;
                disp_highlight_out <= "1111";
                disp_dots_out <= "0101";
                alarm_out <= '0';

                when wait10hz =>
                alu_instruction_out <= alu_none;
                disp_highlight_out <= "1111";
                disp_dots_out <= "0101";


                when cntdwn =>
                alu_instruction_out <= alu_dec_timer;
                disp_highlight_out <= "1111";
                disp_dots_out <= "0101";

                when timer_end =>
                alu_instruction_out <= alu_store;
                disp_highlight_out <= "1111";
                disp_dots_out <= "0101";
                alarm_out <= '1';

                when sel_min =>
                alu_instruction_out <= alu_none;
                disp_highlight_out <= "1000";
                disp_dots_out <= "0101";

                when inc_min =>
                alu_instruction_out <= alu_single_inc_min;
                disp_highlight_out <= "1000";
                disp_dots_out <= "0101";

                when dec_min =>
                alu_instruction_out <= alu_single_dec_min;
                disp_highlight_out <= "1000";
                disp_dots_out <= "0101";

                when sel_sec10 =>
                alu_instruction_out <= alu_none;
                disp_highlight_out <= "0100";
                disp_dots_out <= "0101";

                when dec_sec10 =>
                alu_instruction_out <= alu_single_dec_sec10;
                disp_highlight_out <= "0100";
                disp_dots_out <= "0101";               

                when inc_sec10 =>
                alu_instruction_out <= alu_single_inc_sec10;
                disp_highlight_out <= "0100";
                disp_dots_out <= "0101";

                when dec_sec =>
                alu_instruction_out <= alu_single_dec_sec;
                disp_highlight_out <= "0010";
                disp_dots_out <= "0101";

                when inc_sec =>
                alu_instruction_out <= alu_single_inc_sec;
                disp_highlight_out <= "0010";
                disp_dots_out <= "0101";

                when sel_sec =>
                alu_instruction_out <= alu_none;
                disp_highlight_out <= "0010";
                disp_dots_out <= "0101";
                when others =>
                alu_instruction_out <= alu_none;


                end case;
                end process;



end Behavioral;

希望有人可以帮忙! 迎接

1 个答案:

答案 0 :(得分:1)

虽然可以实现2进程状态机,但是更难以阅读和管理。

但是,如果您使用2个流程,那么: - 第一个进程是时钟(就像你的P1一样) - 第二个过程在灵敏度列表中使用了所有输入。您的P2在灵敏度列表中没有“clk_10hz_in”且没有“状态”信号。但是您在灵敏度列表中有“sysclk_in”,它不用作组合P2中的输入。

- &GT;如果不同信号在(几乎)同时改变电平(例如sysclk_in和其他信号),这可能会导致意外行为。