-
Notifications
You must be signed in to change notification settings - Fork 0
/
ps2.v
313 lines (297 loc) · 8.66 KB
/
ps2.v
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
//
// Permission:
//
// Terasic grants permission to use and modify this code for use
// in synthesis for all Terasic Development Boards and Altera Development
// Kits made by Terasic. Other use of this code, including the selling
// ,duplication, or modification of any portion is strictly prohibited.
//
// Disclaimer:
//
// This VHDL/Verilog or C/C++ source code is intended as a design reference
// which illustrates how these types of functions can be implemented.
// It is the user's responsibility to verify their design for
// consistency and functionality through the use of formal
// verification methods. Terasic provides no warranty regarding the use
// or functionality of this code.
//
// --------------------------------------------------------------------
//
// Terasic Technologies Inc
// 356 Fu-Shin E. Rd Sec. 1. JhuBei City,
// HsinChu County, Taiwan
// 302
//
// web: http://www.terasic.com/
// email: [email protected]
//
// --------------------------------------------------------------------
//
// Major Functions: DE2_115_PS2 Mouse Controller
//
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
// Ver :| Author :| Mod. Date :| Changes Made:
// V1.0 :| Johnny FAN,HdHuang :| 05/16/10 :| Initial Revision
// V2.0 :| Kyle Gagner :| 12/6/15 :| Modified for EE 271 students @ UW
// V2.1 :| Kyle Gagner :| 1/17/16 :| Made start & reset active high
// V2.2 :| Jerrold Erickson :| 11/14/19 :| Fixed oX_BIN and oY_BIN counter and changed WIDTH/HEIGH parameters
// --------------------------------------------------------------------
module ps2
#(
parameter WIDTH = 2048,
parameter HEIGHT = 2048,
parameter BIN = 10,
parameter HYSTERESIS = 3
)
(
start, // transmit instrucions to device
reset, // FSM reset signal
CLOCK_50, //clock source
PS2_CLK, //ps2_clock signal inout
PS2_DAT, //ps2_data signal inout
button_left, //left button press display
button_right, //right button press display
button_middle, //middle button press display
bin_x, //binned X position with hysteresis
bin_y //binned Y position with hysteresis
);
//=======================================================
// PARAMETERS
//=======================================================
parameter UPPER_BITS = $clog2(WIDTH>HEIGHT?WIDTH:HEIGHT);
parameter LOWER_BITS = $clog2(BIN+HYSTERESIS+256)+1;
parameter THRESHOLD = BIN+HYSTERESIS;
//=======================================================
// PORT declarations
//=======================================================
input start;
input reset;
input CLOCK_50;
inout PS2_CLK;
inout PS2_DAT;
output reg button_left;
output reg button_right;
output reg button_middle;
output reg [UPPER_BITS-1:0] bin_x;
output reg [UPPER_BITS-1:0] bin_y;
//instruction define, users can charge the instruction byte here for other purpose according to ps/2 mouse datasheet.
//the MSB is of parity check bit, that's when there are odd number of 1's with data bits, it's value is '0',otherwise it's '1' instead.
parameter enable_byte =9'b011110100;
//=======================================================
// REG/WIRE declarations
//=======================================================
reg [1:0] cur_state,nex_state;
reg ce,de;
reg [3:0] byte_cnt,delay;
reg [5:0] ct;
reg [7:0] cnt;
reg [8:0] clk_div;
reg [9:0] dout_reg;
reg [32:0] shift_reg;
reg leflatch,riglatch,midlatch;
reg ps2_clk_in,ps2_clk_syn1,ps2_dat_in,ps2_dat_syn1;
wire clk,ps2_dat_syn0,ps2_clk_syn0,ps2_dat_out,ps2_clk_out,flag;
reg [LOWER_BITS-1:0] x_latch;
reg [LOWER_BITS-1:0] y_latch;
reg [UPPER_BITS-1:0] oX_BIN;
reg [UPPER_BITS-1:0] oY_BIN;
//=======================================================
// PARAMETER declarations
//=======================================================
//state define
parameter listen =2'b00,
pullclk=2'b01,
pulldat=2'b10,
trans =2'b11;
//=======================================================
// Structural coding
//=======================================================
//clk division, derive a 97.65625KHz clock from the 50MHz source;
always@(posedge CLOCK_50)
begin
clk_div <= clk_div+1;
end
assign clk = clk_div[8];
//tristate output control for PS2_DAT and PS2_CLK;
assign PS2_CLK = ce?ps2_clk_out:1'bZ;
assign PS2_DAT = de?ps2_dat_out:1'bZ;
assign ps2_clk_out = 1'b0;
assign ps2_dat_out = dout_reg[0];
assign ps2_clk_syn0 = ce?1'b1:PS2_CLK;
assign ps2_dat_syn0 = de?1'b1:PS2_DAT;
// deal with any issues which may be due to moving between clock domains
reg [9:0] starttimer;
always @(posedge CLOCK_50)
begin
if(start) starttimer <= 1'b1;
else if(starttimer) starttimer <= starttimer + 1'b1;
button_left = leflatch;
button_right = riglatch;
button_middle = midlatch;
bin_x = oX_BIN;
bin_y = oY_BIN;
end
//multi-clock region simple synchronization
always@(posedge clk)
begin
ps2_clk_syn1 <= ps2_clk_syn0;
ps2_clk_in <= ps2_clk_syn1;
ps2_dat_syn1 <= ps2_dat_syn0;
ps2_dat_in <= ps2_dat_syn1;
end
//FSM shift
always@(*)
begin
case(cur_state)
listen :begin
if (starttimer && (cnt == 8'b11111111))
nex_state = pullclk;
else
nex_state = listen;
ce = 1'b0;
de = 1'b0;
end
pullclk :begin
if (delay == 4'b1100)
nex_state = pulldat;
else
nex_state = pullclk;
ce = 1'b1;
de = 1'b0;
end
pulldat :begin
nex_state = trans;
ce = 1'b1;
de = 1'b1;
end
trans :begin
if (byte_cnt == 4'b1010)
nex_state = listen;
else
nex_state = trans;
ce = 1'b0;
de = 1'b1;
end
default : nex_state = listen;
endcase
end
//idle counter
always@(posedge clk)
begin
if ({ps2_clk_in,ps2_dat_in} == 2'b11)
begin
cnt <= cnt+1;
end
else begin
cnt <= 8'd0;
end
end
//periodically reset ct; ct counts the received data length;
assign flag = (cnt == 8'hff)?1:0;
always@(posedge ps2_clk_in,posedge flag)
begin
if (flag)
ct <= 6'b000000;
else
ct <= ct+1;
end
//latch data from shift_reg;outputs is of 2's complement;
//Please treat the cnt value here with caution, otherwise wrong data will be latched.
always@(posedge clk, posedge reset)
begin
if(reset)
begin
leflatch <= 1'b0;
riglatch <= 1'b0;
midlatch <= 1'b0;
x_latch <= 0;
y_latch <= 0;
oX_BIN <= 0;
oY_BIN <= 0;
end
else if (cnt == 8'b00011110 && (ct[5] == 1'b1 || ct[4] == 1'b1))
begin
leflatch <= shift_reg[1];
riglatch <= shift_reg[2];
midlatch <= shift_reg[3];
x_latch <= x_latch+{{(LOWER_BITS-8){shift_reg[19]}},shift_reg[19 : 12]};
y_latch <= y_latch+{{(LOWER_BITS-8){shift_reg[30]}},shift_reg[30 : 23]};
end
else
begin
if($signed(x_latch) >= THRESHOLD)
begin
x_latch <= x_latch - BIN;
if(oX_BIN != WIDTH-1)
begin
oX_BIN <= oX_BIN + 1'b1;
end
end
else if($signed(x_latch) <= -THRESHOLD)
begin
x_latch <= x_latch + BIN;
if(oX_BIN != 0)
begin
oX_BIN <= oX_BIN - 1'b1;
end
end
if($signed(y_latch) >= THRESHOLD)
begin
y_latch <= y_latch - BIN;
if(oY_BIN != HEIGHT-1)
begin
oY_BIN <= oY_BIN + 1'b1;
end
end
else if($signed(y_latch) <= -THRESHOLD)
begin
y_latch <= y_latch + BIN;
if(oY_BIN != 0)
begin
oY_BIN <= oY_BIN - 1'b1;
end
end
end
end
//pull ps2_clk low for 100us before transmit starts;
always@(posedge clk)
begin
if (cur_state == pullclk)
delay <= delay+1;
else
delay <= 4'b0000;
end
//transmit data to ps2 device;eg. 0xF4
always@(negedge ps2_clk_in)
begin
if (cur_state == trans)
dout_reg <= {1'b0,dout_reg[9:1]};
else
dout_reg <= {enable_byte,1'b0};
end
//transmit byte length counter
always@(negedge ps2_clk_in)
begin
if (cur_state == trans)
byte_cnt <= byte_cnt+1;
else
byte_cnt <= 4'b0000;
end
//receive data from ps2 device;
always@(negedge ps2_clk_in)
begin
if (cur_state == listen)
shift_reg <= {ps2_dat_in,shift_reg[32:1]};
end
//FSM movement
always@(posedge clk,posedge reset)
begin
if (reset)
cur_state <= listen;
else
cur_state <= nex_state;
end
endmodule