forked from aslak3/MAXI030
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathps2_controller.vhd
More file actions
executable file
·224 lines (198 loc) · 6.84 KB
/
ps2_controller.vhd
File metadata and controls
executable file
·224 lines (198 loc) · 6.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
-- PS/2 edge finder
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ps2_edge_finder is
port ( clock : in STD_LOGIC;
edge_found : out STD_LOGIC; -- '1' when a falling edge is found
ps2_clock : in STD_LOGIC); -- The input clock to look at
end entity;
architecture behavioral of ps2_edge_finder is
signal edge_finder : STD_LOGIC_VECTOR (7 downto 0) := (others => '0');
begin
process (clock)
begin
if (clock'event and clock = '1') then
-- Shift the incoming clock signal in
edge_finder <= edge_finder (6 downto 0) & ps2_clock;
-- Check for a match against a falling edge
if (edge_finder = x"f0") then
edge_found <= '0';
elsif (edge_finder = x"0f") then
edge_found <= '1';
end if;
end if;
end process;
end architecture;
-- PS2 RX Shifter
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ps2_rx_shifter is
port ( clock : in STD_LOGIC;
edge_found : in STD_LOGIC; -- Has a clock edge been found?
rx_scancode : out STD_LOGIC_VECTOR (7 downto 0); -- What have we shifted in
scancode_ready_set : out STD_LOGIC;
parity_error : out STD_LOGIC;
ps2_data : in STD_LOGIC; -- PS2 data pin
tx_ready : in STD_LOGIC);
end entity;
architecture behavioral of ps2_rx_shifter is
signal byte_buffer : STD_LOGIC_VECTOR (7 downto 0) := x"00"; -- Currently shifting byte out
signal byte_counter : integer range 0 to 7; -- Byte shifting counter (0..7)
signal parity_check : STD_LOGIC := '0';
signal scancode_rx_counter : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
type T_STATE is (RX_START, RX_BYTE, RX_ODD_PARITY, RX_STOP);
signal state : T_STATE := RX_START;
signal last_edge_found : STD_LOGIC := '0';
begin
process (clock)
begin
if (clock'Event and clock = '1') then
last_edge_found <= edge_found;
scancode_ready_set <= '0';
if (scancode_rx_counter = x"ffff") then
state <= RX_START;
end if;
scancode_rx_counter <= scancode_rx_counter + '1';
if (edge_found = '0' and last_edge_found = '1' and tx_ready = '1') then
scancode_rx_counter <= (others => '0');
case state is
when RX_START =>
parity_error <= '0';
byte_counter <= 0;
byte_buffer <= x"00";
parity_check <= '1'; --'0';
state <= RX_BYTE;
when RX_BYTE =>
parity_check <= parity_check xor ps2_data;
byte_buffer (byte_counter) <= ps2_data;
if (byte_counter = 7) then
state <= RX_ODD_PARITY;
end if;
byte_counter <= byte_counter + 1;
when RX_ODD_PARITY =>
-- Check for an even number of ones: good!
if (parity_check = not ps2_data) then
-- No error
parity_error <= '0';
else
parity_error <= '1';
end if;
rx_scancode <= byte_buffer;
state <= RX_STOP;
when RX_STOP =>
scancode_ready_set <= '1';
state <= RX_START;
end case;
end if;
end if;
end process;
end architecture;
-- PS/2 TX Shifter
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ps2_tx_shifter is
port ( clock : in STD_LOGIC;
reset : in STD_LOGIC; -- Global reset
edge_found : in STD_LOGIC; -- PS/2 falling clock edge?
tx_command_byte : in STD_LOGIC_VECTOR (7 downto 0); -- What we are shifting out
tx_command_trigger : in STD_LOGIC; -- Go signal
tx_clock_driven : out STD_LOGIC; -- Drive the clock pin?
tx_data_driven : out STD_LOGIC; -- Drive the data pin?
ps2_clock : out STD_LOGIC; -- PS/2 clock OUT
ps2_data : out STD_LOGIC; -- PS2 data pin OUT
tx_ready : out STD_LOGIC); -- TX is ready for another character
end entity;
architecture behavioral of ps2_tx_shifter is
signal clock_counter : STD_LOGIC_VECTOR (8 downto 0) := (others => '0');
signal byte_counter : integer range 0 to 7 := 0; -- Byte shifting counter (0..7)
signal parity_check : STD_LOGIC := '0'; -- Accumulated parity
signal request_to_send1 : STD_LOGIC := '0'; -- Sending clock pulse?
signal request_to_send2 : STD_LOGIC := '0'; -- Sending data pulse?
signal request_to_send3 : STD_LOGIC := '0'; -- Sending data pulse?
signal tx_busy : STD_LOGIC := '0'; -- Transmittion is busy
type T_STATE is (TX_BYTE, TX_ODD_PARITY, TX_STOP, TX_END);
signal state : T_STATE := TX_BYTE;
signal last_edge_found : STD_LOGIC := '0';
begin
process (clock, reset)
begin
if (reset = '1') then
tx_clock_driven <= '0';
tx_data_driven <= '0';
request_to_send1 <= '0';
request_to_send2 <= '0';
request_to_send3 <= '0';
tx_busy <= '0';
tx_ready <= '1';
elsif (clock'event and clock = '1') then
last_edge_found <= edge_found;
if (tx_command_trigger = '1') then
-- Pull clock low to tell the device we want to tx
clock_counter <= (others => '0');
parity_check <= '0';
request_to_send1 <= '1';
tx_clock_driven <= '1';
ps2_clock <= '0';
tx_ready <= '0';
end if;
-- Send a "reqest to send" pulse on data
if (request_to_send1 = '1') then
if (clock_counter = "111111111") then
request_to_send1 <= '0';
tx_data_driven <= '1';
ps2_data <= '0';
clock_counter <= (others => '0');
request_to_send2 <= '1';
end if;
clock_counter <= clock_counter + '1';
end if;
-- Send start bit, but at this point the device is not driving the clock
if (request_to_send2 = '1') then
if (clock_counter = "111111111") then
request_to_send2 <= '0';
tx_clock_driven <= '1';
ps2_clock <= '1';
request_to_send3 <= '1';
end if;
clock_counter <= clock_counter + '1';
end if;
-- Send start bit, but at this point the device is not driving the clock
if (request_to_send3 = '1') then
if (clock_counter = "111111111") then
request_to_send3 <= '0';
tx_clock_driven <= '0';
tx_busy <= '1';
byte_counter <= 0;
state <= TX_BYTE;
end if;
clock_counter <= clock_counter + '1';
end if;
if (tx_busy = '1' and edge_found = '0' and last_edge_found = '1') then
case state is
when TX_BYTE =>
-- Calculate the parity and send the bit
parity_check <= parity_check xor tx_command_byte (byte_counter);
ps2_data <= tx_command_byte (byte_counter);
if (byte_counter = 7) then
state <= TX_ODD_PARITY;
end if;
byte_counter <= byte_counter + 1;
when TX_ODD_PARITY =>
ps2_data <= not parity_check;
state <= TX_STOP;
when TX_STOP =>
ps2_data <= '1';
state <= TX_END;
when TX_END =>
tx_busy <= '0';
tx_data_driven <= '0';
tx_ready <= '1';
state <= TX_BYTE;
end case;
end if;
end if;
end process;
end architecture;