mirror of https://github.com/zxdos/zxuno.git
159 lines
4.5 KiB
VHDL
159 lines
4.5 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
|
|
entity ps2 is
|
|
port
|
|
(
|
|
clockPs2 : in std_logic;
|
|
clock : inout std_logic;
|
|
data : inout std_logic;
|
|
received : out std_logic;
|
|
scancode : out std_logic_vector(7 downto 0)
|
|
);
|
|
end;
|
|
|
|
architecture behavioral of ps2 is
|
|
|
|
constant state_idle : std_logic_vector(1 downto 0) := "00";
|
|
constant state_receiving : std_logic_vector(1 downto 0) := "01";
|
|
constant state_waiting : std_logic_vector(1 downto 0) := "10";
|
|
constant state_received : std_logic_vector(1 downto 0) := "11";
|
|
|
|
constant minClockPulseLen : natural := 30*7; -- 30us @ 7 MHz
|
|
constant maxClockPulseLen : natural := 50*7; -- 50us @ 7 MHz
|
|
|
|
type reg is
|
|
record
|
|
state : std_logic_vector( 1 downto 0);
|
|
clockCounter : std_logic_vector(10 downto 0);
|
|
dataReg : std_logic_vector(10 downto 0);
|
|
receivedCount : std_logic_vector( 3 downto 0);
|
|
ps2clkDeglitch : std_logic_vector( 4 downto 0);
|
|
ps2dataDeglitch : std_logic_vector( 4 downto 0);
|
|
scancode : std_logic_vector( 7 downto 0);
|
|
ps2lastClkDeglitched : std_logic;
|
|
ps2lastDataDeglitched : std_logic;
|
|
ps2ClkDeglitched : std_logic;
|
|
ps2DataDeglitched : std_logic;
|
|
dataReceived : std_logic;
|
|
end record;
|
|
|
|
signal n : reg;
|
|
signal r : reg :=
|
|
(
|
|
(others => '0'),
|
|
(others => '0'),
|
|
(others => '0'),
|
|
(others => '0'),
|
|
(others => '0'),
|
|
(others => '0'),
|
|
(others => '0'),
|
|
'0',
|
|
'0',
|
|
'0',
|
|
'0',
|
|
'0'
|
|
);
|
|
|
|
begin
|
|
clock <= 'Z';
|
|
data <= 'Z';
|
|
|
|
received <= r.dataReceived;
|
|
scancode <= r.scancode;
|
|
|
|
r <= n when rising_edge(clockPs2);
|
|
|
|
process(r, clock, data)
|
|
begin
|
|
n <= r;
|
|
|
|
-- remember what the last signals were
|
|
n.ps2lastClkDeglitched <= r.ps2clkDeglitched;
|
|
n.ps2lastClkDeglitched <= r.ps2clkDeglitched;
|
|
|
|
-- Deglitch the clock signal
|
|
if clock = '1' then
|
|
if r.ps2clkDeglitch < 31 then
|
|
n.ps2clkDeglitch <= r.ps2clkDeglitch+1;
|
|
else
|
|
n.ps2clkDeglitched <= '1';
|
|
n.clockCounter <= (others => '0');
|
|
end if;
|
|
else
|
|
if r.ps2clkDeglitch > 0 then
|
|
n.ps2clkDeglitch <= r.ps2clkDeglitch-1;
|
|
else
|
|
n.ps2clkDeglitched <= '0';
|
|
n.clockCounter <= (others => '0');
|
|
end if;
|
|
end if;
|
|
|
|
-- Deglitch the data signal
|
|
if data = '1' then
|
|
if r.ps2dataDeglitch < 31 then
|
|
n.ps2dataDeglitch <= r.ps2dataDeglitch+1;
|
|
else
|
|
n.ps2dataDeglitched <= '1';
|
|
end if;
|
|
else
|
|
if r.ps2dataDeglitch > 0 then
|
|
n.ps2dataDeglitch <= r.ps2dataDeglitch-1;
|
|
else
|
|
n.ps2dataDeglitched <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
----------------------------------------------------
|
|
-- Now the actual processing of the tidied up signal
|
|
----------------------------------------------------
|
|
case r.state is
|
|
when state_idle =>
|
|
-- Are we waiting for the ps2clk to go low? (start of data)
|
|
n.clockCounter <= (others => '0');
|
|
n.receivedCount <= (others => '0');
|
|
n.dataReceived <= '0';
|
|
if r.ps2clkDeglitched = '0' then n.state <= state_receiving; end if;
|
|
|
|
when state_receiving =>
|
|
n.clockCounter <= r.clockCounter+1;
|
|
-- is the pulse too long?
|
|
if r.clockCounter > maxClockPulseLen then
|
|
if r.ps2clkDeglitched = '1' then n.state <= state_idle; else n.state <= state_receiving; end if;
|
|
end if;
|
|
|
|
if r.ps2lastClkDeglitched = '0' and r.ps2clkDeglitched = '1' then
|
|
-- we on the rising edge of the clock singal
|
|
if r.clockCounter < minClockPulseLen then
|
|
n.state <= state_idle;
|
|
else
|
|
n.receivedCount <= r.receivedCount+1;
|
|
n.clockCounter <= (others => '0');
|
|
n.dataReg <= r.ps2dataDeglitched & r.dataReg(10 downto 1);
|
|
|
|
if r.receivedCount = 10 then n.state <= state_received; else n.receivedCount <= r.receivedCount+1; end if;
|
|
end if;
|
|
elsif r.ps2lastClkDeglitched = '1' and r.ps2clkDeglitched = '0' then
|
|
-- we on the falling edge of the clock singal
|
|
if r.clockCounter < minClockPulseLen then n.state <= state_waiting; end if;
|
|
n.clockCounter <= (others => '0');
|
|
end if;
|
|
|
|
when state_received =>
|
|
-- Check the start, parity and stopbits are valid, if all are correct, set the "data Received" signal
|
|
if r.dataReg(10) = '1' and (r.dataReg(9) xor r.dataReg(8) xor r.dataReg(7) xor r.dataReg(6) xor r.dataReg(5) xor r.dataReg(4) xor r.dataReg(3) xor r.dataReg(2) xor r.dataReg(1)) = '1' and r.dataReg (0) = '0' then
|
|
n.scancode <= r.dataReg(8 downto 1);
|
|
n.dataReceived <= '1';
|
|
n.state <= state_idle;
|
|
end if;
|
|
|
|
when others =>
|
|
-- We are waiting for the ps2clk to go high
|
|
if r.ps2clkDeglitched = '1' then n.state <= state_idle; end if;
|
|
|
|
end case;
|
|
end process;
|
|
|
|
end;
|