2017-04-23 6 views
0

Ich arbeite an dem Versuch, ein billiges FPGA (das Altera Cyclone II Mini-Board ep2c5t144) mit einem SNES zu verbinden, um als SNES-Controller zu arbeiten. Bis jetzt scheint es ein- und auszuschalten ... mit dem aktuellen Problem, es funktioniert nach dem Einschalten für etwa 1 Sekunde ... aber dann scheint es in einem Zustand stecken zu bleiben, bis es zurückgesetzt wird.VHDL - SNES Schnittstelle über Controller-Port mit FPGA

Da ich mich lange mit dem Code für ein logisches Problem beschäftigt habe, frage ich mich, ob es eine merkwürdige Eigenart ist, FPGAs zu verwenden, aber ich habe bereits versucht, nach Zuständen zu suchen, die nicht definiert sind und das hat das Problem nicht behoben. Ich werde den SNES-Code unten und den Ausgang von meinem billigen Logikanalysator veröffentlichen, der das Problem zeigt. Warnung, der Code ist ziemlich chaotisch ... vor allem, wenn ich etwas herumwechsle, um es zu reparieren. Irgendwelche Ideen überhaupt werden sehr geschätzt!

Vielen Dank im Voraus für jede Hilfe!

Problem vom Logikanalysator:

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

Ihre Frage schlägt vor, dass Sie Ihren Code nicht simulieren, aber versuchen, es auf der Bank zu debuggen. Es ist eine viel bessere Idee, eine Testbench zu schreiben und zuerst Ihren Code zu simulieren. Wenn Sie in einer Testbench Ihren eigenen Stimulus erzeugen, haben Sie die volle Kontrolle. Eine Simulation ist reproduzierbar. Sie können überall in Ihrem Design testen, um beim Debuggen zu helfen. Sie können das Verhalten Ihres Entwurfs automatisch überprüfen (manuelle Überprüfung ist zu fehleranfällig). Wenn Sie im Rahmen von "Stack Overflow" eine Testbench gehabt hätten, könnte Ihnen jemand anders helfen, Ihre Simulation auszuführen, um Ihren Fehler zu reproduzieren. –

+0

@MatthewTaylor In diesem Fall würde ein Prüfstand nur funktionieren, wenn Sie die Asynchronität der Eingänge korrekt simulieren würden. Ich wette, dass die Antwort von Oron Port korrekt ist. Das Fehlen von Synchronisierern blockiert wahrscheinlich die FSMs. – JHBonarius

Antwort

1

Sie verwenden asynchrone externe Eingänge und führen sie in eine synchrone, taktbasierte Zustandsmaschine. Metastabilität bei der Probenahme kann zu Ihrem Problem führen. Stellen Sie sicher, dass Sie für jedes Eingangssignal mindestens einen Zwei-Flop-Synchronizer implementieren.

Lesen Sie mehr darüber hier: 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; 

Außerdem schlage ich vor, eine Art Filter erstellen Entprellung von Tastenklicks zu handhaben. http://www.eng.utah.edu/~cs5780/debouncing.pdf

+0

Hallo, Sie waren genau richtig ... aber es waren tatsächlich die Takt- und Latch-Eingänge der SNES, die das Problem waren, vermutlich weil sie an einer separaten Uhr arbeiteten, die viel schneller ist als die interne Uhr. Die Tasteneingaben waren eigentlich in Ordnung ... Ich hätte in meinem vorherigen Beitrag erwähnen sollen, dass die Tasteneingaben tatsächlich intern gesteuert werden, und zwar zur selben Uhr, sorry! Ich habe auch meinen Code so eingestellt, dass er mehr wie ein Schieberegister funktioniert ... im Gegensatz dazu, dass er rein zeitbasiert vom Latch ist. Danke vielmals! Ich muss darüber nachdenken, warum das Hinzufügen einer Menge Flip-Flops dazu führt, dass es jetzt richtig herumschwingt. –

+0

Es ist wichtig, diese Konzepte zu verstehen. Grundsätzlich muss jede Übertragung von Signalen zwischen Taktdomänen (oder asynchron zu synchron) korrekt synchronisiert werden. BTW, ein upvote wird nett sein;) –