OpenCores
URL https://opencores.org/ocsvn/layer2/layer2/trunk

Subversion Repositories layer2

[/] [layer2/] [trunk/] [vhdl/] [keyb/] [rtl/] [keyb.vhd] - Rev 2

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------------
-- PS2 Keyboard Controller                                                    --
--------------------------------------------------------------------------------
-- Copyright (C)2011  Mathias Hörtnagl <mathias.hoertnagl@gmail.comt>         --
--                                                                            --
-- This program is free software: you can redistribute it and/or modify       --
-- it under the terms of the GNU General Public License as published by       --
-- the Free Software Foundation, either version 3 of the License, or          --
-- (at your option) any later version.                                        --
--                                                                            --
-- This program is distributed in the hope that it will be useful,            --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of             --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              --
-- GNU General Public License for more details.                               --
--                                                                            --
-- You should have received a copy of the GNU General Public License          --
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.      --
--------------------------------------------------------------------------------
-- http://www.computer-engineering.org/ps2keyboard/
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library work;
use work.iwb.all;
 
entity keyb is
   port(
      si        : in  slave_in_t;
      so        : out slave_out_t;
   -- Non-Wishbone Signals
      PS2_CLK   : in  std_logic;
      PS2_DATA  : in  std_logic;
      intr      : out std_logic
   );
end keyb;
 
architecture rtl of keyb is
 
   constant EXTENDED_CODE : std_logic_vector(7 downto 0) := x"E0";
   constant BREAK_CODE    : std_logic_vector(7 downto 0) := x"F0";
   constant CAPS          : std_logic_vector(7 downto 0) := x"58";
   constant LEFT_SHIFT    : std_logic_vector(7 downto 0) := x"12";
   constant RIGHT_SHIFT   : std_logic_vector(7 downto 0) := x"59";
   constant LEFT_CTRL     : std_logic_vector(7 downto 0) := x"14";
   constant LEFT_ALT      : std_logic_vector(7 downto 0) := x"11";
   constant RIGHT_CTRL    : std_logic_vector(7 downto 0) := x"14";
   constant RIGHT_ALT     : std_logic_vector(7 downto 0) := x"11";
 
   component ps2 is
      port(
         clk      : in  std_logic;
         rst      : in  std_logic;
         PS2_CLK  : in  std_logic;
         PS2_DATA : in  std_logic;
         char     : out std_logic_vector(7 downto 0);
         rx_done  : out std_logic
      );
   end component;
 
   component ascii is
      port(
         clk   : in  std_logic;
         shft  : in  std_logic;
         altgr : in std_logic;
         code  : in  std_logic_vector(7 downto 0);
         char  : out std_logic_vector(7 downto 0)
      );
   end component;
 
   attribute RAM_STYLE : string;
   attribute RAM_STYLE of ascii : component is "BLOCK";
 
   type state_t is (Idle, ExtCode, BrkCode, ExtRelease, Translate, Check,
                    Ack, Ack2);
 
   type char_t is record
      shft  : std_logic;                           -- Shift key.
      cps   : std_logic;                           -- Caps key.
      ctrl  : std_logic;                           -- Control key.
      alt   : std_logic;                           -- Alt key.
      altgr : std_logic;                           -- Alt Gr key.
      m     : std_logic_vector(7 downto 0);        -- Scan code.
   end record;
 
   signal k, kin   : state_t := Idle;              -- Keyboard controller state.
   signal c, cin   : char_t;                       -- Character structure.
   signal code     : std_logic_vector(7 downto 0); -- PS2 scan code.
   signal char     : std_logic_vector(7 downto 0); -- ASCII character.
   signal shftcps  : std_logic;                    -- SHIFT xor CAPS.
   signal rx_done  : std_logic;                    -- PS2 receive done tick.
   signal key_done : std_logic;                    -- Keyboard ctrl done tick.
begin
 
   -----------------------------------------------------------------------------
   -- PS2 Controller                                                          --
   -----------------------------------------------------------------------------
   ps2_ctrl : ps2 port map(
      clk      => si.clk,
      rst      => si.rst,
      PS2_CLK  => PS2_CLK,
      PS2_DATA => PS2_DATA,
      char     => code,
      rx_done  => rx_done
   );
 
   -----------------------------------------------------------------------------
   -- ScanCode To ASCII ROM                                                   --
   -----------------------------------------------------------------------------
   shftcps <= c.shft xor c.cps;     -- If both are set, turn to lower case.
 
   ascii_rom : ascii port map(
      clk   => si.clk,
      shft  => shftcps,
      altgr => c.altgr,
      code  => c.m,
      char  => char
   );
 
   -----------------------------------------------------------------------------
   -- Keyboard Control                                                        --
   -----------------------------------------------------------------------------
   key : process(k, c, rx_done, code, si.stb, si.we, si, char)
   begin
 
      kin <= k;
      cin <= c;
 
      intr   <= '0';
      so.ack <= '0';
      --key_done <= '0';  
 
      case k is
 
         -- Wait for some key input.
         when Idle =>
            if rx_done = '1' then
               case code is
 
                  when EXTENDED_CODE =>
                     kin   <= ExtCode;
 
                  when BREAK_CODE =>
                     kin   <= BrkCode;
 
                  -- User pressed a functional key. Just latch and then return
                  -- to Idle state. The CPU does not need to be bothered.
                  when LEFT_SHIFT | RIGHT_SHIFT =>
                     cin.shft <= '1';
                     kin      <= Idle;
                  when CAPS =>
                     cin.cps  <= not c.cps;
                     kin      <= Idle;
                  when LEFT_CTRL =>
                     cin.ctrl <= '1';
                     kin      <= Idle;
                  when LEFT_ALT =>
                     cin.alt  <= '1';
                     kin      <= Idle;
 
                  -- The actual key code.
                  when others =>
                     cin.m <= code;
                     kin   <= Translate;
               end case;
            end if;
 
         -- PREVIOUS STATE: Idle.
         when ExtCode =>
            if rx_done = '1' then
               case code is
 
                  -- If we receive a BREAK CODE we know that the following
                  -- pressed key (represented by the next byte) has been
                  -- released.
                  when BREAK_CODE =>
                     kin   <= ExtRelease;
 
                  -- The RIGHT CTRL and RIGHT ALT (ALT GR) are the same key
                  -- codes as LEFT CTRL and LEFT ALT plus an preceeding EXTENDED
                  -- CODE. RIGHT ALT (ALT GR) has a different functional
                  -- meaning.
                  when RIGHT_CTRL =>
                     cin.ctrl  <= '1';
                     kin       <= Idle;
                  when RIGHT_ALT =>
                     cin.altgr <= '1';
                     kin       <= Idle;
 
                  -- Once more the actual key code.
                  when others =>
                     cin.m <= code;
                     kin   <= Translate;
               end case;
            end if;
 
         -- PREVIOUS STATE: Idle.
         when BrkCode =>
            if rx_done = '1' then
               case code is
 
                  -- A functional key has been released.
                  when LEFT_SHIFT | RIGHT_SHIFT =>
                     cin.shft <= '0';
                     kin      <= Idle;
                  when LEFT_CTRL =>
                     cin.ctrl <= '0';
                     kin      <= Idle;
                  when LEFT_ALT =>
                     cin.alt  <= '0';
                     kin      <= Idle;
 
                  -- Do nothing when CAPS is released.
                  when CAPS =>
                     kin <= Idle;
 
                  -- Do nothing on key release.
                  when others =>
                     kin <= Idle;
               end case;
            end if;
 
         -- PREVIOUS STATE: ExtCode.
         -- Either turn off the RIGHT CTRL or RIGHT ALT flags, or receive a non
         -- functional key code release.
         when ExtRelease =>
            if rx_done = '1' then
               case code is
 
                  -- The RIGHT CTRL and RIGHT ALT (ALT GR) are the same key
                  -- codes as LEFT CTRL and LEFT ALT plus an preceeding EXTENDED
                  -- CODE. RIGHT ALT (ALT GR) has a different functional
                  -- meaning.
                  when RIGHT_CTRL =>
                     cin.ctrl <= '0';
                     kin      <= Idle;
                  when RIGHT_ALT =>
                     cin.altgr <= '0';
                     kin       <= Idle;
 
                  -- Do nothing on key release.
                  when others =>
                     kin   <= Idle;
               end case;
            end if;
 
         -- PREVIOUS STATES: Idle, ExtCode.
         -- One cycle delay for the ASCII-ROM to translate the keyboard code.
         when Translate =>
            kin <= Check;
 
         -- Ignore all undefined keys.
         when Check =>
            if char = x"00" then
               kin <= Idle;
            else
               kin <= Ack;
            end if;
 
         -- Wait for a Wishbone read, set interrrupt meanwhile.
         when Ack =>
            intr <= '1';
            if wb_read(si) then
               so.ack <= '1';
               --key_done <= '1';
               kin      <= Ack2;
            end if;
 
         -- Wait and hold done signal until master notices ack signal and pulls
         -- stb down.
         when Ack2 =>
            intr   <= '1';
            so.ack <= '1';
            --key_done <= '1';
            if si.stb = '0' then
               kin <= Idle;
            end if;
 
      end case;
   end process;
 
   so.dat <= x"0000" & c.shft & c.ctrl & c.alt & c.altgr & x"0" & char;
   --so.ack <= key_done;
 
   -----------------------------------------------------------------------------
   -- Registers                                                               --
   -----------------------------------------------------------------------------
     reg : process(si.clk)
   begin
      if rising_edge(si.clk) then
         k <= kin;
         c <= cin;
         if si.rst = '1' then
            k <= Idle;
            c <= ('0','0','0','0','0',(others => '-'));
         end if;
      end if;
   end process;
end rtl;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.