2017-04-23 84 views
0

我正在嘗試將廉價FPGA(ep2c5t144 Altera Cyclone II迷你電路板)與SNES連接起來,以便作爲SNES控制器使用。到目前爲止,它似乎可以開啓和關閉......目前的問題是,開機後它可以工作約1秒鐘......但是似乎一直處於一種狀態直到它被重置。VHDL - SNES使用FPGA通過控制器端口接口

由於我花了很長時間來看一個邏輯問題的代碼,我開始懷疑這是否使用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; 
+0

你的問題表明你沒有模擬你的代碼,而是試圖在板凳上調試它。編寫測試臺並首先模擬您的代碼是一個更好的主意。如果您在測試平臺中生成自己的刺激,則可以完全控制。模擬是可重現的。您可以輕鬆探測設計中的任何位置以幫助您進行調試。您可以自動檢查設計的行爲(手動檢查太容易出錯)。在堆棧溢出的情況下,如果你有一個測試臺,爲了幫助其他人可以運行你的模擬來重現你的錯誤。 –

+0

@MatthewTaylor在這種情況下,只有在您正確模擬輸入的異步性時,測試平臺才能正常工作。我敢打賭,奧倫港的答案是正確的。缺乏同步可能會鎖定FSM。 – JHBonarius

回答

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

+0

嗨,你是完全正確的......但它實際上是SNES的時鐘和鎖存輸入是問題,大概是因爲他們正在使用比內部時鐘快得多的單獨時鐘。按鈕輸入實際上很好......我應該在我以前的文章中提到,按鈕輸入實際上是在內部控制的,並且在同一時鐘,對不起!我還修正了我的代碼,使其更像移位寄存器......而不是純粹以鎖定時間爲基礎。非常感謝!我將不得不閱讀爲什麼添加一堆觸發器使其現在擺動正確。 –

+0

理解這些概念很重要。基本上,時鐘域之間的任何信號傳輸(或異步到同步)必須正確同步。順便說一句,upvote會很好;) –