Странное поведение конечного автомата в VHDL

Так что я недавно начал изучать VHDL как часть практики в университете. На этот раз наша задача состояла в том, чтобы создать аппарат для швартовки, на котором вы можете установить время определенным образом и использовать его в качестве обратного отсчета, вызывая сигнал тревоги, как только он достигает 0.

Начальное состояние "бездействует", если вы нажмете "keySet_in", вы можете установить минуты, нажав "keyUp_in", чтобы увеличить его, или "keyDown_in", чтобы уменьшить его. Если вы нажмете любую другую клавишу, обратный отсчет перейдет к "Пуск" и начнется со значения по умолчанию 1 минута. Есть также светодиоды для управления десятичными точками на часах и подсветкой цифр. Это не важно, и они работали, насколько я могу судить.

Из выбора минут вы можете получить первую / вторую цифру второго счетчика, нажав "keyRight_in". Вы можете увеличить / уменьшить его так же, как с помощью минут. Как только вы достигнете меньшего значения, вы начнете, если вы снова "keyRight_in". Вы всегда можете вернуться с keyLeft_in, если у вас нет минут, в этом случае он ничего не делает.

Если вы нажмете любую клавишу во время обратного отсчета, обратный отсчет прекратится и вернется в режим ожидания с предыдущим значением. Если он достигнет 0, будильник будет звучать до тех пор, пока вы не нажмете кнопку, а затем вернетесь в режим ожидания.

Теперь мы попытались реализовать мой код на FPGA сегодня, и было некоторое странное неправильное поведение, которое ни я, ни преподаватели не могли объяснить, даже если мы переписали весь код и проверяли его по крупицам. Теперь эти учителя также являются просто учениками, поэтому я предполагаю, что их знания не совершенны, и, возможно, кто-то здесь может знать больше:

Например, у нас было странное поведение (из моей памяти, возможно, не на 100% точно), что большинство кнопок не работают. При попытке увеличить / уменьшить минуты, он будет просто переключаться между 9 и 8. При попытке увеличить / уменьшить большее количество секунд, он всегда будет делать 2 шага одновременно (от 9 до 7 до 5, ...). Большинство других кнопок даже не реагировали, например, вы не можете вернуться с помощью leftKey_in. Начальное значение составляло 1 минуту. Мы также пробовали 3 разных ПЛИС.

С тех пор я подумал о 2 (маловероятных) вариантах решения проблем: 1. добавление списка чувствительности к процессу P1 2. добавление ' state <= idle; 'как начальное значение (включено в код)

Так что я знаю, что это довольно стена текста, поэтому, если кто-то все еще читает, вот код: ссылка на вставку (возникли проблемы с использованием кода в stackru, поэтому я использовал 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 ответ

Хотя можно реализовать двухпроцессный конечный автомат, его труднее читать и управлять им.

однако, если вы используете 2-процессы, то: - 1-й процесс синхронизируется (как и ваш P1) - 2-й процесс имеет ВСЕ используемые входы в списке чувствительности. Ваш P2 не имеет сигнала "clk_10hz_in" и NO "состояние" в списке чувствительности. НО у вас есть "sysclk_in", который не используется в качестве входных данных в комбинаторном P2, в списке чувствительности.

-> это может привести к неожиданному поведению в случае, когда разные сигналы изменяют уровни в одно и то же время (например, sysclk_in и другие сигналы).

Другие вопросы по тегам