mirror of
https://github.com/mandl/Apple_II_vhdl.git
synced 2024-12-27 10:32:58 +00:00
add PS2 Keyboard
This commit is contained in:
parent
cc4743296e
commit
5258fcf4d9
45
src/PS2/Debouncer.vhd
Normal file
45
src/PS2/Debouncer.vhd
Normal file
@ -0,0 +1,45 @@
|
||||
-- (C) Rui T. Sousa from http://sweet.ua.pt/~a16360
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.STD_LOGIC_ARITH.ALL;
|
||||
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
||||
|
||||
entity Debouncer is
|
||||
generic (Delay : positive);
|
||||
port (
|
||||
Clock : in STD_LOGIC;
|
||||
Reset : in STD_LOGIC;
|
||||
Input : in STD_LOGIC;
|
||||
Output : out STD_LOGIC
|
||||
);
|
||||
end Debouncer;
|
||||
|
||||
architecture Behavioral of Debouncer is
|
||||
|
||||
signal DelayCounter : natural range 0 to Delay;
|
||||
signal Internal : STD_LOGIC;
|
||||
|
||||
begin
|
||||
|
||||
process(Clock, Reset)
|
||||
begin
|
||||
if rising_edge(Clock) then
|
||||
if Reset = '1' then
|
||||
Output <= '0';
|
||||
Internal <= '0';
|
||||
DelayCounter <= 0;
|
||||
else
|
||||
if Input /= Internal then
|
||||
Internal <= Input;
|
||||
DelayCounter <= 0;
|
||||
elsif DelayCounter = Delay then
|
||||
Output <= Internal;
|
||||
else
|
||||
DelayCounter <= DelayCounter + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
166
src/PS2/KeyboardMapper.vhd
Normal file
166
src/PS2/KeyboardMapper.vhd
Normal file
@ -0,0 +1,166 @@
|
||||
-- (C) Rui T. Sousa from http://sweet.ua.pt/~a16360
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_arith.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
|
||||
entity KeyboardMapper is
|
||||
port (
|
||||
Clock : in std_logic;
|
||||
Reset : in std_logic;
|
||||
PS2Busy : in std_logic;
|
||||
PS2Error : in std_logic;
|
||||
DataReady : in std_logic;
|
||||
DataByte : in std_logic_vector(7 downto 0);
|
||||
Send : out std_logic;
|
||||
Command : out std_logic_vector(7 downto 0);
|
||||
CodeReady : out std_logic;
|
||||
ScanCode : out std_logic_vector(9 downto 0)
|
||||
);
|
||||
end KeyboardMapper;
|
||||
|
||||
-- ScanCode(9) = 1 -> Extended
|
||||
-- = 0 -> Regular (Not Extended)
|
||||
-- ScanCode(8) = 1 -> Break
|
||||
-- = 0 -> Make
|
||||
-- ScanCode(7 downto 0) -> Key Code
|
||||
|
||||
architecture Behavioral of KeyboardMapper is
|
||||
|
||||
type StateType is (ResetKbd, ResetAck, WaitForBAT, Start, Extended, ExtendedBreak, Break, LEDs, CheckAck);
|
||||
signal State : StateType := Start;
|
||||
signal CapsLock : STD_LOGIC;
|
||||
signal NumLock : STD_LOGIC;
|
||||
signal ScrollLock : STD_LOGIC;
|
||||
-- signal PauseON : STD_LOGIC;
|
||||
|
||||
begin
|
||||
|
||||
process(Reset, PS2Error, Clock)
|
||||
begin
|
||||
if Reset = '1' or PS2Error = '1' then
|
||||
CapsLock <= '0';
|
||||
NumLock <= '0';
|
||||
ScrollLock <= '0';
|
||||
-- PauseON <= '0';
|
||||
Send <= '0';
|
||||
Command <= (others => '0');
|
||||
CodeReady <= '0';
|
||||
ScanCode <= (others => '0');
|
||||
State <= Start;
|
||||
elsif rising_edge(Clock) then
|
||||
case State is
|
||||
when ResetKbd =>
|
||||
if PS2Busy = '0' then
|
||||
Send <= '1';
|
||||
Command <= x"FF";
|
||||
State <= ResetAck;
|
||||
end if;
|
||||
when ResetAck =>
|
||||
Send <= '0';
|
||||
if Dataready = '1' then
|
||||
if DataByte = x"FA" then
|
||||
State <= WaitForBAT;
|
||||
else
|
||||
State <= ResetKbd;
|
||||
end if;
|
||||
end if;
|
||||
when WaitForBAT =>
|
||||
if DataReady = '1' then
|
||||
if DataByte = x"AA" then -- BAT(self test) completed successfully
|
||||
State <= Start;
|
||||
else
|
||||
State <= ResetKbd;
|
||||
end if;
|
||||
end if;
|
||||
when Start =>
|
||||
CodeReady <= '0';
|
||||
if DataReady = '1' then
|
||||
case DataByte is
|
||||
when x"E0" =>
|
||||
State <= Extended;
|
||||
when x"F0" =>
|
||||
State <= Break;
|
||||
when x"FA" => --Acknowledge
|
||||
null;
|
||||
when x"AA" =>
|
||||
State <= Start;
|
||||
when x"FC" =>
|
||||
State <= ResetKbd;
|
||||
when x"58" =>
|
||||
Send <= '1';
|
||||
Command <= x"ED";
|
||||
CapsLock <= not CapsLock;
|
||||
ScanCode <= "00" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= LEDs;
|
||||
when x"77" =>
|
||||
Send <= '1';
|
||||
Command <= x"ED";
|
||||
NumLock <= not NumLock;
|
||||
ScanCode <= "00" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= LEDs;
|
||||
when x"7E" =>
|
||||
Send <= '1';
|
||||
Command <= x"ED";
|
||||
ScrollLock <= not ScrollLock;
|
||||
ScanCode <= "00" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= LEDs;
|
||||
when others =>
|
||||
ScanCode <= "00" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= Start;
|
||||
end case;
|
||||
end if;
|
||||
when Extended =>
|
||||
if DataReady = '1' then
|
||||
if DataByte = x"F0" then
|
||||
State <= ExtendedBreak;
|
||||
else
|
||||
ScanCode <= "10" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= Start;
|
||||
end if;
|
||||
end if;
|
||||
when ExtendedBreak =>
|
||||
if DataReady = '1' then
|
||||
ScanCode <= "11" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= Start;
|
||||
end if;
|
||||
when Break =>
|
||||
if DataReady = '1' then
|
||||
ScanCode <= "01" & DataByte;
|
||||
CodeReady <= '1';
|
||||
State <= Start;
|
||||
end if;
|
||||
when LEDs =>
|
||||
Send <= '0';
|
||||
CodeReady <= '0';
|
||||
if Dataready = '1' then
|
||||
if DataByte = x"FA" then
|
||||
Send <= '1';
|
||||
Command <= "00000" & CapsLock & NumLock & ScrollLock;
|
||||
State <= CheckAck;
|
||||
elsif DataByte = x"FE" then
|
||||
Send <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when CheckAck =>
|
||||
Send <= '0';
|
||||
if Dataready = '1' then
|
||||
if DataByte = x"FA" then
|
||||
State <= Start;
|
||||
elsif DataByte = x"FE" then
|
||||
Send <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
211
src/PS2/PS2Controller.vhd
Normal file
211
src/PS2/PS2Controller.vhd
Normal file
@ -0,0 +1,211 @@
|
||||
-- (C) Rui T. Sousa from http://sweet.ua.pt/~a16360
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_arith.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
|
||||
entity PS2Controller is
|
||||
GENERIC(
|
||||
clk_freq : INTEGER := 32 );-- system clock frequency in MHz
|
||||
port (
|
||||
Reset : in std_logic;
|
||||
Clock : in std_logic;
|
||||
PS2Clock : inout std_logic;
|
||||
PS2Data : inout std_logic;
|
||||
Send : in std_logic;
|
||||
Command : in std_logic_vector(7 downto 0);
|
||||
PS2Busy : out std_logic;
|
||||
PS2Error : buffer std_logic;
|
||||
DataReady : out std_logic;
|
||||
DataByte : out std_logic_vector(7 downto 0)
|
||||
);
|
||||
end PS2Controller;
|
||||
|
||||
architecture Behavioral of PS2Controller is
|
||||
|
||||
constant ClockFreq : natural := clk_freq; -- MHz
|
||||
constant Time100us : natural := 100 * ClockFreq;
|
||||
constant Time20us : natural := 20 * ClockFreq;
|
||||
constant DebounceDelay : natural := 16;
|
||||
|
||||
type StateType is (Idle, ReceiveData, InhibitComunication, RequestToSend, SendData, CheckAck, WaitRiseClock);
|
||||
signal State : StateType;
|
||||
signal BitsRead : natural range 0 to 10;
|
||||
signal BitsSent : natural range 0 to 10;
|
||||
signal Byte : std_logic_vector(7 downto 0);
|
||||
signal CountOnes : std_logic; -- One bit only to know if even or odd number of ones
|
||||
signal DReady : std_logic;
|
||||
signal PS2ClockPrevious : std_logic;
|
||||
signal PS2ClockOut : std_logic;
|
||||
signal PS2Clock_Z : std_logic;
|
||||
signal PS2Clock_D : std_logic;
|
||||
signal PS2DataOut : std_logic;
|
||||
signal PS2Data_Z : std_logic;
|
||||
signal PS2Data_D : std_logic;
|
||||
signal TimeCounter : natural range 0 to Time100us;
|
||||
|
||||
begin
|
||||
|
||||
DebounceClock: entity work.Debouncer
|
||||
generic map (Delay => DebounceDelay)
|
||||
port map (
|
||||
Clock => Clock,
|
||||
Reset => Reset,
|
||||
Input => PS2Clock,
|
||||
Output => PS2Clock_D
|
||||
);
|
||||
|
||||
DebounceData: entity work.Debouncer
|
||||
generic map (Delay => DebounceDelay)
|
||||
port map (
|
||||
Clock => Clock,
|
||||
Reset => Reset,
|
||||
Input => PS2Data,
|
||||
Output => PS2Data_D
|
||||
);
|
||||
|
||||
PS2Clock <= PS2ClockOut when PS2Clock_Z <= '0' else 'Z';
|
||||
PS2Data <= PS2DataOut when PS2Data_Z <= '0' else 'Z';
|
||||
|
||||
process(Reset, Clock)
|
||||
begin
|
||||
if rising_edge(Clock) then
|
||||
if Reset = '1' then
|
||||
PS2Clock_Z <= '1';
|
||||
PS2ClockOut <= '1';
|
||||
PS2Data_Z <= '1';
|
||||
PS2DataOut <= '1';
|
||||
DataReady <= '0';
|
||||
DReady <= '0';
|
||||
DataByte <= (others => '0');
|
||||
PS2Busy <= '0';
|
||||
PS2Error <= '0';
|
||||
BitsRead <= 0;
|
||||
BitsSent <= 0;
|
||||
CountOnes <= '0';
|
||||
TimeCounter <= 0;
|
||||
PS2ClockPrevious <= '1';
|
||||
Byte <= x"FF";
|
||||
State <= InhibitComunication;
|
||||
else
|
||||
PS2ClockPrevious <= PS2Clock_D;
|
||||
case State is
|
||||
when Idle =>
|
||||
DataReady <= '0';
|
||||
DReady <= '0';
|
||||
BitsRead <= 0;
|
||||
PS2Error <= '0';
|
||||
CountOnes <= '0';
|
||||
if PS2Data_D = '0' then -- Start bit
|
||||
PS2Busy <= '1';
|
||||
State <= ReceiveData;
|
||||
elsif Send = '1' then
|
||||
Byte <= Command;
|
||||
PS2Busy <= '1';
|
||||
TimeCounter <= 0;
|
||||
State <= InhibitComunication;
|
||||
else
|
||||
State <= Idle;
|
||||
end if;
|
||||
when ReceiveData =>
|
||||
if PS2ClockPrevious = '1' and PS2Clock_D = '0' then -- falling edge
|
||||
case BitsRead is
|
||||
when 1 to 8 => -- 8 Data bits
|
||||
Byte(BitsRead - 1) <= PS2Data_D;
|
||||
if PS2Data_D = '1' then
|
||||
CountOnes <= not CountOnes;
|
||||
end if;
|
||||
when 9 => -- Parity bit
|
||||
case CountOnes is
|
||||
when '0' =>
|
||||
if PS2Data_D = '0' then
|
||||
PS2Error <= '1'; -- Error when CountOnes is even (0)
|
||||
else -- and parity bit is unasserted
|
||||
PS2Error <= '0';
|
||||
end if;
|
||||
when others =>
|
||||
if PS2Data_D = '1' then
|
||||
PS2Error <= '1'; -- Error when CountOnes is odd (1)
|
||||
else -- and parity bit is asserted
|
||||
PS2Error <= '0';
|
||||
end if;
|
||||
end case;
|
||||
when 10 => -- Stop bit
|
||||
if PS2Error = '0' then
|
||||
DataByte <= Byte;
|
||||
DReady <= '1';
|
||||
else
|
||||
DReady <= '0';
|
||||
end if;
|
||||
State <= WaitRiseClock;
|
||||
when others => null;
|
||||
end case;
|
||||
BitsRead <= BitsRead + 1;
|
||||
end if;
|
||||
when InhibitComunication =>
|
||||
PS2Clock_Z <= '0';
|
||||
PS2ClockOut <= '0';
|
||||
if TimeCounter = Time100us then
|
||||
TimeCounter <= 0;
|
||||
State <= RequestToSend;
|
||||
else
|
||||
TimeCounter <= TimeCounter + 1;
|
||||
end if;
|
||||
when RequestToSend =>
|
||||
PS2Clock_Z <= '1';
|
||||
PS2Data_Z <= '0';
|
||||
PS2DataOut <= '0'; -- Sets the start bit, valid when PS2Clock is high
|
||||
if TimeCounter = Time20us then
|
||||
TimeCounter <= 0;
|
||||
PS2ClockOut <= '1';
|
||||
BitsSent <= 1;
|
||||
State <= SendData;
|
||||
else
|
||||
TimeCounter <= TimeCounter + 1;
|
||||
end if;
|
||||
when SendData =>
|
||||
PS2Clock_Z <= '1';
|
||||
if PS2ClockPrevious = '1' and PS2Clock_D = '0' then -- falling edge
|
||||
case BitsSent is
|
||||
when 1 to 8 => -- 8 Data bits
|
||||
if Byte(BitsSent - 1) = '0' then
|
||||
PS2DataOut <= '0';
|
||||
else
|
||||
CountOnes <= not CountOnes;
|
||||
PS2DataOut <= '1';
|
||||
end if;
|
||||
when 9 => -- Parity bit
|
||||
if CountOnes = '0' then
|
||||
PS2DataOut <= '1';
|
||||
else
|
||||
PS2DataOut <= '0';
|
||||
end if;
|
||||
when 10 => -- Stop bit
|
||||
PS2DataOut <= '1';
|
||||
State <= CheckAck;
|
||||
when others => null;
|
||||
end case;
|
||||
BitsSent <= BitsSent + 1;
|
||||
end if;
|
||||
when CheckAck =>
|
||||
PS2Data_Z <= '1';
|
||||
if PS2ClockPrevious = '1' and PS2Clock_D = '0' then
|
||||
if PS2Data_D = '1' then -- no Acknowledge received
|
||||
PS2Error <= '1';
|
||||
end if;
|
||||
State <= WaitRiseClock;
|
||||
end if;
|
||||
when WaitRiseClock =>
|
||||
if PS2ClockPrevious = '0' and PS2Clock_D = '1' then
|
||||
PS2Busy <= '0';
|
||||
DataReady <= DReady;
|
||||
State <= Idle;
|
||||
end if;
|
||||
when others => null;
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
Loading…
Reference in New Issue
Block a user