-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathkbd_ps2.v
More file actions
148 lines (131 loc) · 4.95 KB
/
kbd_ps2.v
File metadata and controls
148 lines (131 loc) · 4.95 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
/*==========================================================
ECE 641 Spring 2018
Thomas Gorham
(based on kbd_ps2.v from Dr. Gruenbacher)
ps2_controller.v
Handles data input from a ps2 keyboard.
Keyboards do not require bidirectional data, so only input
is implemented. Output comes in the form of a bitmask
representing piano keys from C to B with minors included
where appropriate (notes range from index 0 to index 11).
Special indices: 12: +
13: -
14: \
15: unrecognized
==========================================================*/
module kbd(ar, clk, ps2_clk, ps2_dat, bitmask, keyval, keyOn, select );
input ar;
input clk;
input ps2_clk;
input ps2_dat;
output reg [15:0] bitmask;
output reg [3:0] keyval;
output keyOn;
output reg [1:0] select;
reg [7:0] code;
reg ps2_clk_filt; // We need to filter the ps2 clock for edges
reg [7:0] filter_sr;
always @(negedge ar or posedge clk)
if(~ar) begin
// Initialize to all zeros
ps2_clk_filt <= 1'b0;
filter_sr <= 8'hff;
end else begin
// Shift filter_sr towards LSB (right shift) and insert ps2_clk as bit MSB
filter_sr <= {ps2_clk, filter_sr[7:1]};
if(filter_sr == 8'hff) // If ps2_clk has been high for 8 cycles
ps2_clk_filt <= 1'b0; // Set filtered value high
else if(filter_sr == 8'h00) // If ps2_clk has been low for 8 cycles
ps2_clk_filt <= 1'b1; // Set filtered value low
end
reg [3:0] bit_count;
reg currently_receiving;
reg received_stop;
reg [3:0] bitindex;
always @(negedge ar or posedge ps2_clk_filt)
if(~ar) begin
// Initialize values to zero
bit_count <= 0;
code <= 7'h00;
currently_receiving <= 1'b0;
bitmask <= 0;
end else begin
// When not receiving, listen for ps2_dat to drop low (start bit)
if(~currently_receiving && ps2_dat == 1'b0) begin
currently_receiving <= 1'b1;
bit_count <= 0;
end else begin
// Always increment bit count when triggered and receiving
if(currently_receiving) begin
bit_count <= bit_count + 1'b1;
if(bit_count <= 4'd7)
code <= {ps2_dat, code[7:1]}; // Shift in the latest ps2 data bit_count
else begin
// We've received 8 bits!
// If we receive F0, the next index received will be
// the subject of a stop code
if(code == 8'hF0) begin
received_stop <= 1;
end else if(received_stop) begin
// If the last character received was a stop code clear that bit
bitmask[bitindex] <= 0;
received_stop <= 0;
end else begin
// Last character received was not a stop code
// so we should mark a bit high
bitmask[bitindex] <= 1;
// Output the currently held key
if(bitindex<=12)
begin
keyval <= bitindex;
end
end
currently_receiving <= 1'b0;
end
end
end
end
// This always block defines the lookup table that converts
// scan codes into bit positions for the output vector
always@(code)
case(code)
8'h1A: bitindex = 0; //Z
8'h1B: bitindex = 1; //S
8'h22: bitindex = 2; //X
8'h21: bitindex = 3; //C
8'h2B: bitindex = 4; //F
8'h2A: bitindex = 5; //V
8'h34: bitindex = 6; //G
8'h32: bitindex = 7; //B
8'h31: bitindex = 8; //N
8'h3B: bitindex = 9; //J
8'h3A: bitindex = 10; //M
8'h42: bitindex = 11; //K
8'h41: bitindex = 12; //<
8'h55: bitindex = 13; //+
8'h4E: bitindex = 14; //-
default: bitindex = 15;//
endcase
wire [12:0] pianoKeys;
assign pianoKeys = bitmask[12:0];
assign keyOn = |pianoKeys;
//Process +/- keys
reg plus_prev, minus_prev;
wire plus_rising, minus_rising;
assign plus_rising = (plus_prev==0)&&(bitmask[13]==1);
assign minus_rising = (minus_prev==0)&&(bitmask[14]==1);
always @(negedge ar or posedge clk)
if(~ar) begin
// Initialize values to zero
select <= 0;
plus_prev <= 0;
minus_prev <= 0;
end else begin
if(plus_rising)
select <= select + 1;
if(minus_rising)
select <= select - 1;
plus_prev <= bitmask[13];
minus_prev <= bitmask[14];
end
endmodule