VHDL中有限状态机的奇怪行为 [英] Weird behaviour of finite state machine in VHDL

查看:27
本文介绍了VHDL中有限状态机的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So I've recently started learning VHDL as part of a practicum at the university. This time, our task was to create a moore-machine on which you can set the time in a certain way and use it as a countdown, triggering an alarm as soon as it reaches 0.

开始状态是空闲",如果你按keySet_in",你可以通过按keyUp_in"增加它或keyDown_in"减少它来设置分钟.如果您按任何其他键,倒计时将转到开始"并以默认值 1 分钟开始.还有LED控制时钟上的小数点和数字的突出显示.这些并不重要,据我所知,这些都在起作用.

The starting state is "idle", if you press "keySet_in" you can set the minutes by pressing "keyUp_in" to increase it or "keyDown_in" to decrease it. If you press any other key, the countdown will go to "start" and start with the default value of 1 Minute. There are also LEDs to controll the the decimal points on the clock and the highlighting of the digits. Those are not important tho and were working as far as I could tell.

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

From the minute selection you can reach the first/second-digit of the second counter by pressing "keyRight_in". You can increase/decrease it in the same way as with minutes. Once you have reached the lesser value digit you will go to start if you "keyRight_in" again. You can always go back with keyLeft_in unless you are at minutes, in that case it does nothing.

如果您在倒计时期间按任意键,倒计时将取消并重置为空闲状态并使用之前的值.如果达到 0,闹钟将一直播放,直到您按下按钮,然后您将返回空闲状态.

If you press any key during countdown, the countdown will cancel and reset to idle with the previous value. If it reaches 0, the alarm will play until you press a button and then you will go back to idle.

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

Now we tried implementing my code on an FPGA today and there was some very weird misbehaviour which neither me nor the teachers could explain even tho we rewrote the entire code and checked it bit for bit. Now those teachers are also just students so I imagine that their knowledge is not perfect and maybe someone here might know more:

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

The kind of weird behaviour we had was for example (from my memory, might not be 100% accurate) that most buttons would not work. When trying to increase/decrease the minutes, it would just toggle between 9 and 8. When trying to increase/decrease higher digit seconds, it would always take 2 steps at once (from 9 to 7 to 5, ...). Most of the other buttons didnt even react, you could for example not go back with leftKey_in. The initial value was 1 minute tho. We tried 3 different FPGA's as well.

从那时起,我想到了 2 个(不太可能)解决问题的选项:1.添加敏感列表到进程P12.添加'状态<=空闲;' 作为初始值(包含在代码中)

Since then I have thought of 2 (unlikely) options of solving the problems: 1. adding a sensitivty list to process P1 2. adding ' state <= idle; ' as initial value (included in the code)

所以我知道这是一大堆文字,所以如果有人还在阅读,这里是代码:pastebin 链接(在使用 stackoverflow 的代码时遇到问题,所以我使用了 pastebin)

So I know that this is quite a wall of text, so in case anyones still reading, heres the code: pastebin link (had problems using the code-thingy of stackoverflow, so I used 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;

希望有人能帮忙!问候

推荐答案

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

while it is possible to implement 2-process state-machine it is more difficult to read and manage.

但是,如果您使用 2-processes,则:- 第一个进程被计时(就像你的 P1 一样)- 第二个进程在敏感度列表中有所有使用过的输入.您的 P2 在灵敏度列表中没有clk_10hz_in"和状态"信号.但是你有sysclk_in",它没有用作组合 P2 中的输入,在敏感性列表中.

however, if you use 2-processes then: - 1st process is clocked (as is your P1) - 2nd process has ALL used inputs in the sensitivity list. Your P2 has NO "clk_10hz_in" and NO "state" signal in the sensitivity list. BUT you have "sysclk_in", that is not used as input in the combinatorial P2, in the sensitivity list.

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

--> this might lead to unexpected behavior in case of different signals changing levels at (almost) the same time (e.g. sysclk_in and other signals).

这篇关于VHDL中有限状态机的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆