aboutsummaryrefslogtreecommitdiffstats
path: root/keyboard.vhd
diff options
context:
space:
mode:
authorMike Stirling <opensource@mikestirling.co.uk>2011-07-29 21:14:17 +0100
committerMike Stirling <opensource@mikestirling.co.uk>2011-07-29 21:14:17 +0100
commitabb341bccf06bca03f56d2bc7612b2f81721b454 (patch)
tree5724ccb6d2321e7c58140779f81207aea0311bec /keyboard.vhd
parent3ea54eb8b11e87333ad809c7bbfd9537c2fc8250 (diff)
downloadfpga-bbc-abb341bccf06bca03f56d2bc7612b2f81721b454.tar.gz
fpga-bbc-abb341bccf06bca03f56d2bc7612b2f81721b454.tar.bz2
fpga-bbc-abb341bccf06bca03f56d2bc7612b2f81721b454.zip
Work in progress. Added PS/2 keyboard interface, hardware debugger. Interrupt test output to 6522 (remove later). Fixed error in pin assignments that blocked access to Flash chip select. Added reading sideways ROMs from external Flash (all but BASIC masked off for now).
Diffstat (limited to 'keyboard.vhd')
-rw-r--r--keyboard.vhd251
1 files changed, 251 insertions, 0 deletions
diff --git a/keyboard.vhd b/keyboard.vhd
new file mode 100644
index 0000000..0558469
--- /dev/null
+++ b/keyboard.vhd
@@ -0,0 +1,251 @@
+-- BBC keyboard implementation with interface to PS/2
+--
+-- (C) 2011 Mike Stirling
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+entity keyboard is
+port (
+ CLOCK : in std_logic;
+ nRESET : in std_logic;
+ CLKEN_1MHZ : in std_logic;
+
+ -- PS/2 interface
+ PS2_CLK : in std_logic;
+ PS2_DATA : in std_logic;
+
+ -- If 1 then column is incremented automatically at
+ -- 1 MHz rate
+ AUTOSCAN : in std_logic;
+
+ COLUMN : in std_logic_vector(3 downto 0);
+ ROW : in std_logic_vector(2 downto 0);
+
+ -- 1 when currently selected key is down (AUTOSCAN disabled)
+ KEYPRESS : out std_logic;
+ -- 1 when any key is down (except row 0)
+ INT : out std_logic;
+ -- BREAK key output - 1 when pressed
+ BREAK_OUT : out std_logic;
+
+ -- DIP switch inputs
+ DIP_SWITCH : in std_logic_vector(7 downto 0)
+ );
+end entity;
+
+architecture rtl of keyboard is
+
+-- PS/2 interface
+component ps2_intf is
+generic (filter_length : positive := 8);
+port(
+ CLK : in std_logic;
+ nRESET : in std_logic;
+
+ -- PS/2 interface (could be bi-dir)
+ PS2_CLK : in std_logic;
+ PS2_DATA : in std_logic;
+
+ -- Byte-wide data interface - only valid for one clock
+ -- so must be latched externally if required
+ DATA : out std_logic_vector(7 downto 0);
+ VALID : out std_logic;
+ ERROR : out std_logic
+ );
+end component;
+
+-- Interface to PS/2 block
+signal keyb_data : std_logic_vector(7 downto 0);
+signal keyb_valid : std_logic;
+signal keyb_error : std_logic;
+
+-- Internal signals
+type key_matrix is array(0 to 9) of std_logic_vector(7 downto 0);
+signal keys : key_matrix;
+signal col : unsigned(3 downto 0);
+signal release : std_logic;
+signal extended : std_logic;
+begin
+
+ ps2 : ps2_intf port map (
+ CLOCK, nRESET,
+ PS2_CLK, PS2_DATA,
+ keyb_data, keyb_valid, keyb_error
+ );
+
+ -- Column counts automatically when AUTOSCAN is enabled, otherwise
+ -- value is loaded from external input
+ process(CLOCK,nRESET)
+ begin
+ if nRESET = '0' then
+ col <= (others => '0');
+ elsif rising_edge(CLOCK) then
+ if AUTOSCAN = '0' then
+ -- If autoscan disabled then transfer current COLUMN to counter
+ -- immediately (don't wait for next 1 MHz cycle)
+ col <= unsigned(COLUMN);
+ elsif CLKEN_1MHZ = '1' then
+ -- Otherwise increment the counter once per 1 MHz tick
+ col <= col + 1;
+ end if;
+ end if;
+ end process;
+
+ -- Generate interrupt if any key in currently scanned column is pressed
+ -- (apart from in row 0). Output selected key status if autoscan disabled.
+ process(keys,col,ROW,AUTOSCAN)
+ variable k : std_logic_vector(7 downto 0);
+ begin
+ -- Shortcut to current key column
+ k := keys(to_integer(col));
+
+ -- Interrupt if any key pressed in rows 1 to 7.
+ INT <= k(7) or k(6) or k(5) or k(4) or k(3) or k(2) or k(1);
+
+ -- Determine which key is pressed
+ -- Inhibit output during auto-scan
+ if AUTOSCAN = '0' then
+ KEYPRESS <= k(to_integer(unsigned(ROW)));
+ else
+ KEYPRESS <= '0';
+ end if;
+ end process;
+
+ -- Decode PS/2 data
+ process(CLOCK,nRESET)
+ begin
+ if nRESET = '0' then
+ release <= '0';
+ extended <= '0';
+
+ BREAK_OUT <= '0';
+
+ keys(0) <= (others => '0');
+ keys(1) <= (others => '0');
+ keys(2) <= (others => '0');
+ keys(3) <= (others => '0');
+ keys(4) <= (others => '0');
+ keys(5) <= (others => '0');
+ keys(6) <= (others => '0');
+ keys(7) <= (others => '0');
+ keys(8) <= (others => '0');
+ keys(9) <= (others => '0');
+ elsif rising_edge(CLOCK) then
+ -- Copy DIP switches through to row 0
+ keys(2)(0) <= DIP_SWITCH(7);
+ keys(3)(0) <= DIP_SWITCH(6);
+ keys(4)(0) <= DIP_SWITCH(5);
+ keys(5)(0) <= DIP_SWITCH(4);
+ keys(6)(0) <= DIP_SWITCH(3);
+ keys(7)(0) <= DIP_SWITCH(2);
+ keys(8)(0) <= DIP_SWITCH(1);
+ keys(9)(0) <= DIP_SWITCH(0);
+
+ if keyb_valid = '1' then
+ -- Decode keyboard input
+ if keyb_data = X"e0" then
+ -- Extended key code follows
+ extended <= '1';
+ elsif keyb_data = X"f0" then
+ -- Release code follows
+ release <= '1';
+ else
+ -- Cancel extended/release flags for next time
+ release <= '0';
+ extended <= '0';
+
+ -- Decode scan codes
+ case keyb_data is
+ when X"12" => keys(0)(0) <= not release; -- Left SHIFT
+ when X"59" => keys(0)(0) <= not release; -- Right SHIFT
+ when X"15" => keys(0)(1) <= not release; -- Q
+ when X"09" => keys(0)(2) <= not release; -- F10 (F0)
+ when X"16" => keys(0)(3) <= not release; -- 1
+ when X"58" => keys(0)(4) <= not release; -- CAPS LOCK
+ when X"11" => keys(0)(5) <= not release; -- LEFT ALT (SHIFT LOCK)
+ when X"0D" => keys(0)(6) <= not release; -- TAB
+ when X"76" => keys(0)(7) <= not release; -- ESCAPE
+ when X"14" => keys(1)(0) <= not release; -- LEFT/RIGHT CTRL (CTRL)
+ when X"26" => keys(1)(1) <= not release; -- 3
+ when X"1D" => keys(1)(2) <= not release; -- W
+ when X"1E" => keys(1)(3) <= not release; -- 2
+ when X"1C" => keys(1)(4) <= not release; -- A
+ when X"1B" => keys(1)(5) <= not release; -- S
+ when X"1A" => keys(1)(6) <= not release; -- Z
+ when X"05" => keys(1)(7) <= not release; -- F1
+ when X"25" => keys(2)(1) <= not release; -- 4
+ when X"24" => keys(2)(2) <= not release; -- E
+ when X"23" => keys(2)(3) <= not release; -- D
+ when X"22" => keys(2)(4) <= not release; -- X
+ when X"21" => keys(2)(5) <= not release; -- C
+ when X"29" => keys(2)(6) <= not release; -- SPACE
+ when X"06" => keys(2)(7) <= not release; -- F2
+ when X"2E" => keys(3)(1) <= not release; -- 5
+ when X"2C" => keys(3)(2) <= not release; -- T
+ when X"2D" => keys(3)(3) <= not release; -- R
+ when X"2B" => keys(3)(4) <= not release; -- F
+ when X"34" => keys(3)(5) <= not release; -- G
+ when X"2A" => keys(3)(6) <= not release; -- V
+ when X"04" => keys(3)(7) <= not release; -- F3
+ when X"0C" => keys(4)(1) <= not release; -- F4
+ when X"3D" => keys(4)(2) <= not release; -- 7
+ when X"36" => keys(4)(3) <= not release; -- 6
+ when X"35" => keys(4)(4) <= not release; -- Y
+ when X"33" => keys(4)(5) <= not release; -- H
+ when X"32" => keys(4)(6) <= not release; -- B
+ when X"03" => keys(4)(7) <= not release; -- F5
+ when X"3E" => keys(5)(1) <= not release; -- 8
+ when X"43" => keys(5)(2) <= not release; -- I
+ when X"3C" => keys(5)(3) <= not release; -- U
+ when X"3B" => keys(5)(4) <= not release; -- J
+ when X"31" => keys(5)(5) <= not release; -- N
+ when X"3A" => keys(5)(6) <= not release; -- M
+ when X"0B" => keys(5)(7) <= not release; -- F6
+ when X"83" => keys(6)(1) <= not release; -- F7
+ when X"46" => keys(6)(2) <= not release; -- 9
+ when X"44" => keys(6)(3) <= not release; -- O
+ when X"42" => keys(6)(4) <= not release; -- K
+ when X"4B" => keys(6)(5) <= not release; -- L
+ when X"41" => keys(6)(6) <= not release; -- ,
+ when X"0A" => keys(6)(7) <= not release; -- F8
+ when X"4E" => keys(7)(1) <= not release; -- -
+ when X"45" => keys(7)(2) <= not release; -- 0
+ when X"4D" => keys(7)(3) <= not release; -- P
+ when X"0E" => keys(7)(4) <= not release; -- ` (@)
+ when X"4C" => keys(7)(5) <= not release; -- ;
+ when X"49" => keys(7)(6) <= not release; -- .
+ when X"01" => keys(7)(7) <= not release; -- F9
+ when X"55" => keys(8)(1) <= not release; -- = (^)
+ when X"5D" => keys(8)(2) <= not release; -- # (_)
+ when X"54" => keys(8)(3) <= not release; -- [
+ when X"52" => keys(8)(4) <= not release; -- '
+ when X"5B" => keys(8)(5) <= not release; -- ]
+ when X"4A" => keys(8)(6) <= not release; -- /
+ when X"61" => keys(8)(7) <= not release; -- \
+ when X"6B" => keys(9)(1) <= not release; -- LEFT
+ when X"72" => keys(9)(2) <= not release; -- DOWN
+ when X"75" => keys(9)(3) <= not release; -- UP
+ when X"5A" => keys(9)(4) <= not release; -- RETURN
+ when X"66" => keys(9)(5) <= not release; -- BACKSPACE (DELETE)
+ when X"69" => keys(9)(6) <= not release; -- END (COPY)
+ when X"74" => keys(9)(7) <= not release; -- RIGHT
+
+ -- F12 is used for the BREAK key, which in the real BBC asserts
+ -- reset. Here we pass this out to the top level which may
+ -- optionally OR it in to the system reset
+ when X"07" => BREAK_OUT <= not release; -- F12 (BREAK)
+
+ when others => null;
+ end case;
+
+ end if;
+ end if;
+ end if;
+ end process;
+
+end architecture;
+
+