【问题标题】:VHDL - SNES Interface via controller port using FPGAVHDL - 使用 FPGA 通过控制器端口的 SNES 接口
【发布时间】:2017-04-23 16:34:38
【问题描述】:

我正在尝试将廉价的 FPGA(ep2c5t144 Altera Cyclone II 迷你板)与 SNES 接口,以充当 SNES 控制器。到目前为止,它似乎可以打开和关闭......当前的问题是,它在打开后工作大约 1 秒......但随后似乎卡在一个状态直到它被重置。

由于我花了很长时间查看逻辑问题的代码,我开始怀疑使用 FPGA 是否有一些奇怪的怪癖,但我已经尝试测试任何未定义的状态,这并没有解决问题。我将在下面发布 SNES 代码,以及显示问题的廉价逻辑分析仪的输出。警告,代码非常混乱......尤其是我改变了一些东西来尝试修复它。任何想法都非常感谢!

非常感谢您的帮助!

逻辑分析仪的问题:

When a request works - State transitions occur as expected

When a request fails - SEEMS to incorrectly transition directly to "working" state and get stuck for some reason

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity snes_controller is
    generic (
        hp : integer := 300
    );
    port    (
        clk       : in std_logic;
        latch    : in std_logic;
        data      : out std_logic := '0';
        clock     : in std_logic;
        enable    : in std_logic;
        btn_B : in std_logic;
        btn_Y : in std_logic;
        btn_select : in std_logic;
        btn_start : in std_logic;
        btn_up : in std_logic;
        btn_down : in std_logic;
        btn_left : in std_logic;
        btn_right : in std_logic;
        btn_A : in std_logic;
        btn_X : in std_logic;
        btn_L : in std_logic;
        btn_R : in std_logic;
        helpA : out std_logic := '0';
        helpB : out std_logic := '0';
        helpC : out std_logic := '0';
        helpD : out std_logic := '0';
        helpE : out std_logic := '0'
    );
end entity;

architecture Behav of snes_controller is

    signal buttons : unsigned(16 downto 0) := "10000000000000000";

    type state_type is (s_idle, s_latching_1, s_latching_2, s_working);
    signal state : state_type := s_idle;

    type cycle_type is (c_high, c_low);
    signal cycle : cycle_type := c_high;

begin       

    process (clk)
        variable i : integer range 0 to 16;
        variable count : integer range 0 to hp;
    begin   
        if(rising_edge(clk)) then

            data <= not buttons(i);

            if(state = s_latching_1 or state = s_latching_2 or state = s_working) then
                if(count < hp) then
                    count := count+1;
                else
                    count := 0;

                    if(state = s_latching_1) then
                        if(latch = '1') then
                            state <= s_latching_2;
                            buttons(0) <= btn_B;
                            buttons(1) <= btn_Y;
                            buttons(2) <= btn_select;
                            buttons(3) <= btn_start;
                            buttons(4) <= btn_up;
                            buttons(5) <= btn_down;
                            buttons(6) <= btn_left;
                            buttons(7) <= btn_right;    
                            buttons(8) <= btn_A;
                            buttons(9) <= btn_X;
                            buttons(10) <= btn_L;
                            buttons(11) <= btn_R;
                        else
                            state <= s_idle;
                        end if;
                    elsif(state = s_latching_2) then
                        state <= s_working;
                        i := 0;
                        cycle <= c_high;
                    elsif(state = s_working) then       
                        if(latch = '1') then
                            state <= s_idle;
                            helpD <= '1';
                        elsif(cycle = c_low) then
                            cycle <= c_high;
                            if(i < 16) then
                                i := i+1;
                            else
                                state <= s_idle;
                                helpD <= '0';
                                helpE <= '0';
                            end if;
                        else
                            cycle <= c_low;
                        end if;
                    end if;

                end if;
            elsif(state = s_idle) then
                if(latch = '1') then
                    state <= s_latching_1;
                    count := 0;
                    i := 0;
                end if;
            else
                helpE <= '1';
                state <= s_idle;
                count := 0;
                i := 0;
            end if;

        end if;

    end process;

    process(state)
    begin
        if(state = s_idle) then
            helpA <= '0';
            helpB <= '0';
        elsif(state = s_latching_1) then
            helpA <= '1';
            helpB <= '0';
        elsif(state = s_latching_2) then
            helpA <= '0';
            helpB <= '1';
        elsif(state = s_working) then
            helpA <= '1';
            helpB <= '1';
        else
            helpA <= clk;
            helpB <= not clk;
        end if;

        if(cycle = c_low) then
            helpC <= '0';
        elsif(cycle = c_high) then
            helpC <= '1';
        end if;
    end process;

end Behav;

【问题讨论】:

  • 你的问题表明你不是在模拟你的代码,而是试图在工作台上调试它。编写一个测试平台并首先模拟您的代码是一个非常 更好的主意。如果您在测试台中生成自己的激励,则可以完全控制。模拟是可重现的。您可以轻松探测设计中的任何位置以帮助您进行调试。您可以自动检查设计的行为(手动检查太容易出错)。在 Stack Overflow 的上下文中,如果您有一个测试平台,以帮助您,其他人可以运行您的模拟来重现您的错误。
  • @MatthewTaylor 在这种情况下,只有正确模拟输入的异步性,测试台才能工作。我敢打赌 Oron Port 的答案是正确的。缺少同步器可能会锁定 FSM。

标签: vhdl fpga super nintendo


【解决方案1】:

您正在使用异步外部输入并将它们馈送到基于时钟的同步状态机。采样中的亚稳态可能会导致您的问题。确保为每个输入信号至少实现一个双触发器同步器。

在此处了解更多信息:http://webee.technion.ac.il/~ran/papers/Metastability%20and%20Synchronizers.posted.pdf

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity snes_controller is
    generic (
        hp : integer := 300
    );
    port    (
        clk       : in std_logic;
        latch    : in std_logic;
        data      : out std_logic := '0';
        clock     : in std_logic;
        enable    : in std_logic;
        btn_B : in std_logic;
        btn_Y : in std_logic;
        btn_select : in std_logic;
        btn_start : in std_logic;
        btn_up : in std_logic;
        btn_down : in std_logic;
        btn_left : in std_logic;
        btn_right : in std_logic;
        btn_A : in std_logic;
        btn_X : in std_logic;
        btn_L : in std_logic;
        btn_R : in std_logic;
        helpA : out std_logic := '0';
        helpB : out std_logic := '0';
        helpC : out std_logic := '0';
        helpD : out std_logic := '0';
        helpE : out std_logic := '0'
    );
end entity;

architecture Behav of snes_controller is

    signal synch0 : unsigned(11 downto 0) := (others => '0');
    signal synch1 : unsigned(11 downto 0) := (others => '0');
    signal synch2 : unsigned(11 downto 0) := (others => '0');
    signal buttons : unsigned(16 downto 0) := "10000000000000000";

    type state_type is (s_idle, s_latching_1, s_latching_2, s_working);
    signal state : state_type := s_idle;

    type cycle_type is (c_high, c_low);
    signal cycle : cycle_type := c_high;

begin       

    process (clk)
        variable i : integer range 0 to 16;
        variable count : integer range 0 to hp;
    begin   
        if(rising_edge(clk)) then
                            synch0(0) <= btn_B;
                            synch0(1) <= btn_Y;
                            synch0(2) <= btn_select;
                            synch0(3) <= btn_start;
                            synch0(4) <= btn_up;
                            synch0(5) <= btn_down;
                            synch0(6) <= btn_left;
                            synch0(7) <= btn_right;    
                            synch0(8) <= btn_A;
                            synch0(9) <= btn_X;
                            synch0(10) <= btn_L;
                            synch0(11) <= btn_R;
            synch1 <= synch0;
            synch2 <= synch1;    

            data <= not buttons(i);

            if(state = s_latching_1 or state = s_latching_2 or state = s_working) then
                if(count < hp) then
                    count := count+1;
                else
                    count := 0;

                    if(state = s_latching_1) then
                        if(latch = '1') then
                            state <= s_latching_2;
                            buttons(11 downto 0) <= synch2(11 downto 0);
                        else
                            state <= s_idle;
                        end if;
                    elsif(state = s_latching_2) then
                        state <= s_working;
                        i := 0;
                        cycle <= c_high;
                    elsif(state = s_working) then       
                        if(latch = '1') then
                            state <= s_idle;
                            helpD <= '1';
                        elsif(cycle = c_low) then
                            cycle <= c_high;
                            if(i < 16) then
                                i := i+1;
                            else
                                state <= s_idle;
                                helpD <= '0';
                                helpE <= '0';
                            end if;
                        else
                            cycle <= c_low;
                        end if;
                    end if;

                end if;
            elsif(state = s_idle) then
                if(latch = '1') then
                    state <= s_latching_1;
                    count := 0;
                    i := 0;
                end if;
            else
                helpE <= '1';
                state <= s_idle;
                count := 0;
                i := 0;
            end if;

        end if;

    end process;

    process(state)
    begin
        if(state = s_idle) then
            helpA <= '0';
            helpB <= '0';
        elsif(state = s_latching_1) then
            helpA <= '1';
            helpB <= '0';
        elsif(state = s_latching_2) then
            helpA <= '0';
            helpB <= '1';
        elsif(state = s_working) then
            helpA <= '1';
            helpB <= '1';
        else
            helpA <= clk;
            helpB <= not clk;
        end if;

        if(cycle = c_low) then
            helpC <= '0';
        elsif(cycle = c_high) then
            helpC <= '1';
        end if;
    end process;

end Behav;

另外,我建议创建某种过滤器来处理按钮点击的去抖动。 http://www.eng.utah.edu/~cs5780/debouncing.pdf

【讨论】:

  • 嗨,你完全正确......但实际上问题在于 SNES 的时钟和锁存器输入,可能是因为它们使用的是比内部时钟快得多的单独时钟.按钮输入实际上很好......我应该在上一篇文章中提到按钮输入实际上是在内部控制的,并且在同一个时钟上,对不起!我还修复了我的代码,使其更像一个移位寄存器......而不是纯粹基于时间的锁存器。非常感谢!我将不得不阅读为什么添加一堆人字拖会导致它现在以正确的方式摆动。
  • 理解这些概念很重要。基本上时钟域(或异步到同步)之间的任何信号传输都必须正确同步。顺便说一句,赞成票会很好;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
  • 2020-04-04
  • 1970-01-01
  • 1970-01-01
  • 2017-06-13
  • 2021-08-24
  • 1970-01-01
相关资源
最近更新 更多