Papilio Plus/Keyboard Joystick

From Hamsterworks Wiki!

Revision as of 17:55, 4 February 2012 by User (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Papilio Plus has two PS/2 ports and two joystick ports, but not everybody has a DE9 style joystick. This project allows a PS/2 keyboard to be embedded into a project that usually uses a joystick.

Please note that as designed this required a clock of 32MHz, but can run at other speeds if minClockPulseLen and maxClockPulseLen are set appropriately

Source files

keyboardJoystick.vhd

Here is where the scancodes for the arrow keys and numbers 1 through 4 are decoded.

If you want to use different keys, change the constants "key_" appropriately.

----------------------------------------------------------------------------------
-- Engineer:       Mike Field <hamster@snap.net.nz>
-- 
-- Create Date:    20:56:04 10/03/2011 
-- Module Name:    keyboardJoystick - Behavioral 
-- Description:    
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity keyboardJoystick is
    Port ( clk32        : in  STD_LOGIC;
           ps2clk       : inout  STD_LOGIC;
           ps2data      : inout  STD_LOGIC;

           joy_up         : out  STD_LOGIC;
           joy_down      : out  STD_LOGIC;
           joy_left      : out  STD_LOGIC;
           joy_right      : out  STD_LOGIC;
           buttons      : out  STD_LOGIC_VECTOR(4 downto 0)
        );
end keyboardJoystick;

architecture Behavioral of keyboardJoystick is
   constant state_idle           : std_logic_vector (1 downto 0) := "00";
   constant state_keyup          : std_logic_vector (1 downto 0) := "01";
   constant state_extended       : std_logic_vector (1 downto 0) := "10";
   constant state_extended_keyup : std_logic_vector (1 downto 0) := "11";
   
   constant key_break    : std_logic_vector(7 downto 0) := x"F0";
   constant key_one        : std_logic_vector(7 downto 0) := x"16";
   constant key_two      : std_logic_vector(7 downto 0) := x"1e";
   constant key_three    : std_logic_vector(7 downto 0) := x"26";
   constant key_four     : std_logic_vector(7 downto 0) := x"25";
   constant key_extended : std_logic_vector(7 downto 0) := x"E0";
   constant key_ex_up     : std_logic_vector(7 downto 0) := x"75";
   constant key_ex_down  : std_logic_vector(7 downto 0) := x"72";
   constant key_ex_left  : std_logic_vector(7 downto 0) := x"6B";
   constant key_ex_right : std_logic_vector(7 downto 0) := x"74";
   
   type reg is record
      switches : std_logic_vector(7 downto 0); 
      state    : std_logic_vector(1 downto 0);
   end record;
   
   signal r : reg := ((others => '0'),(others => '0'));
   signal n : reg;

   COMPONENT ps2interface
   PORT(
      clk32    : IN std_logic;
      ps2clk   : IN std_logic;
      ps2data  : IN std_logic;          
      scancode : OUT std_logic_vector(7 downto 0);
      valid    : OUT std_logic
      );
   END COMPONENT;

   signal scancode : STD_LOGIC_VECTOR(7 downto 0);
   signal valid     : STD_LOGIC;
begin
   ps2clk   <= 'Z';
   ps2data  <= 'Z';
   
   joy_up       <= r.switches(0);
   joy_down      <= r.switches(1);
   joy_left      <= r.switches(2);
   joy_right   <= r.switches(3);
   buttons(3 downto 0) <= r.switches(7 downto 4);

   Inst_ps2interface: ps2interface PORT MAP(
      clk32    => clk32,
      ps2clk    => ps2clk,
      ps2data    => ps2data,
      scancode => scancode,
      valid    => valid
   );
      
   process(r, scancode, valid)
   begin
      n <= r;
      if valid = '1' then      
         case r.state is
         when   state_idle   =>
            case scancode is
            when key_one      =>  n.switches(4) <= '1';
            when key_two      =>  n.switches(5) <= '1';
            when key_three    =>  n.switches(6) <= '1';
            when key_four     =>  n.switches(7) <= '1';
            when key_break    =>  n.state <= state_keyup;
            when key_extended =>  n.state <= state_extended;
            when others       =>  n.state  <= state_idle;
            end case;   
            
         when state_keyup =>
            case scancode is
            when key_one      =>  n.switches(4) <= '0';
                                  n.state  <= state_idle;
            when key_two      =>  n.switches(5) <= '0';
                                  n.state  <= state_idle;
            when key_three    =>  n.switches(6) <= '0';
                                  n.state  <= state_idle;
            when key_four     =>  n.switches(7) <= '0';
                                  n.state  <= state_idle;
            when key_extended =>  n.state <= state_extended;
            when others       =>  n.state  <= state_idle;
            end case;   

         when state_extended =>
            case scancode is
            when key_ex_up    =>  n.switches(0) <= '1';
                                  n.state  <= state_idle;
            when key_ex_down  =>  n.switches(1) <= '1';
                                  n.state  <= state_idle;
            when key_ex_left  =>  n.switches(2) <= '1';
                                  n.state  <= state_idle;
            when key_ex_right =>  n.switches(3) <= '1';
                                  n.state  <= state_idle;
            when key_break    =>  n.state  <= state_extended_keyup;
            when others       =>  n.state  <= state_idle;
            end case;   

         when state_extended_keyup =>
            case scancode is
            when key_ex_up    =>  n.switches(0) <= '0';
                                  n.state  <= state_idle;
            when key_ex_down  =>  n.switches(1) <= '0';
                                  n.state  <= state_idle;
            when key_ex_left  =>  n.switches(2) <= '0';
                                  n.state  <= state_idle;
            when key_ex_right =>  n.switches(3) <= '0';
                                  n.state  <= state_idle;
            when others       =>  n.state  <= state_idle;
            end case;   
            
         when others =>
            n.state  <= state_idle;
         end case;
      end if;
   end process;
   
   process(clk32, n)
   begin
      if rising_edge(clk32) then 
         r <= n;
      end if;
   end process;
end Behavioral;

ps2interface.vhd

----------------------------------------------------------------------------------
-- Engineer:       Mike Field <hamster@snap.net.nz>
-- 
-- Create Date:    20:51:45 10/22/2011 
-- Module Name:    ps2interface - Behavioral 
-- Description:    Low level PS/2 interface - unidirectional
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ps2interface is
    Port ( clk32    : in  STD_LOGIC;
           ps2clk   : in  STD_LOGIC;
           ps2data  : in  STD_LOGIC;
           scancode : out STD_LOGIC_VECTOR (7 downto 0);
           valid    : out STD_LOGIC);
end ps2interface;

architecture Behavioral of ps2interface is
   constant state_idle      : std_logic_vector(1 downto 0) := "00";
   constant state_receiving : std_logic_vector(1 downto 0) := "01";
   constant state_waiting   : std_logic_vector(1 downto 0) := "10";
   constant state_received  : std_logic_vector(1 downto 0) := "11";
   
   constant minClockPulseLen : natural := 30*32; -- 30us @ 32MHz
   constant maxClockPulseLen : natural := 50*32; -- 50us @ 32MHz

   type reg is record
      state               	 : std_logic_vector(1 downto 0);
      clockCounter      	 : std_logic_vector(10 downto 0);
      dataReg            	 : std_logic_vector(10 downto 0);
      receivedCount     	 : std_logic_vector(3 downto 0);
      ps2clkDeglitch    	 : std_logic_vector(4 downto 0);
      ps2dataDeglitch   	 : std_logic_vector(4 downto 0);
      ps2lastClkDeglitched  : std_logic;
      ps2lastDataDeglitched : std_logic;
      ps2ClkDeglitched  	 : std_logic;
      ps2DataDeglitched 	 : std_logic;
      dataReceived      	 : std_logic;
   end record;
   signal r : reg := ("00",(others => '0'),(others => '0'),
                      (others => '0'),(others => '0'),(others => '0'),
                      '0','0','0','0','0');
   signal n : reg;
   signal dataReceived    : STD_LOGIC;
begin
   
	scancode  <= r.dataReg(8 downto 1);
   valid <= r.dataReceived;
      
   process(r, ps2clk, ps2data)
   begin
      n <= r;
      
      -- remember what the last signals were
      n.ps2lastClkDeglitched <= r.ps2clkDeglitched;
      n.ps2lastClkDeglitched <= r.ps2clkDeglitched;


      -- Deglitch the clock signal
      if ps2clk = '1' then
         if r.ps2clkDeglitch < 31 then
            n.ps2clkDeglitch <= r.ps2clkDeglitch+1;
         else
            n.ps2clkDeglitched <= '1';
            n.clockCounter     <= (others => '0');
         end if;
      else
         if r.ps2clkDeglitch > 0 then
            n.ps2clkDeglitch <= r.ps2clkDeglitch-1;
         else
            n.ps2clkDeglitched <= '0';
            n.clockCounter <= (others => '0');
         end if;      
      end if;

      -- Deglitch the data signal
      if ps2data = '1' then
         if r.ps2dataDeglitch < 31 then
            n.ps2dataDeglitch <= r.ps2dataDeglitch+1;
         else
            n.ps2dataDeglitched <= '1';
         end if;
      else
         if r.ps2dataDeglitch > 0 then
            n.ps2dataDeglitch <= r.ps2dataDeglitch-1;
         else
            n.ps2dataDeglitched <= '0';
         end if;
      end if;

      ----------------------------------------------------
      -- Now the actual processing of the tidied up signal
      ----------------------------------------------------
      case r.state is
      when   state_idle   =>
         -- Are we waiting for the ps2clk to go low? (start of data)
         n.clockCounter  <= (others => '0');
         n.receivedCount <= (others => '0');      
         n.dataReceived  <= '0';
         if r.ps2clkDeglitched = '0' then
            n.state <= state_receiving;
         end if;

      when state_receiving =>
         n.clockCounter <= r.clockCounter + 1;
         -- is the pulse too long?
         if r.clockCounter > maxClockPulseLen then
            if r.ps2clkDeglitched = '1' then
               n.state <= state_idle;
            else
               n.state <= state_receiving;
            end if;
         end if;
         
         if r.ps2lastClkDeglitched = '0' and r.ps2clkDeglitched = '1' then
            -- are we on the rising edge of the clock singal
            if r.clockCounter < minClockPulseLen then
               n.state <= state_idle;
            else
               n.receivedCount <= r.receivedCount+1;
               n.clockCounter  <= (others => '0');
               n.dataReg       <= r.ps2dataDeglitched & r.dataReg(10 downto 1);
               if r.receivedCount = 10 then
                  n.state            <= state_received;
               else
                  n.receivedCount    <= r.receivedCount+1;
               end if;
            end if;
         elsif r.ps2lastClkDeglitched = '1' and r.ps2clkDeglitched = '0' then
            -- are we on the falling edge of the clock singal
            if r.clockCounter < minClockPulseLen then
               n.state <= state_waiting;
            end if;
            n.clockCounter  <= (others => '0');
         end if;

      when state_received =>
         -- Check the start, parity and stopbits are valid, if all are correct, set the "data Received" signal
         if r.dataReg(10) = '1' and (r.dataReg(9) xor r.dataReg(8) xor r.dataReg(7) xor r.dataReg(6) xor r.dataReg(5) xor r.dataReg(4) xor r.dataReg(3) xor r.dataReg(2) xor r.dataReg(1)) = '1'  and r.dataReg (0) = '0' then            
--            n.scancode      <= r.dataReg(8 downto 1);
            n.dataReceived <= '1';
            n.state          <= state_idle;
         end if;

      when others =>
         -- We are waiting for the ps2clk to go high
         if r.ps2clkDeglitched = '1' then
            n.state <= state_idle;
         end if;
      end case;
   end process;
   
   process(clk32, n)
   begin
      if rising_edge(clk32) then 
         r <= n;
      end if;
   end process;
end Behavioral;

Personal tools