|
---------------------------------------------------------------------------
|
|
-- (c) 2013 mark watson
|
|
-- I am happy for anyone to use this for non-commercial use.
|
|
-- If my vhdl files are used commercially or otherwise sold,
|
|
-- please contact me for explicit permission at scrameta (gmail).
|
|
-- This applies for source and binary form and derived works.
|
|
---------------------------------------------------------------------------
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
ENTITY pokey_ps2_decoder IS
|
|
PORT
|
|
(
|
|
CLK : IN STD_LOGIC;
|
|
RESET_N : std_logic;
|
|
-- ENABLE : IN STD_LOGIC; TODO Pokey debounce and scanning can be disabled
|
|
|
|
-- ps2 keyboard input
|
|
KEY_EVENT : IN STD_LOGIC;
|
|
KEY_CODE : IN STD_LOGIC_VECTOR(7 downto 0);
|
|
KEY_EXTENDED : IN STD_LOGIC;
|
|
KEY_UP : IN STD_LOGIC;
|
|
|
|
-- pokey output
|
|
KBCODE : OUT STD_LOGIC_VECTOR(7 downto 0);
|
|
KEY_HELD : OUT STD_LOGIC;
|
|
SHIFT_PRESSED : OUT STD_LOGIC;
|
|
BREAK_PRESSED : OUT STD_LOGIC;
|
|
KEY_INTERRUPT : OUT STD_LOGIC;
|
|
|
|
-- other output
|
|
CONSOL_START : OUT STD_LOGIC;
|
|
CONSOL_SELECT : OUT STD_LOGIC;
|
|
CONSOL_OPTION : OUT STD_LOGIC;
|
|
|
|
VIRTUAL_STICKS : out std_logic_vector(7 downto 0);
|
|
VIRTUAL_TRIGGER : out std_logic_vector(3 downto 0);
|
|
|
|
SYSTEM_RESET : out std_logic;
|
|
|
|
VIRTUAL_KEYS : out std_logic_vector(3 downto 0)
|
|
);
|
|
END pokey_ps2_decoder;
|
|
|
|
ARCHITECTURE vhdl OF pokey_ps2_decoder IS
|
|
signal left_shift_pressed_reg : std_logic;
|
|
signal left_shift_pressed_next : std_logic;
|
|
signal right_shift_pressed_reg : std_logic;
|
|
signal right_shift_pressed_next : std_logic;
|
|
|
|
signal left_control_pressed_reg : std_logic;
|
|
signal left_control_pressed_next : std_logic;
|
|
signal right_control_pressed_reg : std_logic;
|
|
signal right_control_pressed_next : std_logic;
|
|
|
|
signal kbcode_next : std_logic_vector(7 downto 0);
|
|
signal kbcode_reg : std_logic_vector(7 downto 0); -- XXX remove unused upper bits
|
|
|
|
signal interrupt_next : std_logic;
|
|
signal interrupt_reg : std_logic;
|
|
|
|
signal break_next : std_logic;
|
|
signal break_reg : std_logic;
|
|
|
|
signal key_held_next : std_logic;
|
|
signal key_held_reg : std_logic;
|
|
|
|
signal start_next : std_logic;
|
|
signal start_reg : std_logic;
|
|
signal select_next : std_logic;
|
|
signal select_reg : std_logic;
|
|
signal option_next : std_logic;
|
|
signal option_reg : std_logic;
|
|
|
|
signal virtual_up_next : std_logic;
|
|
signal virtual_up_reg : std_logic;
|
|
signal virtual_down_next : std_logic;
|
|
signal virtual_down_reg : std_logic;
|
|
signal virtual_left_next : std_logic;
|
|
signal virtual_left_reg : std_logic;
|
|
signal virtual_right_next : std_logic;
|
|
signal virtual_right_reg : std_logic;
|
|
signal virtual_stick_pressed_next : std_logic;
|
|
signal virtual_stick_pressed_reg : std_logic;
|
|
|
|
signal system_reset_next : std_logic;
|
|
signal system_reset_reg : std_logic;
|
|
|
|
signal virtual_keys_next : std_logic_vector(3 downto 0);
|
|
signal virtual_keys_reg : std_logic_vector(3 downto 0);
|
|
|
|
signal no_kbcode_update : std_logic;
|
|
BEGIN
|
|
-- register
|
|
process(clk,reset_n)
|
|
begin
|
|
if (reset_n = '0') then
|
|
left_shift_pressed_reg <= '0';
|
|
right_shift_pressed_reg <= '0';
|
|
|
|
left_control_pressed_reg <= '0';
|
|
right_control_pressed_reg <= '0';
|
|
|
|
kbcode_reg <= X"3F";
|
|
|
|
interrupt_reg <= '0';
|
|
|
|
break_reg <= '0';
|
|
|
|
key_held_reg <= '0';
|
|
|
|
start_reg <= '0';
|
|
select_reg <= '0';
|
|
option_reg <= '0';
|
|
|
|
virtual_up_reg <= '0';
|
|
virtual_down_reg <= '0';
|
|
virtual_left_reg <= '0';
|
|
virtual_right_reg <= '0';
|
|
virtual_stick_pressed_reg <= '0';
|
|
|
|
system_reset_reg <= '0';
|
|
|
|
virtual_keys_reg <= (others=>'0');
|
|
elsif (clk'event and clk='1') then
|
|
left_shift_pressed_reg <= left_shift_pressed_next;
|
|
right_shift_pressed_reg <= right_shift_pressed_next;
|
|
|
|
left_control_pressed_reg <= left_control_pressed_next;
|
|
right_control_pressed_reg <= right_control_pressed_next;
|
|
|
|
kbcode_reg <= kbcode_next;
|
|
|
|
interrupt_reg <= interrupt_next;
|
|
|
|
break_reg <= break_next;
|
|
|
|
key_held_reg <= key_held_next;
|
|
|
|
start_reg <= start_next;
|
|
select_reg <= select_next;
|
|
option_reg <= option_next;
|
|
|
|
virtual_up_reg <= virtual_up_next;
|
|
virtual_down_reg <= virtual_down_next;
|
|
virtual_left_reg <= virtual_left_next;
|
|
virtual_right_reg <= virtual_right_next;
|
|
virtual_stick_pressed_reg <= virtual_stick_pressed_next;
|
|
|
|
system_reset_reg <= system_reset_next;
|
|
virtual_keys_reg <= virtual_keys_next;
|
|
end if;
|
|
end process;
|
|
|
|
-- update key pressed
|
|
process(key_event, key_up, key_code, key_extended, left_shift_pressed_reg, right_shift_pressed_reg, left_control_pressed_reg, right_control_pressed_reg, kbcode_reg, break_reg, start_reg, select_reg, option_reg, key_held_reg, no_kbcode_update, virtual_up_reg, virtual_down_reg, virtual_left_reg, virtual_right_reg, virtual_stick_pressed_reg, system_reset_reg, virtual_keys_reg)
|
|
begin
|
|
left_shift_pressed_next <= left_shift_pressed_reg;
|
|
right_shift_pressed_next <= right_shift_pressed_reg;
|
|
|
|
left_control_pressed_next <= left_control_pressed_reg;
|
|
right_control_pressed_next <= right_control_pressed_reg;
|
|
|
|
kbcode_next <= kbcode_reg;
|
|
interrupt_next <= '0';
|
|
|
|
break_next <= break_reg;
|
|
|
|
start_next <= start_reg;
|
|
select_next <= select_reg;
|
|
option_next <= option_reg;
|
|
|
|
virtual_up_next <= virtual_up_reg;
|
|
virtual_down_next <= virtual_down_reg;
|
|
virtual_left_next <= virtual_left_reg;
|
|
virtual_right_next <= virtual_right_reg;
|
|
virtual_stick_pressed_next <= virtual_stick_pressed_reg;
|
|
|
|
system_reset_next <= system_reset_reg;
|
|
virtual_keys_next <= virtual_keys_reg;
|
|
|
|
key_held_next <= key_held_reg;
|
|
|
|
no_kbcode_update <= '0';
|
|
|
|
-- Core functionality exactly as the Atari layout
|
|
if (key_event = '1') then
|
|
interrupt_next <= not(key_up);
|
|
key_held_next <= not(key_up);
|
|
|
|
case key_extended&key_code is
|
|
|
|
-- Basic mapping - should allow all keys on Atari, just fiddly
|
|
when
|
|
'0'&X"AA"|'1'&X"AA"| -- BAT SUCCESSFUL
|
|
'0'&X"FC"|'1'&X"FC" -- BAT FAIL
|
|
=>
|
|
no_kbcode_update <= '1';
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '0'&X"4B" => --L
|
|
kbcode_next <= X"00";
|
|
when '0'&X"3B" => --J
|
|
kbcode_next <= X"01";
|
|
when '0'&X"4C" => --;
|
|
kbcode_next <= X"02";
|
|
when '0'&X"42" => --K
|
|
kbcode_next <= X"05";
|
|
when '0'&X"79" => --+
|
|
kbcode_next <= X"06";
|
|
when '0'&X"7C" => --*
|
|
kbcode_next <= X"07";
|
|
when '0'&X"44" => --O
|
|
kbcode_next <= X"08";
|
|
when '0'&X"4D" => --P
|
|
kbcode_next <= X"0A";
|
|
when '0'&X"3C" => --U
|
|
kbcode_next <= X"0B";
|
|
when '0'&X"5A" => --Enter
|
|
kbcode_next <= X"0C";
|
|
when '0'&X"43" => --I
|
|
kbcode_next <= X"0D";
|
|
when '0'&X"4E" => -- -
|
|
kbcode_next <= X"0E";
|
|
when '0'&X"55" => -- =
|
|
kbcode_next <= X"0F";
|
|
|
|
when '0'&X"2A" => --V
|
|
kbcode_next <= X"10";
|
|
when '0'&X"05" => --Help (Using F1)
|
|
kbcode_next <= X"11";
|
|
when '0'&X"21" => --C
|
|
kbcode_next <= X"12";
|
|
when '0'&X"32" => --B
|
|
kbcode_next <= X"15";
|
|
when '0'&X"22" => --X
|
|
kbcode_next <= X"16";
|
|
when '0'&X"1A" => --Z
|
|
kbcode_next <= X"17";
|
|
when '0'&X"25" => --4
|
|
kbcode_next <= X"18";
|
|
when '0'&X"26" => --3
|
|
kbcode_next <= X"1A";
|
|
when '0'&X"36" => --6
|
|
kbcode_next <= X"1B";
|
|
when '0'&X"76" => --Esc
|
|
kbcode_next <= X"1C";
|
|
when '0'&X"2E" => --5
|
|
kbcode_next <= X"1D";
|
|
when '0'&X"1E" => --2
|
|
kbcode_next <= X"1E";
|
|
when '0'&X"16" => --1
|
|
kbcode_next <= X"1F";
|
|
|
|
when '0'&X"41" => --,
|
|
kbcode_next <= X"20";
|
|
when '0'&X"29" => --Spc
|
|
kbcode_next <= X"21";
|
|
when '0'&X"49" => --.
|
|
kbcode_next <= X"22";
|
|
when '0'&X"31" => --N
|
|
kbcode_next <= X"23";
|
|
when '0'&X"3A" => --M
|
|
kbcode_next <= X"25";
|
|
when '0'&X"4A" => --/
|
|
kbcode_next <= X"26";
|
|
when '1'&X"11" => --Inv
|
|
kbcode_next <= X"27";
|
|
when '0'&X"2D" => --R
|
|
kbcode_next <= X"28";
|
|
when '0'&X"24" => --E
|
|
kbcode_next <= X"2A";
|
|
when '0'&X"35" => --Y
|
|
kbcode_next <= X"2B";
|
|
when '0'&X"0D" => --Tab
|
|
kbcode_next <= X"2C";
|
|
when '0'&X"2C" => --T
|
|
kbcode_next <= X"2D";
|
|
when '0'&X"1D" => --W
|
|
kbcode_next <= X"2E";
|
|
when '0'&X"15" => --Q
|
|
kbcode_next <= X"2F";
|
|
|
|
when '0'&X"46" => --9
|
|
kbcode_next <= X"30";
|
|
when '0'&X"45" => --0
|
|
kbcode_next <= X"32";
|
|
when '0'&X"3D" => --7
|
|
kbcode_next <= X"33";
|
|
when '0'&X"66" => --Backspace
|
|
kbcode_next <= X"34";
|
|
when '0'&X"3E" => --8
|
|
kbcode_next <= X"35";
|
|
when '0'&X"54" => --< (using [)
|
|
kbcode_next <= X"36";
|
|
when '0'&X"5B" => --> (using ])
|
|
kbcode_next <= X"37";
|
|
when '0'&X"2B" => --F
|
|
kbcode_next <= X"38";
|
|
when '0'&X"33" => --H
|
|
kbcode_next <= X"39";
|
|
when '0'&X"23" => --D
|
|
kbcode_next <= X"3A";
|
|
when '0'&X"58" => --Caps
|
|
kbcode_next <= X"3C";
|
|
when '0'&X"34" => --G
|
|
kbcode_next <= X"3D";
|
|
when '0'&X"1B" => --S
|
|
kbcode_next <= X"3E";
|
|
when '0'&X"1C" => --A
|
|
kbcode_next <= X"3F";
|
|
|
|
when '0'&X"77" => --Break - XXX BUG, also presses 14, since E1 ext code...
|
|
no_kbcode_update <= '1';
|
|
break_next <= not(key_up);
|
|
key_held_next <= '0';
|
|
when '1'&X"77" => --Break
|
|
no_kbcode_update <= '1';
|
|
break_next <= not(key_up);
|
|
key_held_next <= '0';
|
|
|
|
-- XXX BUGS
|
|
-- i) press shift when already holding key - does not update kbcode
|
|
-- ii) press key, then press another, then release second key. Should go back to first...
|
|
when '0'&X"12" => --Left shift
|
|
no_kbcode_update <= '1';
|
|
left_shift_pressed_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '0'&X"59" => --Right shift
|
|
no_kbcode_update <= '1';
|
|
right_shift_pressed_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"14" => --Left control
|
|
no_kbcode_update <= '1';
|
|
left_control_pressed_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '1'&X"14" => --Right control
|
|
no_kbcode_update <= '1';
|
|
right_control_pressed_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"06" => --Start (F2)
|
|
no_kbcode_update <= '1';
|
|
start_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '0'&X"04" => --Select (F3)
|
|
no_kbcode_update <= '1';
|
|
select_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '0'&X"0C" => --Option (F4)
|
|
no_kbcode_update <= '1';
|
|
option_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
-- TODO will also be useful to cursor control...
|
|
when '1'&X"75" => -- up
|
|
no_kbcode_update <= '1';
|
|
virtual_up_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '1'&X"72" => -- down
|
|
no_kbcode_update <= '1';
|
|
virtual_down_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '1'&X"6b" => -- left
|
|
no_kbcode_update <= '1';
|
|
virtual_left_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '1'&X"74" => -- right
|
|
no_kbcode_update <= '1';
|
|
virtual_right_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
when '1'&X"27" => -- right windows key -> fire button
|
|
no_kbcode_update <= '1';
|
|
virtual_stick_pressed_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"0a" => -- f8 => system reset
|
|
no_kbcode_update <= '1';
|
|
virtual_keys_next(0) <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"01" => -- f9 => system reset
|
|
no_kbcode_update <= '1';
|
|
virtual_keys_next(1) <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"09" => -- f10 => system reset
|
|
no_kbcode_update <= '1';
|
|
virtual_keys_next(2) <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"78" => -- f11 => system reset
|
|
no_kbcode_update <= '1';
|
|
virtual_keys_next(3) <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when '0'&X"07" => -- f12 => system reset
|
|
no_kbcode_update <= '1';
|
|
system_reset_next <= not(key_UP);
|
|
interrupt_next <= '0';
|
|
key_held_next <= '0';
|
|
|
|
when others =>
|
|
no_kbcode_update <= '1';
|
|
-- nop
|
|
-- Idea: Use Windows key and Alt for atari shift/control. Then use keyboard ones for 'nice' mapping as displayed on keyboard?
|
|
end case;
|
|
|
|
if (key_up = '1' or no_kbcode_update = '1') then
|
|
kbcode_next <= kbcode_reg;
|
|
else
|
|
kbcode_next(7 downto 6) <= (left_control_pressed_reg or right_control_pressed_reg)&(left_shift_pressed_reg or right_shift_pressed_reg);
|
|
end if;
|
|
end if;
|
|
|
|
-- Then override a few for convenience
|
|
-- e.g. if we press '#' on the keyboard we want to see '#' on the atari, even though on the atari its shift a different key.
|
|
|
|
--http://atariwiki.de/wiki/Wiki.jsp?page=KBCODE
|
|
-- $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
|
|
-- $00 L J ; F1 F2 K + * O P U CR I - =
|
|
-- $10 V Help C F3 F4 B X Z 4 3 6 Esc 5 2 1
|
|
-- $20 , Spc . N M / Inv R E Y Tab T W Q
|
|
-- $30 9 0 7 BS 8 < > F H D Caps G S A
|
|
--together with Shift Key: add +$40
|
|
--together with Control key: add +$80
|
|
|
|
-- Would be great to have option of using real Atari keyboard, but probably not worthwhile yet.
|
|
|
|
end process;
|
|
|
|
-- output
|
|
kbcode <= kbcode_reg;
|
|
KEY_HELD <= key_held_reg;
|
|
shift_pressed <= left_shift_pressed_reg or right_shift_pressed_reg;
|
|
break_pressed <= break_reg;
|
|
|
|
key_interrupt <= interrupt_reg;
|
|
|
|
consol_start <= start_reg;
|
|
consol_select <= select_reg;
|
|
consol_option <= option_reg;
|
|
|
|
VIRTUAL_STICKS <= not(virtual_right_reg&virtual_left_reg&virtual_down_reg&virtual_up_reg&virtual_right_reg&virtual_left_reg&virtual_down_reg&virtual_up_reg);
|
|
VIRTUAL_TRIGGER <= "00"¬(virtual_stick_pressed_reg)¬(virtual_stick_pressed_reg);
|
|
|
|
system_reset <= system_reset_reg;
|
|
virtual_keys <= virtual_keys_reg;
|
|
|
|
END vhdl;
|