------------------------------------------------------------------------------------ Company: www.mlab.cz-- Engineer: miho---- Create Date: 19:31:10 02/20/2011-- Design Name: S3AN01A Test Design-- Module Name: PS2-- Project Name: S3AN01A Test Design-- Target Devices: XILINX FPGA (Spartan3A/3AN)-- Tool versions: ISE 12.4 / 13.1 / 13.3-- Description: Test design for PCB verification---- Dependencies: None---- Revision: 0.01 File Created---------------------------------------------------------------------------------------- PS/2 Keyboard Driver-- ====================---- PS2_Code-- ------------ Standard PS/2 Scan Code------ PS2_Attribs-- --------------- Bit 0 - Shift-- Bit 1 - Ctrl-- Bit 2 - Alt-- Bit 3 - Ext0 (arrows, ...)-- Bit 4 - Ext1-- Bit 5 - Shift Num (arrows with NumLock)-- Bit 6-- Bit 7 - Break (key release)------ PS2_Shifts-- -------------- Bit 0 - Shift Left-- Bit 1 - Shift Right-- Bit 2 - Ctrl Left-- Bit 3 - Ctrl Right-- Bit 4 - Alt Left-- Bit 5 - Alt Right-- Bit 6 - Num Lock-- Bit 7 - Caps Lock-- Bit 8 - Scroll Lock-- Bit 9 - Shift Num (virtual state) - Not to be used------------------------------------------------------------------------------------library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.NUMERIC_STD.ALL;entity PS2 isgeneric (-- Top Value for 100MHz Clock CounterCLKFREQ: integer -- Frequency in Hz (minimum cca 50_000));port (-- Main ClockClk: in std_logic;-- PS/2 PortPS2_Clk: inout std_logic;PS2_Data: inout std_logic;-- Result - valid when PS2_ValidPS2_Valid: out boolean; -- Valid Data (synchronous with Clk)PS2_Code: out std_logic_vector(7 downto 0); -- Key Scan CodePS2_Attribs: out std_logic_vector(7 downto 0); -- State of Shifts for Scan Code-- Immediate State of ShiftsPS2_Shifts: out std_logic_vector(9 downto 0) -- Immediate (live) State of Shift/Alt/Ctrl etc.);end entity PS2;library IEEE;use IEEE.STD_LOGIC_1164.ALL;package PS2_pkg iscomponent PS2generic (-- Top Value for 100MHz Clock CounterCLKFREQ: integer -- Frequency in Hz (minimum cca 50_000));port (-- Main ClockClk: in std_logic;-- PS/2 PortPS2_Clk: inout std_logic;PS2_Data: inout std_logic;-- Result - valid when PS2_ValidPS2_Valid: out boolean; -- Valid Data (synchronous with Main Clock)PS2_Code: out std_logic_vector(7 downto 0); -- Key Scan CodePS2_Attribs: out std_logic_vector(7 downto 0); -- State of Shifts for Scan Code-- Immediate State of ShiftsPS2_Shifts: out std_logic_vector(9 downto 0) -- Immediate (live) State of Shift/Alt/Ctrl etc.);end component PS2;end package;architecture PS2_a of PS2 isfunction to_std_logic(State: boolean) return std_logic isbeginif State thenreturn '1';elsereturn '0';end if;end function to_std_logic;-- Sampled PS/2 Clock and Datasignal PS2_Clk_d: std_logic := '0'; -- For sync with systerm clocksignal PS2_Clk_dd: std_logic := '0'; -- For falling edge detectionsignal PS2_Data_d: std_logic := '0'; -- For sync with systerm clock-- Level 0 - Read Byte from PS/2 Interfacetype ReadByte_t is ( -- Read Byte FSM State TypeIdle, -- Inactive StateD0, D1, D2, D3, D4, D5, D6, D7, -- Receiving BitsParity, -- Receiving ParityFinal -- Receiving Stop Bit and Sending ReadByte_rdy);signal ReadByteState: ReadByte_t := Idle; -- Read Byte FSM Statesignal ReadByte: std_logic_vector(7 downto 0) := (others => '0'); -- Read Byte (Raw Scan Code Byte)signal ReadByte_rdy: boolean := false; -- Read Byte Ready (synchronous with Clk)-- Level 1 - Process Raw Scan Codes E0,F1 and F0 - valid only when Level1_rdysignal FlagE0: boolean := false; -- E0 - Ext0 Keysignal FlagE1: boolean := false; -- E1 - Ext1 Keysignal FlagF0: boolean := false; -- F0 - Break (release) Keysignal Level1_rdy: boolean := false; -- Send Data and Flags to the next level-- Level 2 - Process Raw Scan Codes and Shift-Like Atributes E0, E1 and F0 - valid only when Level2_rdysignal FlagBreak: boolean := false; -- F0 - Break (depress) Keysignal FlagAltR: boolean := false; -- E0 11 - State of Right Alt Keysignal FlagAltL: boolean := false; -- 11 - State of Left Alt Keysignal FlagShiftNum: boolean := false; -- E0 12 - State of Ext Left Shift (pseudo key)signal FlagShiftL: boolean := false; -- 12signal FlagShiftR: boolean := false; -- 59signal FlagCtrlR: boolean := false; -- E0 14signal FlagCtrlL: boolean := false; -- 14signal FlagExt0: boolean := false; -- E0 Keys (extended keys)signal FlagExt1: boolean := false; -- E1 Keys (extended keys - Prt_Scr and Pause_Brk)signal FlagNumLock: boolean := false; -- 77 Num Lock Statesignal FlagScrollLock: boolean := false; -- 7E Scroll Lock Statesignal FlagCapsLock: boolean := false; -- 58 Caps Lock Statesignal Level2_rdy: boolean := false; -- Send Data and Flags to the next levelsignal Level2a_rdy: boolean := false; -- Send Read Ack for Write Byte-- Write Bytetype WriteByteState_t is ( -- Write Byte FSM State TypeIdle, -- Idle StateWriteStart, -- Start (pull PS2_Clk down)WaitStart, -- WaitSendBits, -- Send Data BitsWriteParity, -- Send ParityWriteStop, -- Send Stop BitAckBit, -- Wait for Ack Bit from KeyboardFinal, -- Wait for Idle on PS2_Clk and PS2_DataWaitAckByte -- Wait for Ack Byte from Keyboard);signal WriteByteState: WriteByteState_t := Idle; -- Write Byte FSM Statesignal WriteCode: std_logic_vector(7 downto 0) := (others =>'0'); -- What to Writesignal WriteByte: boolean := false; -- Init Write Byte Sequencesignal SendingData: boolean := false; -- Block Receiver when Sending Datasignal WriteByte_ack: boolean := false; -- Ack Writen Bytesignal WriteReg: std_logic_vector(7 downto 0) := (others =>'0'); -- Transmit Shift Registersignal ParityBit: std_logic := '0'; -- Parity Bitsignal StartTime: unsigned(31 downto 0) := (others =>'0'); -- Timer for Start of Write (PS2_Clk low)signal WriteBits: unsigned(3 downto 0) := (others =>'0'); -- Bit Counter-- Update LED Indicatorstype UpdState_t is ( -- Update Led Indicators FSM State TypeIdle, -- Inactive StateSendReset, -- For Debug - Reset KeyboardSendLed1, -- Send FDSendLed2, -- Send New LED StateSendFinal --);signal UpdState: UpdState_t := Idle; -- Update Led Indicators FSM Statesignal UpdateLed: boolean := false; -- Send new LED State to the Keyboardsignal UpdateLed_ack: boolean := false; -- Ack (1 clock pulse)begin-- Sync External Signals with Clockprocess (Clk)beginif rising_edge(Clk) then-- SyncPS2_Clk_d <= PS2_Clk;PS2_Data_d <= PS2_Data;-- For Falling Edge DetectionPS2_Clk_dd <= PS2_Clk_d;end if;end process;-- Level 0 - Read Byte from PS/2 Interfaceprocess (Clk)beginif rising_edge(Clk) thenReadByte_rdy <= false;if PS2_Clk_dd='1' and PS2_Clk_d='0' and not SendingData then-- Falling Edge of PS2_Clkcase ReadByteState iswhen Idle =>-- Test Start Bitif PS2_Data='0' thenReadByteState <= D0;end if;when D0 =>-- Bit 0ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D1;when D1 =>-- Bit 1ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D2;when D2 =>-- Bit 2ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D3;when D3 =>-- Bit 3ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D4;when D4 =>-- Bit 4ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D5;when D5 =>-- Bit 5ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D6;when D6 =>-- Bit 6ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= D7;when D7 =>-- Bit 7ReadByte <= PS2_Data & ReadByte(7 downto 1);ReadByteState <= Parity;when Parity =>-- Check Parity Here...ReadByteState <= Final;when Final =>-- End of ByteReadByteState <= Idle;ReadByte_rdy <= true; -- Scan Code Ready (8 bit word)end case;end if;end if;end process;-- Level 1 - Process Raw Scan Codes and ESC Atributes E0, E1 and F0process (Clk)beginif rising_edge(Clk) thenif Level1_rdy then-- Clean State when Sent Data from Level1 processingLevel1_rdy <= false;FlagE0 <= false;FlagE1 <= false;FlagF0 <= false;elseif ReadByte_rdy then-- Process Scan Code Byte from Level 0if ReadByte=X"E0" then-- Ext CodeFlagE0 <= true;elsif ReadByte=X"E1" then-- Special Ext CodeFlagE1 <= true;elsif ReadByte=X"F0" then-- Break FlagFlagF0 <= true;else-- Scan CodeLevel1_rdy <= true;end if;end if;end if;end if;end process;-- Level 2 - Process Shift (left and right shift, alt and ctrl) and Num Lock (numeric virtual shift)process (Clk)beginif rising_edge(Clk) then-- Clear Comands to Higher LevelUpdateLed <= false;Level2a_rdy <= false;Level2_rdy <= false;-- Process Read Byteif Level1_rdy thenif ReadByte=X"11" then-- Alt Keyif FlagE0 thenFlagAltR <= not FlagF0;elseFlagAltL <= not FlagF0;end if;elsif ReadByte=X"12" then-- Left Shiftif FlagE0 thenFlagShiftNum <= not FlagF0;elseFlagShiftL <= not FlagF0;end if;elsif ReadByte=X"59" then-- Right ShiftFlagShiftR <= not FlagF0;elsif ReadByte=X"14" then-- Ctrlif FlagE0 thenFlagCtrlR <= not FlagF0;elseFlagCtrlL <= not FlagF0;end if;elsif ReadByte=X"77" and not FlagCtrlL and not FlagCtrlR and not FlagAltL and not FlagAltR then-- Num Lock On/Offif not FlagF0 thenFlagNumLock <= not FlagNumLock;UpdateLed <= true; -- Set UpdateLed Requestend if;elsif ReadByte=X"58" then-- Caps Lockif not FlagF0 thenFlagCapsLock <= not FlagCapsLock;UpdateLed <= true; -- Set UpdateLed Requestend if;elsif ReadByte=X"7E" thenif not FlagF0 thenFlagScrollLock <= not FlagScrollLock;UpdateLed <= true; -- Set UpdateLed Requestend if;else-- Send Data to the next LevelFlagExt0 <= FlagE0;FlagExt1 <= FlagE1;FlagBreak <= FlagF0;if WriteByteState=WaitAckByte then-- Send Data (Ack Byte) to WriteByteLevel2a_rdy <= true;else-- Send Scan Code to the next LevelLevel2_rdy <= true;end if;end if;end if;end if;end process;-- Send DataPS2_Valid <= Level2_rdy;-- Scan COdePS2_Code(7 downto 0) <= ReadByte;-- AttribsPS2_Attribs(0) <= '1' when FlagShiftL or FlagShiftR else '0'; -- Bit 0 - ShiftPS2_Attribs(1) <= '1' when FlagCtrlL or FlagCtrlR else '0'; -- Bit 1 - CtrlPS2_Attribs(2) <= '1' when FlagAltL or FlagAltR else '0'; -- Bit 2 - AltPS2_Attribs(3) <= '1' when FlagExt0 else '0'; -- Bit 3 - Ext Code E0PS2_Attribs(4) <= '1' when FlagExt1 else '0'; -- Bit 4 - Ext Code E1PS2_Attribs(5) <= '1' when FlagShiftNum else '0'; -- Bit 5 - Shift Num (Arrows,...) - only if NumLock Led is OffPS2_Attribs(6) <= '0';PS2_Attribs(7) <= '1' when FlagBreak else '0'; -- Bit 7 - Break (release) Key-- Immediate State of Shift Like KeysPS2_Shifts(0) <= '1' when FlagShiftL else '0'; -- Bit 0 - Shift LeftPS2_Shifts(1) <= '1' when FlagShiftR else '0'; -- Bit 1 - Shift RightPS2_Shifts(2) <= '1' when FlagCtrlL else '0'; -- Bit 2 - Ctrl LeftPS2_Shifts(3) <= '1' when FlagCtrlR else '0'; -- Bit 3 - Ctrl RightPS2_Shifts(4) <= '1' when FlagAltL else '0'; -- Bit 4 - Alt LeftPS2_Shifts(5) <= '1' when FlagAltR else '0'; -- Bit 5 - Alt RightPS2_Shifts(6) <= '1' when FlagNumLock else '0'; -- Bit 7 - Num LockPS2_Shifts(7) <= '1' when FlagCapsLock else '0'; -- Bit 8 - Caps LockPS2_Shifts(8) <= '1' when FlagScrollLock else '0'; -- Bit 9 - Scroll LockPS2_Shifts(9) <= '1' when FlagShiftNum else '0'; -- Bit 6 - Shift Num (virtual state) - Not to be used-- Write Byte to PS/2 Interface-- Init By: WriteByte-- Finish Indication: WriteByte_ackprocess (Clk)beginif rising_edge(Clk) thenWriteByte_ack <= false;case WriteByteState iswhen Idle =>PS2_Clk <= 'Z';PS2_Data <= 'Z';if WriteByte thenWriteByteState <= WriteStart;WriteReg <= WriteCode;end if;when WriteStart =>if PS2_Data_d='1' and PS2_Clk_d='1' then-- PS2 Interface in Idle StatePS2_Clk <= '0'; -- Start of Write (PS2_Clk=L)StartTime <= to_unsigned(CLKFREQ/16000, StartTime'length); -- cca 60us StartWriteBits <= to_unsigned(7, WriteBits'length); -- 8 bitsWriteByteState <= WaitStart;SendingData <= true;end if;when WaitStart =>if StartTime>0 thenStartTime <= StartTime - 1;elsePS2_Data <= '0'; -- Start BitPS2_Clk <= 'Z'; -- Release ClkParityBit <= '1'; -- Init Parity Generator (code 1111_1111 has parity 1)WriteByteState <= SendBits;end if;when SendBits =>if PS2_Clk_dd='1' and PS2_Clk_d='0' thenPS2_Data <= WriteReg(0);ParityBit <= ParityBit xor WriteReg(0);WriteReg <= '1' & WriteReg(7 downto 1);if WriteBits>0 thenWriteBits <= WriteBits - 1;elseWriteByteState <= WriteParity;end if;end if;when WriteParity =>if PS2_Clk_dd='1' and PS2_Clk_d='0' thenPS2_Data <= ParityBit;WriteByteState <= WriteStop;end if;when WriteStop =>if PS2_Clk_dd='1' and PS2_Clk_d='0' thenPS2_Data <= '1';WriteByteState <= AckBit;end if;when AckBit =>PS2_Data <= 'Z';if PS2_Clk_dd='1' and PS2_Clk_d='0' thenWriteByteState <= Final;end if;when Final =>if PS2_Clk_d='1' thenWriteByteState <= WaitAckByte;SendingData <= false;end if;when WaitAckByte =>if Level2a_rdy thenWriteByteState <= Idle;WriteByte_ack <= true;end if;end case;end if;end process;-- Level 3 - Update LED Indicators-- Init By: UpdateLed or Level2_rdy(with scan code and attrib)-- Finish Indication: UpdateLed_ack (not used)process (Clk)beginif rising_edge(Clk) thenUpdateLed_ack <= false; -- 1 Clock PulseWriteByte <= false;case UpdState iswhen Idle =>-- Register the requestif Level2_rdy and ReadByte=X"07" and not FlagBreak thenWriteCode <= X"FF";WriteByte <= true;elsif UpdateLed thenUpdateLed_ack <= true;UpdState <= SendLed1;end if;when SendReset =>if WriteByteState=Idle then-- Send Keyborad ResetWriteCode <= X"FF";WriteByte <= true;UpdState <= SendFinal;end if;when SendLed1 =>if WriteByteState=Idle then-- Send LED CommandWriteCode <= X"ED";WriteByte <= true;UpdState <= SendLed2;end if;when SendLed2 =>if WriteByte_ack then-- Send LED StateWriteCode <= "00000" & to_std_logic(FlagCapsLock)& to_std_logic(FlagNumLock)& to_std_logic(FlagScrollLock);WriteByte <= true;UpdState <= SendFinal;end if;when SendFinal =>if WriteByte_ack then ---WriteByteState=Idle then-- Last Data has been SendUpdState <= Idle;end if;end case;end if;end process;end architecture PS2_a;