2017-04-23 11 views
0

SNES 컨트롤러로 ACT를 사용하기 위해 저렴한 FPGA (ep2c5t144 Altera Cyclone II 미니 보드)와 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

귀하의 질문은 귀하가 귀하의 코드를 시뮬레이트하지 않았지만 벤치에서 디버깅하려고한다는 것을 나타냅니다. 테스트 벤치를 작성하고 코드를 먼저 시뮬레이트하는 것이 훨씬 좋은 생각입니다. 테스트 벤치에서 직접 자극을 생성하면 완벽하게 제어 할 수 있습니다. 시뮬레이션을 재현 할 수 있습니다. 디버깅을 돕기 위해 설계의 어느 곳에서나 쉽게 프로브 할 수 있습니다. 디자인의 동작을 자동으로 확인할 수 있습니다 (수동 검사도 오류가 발생하기 쉽습니다). Stack Overflow의 컨텍스트에서 테스트 벤치를 가지고 있었기 때문에 다른 사람이 실수를 재현하기 위해 시뮬레이션을 실행할 수있었습니다. –

+0

@MatthewTaylor이 경우 테스트 벤치는 입력의 비동기를 정확하게 시뮬레이트하는 경우에만 작동합니다. 나는 Oron 항구에 의한 답이 맞을 것이라고 확신한다. 싱크로 나이저가 없으면 FSM이 잠길 수 있습니다. – JHBonarius

답변

1

비동기 외부 입력을 이용하여 동기 클록 기반 상태 기계로 공급된다. 샘플링의 준 안정성 (metastability)은 문제를 일으킬 수 있습니다. 모든 입력 신호에 적어도 2 개의 2- 플롭 싱크로 나이저를 구현해야합니다.

여기에 대해 자세히 알아보기 : 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

이러한 개념을 이해하는 것이 중요합니다. 기본적으로 클록 도메인 간 (또는 비동기와 동기) 모든 신호 전송은 적절하게 동기화되어야합니다. BTW, upvote 좋을 것이다;) –