--------------------------------------------------------------------------- -- (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) = "1111") then case bincnt_reg(5 downto 4) is when "00" => break_pressed_next <= not(keyboard_response(1)); --0x30 when "10" => shift_pressed_next <= not(keyboard_response(1)); --0x10 when "11" => 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 <= 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;