1 |
3 |
howe.r.j.8 |
--------------------------------------------------------------------------------
|
2 |
|
|
--
|
3 |
|
|
-- FileName: kbd.vhd
|
4 |
|
|
-- Dependencies: debounce.vhd
|
5 |
|
|
-- Design Software: Quartus II 32-bit Version 12.1 Build 177 SJ Full Version
|
6 |
|
|
--
|
7 |
|
|
-- HDL CODE is PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
|
8 |
|
|
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
9 |
|
|
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
10 |
|
|
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
|
11 |
|
|
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
|
12 |
|
|
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
|
13 |
|
|
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
|
14 |
|
|
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
|
15 |
|
|
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
|
16 |
|
|
--
|
17 |
|
|
-- Version History
|
18 |
|
|
-- Version 1.0 11/29/2013 Scott Larson
|
19 |
|
|
-- Initial Public Release
|
20 |
|
|
--
|
21 |
|
|
-- See https://eewiki.net/pages/viewpage.action?pageId=28279002
|
22 |
|
|
--
|
23 |
|
|
-- @note This file has been renamed and updated from the original.
|
24 |
|
|
--------------------------------------------------------------------------------
|
25 |
|
|
library ieee;
|
26 |
|
|
use ieee.std_logic_1164.all;
|
27 |
5 |
howe.r.j.8 |
use work.util.common_generics;
|
28 |
3 |
howe.r.j.8 |
|
29 |
|
|
package kbd_pkg is
|
30 |
|
|
|
31 |
|
|
component ps2_kbd_top is
|
32 |
|
|
generic(
|
33 |
5 |
howe.r.j.8 |
clock_frequency: integer := 50000000; -- system clock frequency in Hz
|
34 |
|
|
ps2_debounce_counter_size: integer := 8); -- set such that 2^size/clock_frequency = 5us (size = 8 for 50MHz)
|
35 |
3 |
howe.r.j.8 |
port(
|
36 |
|
|
clk: in std_ulogic; -- system clock input
|
37 |
|
|
ps2_clk: in std_ulogic; -- clock signal from PS2 keyboard
|
38 |
|
|
ps2_data: in std_ulogic; -- data signal from PS2 keyboard
|
39 |
|
|
ascii_new: out std_ulogic := '0'; -- output flag indicating new ascii value
|
40 |
|
|
ascii_code: out std_ulogic_vector(6 downto 0)); -- ASCII value
|
41 |
|
|
end component;
|
42 |
|
|
|
43 |
|
|
component ps2_kbd_core is
|
44 |
|
|
generic(
|
45 |
5 |
howe.r.j.8 |
clock_frequency: integer := 50000000; -- system clock frequency in Hz
|
46 |
|
|
debounce_counter_size: integer := 8); -- set such that (2^size)/clock_frequency = 5us (size = 8 for 50MHz)
|
47 |
3 |
howe.r.j.8 |
port(
|
48 |
|
|
clk: in std_ulogic; -- system clock
|
49 |
|
|
ps2_clk: in std_ulogic; -- clock signal from PS/2 keyboard
|
50 |
|
|
ps2_data: in std_ulogic; -- data signal from PS/2 keyboard
|
51 |
|
|
ps2_code_new: out std_ulogic; -- flag that new PS/2 code is available on ps2_code bus
|
52 |
|
|
ps2_code: out std_ulogic_vector(7 downto 0)); -- code received from PS/2
|
53 |
|
|
end component;
|
54 |
|
|
|
55 |
|
|
component ps2_debounce is
|
56 |
5 |
howe.r.j.8 |
generic(counter_size: integer := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
|
57 |
3 |
howe.r.j.8 |
port(
|
58 |
|
|
clk: in std_ulogic;
|
59 |
|
|
button: in std_ulogic; --input signal to be debounced
|
60 |
|
|
result: out std_ulogic := '0'); --debounced signal
|
61 |
|
|
end component;
|
62 |
|
|
|
63 |
|
|
component keyboard is
|
64 |
|
|
generic(
|
65 |
5 |
howe.r.j.8 |
g: common_generics;
|
66 |
|
|
ps2_debounce_counter_size: integer := 8); -- set such that 2^size/clock_frequency = 5us (size = 8 for 50MHz)
|
67 |
3 |
howe.r.j.8 |
port(
|
68 |
|
|
clk: in std_ulogic; -- system clock input
|
69 |
|
|
rst: in std_ulogic; -- system reset
|
70 |
|
|
|
71 |
|
|
ps2_clk: in std_ulogic; -- clock signal from PS2 keyboard
|
72 |
|
|
ps2_data: in std_ulogic; -- data signal from PS2 keyboard
|
73 |
|
|
|
74 |
|
|
kbd_char_re: in std_ulogic; -- acknowledge kbd_char_buf_new
|
75 |
|
|
kbd_char_buf_new: out std_ulogic := '0'; -- output flag indicating new ascii value
|
76 |
|
|
kbd_char_buf: out std_ulogic_vector(6 downto 0)); -- ASCII value
|
77 |
|
|
end component;
|
78 |
|
|
end package;
|
79 |
|
|
|
80 |
|
|
------ Keyboard ----------------------------------------------------------------
|
81 |
5 |
howe.r.j.8 |
library ieee, work;
|
82 |
3 |
howe.r.j.8 |
use ieee.std_logic_1164.all;
|
83 |
|
|
use work.kbd_pkg.all;
|
84 |
5 |
howe.r.j.8 |
use work.util.common_generics;
|
85 |
3 |
howe.r.j.8 |
|
86 |
|
|
entity keyboard is
|
87 |
|
|
generic(
|
88 |
5 |
howe.r.j.8 |
g: common_generics;
|
89 |
|
|
ps2_debounce_counter_size: integer := 8); -- set such that 2^size/clock_frequency = 5us (size = 8 for 50MHz)
|
90 |
3 |
howe.r.j.8 |
port(
|
91 |
|
|
clk: in std_ulogic; -- system clock input
|
92 |
|
|
rst: in std_ulogic; -- system reset
|
93 |
|
|
|
94 |
|
|
ps2_clk: in std_ulogic; -- clock signal from PS2 keyboard
|
95 |
|
|
ps2_data: in std_ulogic; -- data signal from PS2 keyboard
|
96 |
|
|
|
97 |
|
|
kbd_char_re: in std_ulogic; -- acknowledge kbd_char_buf_new
|
98 |
|
|
kbd_char_buf_new: out std_ulogic := '0'; -- output flag indicating new ascii value
|
99 |
|
|
kbd_char_buf: out std_ulogic_vector(6 downto 0)); -- ASCII value
|
100 |
|
|
end entity;
|
101 |
|
|
|
102 |
|
|
architecture rtl of keyboard is
|
103 |
|
|
signal kbd_new_c, kbd_new_n: std_ulogic := '0';
|
104 |
|
|
signal kbd_new_edge: std_ulogic := '0';
|
105 |
5 |
howe.r.j.8 |
signal kbd_new: std_ulogic := '0'; -- new ASCII char available
|
106 |
3 |
howe.r.j.8 |
signal kbd_char: std_ulogic_vector(kbd_char_buf'range) := (others => '0'); -- ASCII char
|
107 |
|
|
begin
|
108 |
5 |
howe.r.j.8 |
kbd_char_buf_new <= kbd_new_c after g.delay;
|
109 |
3 |
howe.r.j.8 |
|
110 |
|
|
ps2_next: process(clk, rst)
|
111 |
|
|
begin
|
112 |
5 |
howe.r.j.8 |
if rst = '1' and g.asynchronous_reset then
|
113 |
|
|
kbd_new_c <= '0' after g.delay;
|
114 |
3 |
howe.r.j.8 |
elsif rising_edge(clk) then
|
115 |
5 |
howe.r.j.8 |
if rst = '1' and not g.asynchronous_reset then
|
116 |
|
|
kbd_new_c <= '0' after g.delay;
|
117 |
|
|
else
|
118 |
|
|
kbd_new_c <= kbd_new_n after g.delay;
|
119 |
|
|
end if;
|
120 |
3 |
howe.r.j.8 |
end if;
|
121 |
|
|
end process;
|
122 |
|
|
|
123 |
|
|
new_char: entity work.reg
|
124 |
5 |
howe.r.j.8 |
generic map(g => g, N => kbd_char'length)
|
125 |
3 |
howe.r.j.8 |
port map(
|
126 |
|
|
clk => clk,
|
127 |
|
|
rst => rst,
|
128 |
|
|
di => kbd_char,
|
129 |
|
|
we => kbd_new_edge,
|
130 |
|
|
do => kbd_char_buf);
|
131 |
|
|
|
132 |
|
|
ps2_proc: process(kbd_new_edge, kbd_new_c, kbd_char_re)
|
133 |
|
|
begin
|
134 |
|
|
if kbd_new_edge = '1' then
|
135 |
5 |
howe.r.j.8 |
kbd_new_n <= '1' after g.delay;
|
136 |
3 |
howe.r.j.8 |
elsif kbd_char_re = '1' then
|
137 |
5 |
howe.r.j.8 |
kbd_new_n <= '0' after g.delay;
|
138 |
3 |
howe.r.j.8 |
else
|
139 |
5 |
howe.r.j.8 |
kbd_new_n <= kbd_new_c after g.delay;
|
140 |
3 |
howe.r.j.8 |
end if;
|
141 |
|
|
end process;
|
142 |
|
|
|
143 |
|
|
-- Process a kbd_new into a single edge for the rest of the
|
144 |
|
|
-- system.
|
145 |
|
|
ps2_edge_new_character_0: entity work.rising_edge_detector
|
146 |
5 |
howe.r.j.8 |
generic map(g => g)
|
147 |
3 |
howe.r.j.8 |
port map(
|
148 |
|
|
clk => clk,
|
149 |
|
|
rst => rst,
|
150 |
|
|
di => kbd_new,
|
151 |
|
|
do => kbd_new_edge);
|
152 |
|
|
|
153 |
|
|
ps2_0: work.kbd_pkg.ps2_kbd_top
|
154 |
|
|
generic map(
|
155 |
5 |
howe.r.j.8 |
clock_frequency => g.clock_frequency,
|
156 |
3 |
howe.r.j.8 |
ps2_debounce_counter_size => ps2_debounce_counter_size)
|
157 |
|
|
port map(
|
158 |
|
|
clk => clk,
|
159 |
|
|
ps2_clk => ps2_clk,
|
160 |
|
|
ps2_data => ps2_data,
|
161 |
|
|
ascii_new => kbd_new,
|
162 |
|
|
ascii_code => kbd_char);
|
163 |
|
|
end architecture;
|
164 |
|
|
------ Keyboard ----------------------------------------------------------------
|
165 |
|
|
|
166 |
|
|
------ PS2 KBD TOP -------------------------------------------------------------
|
167 |
|
|
|
168 |
|
|
library ieee;
|
169 |
|
|
use ieee.std_logic_1164.all;
|
170 |
|
|
use work.kbd_pkg.all;
|
171 |
|
|
|
172 |
|
|
entity ps2_kbd_top is
|
173 |
|
|
generic(
|
174 |
5 |
howe.r.j.8 |
clock_frequency: integer := 50000000; -- system clock frequency in Hz
|
175 |
|
|
ps2_debounce_counter_size: integer := 8); -- set such that 2^size/clock_frequency = 5us (size = 8 for 50MHz)
|
176 |
3 |
howe.r.j.8 |
port(
|
177 |
|
|
clk: in std_ulogic; -- system clock input
|
178 |
|
|
ps2_clk: in std_ulogic; -- clock signal from PS2 keyboard
|
179 |
|
|
ps2_data: in std_ulogic; -- data signal from PS2 keyboard
|
180 |
|
|
ascii_new: out std_ulogic := '0'; -- output flag indicating new ascii value
|
181 |
|
|
ascii_code: out std_ulogic_vector(6 downto 0)); -- ASCII value
|
182 |
|
|
end entity;
|
183 |
|
|
|
184 |
|
|
architecture rtl of ps2_kbd_top is
|
185 |
|
|
type machine is(ready, new_code, translate, output); -- needed states
|
186 |
|
|
signal state: machine; -- state machine
|
187 |
|
|
signal ps2_code_new: std_ulogic; -- new PS2 code flag from ps2_kbd_core component
|
188 |
|
|
signal ps2_code: std_ulogic_vector(7 downto 0); -- PS2 code input form ps2_kbd_core component
|
189 |
|
|
signal prev_ps2_code_new: std_ulogic := '1'; -- value of ps2_code_new flag on previous clock
|
190 |
|
|
signal break: std_ulogic := '0'; -- '1' for break code, '0' for make code
|
191 |
|
|
signal e0_code: std_ulogic := '0'; -- '1' for multi-code commands, '0' for single code commands
|
192 |
|
|
signal caps_lock: std_ulogic := '0'; -- '1' if caps lock is active, '0' if caps lock is inactive
|
193 |
|
|
signal control_r: std_ulogic := '0'; -- '1' if right control key is held down, else '0'
|
194 |
|
|
signal control_l: std_ulogic := '0'; -- '1' if left control key is held down, else '0'
|
195 |
|
|
signal shift_r: std_ulogic := '0'; -- '1' if right shift is held down, else '0'
|
196 |
|
|
signal shift_l: std_ulogic := '0'; -- '1' if left shift is held down, else '0'
|
197 |
|
|
signal ascii: std_ulogic_vector(7 downto 0) := x"FF"; -- internal value of ASCII translation
|
198 |
|
|
|
199 |
|
|
begin
|
200 |
|
|
|
201 |
|
|
-- instantiate PS2 keyboard interface logic
|
202 |
|
|
ps2_kbd_core_0: work.kbd_pkg.ps2_kbd_core
|
203 |
|
|
generic map(
|
204 |
|
|
clock_frequency => clock_frequency,
|
205 |
|
|
debounce_counter_size => ps2_debounce_counter_size)
|
206 |
|
|
port map(
|
207 |
|
|
clk => clk,
|
208 |
|
|
ps2_clk => ps2_clk,
|
209 |
|
|
ps2_data => ps2_data,
|
210 |
|
|
ps2_code_new => ps2_code_new,
|
211 |
|
|
ps2_code => ps2_code);
|
212 |
|
|
|
213 |
|
|
process(clk)
|
214 |
|
|
begin
|
215 |
|
|
if rising_edge(clk) then
|
216 |
|
|
prev_ps2_code_new <= ps2_code_new; -- keep track of previous ps2_code_new values to determine low-to-high transitions
|
217 |
|
|
case state is
|
218 |
|
|
|
219 |
|
|
-- ready state: wait for a new PS2 code to be received
|
220 |
|
|
when ready =>
|
221 |
|
|
if(prev_ps2_code_new = '0' AND ps2_code_new = '1') then -- new PS2 code received
|
222 |
|
|
ascii_new <= '0'; -- reset new ASCII code indicator
|
223 |
|
|
state <= new_code; -- proceed to new_code state
|
224 |
|
|
else -- no new PS2 code received yet
|
225 |
|
|
state <= ready; -- remain in ready state
|
226 |
|
|
end if;
|
227 |
|
|
|
228 |
|
|
-- new_code state: determine what to do with the new PS2 code
|
229 |
|
|
when new_code =>
|
230 |
|
|
if(ps2_code = x"F0") then -- code indicates that next command is break
|
231 |
|
|
break <= '1'; -- set break flag
|
232 |
|
|
state <= ready; -- return to ready state to await next PS2 code
|
233 |
|
|
elsif(ps2_code = x"E0") then -- code indicates multi-key command
|
234 |
|
|
e0_code <= '1'; -- set multi-code command flag
|
235 |
|
|
state <= ready; -- return to ready state to await next PS2 code
|
236 |
|
|
else -- code is the last PS2 code in the make/break code
|
237 |
|
|
ascii(7) <= '1'; -- set internal ascii value to unsupported code (for verification)
|
238 |
|
|
state <= translate; -- proceed to translate state
|
239 |
|
|
end if;
|
240 |
|
|
|
241 |
|
|
-- translate state: translate PS2 code to ASCII value
|
242 |
|
|
when translate =>
|
243 |
|
|
break <= '0'; -- reset break flag
|
244 |
|
|
e0_code <= '0'; -- reset multi-code command flag
|
245 |
|
|
|
246 |
|
|
-- handle codes for control, shift, and caps lock
|
247 |
|
|
case ps2_code is
|
248 |
|
|
when x"58" => -- caps lock code
|
249 |
|
|
if(break = '0') then -- if make command
|
250 |
|
|
caps_lock <= NOT caps_lock; -- toggle caps lock
|
251 |
|
|
end if;
|
252 |
|
|
when x"14" => -- code for the control keys
|
253 |
|
|
if(e0_code = '1') then -- code for right control
|
254 |
|
|
control_r <= NOT break; -- update right control flag
|
255 |
|
|
else -- code for left control
|
256 |
|
|
control_l <= NOT break; -- update left control flag
|
257 |
|
|
end if;
|
258 |
|
|
when x"12" => -- left shift code
|
259 |
|
|
shift_l <= NOT break; -- update left shift flag
|
260 |
|
|
when x"59" => -- right shift code
|
261 |
|
|
shift_r <= NOT break; -- update right shift flag
|
262 |
|
|
when others => null;
|
263 |
|
|
end case;
|
264 |
|
|
|
265 |
|
|
-- translate control codes (these do not depend on shift or caps lock)
|
266 |
|
|
if(control_l = '1' OR control_r = '1') then
|
267 |
|
|
case ps2_code is
|
268 |
|
|
when x"1E" => ascii <= x"00"; -- ^@ NUL
|
269 |
|
|
when x"1C" => ascii <= x"01"; -- ^A SOH
|
270 |
|
|
when x"32" => ascii <= x"02"; -- ^B STX
|
271 |
|
|
when x"21" => ascii <= x"03"; -- ^C ETX
|
272 |
|
|
when x"23" => ascii <= x"04"; -- ^D EOT
|
273 |
|
|
when x"24" => ascii <= x"05"; -- ^E ENQ
|
274 |
|
|
when x"2B" => ascii <= x"06"; -- ^F ACK
|
275 |
|
|
when x"34" => ascii <= x"07"; -- ^G BEL
|
276 |
|
|
when x"33" => ascii <= x"08"; -- ^H BS
|
277 |
|
|
when x"43" => ascii <= x"09"; -- ^I HT
|
278 |
|
|
when x"3B" => ascii <= x"0A"; -- ^J LF
|
279 |
|
|
when x"42" => ascii <= x"0B"; -- ^K VT
|
280 |
|
|
when x"4B" => ascii <= x"0C"; -- ^L FF
|
281 |
|
|
when x"3A" => ascii <= x"0D"; -- ^M CR
|
282 |
|
|
when x"31" => ascii <= x"0E"; -- ^N SO
|
283 |
|
|
when x"44" => ascii <= x"0F"; -- ^O SI
|
284 |
|
|
when x"4D" => ascii <= x"10"; -- ^P DLE
|
285 |
|
|
when x"15" => ascii <= x"11"; -- ^Q DC1
|
286 |
|
|
when x"2D" => ascii <= x"12"; -- ^R DC2
|
287 |
|
|
when x"1B" => ascii <= x"13"; -- ^S DC3
|
288 |
|
|
when x"2C" => ascii <= x"14"; -- ^T DC4
|
289 |
|
|
when x"3C" => ascii <= x"15"; -- ^U NAK
|
290 |
|
|
when x"2A" => ascii <= x"16"; -- ^V SYN
|
291 |
|
|
when x"1D" => ascii <= x"17"; -- ^W ETB
|
292 |
|
|
when x"22" => ascii <= x"18"; -- ^X CAN
|
293 |
|
|
when x"35" => ascii <= x"19"; -- ^Y EM
|
294 |
|
|
when x"1A" => ascii <= x"1A"; -- ^Z SUB
|
295 |
|
|
when x"54" => ascii <= x"1B"; -- ^[ ESC
|
296 |
|
|
when x"5D" => ascii <= x"1C"; -- ^\ FS
|
297 |
|
|
when x"5B" => ascii <= x"1D"; -- ^] GS
|
298 |
|
|
when x"36" => ascii <= x"1E"; -- ^^ RS
|
299 |
|
|
when x"4E" => ascii <= x"1F"; -- ^_ US
|
300 |
|
|
when x"4A" => ascii <= x"7F"; -- ^? DEL
|
301 |
|
|
when others => null;
|
302 |
|
|
end case;
|
303 |
|
|
else -- if control keys are not pressed
|
304 |
|
|
|
305 |
|
|
-- translate characters that do not depend on shift, or caps lock
|
306 |
|
|
case ps2_code is
|
307 |
|
|
when x"29" => ascii <= x"20"; -- space
|
308 |
|
|
when x"66" => ascii <= x"08"; -- backspace (BS control code)
|
309 |
|
|
when x"0D" => ascii <= x"09"; -- tab (HT control code)
|
310 |
|
|
when x"5A" => ascii <= x"0D"; -- enter (CR control code)
|
311 |
|
|
when x"76" => ascii <= x"1B"; -- escape (ESC control code)
|
312 |
|
|
when x"71" =>
|
313 |
|
|
if(e0_code = '1') then -- ps2 code for delete is a multi-key code
|
314 |
|
|
ascii <= x"7F"; -- delete
|
315 |
|
|
end if;
|
316 |
|
|
when others => null;
|
317 |
|
|
end case;
|
318 |
|
|
|
319 |
|
|
-- translate letters (these depend on both shift and caps lock)
|
320 |
|
|
if((shift_r = '0' AND shift_l = '0' AND caps_lock = '0') OR
|
321 |
|
|
((shift_r = '1' OR shift_l = '1') AND caps_lock = '1')) then -- letter is lowercase
|
322 |
|
|
case ps2_code is
|
323 |
|
|
when x"1C" => ascii <= x"61"; -- a
|
324 |
|
|
when x"32" => ascii <= x"62"; -- b
|
325 |
|
|
when x"21" => ascii <= x"63"; -- c
|
326 |
|
|
when x"23" => ascii <= x"64"; -- d
|
327 |
|
|
when x"24" => ascii <= x"65"; -- e
|
328 |
|
|
when x"2B" => ascii <= x"66"; -- f
|
329 |
|
|
when x"34" => ascii <= x"67"; -- g
|
330 |
|
|
when x"33" => ascii <= x"68"; -- h
|
331 |
|
|
when x"43" => ascii <= x"69"; -- i
|
332 |
|
|
when x"3B" => ascii <= x"6A"; -- j
|
333 |
|
|
when x"42" => ascii <= x"6B"; -- k
|
334 |
|
|
when x"4B" => ascii <= x"6C"; -- l
|
335 |
|
|
when x"3A" => ascii <= x"6D"; -- m
|
336 |
|
|
when x"31" => ascii <= x"6E"; -- n
|
337 |
|
|
when x"44" => ascii <= x"6F"; -- o
|
338 |
|
|
when x"4D" => ascii <= x"70"; -- p
|
339 |
|
|
when x"15" => ascii <= x"71"; -- q
|
340 |
|
|
when x"2D" => ascii <= x"72"; -- r
|
341 |
|
|
when x"1B" => ascii <= x"73"; -- s
|
342 |
|
|
when x"2C" => ascii <= x"74"; -- t
|
343 |
|
|
when x"3C" => ascii <= x"75"; -- u
|
344 |
|
|
when x"2A" => ascii <= x"76"; -- v
|
345 |
|
|
when x"1D" => ascii <= x"77"; -- w
|
346 |
|
|
when x"22" => ascii <= x"78"; -- x
|
347 |
|
|
when x"35" => ascii <= x"79"; -- y
|
348 |
|
|
when x"1A" => ascii <= x"7A"; -- z
|
349 |
|
|
when others => null;
|
350 |
|
|
end case;
|
351 |
|
|
else -- letter is uppercase
|
352 |
|
|
case ps2_code is
|
353 |
|
|
when x"1C" => ascii <= x"41"; -- A
|
354 |
|
|
when x"32" => ascii <= x"42"; -- B
|
355 |
|
|
when x"21" => ascii <= x"43"; -- C
|
356 |
|
|
when x"23" => ascii <= x"44"; -- D
|
357 |
|
|
when x"24" => ascii <= x"45"; -- E
|
358 |
|
|
when x"2B" => ascii <= x"46"; -- F
|
359 |
|
|
when x"34" => ascii <= x"47"; -- G
|
360 |
|
|
when x"33" => ascii <= x"48"; -- H
|
361 |
|
|
when x"43" => ascii <= x"49"; -- I
|
362 |
|
|
when x"3B" => ascii <= x"4A"; -- J
|
363 |
|
|
when x"42" => ascii <= x"4B"; -- K
|
364 |
|
|
when x"4B" => ascii <= x"4C"; -- L
|
365 |
|
|
when x"3A" => ascii <= x"4D"; -- M
|
366 |
|
|
when x"31" => ascii <= x"4E"; -- N
|
367 |
|
|
when x"44" => ascii <= x"4F"; -- O
|
368 |
|
|
when x"4D" => ascii <= x"50"; -- P
|
369 |
|
|
when x"15" => ascii <= x"51"; -- Q
|
370 |
|
|
when x"2D" => ascii <= x"52"; -- R
|
371 |
|
|
when x"1B" => ascii <= x"53"; -- S
|
372 |
|
|
when x"2C" => ascii <= x"54"; -- T
|
373 |
|
|
when x"3C" => ascii <= x"55"; -- U
|
374 |
|
|
when x"2A" => ascii <= x"56"; -- V
|
375 |
|
|
when x"1D" => ascii <= x"57"; -- W
|
376 |
|
|
when x"22" => ascii <= x"58"; -- X
|
377 |
|
|
when x"35" => ascii <= x"59"; -- Y
|
378 |
|
|
when x"1A" => ascii <= x"5A"; -- Z
|
379 |
|
|
when others => null;
|
380 |
|
|
end case;
|
381 |
|
|
end if;
|
382 |
|
|
|
383 |
|
|
-- translate numbers and symbols (these depend on shift but not caps lock)
|
384 |
|
|
if(shift_l = '1' OR shift_r = '1') then -- key's secondary character is desired
|
385 |
|
|
case ps2_code is
|
386 |
|
|
when x"16" => ascii <= x"21"; -- |
|
387 |
|
|
when x"52" => ascii <= x"22"; -- "
|
388 |
|
|
when x"26" => ascii <= x"23"; -- #
|
389 |
|
|
when x"25" => ascii <= x"24"; -- $
|
390 |
|
|
when x"2E" => ascii <= x"25"; -- %
|
391 |
|
|
when x"3D" => ascii <= x"26"; -- &
|
392 |
|
|
when x"46" => ascii <= x"28"; -- (
|
393 |
|
|
when x"45" => ascii <= x"29"; -- )
|
394 |
|
|
when x"3E" => ascii <= x"2A"; -- *
|
395 |
|
|
when x"55" => ascii <= x"2B"; -- +
|
396 |
|
|
when x"4C" => ascii <= x"3A"; -- :
|
397 |
|
|
when x"41" => ascii <= x"3C"; -- <
|
398 |
|
|
when x"49" => ascii <= x"3E"; -- >
|
399 |
|
|
when x"4A" => ascii <= x"3F"; -- ?
|
400 |
|
|
when x"1E" => ascii <= x"40"; -- @
|
401 |
|
|
when x"36" => ascii <= x"5E"; -- ^
|
402 |
|
|
when x"4E" => ascii <= x"5F"; -- _
|
403 |
|
|
when x"54" => ascii <= x"7B"; -- {
|
404 |
|
|
when x"5D" => ascii <= x"7C"; -- |
|
405 |
|
|
when x"5B" => ascii <= x"7D"; -- }
|
406 |
|
|
when x"0E" => ascii <= x"7E"; -- ~
|
407 |
|
|
when others => null;
|
408 |
|
|
end case;
|
409 |
|
|
else -- key's primary character is desired
|
410 |
|
|
case ps2_code is
|
411 |
|
|
when x"45" => ascii <= x"30"; -- 0
|
412 |
|
|
when x"16" => ascii <= x"31"; -- 1
|
413 |
|
|
when x"1E" => ascii <= x"32"; -- 2
|
414 |
|
|
when x"26" => ascii <= x"33"; -- 3
|
415 |
|
|
when x"25" => ascii <= x"34"; -- 4
|
416 |
|
|
when x"2E" => ascii <= x"35"; -- 5
|
417 |
|
|
when x"36" => ascii <= x"36"; -- 6
|
418 |
|
|
when x"3D" => ascii <= x"37"; -- 7
|
419 |
|
|
when x"3E" => ascii <= x"38"; -- 8
|
420 |
|
|
when x"46" => ascii <= x"39"; -- 9
|
421 |
|
|
when x"52" => ascii <= x"27"; -- '
|
422 |
|
|
when x"41" => ascii <= x"2C"; -- ,
|
423 |
|
|
when x"4E" => ascii <= x"2D"; -- -
|
424 |
|
|
when x"49" => ascii <= x"2E"; -- .
|
425 |
|
|
when x"4A" => ascii <= x"2F"; -- /
|
426 |
|
|
when x"4C" => ascii <= x"3B"; -- ;
|
427 |
|
|
when x"55" => ascii <= x"3D"; -- =
|
428 |
|
|
when x"54" => ascii <= x"5B"; -- [
|
429 |
|
|
when x"5D" => ascii <= x"5C"; -- \
|
430 |
|
|
when x"5B" => ascii <= x"5D"; -- ]
|
431 |
|
|
when x"0E" => ascii <= x"60"; -- `
|
432 |
|
|
when others => null;
|
433 |
|
|
end case;
|
434 |
|
|
end if;
|
435 |
|
|
|
436 |
|
|
end if;
|
437 |
|
|
|
438 |
|
|
if(break = '0') then -- the code is a make
|
439 |
|
|
state <= output; -- proceed to output state
|
440 |
|
|
else -- code is a break
|
441 |
|
|
state <= ready; -- return to ready state to await next PS2 code
|
442 |
|
|
end if;
|
443 |
|
|
|
444 |
|
|
-- output state: verify the code is valid and output the ASCII value
|
445 |
|
|
when output =>
|
446 |
|
|
if(ascii(7) = '0') then -- the PS2 code has an ASCII output
|
447 |
|
|
ascii_new <= '1'; -- set flag indicating new ASCII output
|
448 |
|
|
ascii_code <= ascii(6 downto 0); -- output the ASCII value
|
449 |
|
|
end if;
|
450 |
|
|
state <= ready; -- return to ready state to await next PS2 code
|
451 |
|
|
|
452 |
|
|
end case;
|
453 |
|
|
end if;
|
454 |
|
|
end process;
|
455 |
|
|
|
456 |
|
|
end;
|
457 |
|
|
|
458 |
|
|
--------------------------------------------------------------------------------
|
459 |
|
|
--
|
460 |
|
|
-- FileName: ps2_kbd_core.vhd
|
461 |
|
|
-- Dependencies: debounce.vhd
|
462 |
|
|
-- Design Software: Quartus II 32-bit Version 12.1 Build 177 SJ Full Version
|
463 |
|
|
--
|
464 |
|
|
-- HDL CODE IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
|
465 |
|
|
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
466 |
|
|
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
467 |
|
|
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
|
468 |
|
|
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
|
469 |
|
|
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
|
470 |
|
|
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
|
471 |
|
|
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
|
472 |
|
|
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
|
473 |
|
|
--
|
474 |
|
|
-- Version History
|
475 |
|
|
-- Version 1.0 11/25/2013 Scott Larson
|
476 |
|
|
-- Initial Public Release
|
477 |
|
|
--
|
478 |
|
|
-- @note This file has been modified from the original one found at
|
479 |
|
|
-- <https://eewiki.net/pages/viewpage.action?pageId=28279002>
|
480 |
|
|
--------------------------------------------------------------------------------
|
481 |
|
|
|
482 |
|
|
library ieee;
|
483 |
|
|
use ieee.std_logic_1164.all;
|
484 |
|
|
|
485 |
|
|
entity ps2_kbd_core is
|
486 |
|
|
generic(
|
487 |
5 |
howe.r.j.8 |
clock_frequency: integer := 50000000; -- system clock frequency in Hz
|
488 |
|
|
debounce_counter_size: integer := 8); -- set such that (2^size)/clock_frequency = 5us (size = 8 for 50MHz)
|
489 |
3 |
howe.r.j.8 |
port(
|
490 |
|
|
clk: in std_ulogic; -- system clock
|
491 |
|
|
ps2_clk: in std_ulogic; -- clock signal from PS/2 keyboard
|
492 |
|
|
ps2_data: in std_ulogic; -- data signal from PS/2 keyboard
|
493 |
|
|
ps2_code_new: out std_ulogic; -- flag that new PS/2 code is available on ps2_code bus
|
494 |
|
|
ps2_code: out std_ulogic_vector(7 downto 0)); -- code received from PS/2
|
495 |
|
|
end entity;
|
496 |
|
|
|
497 |
|
|
architecture rtl of ps2_kbd_core is
|
498 |
|
|
|
499 |
|
|
signal sync_ffs: std_ulogic_vector(1 downto 0); -- synchronizer flip-flops for PS/2 signals
|
500 |
|
|
signal ps2_clk_int: std_ulogic; -- debounced clock signal from PS/2 keyboard
|
501 |
|
|
|
502 |
|
|
attribute buffer_type: string;
|
503 |
|
|
attribute buffer_type of ps2_clk_int: signal is "BUFG";
|
504 |
|
|
|
505 |
|
|
signal ps2_data_int: std_ulogic; -- debounced data signal from PS/2 keyboard
|
506 |
|
|
signal ps2_word: std_ulogic_vector(10 downto 0); -- stores the ps2 data word
|
507 |
|
|
signal parity_error: std_ulogic; -- validate parity, start, and stop bits
|
508 |
|
|
signal count_idle: integer range 0 to clock_frequency/18000; --counter to determine PS/2 is idle
|
509 |
|
|
|
510 |
|
|
begin
|
511 |
|
|
|
512 |
|
|
--synchronizer flip-flops
|
513 |
|
|
process(clk)
|
514 |
|
|
begin
|
515 |
|
|
if rising_edge(clk) then -- rising edge of system clock
|
516 |
|
|
sync_ffs(0) <= ps2_clk; -- synchronize PS/2 clock signal
|
517 |
|
|
sync_ffs(1) <= ps2_data; -- synchronize PS/2 data signal
|
518 |
|
|
end if;
|
519 |
|
|
end process;
|
520 |
|
|
|
521 |
|
|
-- debounce ps2 input signals
|
522 |
|
|
debounce_ps2_clk: work.kbd_pkg.ps2_debounce
|
523 |
|
|
generic map(counter_size => debounce_counter_size)
|
524 |
|
|
port map(clk => clk, button => sync_ffs(0), result => ps2_clk_int);
|
525 |
|
|
|
526 |
|
|
debounce_ps2_data: work.kbd_pkg.ps2_debounce
|
527 |
|
|
generic map(counter_size => debounce_counter_size)
|
528 |
|
|
port map(clk => clk, button => sync_ffs(1), result => ps2_data_int);
|
529 |
|
|
|
530 |
|
|
-- input ps2 data
|
531 |
|
|
process(ps2_clk_int)
|
532 |
|
|
begin
|
533 |
|
|
if(ps2_clk_int'event and ps2_clk_int = '0') then -- falling edge of ps2 clock
|
534 |
|
|
ps2_word <= ps2_data_int & ps2_word(10 downto 1); -- shift in ps2 data bit
|
535 |
|
|
end if;
|
536 |
|
|
end process;
|
537 |
|
|
|
538 |
|
|
-- verify that parity, start, and stop bits are all correct
|
539 |
|
|
parity_error <= not (not ps2_word(0) and ps2_word(10) and (ps2_word(9) xor ps2_word(8) xor
|
540 |
|
|
ps2_word(7) xor ps2_word(6) xor ps2_word(5) xor ps2_word(4) xor ps2_word(3) xor
|
541 |
|
|
ps2_word(2) xor ps2_word(1)));
|
542 |
|
|
|
543 |
|
|
-- determine if ps2 port is idle (i.e. last transaction is finished) and output result
|
544 |
|
|
process(clk)
|
545 |
|
|
begin
|
546 |
|
|
if rising_edge(clk) then -- rising edge of system clock
|
547 |
|
|
if(ps2_clk_int = '0') then -- low ps2 clock, PS/2 is active
|
548 |
|
|
count_idle <= 0; -- reset idle counter
|
549 |
|
|
elsif(count_idle /= clock_frequency/18_000) then -- ps2 clock has been high less than a half clock period (<55us)
|
550 |
|
|
count_idle <= count_idle + 1; -- continue counting
|
551 |
|
|
end if;
|
552 |
|
|
|
553 |
|
|
if(count_idle = clock_frequency/18_000 and parity_error = '0') then -- idle threshold reached and no errors detected
|
554 |
|
|
ps2_code_new <= '1'; -- set flag that new PS/2 code is available
|
555 |
|
|
ps2_code <= ps2_word(8 downto 1); -- output new PS/2 code
|
556 |
|
|
else -- PS/2 port active or error detected
|
557 |
|
|
ps2_code_new <= '0'; -- set flag that PS/2 transaction is in progress
|
558 |
|
|
end if;
|
559 |
|
|
end if;
|
560 |
|
|
end process;
|
561 |
|
|
|
562 |
|
|
end;
|
563 |
|
|
|
564 |
|
|
--------------------------------------------------------------------------------
|
565 |
|
|
--
|
566 |
|
|
-- FileName: (originally) debounce.vhd
|
567 |
|
|
-- Dependencies: none
|
568 |
|
|
-- Design Software: Quartus II 32-bit Version 11.1 Build 173 SJ Full Version
|
569 |
|
|
--
|
570 |
|
|
-- HDL CODE IS PROVIDED "AS IS." DIGI-KEY EXPRESSLY DISCLAIMS ANY
|
571 |
|
|
-- WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
572 |
|
|
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
573 |
|
|
-- PARTICULAR PURPOSE, OR NON-INFRINGEMENT. IN NO EVENT SHALL DIGI-KEY
|
574 |
|
|
-- BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
|
575 |
|
|
-- DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, COST OF
|
576 |
|
|
-- PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
|
577 |
|
|
-- BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
|
578 |
|
|
-- ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS.
|
579 |
|
|
--
|
580 |
|
|
-- Version History
|
581 |
|
|
-- Version 1.0 3/26/2012 Scott Larson
|
582 |
|
|
-- Initial Public Release
|
583 |
|
|
--
|
584 |
|
|
-- @note This file has been modified from the original one found
|
585 |
|
|
-- on the web from: <https://eewiki.net/pages/viewpage.action?pageId=28279002>
|
586 |
|
|
--
|
587 |
|
|
--------------------------------------------------------------------------------
|
588 |
|
|
|
589 |
|
|
library ieee;
|
590 |
|
|
use ieee.std_logic_1164.all;
|
591 |
|
|
use ieee.numeric_std.all;
|
592 |
|
|
|
593 |
|
|
entity ps2_debounce is
|
594 |
5 |
howe.r.j.8 |
generic(counter_size: integer := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
|
595 |
3 |
howe.r.j.8 |
port(
|
596 |
|
|
clk: in std_ulogic;
|
597 |
|
|
button: in std_ulogic; --input signal to be debounced
|
598 |
|
|
result: out std_ulogic := '0'); --debounced signal
|
599 |
|
|
end entity;
|
600 |
|
|
|
601 |
|
|
architecture rtl of ps2_debounce is
|
602 |
|
|
signal flipflops: std_ulogic_vector(1 downto 0); --input flip flops
|
603 |
|
|
signal counter_set: std_ulogic; --sync reset to zero
|
604 |
|
|
signal counter_out: unsigned(counter_size downto 0) := (others => '0'); --counter output
|
605 |
|
|
begin
|
606 |
|
|
counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter
|
607 |
|
|
|
608 |
|
|
process(clk)
|
609 |
|
|
begin
|
610 |
|
|
if rising_edge(clk) then
|
611 |
|
|
flipflops(0) <= button;
|
612 |
|
|
flipflops(1) <= flipflops(0);
|
613 |
5 |
howe.r.j.8 |
if counter_set = '1' then --reset counter because input is changing
|
614 |
3 |
howe.r.j.8 |
counter_out <= (others => '0');
|
615 |
5 |
howe.r.j.8 |
elsif counter_out(counter_size) = '0' then --stable input time is not yet met
|
616 |
3 |
howe.r.j.8 |
counter_out <= counter_out + 1;
|
617 |
|
|
else --stable input time is met
|
618 |
|
|
result <= flipflops(1);
|
619 |
|
|
end if;
|
620 |
|
|
end if;
|
621 |
|
|
end process;
|
622 |
|
|
end;
|
623 |
|
|
|