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

Subversion Repositories cpu8080

[/] [cpu8080/] [trunk/] [project/] [ps2_kbd.vhd] - Blame information for rev 33

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 11 samiam9512
--
2
-- This circuit accepts a serial datastream and clock from a PS/2 keyboard
3
-- and outputs the scancode for any key that is pressed.
4
--
5
-- Notes:
6
--   
7
--   1. The clock from the PS/2 keyboard does not drive the clock inputs of
8
--      any of the registers in this circuit.  Instead, it is sampled at the
9
--      frequency of the main clock input and edges are extracted from the samples.
10
--      So you have to apply a main clock that is substantially faster than
11
--      the 10 KHz PS/2 clock.  It should be 200 KHz or more.
12
--
13
--   2. The scancode is only valid when the ready signal is high.  The scancode
14
--      should be registered by an external circuit on the first clock edge
15
--      after the ready signal goes high.
16
--
17
--   3. The ready signal pulses only after the key is released.
18
--
19
--   4. The error flag is set whenever the PS/2 clock stops pulsing and the
20
--      PS/2 clock is either at a low level or less than 11 bits of serial
21
--      data have been received (start + 8 data + parity + stop).  The circuit
22
--      locks up once an error is detected and will not resume operation until
23
--      a reset is applied.
24
--
25
 
26
 
27
 
28
library IEEE;
29
use IEEE.std_logic_1164.all;
30
use IEEE.numeric_std.all;
31
 
32
 
33
package ps2_kbd_pckg is
34
  component ps2_kbd
35
    generic(
36 18 samiam9512
      FREQ     :     natural := 50_000  -- frequency of the main clock (KHz)
37 11 samiam9512
      );
38
    port(
39
      clk      : in  std_logic;         -- main clock
40
      rst      : in  std_logic;         -- asynchronous reset
41
      ps2_clk  : in  std_logic;         -- clock from keyboard
42
      ps2_data : in  std_logic;         -- data from keyboard
43
      scancode : out std_logic_vector(7 downto 0);  -- key scancode
44
      parity   : out std_logic;         -- parity bit for scancode
45
      busy     : out std_logic;         -- busy receiving scancode
46
      rdy      : out std_logic;         -- scancode ready pulse
47
      error    : out std_logic          -- error receiving scancode
48
      );
49
  end component ps2_kbd;
50
end package ps2_kbd_pckg;
51
 
52
 
53
 
54
library IEEE;
55
use IEEE.std_logic_1164.all;
56
use IEEE.numeric_std.all;
57
 
58
 
59
entity ps2_kbd is
60
  generic(
61 18 samiam9512
    FREQ     :     natural := 50_000   -- frequency of the main clock (KHz)
62 11 samiam9512
    );
63
  port(
64
    clk      : in  std_logic;           -- main clock
65
    rst      : in  std_logic;           -- asynchronous reset
66
    ps2_clk  : in  std_logic;           -- clock from keyboard
67
    ps2_data : in  std_logic;           -- data from keyboard
68
    scancode : out std_logic_vector(7 downto 0);  -- key scancode
69
    parity   : out std_logic;           -- parity bit for scancode
70
    busy     : out std_logic;           -- busy receiving scancode
71
    rdy      : out std_logic;           -- scancode ready pulse
72
    error    : out std_logic            -- error receiving scancode
73
    );
74
end entity ps2_kbd;
75
 
76
 
77
architecture arch of ps2_kbd is
78
 
79
  constant YES         : std_logic                    := '1';
80
  constant NO          : std_logic                    := '0';
81
  constant PS2_FREQ    : natural                      := 10;  -- keyboard clock frequency (KHz)
82
  constant TIMEOUT     : natural                      := FREQ / PS2_FREQ;  -- ps2_clk quiet timeout
83
  constant KEY_RELEASE : std_logic_vector(7 downto 0) := "11110000";  -- scancode sent when key is released
84
 
85
  signal timer_x, timer_r     : natural range 0 to TIMEOUT;  -- counts time since last PS/2 clock edge
86
  signal bitcnt_x, bitcnt_r   : natural range 0 to 11;  -- counts number of received scancode bits
87
  signal ps2_clk_x, ps2_clk_r : std_logic_vector(5 downto 1);  -- PS/2 clock synchronization / edge detect shift register
88
  signal ps2_clk_fall_edge    : std_logic;  -- pulses on falling edge of PS/2 clock
89
  signal ps2_clk_rise_edge    : std_logic;  -- pulses on rising edge of PS/2 clock
90
  signal ps2_clk_edge         : std_logic;  -- pulses on either edge of PS/2 clock
91
  signal ps2_clk_quiet        : std_logic;  -- pulses when no edges on PS/2 clock for TIMEOUT
92
  signal sc_x, sc_r           : std_logic_vector(9 downto 0);  -- scancode shift register
93
  signal keyrel_x, keyrel_r   : std_logic;  -- this flag is set when the key release scancode is received
94
  signal scancode_rdy         : std_logic;  -- indicates when any scancode has been received
95
  signal rdy_x, rdy_r         : std_logic;  -- this flag is set when scancode for the pressed key is ready
96
  signal error_x, error_r     : std_logic;  -- this flag is set when an error occurs
97
 
98
begin
99
 
100
  -- shift the level on the PS/2 clock into a shift register
101
  ps2_clk_x <= ps2_clk_r(4 downto 1) & ps2_clk;
102
 
103
  -- look at the PS/2 clock levels stored in the shift register and find rising or falling edges
104
  ps2_clk_fall_edge <= YES when ps2_clk_r(5 downto 2) = "1100" else NO;
105
  ps2_clk_rise_edge <= YES when ps2_clk_r(5 downto 2) = "0011" else NO;
106
  ps2_clk_edge      <= ps2_clk_fall_edge or ps2_clk_rise_edge;
107
 
108
  -- shift the keyboard scancode into the shift register on the falling edge of the PS/2 clock
109
  sc_x <= ps2_data & sc_r(9 downto 1) when ps2_clk_fall_edge = YES else sc_r;
110
 
111
  -- clear the timer right after a PS/2 clock edge and then keep incrementing it until the next edge
112
  timer_x <= 0 when ps2_clk_edge = YES else timer_r + 1;
113
 
114
  -- indicate when the PS/2 clock has stopped pulsing and is at a high level.
115
  ps2_clk_quiet <= YES when timer_r = TIMEOUT and ps2_clk_r(2) = '1' else NO;
116
 
117
  -- increment the bit counter on each falling edge of the PS/2 clock.
118
  -- reset the bit counter if the PS/2 clock stops pulsing or if there was an error receiving the scancode.
119
  -- otherwise, keep the bit counter unchanged.
120
  bitcnt_x <= bitcnt_r + 1 when ps2_clk_fall_edge = YES              else
121
 
122
              bitcnt_r;
123
 
124
  -- a scancode has been received if the bit counter is 11 and the PS/2 clock has stopped pulsing
125
  scancode_rdy <= YES when bitcnt_r = 11 and ps2_clk_quiet = YES else NO;
126
 
127
  -- look for the scancode sent when the key is released
128
  keyrel_x <= YES when sc_r(scancode'range) = KEY_RELEASE and scancode_rdy = YES else
129
              NO  when rdy_r = YES or error_r = YES                              else
130
              keyrel_r;
131
 
132
  -- the scancode for the pressed key arrives after receiving the key-release scancode 
133 18 samiam9512
  -- Changed: removed key release requirement, send all keys up.
134
  -- rdy_x <= YES when keyrel_r = YES and scancode_rdy = YES else NO;
135
  rdy_x <= YES when scancode_rdy = YES else NO;
136 11 samiam9512
 
137
  -- indicate an error if the clock is low for too long or if it stops pulsing in the middle of a scancode
138
  error_x <= YES when (timer_r = TIMEOUT and ps2_clk_r(2) = '0') or
139
             (ps2_clk_quiet = YES and bitcnt_r/=11 and bitcnt_r/=0) else
140
             error_r;
141
 
142
  scancode <= sc_r(scancode'range);     -- output scancode
143
  parity   <= sc_r(scancode'high+1);    -- output parity bit for the scancode
144
  busy     <= YES when bitcnt_r/=0 else NO;  -- output busy signal when receiving a scancode
145
  rdy      <= rdy_r;                    -- output scancode ready flag
146
  error    <= error_r;                  -- output error flag
147
 
148
  -- update the various registers
149
  process(rst, clk)
150
  begin
151
    if rst = YES then
152
      ps2_clk_r <= (others => '1');     -- start by assuming PS/2 clock has been high for a while
153
      sc_r      <= (others => '0');     -- clear scancode register
154
      keyrel_r  <= NO;                  -- key-release scancode has not been received yet
155
      rdy_r     <= NO;                  -- no scancodes received yet
156
      timer_r   <= 0;                   -- clear PS/2 clock pulse timer
157
      bitcnt_r  <= 0;                   -- clear scancode bit counter
158
      error_r   <= NO;                  -- clear any errors
159
    elsif rising_edge(clk) then
160
      ps2_clk_r <= ps2_clk_x;
161
      sc_r      <= sc_x;
162
      keyrel_r  <= keyrel_x;
163
      rdy_r     <= rdy_x;
164
      timer_r   <= timer_x;
165
      bitcnt_r  <= bitcnt_x;
166
      error_r   <= error_x;
167
    end if;
168
  end process;
169
 
170
end architecture arch;

powered by: WebSVN 2.1.0

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