Project

General

Profile

---------------------------------------------------------------------------
-- (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_keyboard_scanner is
port
(
clk : in std_logic;
reset_n : in std_logic;
enable : in std_logic; -- typically hsync or equiv timing
keyboard_response : in std_logic_vector(1 downto 0);
debounce_disable : in std_logic;
scan_enable : in std_logic;
keyboard_scan : out std_logic_vector(5 downto 0);
key_held : out std_logic;
shift_held : out std_logic;
keycode : out std_logic_vector(7 downto 0);
other_key_irq : out std_logic;
break_irq : out std_logic
);
end pokey_keyboard_scanner;

architecture vhdl of pokey_keyboard_scanner is
signal bincnt_next : std_logic_vector(5 downto 0);
signal bincnt_reg : std_logic_vector(5 downto 0);

signal break_pressed_next : std_logic;
signal break_pressed_reg : std_logic;

signal shift_pressed_next : std_logic;
signal shift_pressed_reg : std_logic;
signal control_pressed_next : std_logic;
signal control_pressed_reg : std_logic;
signal compare_latch_next : std_logic_vector(5 downto 0);
signal compare_latch_reg : std_logic_vector(5 downto 0);
signal keycode_latch_next : std_logic_vector(7 downto 0);
signal keycode_latch_reg : std_logic_vector(7 downto 0);
signal irq_next : std_logic;
signal irq_reg : std_logic;

signal break_irq_next : std_logic;
signal break_irq_reg : std_logic;
signal key_held_next : std_logic;
signal key_held_reg : std_logic;
signal my_key : std_logic;
signal state_next : std_logic_vector(1 downto 0);
signal state_reg : std_logic_vector(1 downto 0);
constant state_wait_key : std_logic_vector(1 downto 0) := "00";
constant state_key_bounce : std_logic_vector(1 downto 0) := "01";
constant state_valid_key : std_logic_vector(1 downto 0) := "10";
constant state_key_debounce : std_logic_vector(1 downto 0) := "11";
begin

-- register
process(clk,reset_n)
begin
if (reset_n = '0') then
bincnt_reg <= (others=>'0');
break_pressed_reg <= '0';
shift_pressed_reg <= '0';
control_pressed_reg <= '0';
compare_latch_reg <= (others=>'0');
keycode_latch_reg <= (others=>'1');
key_held_reg <= '0';
state_reg <= state_wait_key;
irq_reg <= '0';
break_irq_reg <= '0';
elsif (clk'event and clk = '1') then
bincnt_reg <= bincnt_next;
state_reg <= state_next;
break_pressed_reg <= break_pressed_next;
shift_pressed_reg <= shift_pressed_next;
control_pressed_reg <= control_pressed_next;
compare_latch_reg <= compare_latch_next;
keycode_latch_reg <= keycode_latch_next;
key_held_reg <= key_held_next;
state_reg <= state_next;
irq_reg <= irq_next;
break_irq_reg <= break_irq_next;
end if;
end process;

process (enable, keyboard_response, scan_enable, key_held_reg, my_key, state_reg,bincnt_reg, compare_latch_reg, break_pressed_next, break_pressed_reg, shift_pressed_reg, break_irq_reg, control_pressed_reg, keycode_latch_reg, debounce_disable)
begin
bincnt_next <= bincnt_reg;
state_next <= state_reg;
compare_latch_next <= compare_latch_reg;
irq_next <= '0';
break_irq_next <= '0';
break_pressed_next <= break_pressed_reg;
shift_pressed_next <= shift_pressed_reg;
control_pressed_next <= control_pressed_reg;
keycode_latch_next <= keycode_latch_reg;
key_held_next <= key_held_reg;
my_key <= '0';
if (bincnt_reg = compare_latch_reg or debounce_disable='1') then
my_key <= '1';
end if;
if (enable = '1' and scan_enable='1') then
bincnt_next <= std_logic_vector(unsigned(bincnt_reg) + 1); -- check another key
key_held_next<= '0';
case state_reg is
when state_wait_key =>
if (keyboard_response(0) = '0') then -- detected key press
if (debounce_disable = '1') then
keycode_latch_next <= control_pressed_reg&shift_pressed_reg&bincnt_reg;
irq_next <= '1';
key_held_next<= '1';
else
state_next <= state_key_bounce;
compare_latch_next <= bincnt_reg;
end if;
end if;
when state_key_bounce =>
if (keyboard_response(0) = '0') then -- detected key press
if (my_key = '1') then -- same key
keycode_latch_next <= control_pressed_reg&shift_pressed_reg&compare_latch_reg;
irq_next <= '1';
key_held_next<= '1';
state_next <= state_valid_key;
else -- different key (multiple keys pressed)
state_next <= state_wait_key;
end if;
else -- key not pressed
if (my_key = '1') then -- same key, no longer pressed
state_next <= state_wait_key;
end if;
end if;
when state_valid_key =>
key_held_next<= '1';
if (my_key = '1') then -- only response to my key
if (keyboard_response(0) = '1') then -- no longer pressed
state_next <= state_key_debounce;
end if;
end if;
when state_key_debounce =>
key_held_next<= '1';
if (my_key = '1') then
if (keyboard_response(0) = '1') then -- no longer pressed
key_held_next<= '0';
state_next <= state_wait_key;
else
state_next <= state_valid_key;
end if;
end if;

when others=>
state_next <= state_wait_key;
end case;
if (bincnt_reg(3 downto 0) = "0000") then
case bincnt_reg(5 downto 4) is
when "11" =>
break_pressed_next <= not(keyboard_response(1)); --0x30
when "01" =>
shift_pressed_next <= not(keyboard_response(1)); --0x10
when "00" =>
control_pressed_next <= not(keyboard_response(1)); -- 0x00
when others =>
--
end case;
end if;
end if;

if (break_pressed_next='1' and break_pressed_reg='0') then
break_irq_next <= '1';
end if;
end process;
-- outputs
keyboard_scan <= not(bincnt_reg);
key_held <= key_held_reg;
shift_held <= shift_pressed_reg;
keycode <= keycode_latch_reg;
other_key_irq <= irq_reg;
break_irq <= break_irq_reg;
end vhdl;
(15-15/30)