Papilio Plus/Keyboard Joystick
From Hamsterworks Wiki!
(Redirected from Papilio S6/Keyboard Joystick)
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;