-
Notifications
You must be signed in to change notification settings - Fork 0
/
MouseCtrl.vhd
1016 lines (937 loc) · 42.6 KB
/
MouseCtrl.vhd
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
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
------------------------------------------------------------------------
-- mouse_controller.vhd
------------------------------------------------------------------------
-- Author : Ulrich Zoltán
-- Copyright 2006 Digilent, Inc.
------------------------------------------------------------------------
-- Software version : Xilinx ISE 7.1.04i
-- WebPack
-- Device : 3s200ft256-4
------------------------------------------------------------------------
-- This file contains a controller for a ps/2 compatible mouse device.
-- This controller is a client for the ps2interface module.
------------------------------------------------------------------------
-- Behavioral description
------------------------------------------------------------------------
-- Please read the following article on the web for understanding how
-- to interface a ps/2 mouse:
-- http://www.computer-engineering.org/ps2mouse/
-- This controller is implemented as described in the above article.
-- The mouse controller receives bytes from the ps2interface which, in
-- turn, receives them from the mouse device. Data is received on the
-- rx_data input port, and is validated by the read signal. read is
-- active for one clock period when new byte available on rx_data. Data
-- is sent to the ps2interface on the tx_data output port and validated
-- by the write output signal. 'write' should be active for one clock
-- period when tx_data contains the command or data to be sent to the
-- mouse. ps2interface wraps the byte in a 11 bits packet that is sent
-- through the ps/2 port using the ps/2 protocol. Similarly, when the
-- mouse sends data, the ps2interface receives 11 bits for every byte,
-- extracts the byte from the ps/2 frame, puts it on rx_data and
-- activates read for one clock period. If an error occurs when sending
-- or receiving a frame from the mouse, the err input goes high for one
-- clock period. When this occurs, the controller enters reset state.
-- When in reset state, the controller resets the mouse and begins an
-- initialization procedure that consists of tring to put mouse in
-- scroll mode (enables wheel if the mouse has one), setting the
-- resolution of the mouse, the sample rate and finally enables
-- reporting. Implicitly the mouse, after a reset or imediately after a
-- reset, does not send data packets on its own. When reset(or power-up)
-- the mouse enters reset state, where it performs a test, called the
-- bat test (basic assurance test), when this test is done, it sends
-- the result: AAh for test ok, FCh for error. After this it sends its
-- ID which is 00h. When this is done, the mouse enters stream mode,
-- but with reporting disabled (movement data packets are not sent).
-- To enable reporting the enable data reporting command (F4h) must be
-- sent to the mouse. After this command is sent, the mouse will send
-- movement data packets when the mouse is moved or the status of the
-- button changes.
-- After sending a command or a byte following a command, the mouse
-- must respond with ack (FAh). For managing the intialization
-- procedure and receiving the movement data packets, a FSM is used.
-- When the fpga is powered up or the logic is reset using the global
-- reset, the FSM enters reset state. From this state, the FSM will
-- transition to a series of states used to initialize the mouse. When
-- initialization is complete, the FSM remains in state read_byte_1,
-- waiting for a movement data packet to be sent. This is the idle
-- state if the FSM. When a byte is received in this state, this is
-- the first byte of the 3 bytes sent in a movement data packet (4 bytes
-- if mouse in scrolling mode). After reading the last byte from the
-- packet, the FSM enters mark_new_event state and sets new_event high.
-- After that FSM enterss read_byte_1 state, resets new_event and waits
-- for a new packet.
-- After a packet is received, new_event is set high for one clock
-- period to "inform" the clients of this controller a new packet was
-- received and processed.
-- During the initialization procedure, the controller tries to put the
-- mouse in scroll mode (activates wheel, if mouse has one). This is
-- done by successively setting the sample rate to 200, then to 100, and
-- lastly to 80. After this is done, the mouse ID is requested by
-- sending get device ID command (F2h). If the received ID is 00h than
-- the mouse does not have a wheel. If the received ID is 03h than the
-- mouse is in scroll mode, and when sending movement data packets
-- (after enabling data reporting) it will include z movement data.
-- If the mouse is in normal, non-scroll mode, the movement data packet
-- consists of 3 successive bytes. This is their format:
--
--
--
-- bits 7 6 5 4 3 2 1 0
-- -------------------------------------------------
-- byte 1 | YOVF| XOVF|YSIGN|XSIGN| 1 | MBTN| RBTN| LBTN|
-- -------------------------------------------------
-- -------------------------------------------------
-- byte 2 | X MOVEMENT |
-- -------------------------------------------------
-- -------------------------------------------------
-- byte 3 | Y MOVEMENT |
-- -------------------------------------------------
-- OVF = overflow
-- BTN = button
-- M = middle
-- R = right
-- L = left
--
-- When scroll mode is enabled, the mouse send 4 byte movement packets.
-- bits 7 6 5 4 3 2 1 0
-- -------------------------------------------------
-- byte 1 | YOVF| XOVF|YSIGN|XSIGN| 1 | MBTN| RBTN| LBTN|
-- -------------------------------------------------
-- -------------------------------------------------
-- byte 2 | X MOVEMENT |
-- -------------------------------------------------
-- -------------------------------------------------
-- byte 3 | Y MOVEMENT |
-- -------------------------------------------------
-- -------------------------------------------------
-- byte 4 | Z MOVEMENT |
-- -------------------------------------------------
-- x and y movement counters are represented on 8 bits, 2's complement
-- encoding. The first bit (sign bit) of the counters are the xsign and
-- ysign bit from the first packet, the rest of the bits are the second
-- byte for the x movement and the third byte for y movement. For the
-- z movement the range is -8 -> +7 and only the 4 least significant
-- bits from z movement are valid, the rest are sign extensions.
-- The x and y movements are in range: -256 -> +255
-- The mouse uses as axes origin the lower-left corner. For the purpose
-- of displaying a mouse cursor on the screen, the controller inverts
-- the y axis to move the axes origin in the upper-left corner. This
-- is done by negating the y movement value (following the 2s complement
-- encoding). The movement data received from the mouse are delta
-- movements, the data represents the movement of the mouse relative
-- to the last position. The controller keeps track of the position of
-- the mouse relative to the upper-left corner. This is done by keeping
-- the mouse position in two registers x_pos and y_pos and adding the
-- delta movements to their value. The addition uses saturation. That
-- means the value of the mouse position will not exceed certain bounds
-- and will not rollover the a margin. For example, if the mouse is at
-- the left margin and is moved left, the x position remains at the left
-- margin(0). The lower bound is always 0 for both x and y movement.
-- The upper margin can be set using input pins: value, setmax_x,
-- setmax_y. To set the upper bound of the x movement counter, the new
-- value is placed on the value input pins and setmax_x is activated
-- for at least one clock period. Similarly for y movement counter, but
-- setmax_y is activated instead. Notice that value has 10 bits, and so
-- the maximum value for a bound is 1023.
-- The position of the mouse (x_pos and y_pos) can be set at any time,
-- by placing the x or y position on the value input pins and activating
-- the setx, or sety respectively, for at least one clock period. This
-- is useful for setting an original position of the mouse different
-- from (0,0).
------------------------------------------------------------------------
-- Port definitions
------------------------------------------------------------------------
-- clk - global clock signal (100MHz)
-- rst - global reset signal
-- read - input pin, from ps2interface
-- - active one clock period when new data received
-- - and available on rx_data
-- err - input pin, from ps2interface
-- - active one clock period when error occurred when
-- - receiving or sending data.
-- rx_data - input pin, 8 bits, from ps2interface
-- - the byte received from the mouse.
-- xpos - output pin, 10 bits
-- - the x position of the mouse relative to the upper
-- - left corner
-- ypos - output pin, 10 bits
-- - the y position of the mouse relative to the upper
-- - left corner
-- zpos - output pin, 4 bits
-- - last delta movement on z axis
-- left - output pin, high if the left mouse button is pressed
-- middle - output pin, high if the middle mouse button is
-- - pressed
-- right - output pin, high if the right mouse button is
-- - pressed
-- new_event - output pin, active one clock period after receiving
-- - and processing one movement data packet.
-- tx_data - output pin, 8 bits, to ps2interface
-- - byte to be sent to the mouse
-- write - output pin, to ps2interface
-- - active one clock period when sending a byte to the
-- - ps2interface.
------------------------------------------------------------------------
-- Revision History:
-- 09/18/2006(UlrichZ): created
------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- simulation library
library UNISIM;
use UNISIM.VComponents.all;
-- the mouse_controller entity declaration
-- read above for behavioral description and port definitions.
entity mouse_controller is
port(
clk : in std_logic;
rst : in std_logic;
read : in std_logic;
err : in std_logic;
rx_data : in std_logic_vector(7 downto 0);
xpos : out std_logic_vector(9 downto 0);
ypos : out std_logic_vector(9 downto 0);
zpos : out std_logic_vector(3 downto 0);
left : out std_logic;
middle : out std_logic;
right : out std_logic;
new_event : out std_logic;
tx_data : out std_logic_vector(7 downto 0);
write : out std_logic;
value : in std_logic_vector(9 downto 0);
setx : in std_logic;
sety : in std_logic;
setmax_x : in std_logic;
setmax_y : in std_logic
);
end mouse_controller;
architecture Behavioral of mouse_controller is
------------------------------------------------------------------------
-- CONSTANTS
------------------------------------------------------------------------
-- constants defining commands to send or received from the mouse
constant FA: std_logic_vector(7 downto 0) := "11111010"; -- 0xFA(ACK)
constant FF: std_logic_vector(7 downto 0) := "11111111"; -- 0xFF(RESET)
constant AA: std_logic_vector(7 downto 0) := "10101010"; -- 0xAA(BAT_OK)
constant OO: std_logic_vector(7 downto 0) := "00000000"; -- 0x00(ID)
-- (atention: name is 2 letters O not zero)
-- command to read id
constant READ_ID : std_logic_vector(7 downto 0) := x"F2";
-- command to enable mouse reporting
-- after this command is sent, the mouse begins sending data packets
constant ENABLE_REPORTING : std_logic_vector(7 downto 0) := x"F4";
-- command to set the mouse resolution
constant SET_RESOLUTION : std_logic_vector(7 downto 0) := x"E8";
-- the value of the resolution to send after sending SET_RESOLUTION
constant RESOLUTION : std_logic_vector(7 downto 0) := x"03";
-- (8 counts/mm)
-- command to set the mouse sample rate
constant SET_SAMPLE_RATE : std_logic_vector(7 downto 0) := x"F3";
-- the value of the sample rate to send after sending SET_SAMPLE_RATE
constant SAMPLE_RATE : std_logic_vector(7 downto 0) := x"28";
-- (40 samples/s)
-- default maximum value for the horizontal mouse position
constant DEFAULT_MAX_X : std_logic_vector(9 downto 0) := "1001111111";
-- 639
-- default maximum value for the vertical mouse position
constant DEFAULT_MAX_Y : std_logic_vector(9 downto 0) := "0111011111";
-- 479
------------------------------------------------------------------------
-- SIGNALS
------------------------------------------------------------------------
-- after doing the enable scroll mouse procedure, if the ID returned by
-- the mouse is 03 (scroll mouse enabled) then this register will be set
-- If '1' then the mouse is in scroll mode, else mouse is in simple
-- mouse mode.
signal haswheel: std_logic := '0';
-- horizontal and veritcal mouse position
-- origin of axes is upper-left corner
-- the origin of axes the mouse uses is the lower-left corner
-- The y-axis is inverted, by making negative the y movement received
-- from the mouse (if it was positive it becomes negative
-- and vice versa)
signal x_pos,y_pos: std_logic_vector(10 downto 0) := (others => '0');
-- active when an overflow occurred on the x and y axis
-- bits 6 and 7 from the first byte received from the mouse
signal x_overflow,y_overflow: std_logic := '0';
-- active when the x,y movement is negative
-- bits 4 and 5 from the first byte received from the mouse
signal x_sign,y_sign: std_logic := '0';
-- 2's complement value for incrementing the x_pos,y_pos
-- y_inc is the negated value from the mouse in the third byte
signal x_inc,y_inc: std_logic_vector(7 downto 0) := (others => '0');
-- active for one clock period, indicates new delta movement received
-- on x,y axis
signal x_new,y_new: std_logic := '0';
-- maximum value for x and y position registers(x_pos,y_pos)
signal x_max: std_logic_vector(9 downto 0) := DEFAULT_MAX_X;
signal y_max: std_logic_vector(9 downto 0) := DEFAULT_MAX_Y;
-- active when left,middle,right mouse button is down
signal left_down,middle_down,right_down: std_logic := '0';
-- the FSM states
-- states that begin with "reset" are part of the reset procedure.
-- states that end in "_wait_ack" are states in which ack is waited
-- as response to sending a byte to the mouse.
-- read behavioral description above for details.
type fsm_state is
(
reset,reset_wait_ack,reset_wait_bat_completion,reset_wait_id,
reset_set_sample_rate_200,reset_set_sample_rate_200_wait_ack,
reset_send_sample_rate_200,reset_send_sample_rate_200_wait_ack,
reset_set_sample_rate_100,reset_set_sample_rate_100_wait_ack,
reset_send_sample_rate_100,reset_send_sample_rate_100_wait_ack,
reset_set_sample_rate_80,reset_set_sample_rate_80_wait_ack,
reset_send_sample_rate_80,reset_send_sample_rate_80_wait_ack,
reset_read_id,reset_read_id_wait_ack,reset_read_id_wait_id,
reset_set_resolution,reset_set_resolution_wait_ack,
reset_send_resolution,reset_send_resolution_wait_ack,
reset_set_sample_rate_40,reset_set_sample_rate_40_wait_ack,
reset_send_sample_rate_40,reset_send_sample_rate_40_wait_ack,
reset_enable_reporting,reset_enable_reporting_wait_ack,
read_byte_1,read_byte_2,read_byte_3,read_byte_4,mark_new_event
);
-- holds current state of the FSM
signal state: fsm_state := reset;
begin
-- left output the state of the left_down register
left <= left_down when rising_edge(clk);
-- middle output the state of the middle_down register
middle <= middle_down when rising_edge(clk);
-- right output the state of the right_down register
right <= right_down when rising_edge(clk);
-- xpos output is the horizontal position of the mouse
-- it has the range: 0-x_max
xpos <= x_pos(9 downto 0) when rising_edge(clk);
-- ypos output is the vertical position of the mouse
-- it has the range: 0-y_max
ypos <= y_pos(9 downto 0) when rising_edge(clk);
-- sets the value of x_pos from another module when setx is active
-- else, computes the new x_pos from the old position when new x
-- movement detected by adding the delta movement in x_inc, or by
-- adding 256 or -256 when overflow occurs.
set_x: process(clk)
variable x_inter: std_logic_vector(10 downto 0);
variable inc: std_logic_vector(10 downto 0);
begin
if(rising_edge(clk)) then
-- if setx active, set new x_pos value
if(setx = '1') then
x_pos <= '0' & value;
-- if delta movement received from mouse
elsif(x_new = '1') then
-- if negative movement on x axis
if(x_sign = '1') then
-- if overflow occurred
if(x_overflow = '1') then
-- inc is -256
inc := "11100000000";
else
-- inc is sign extended x_inc
inc := "111" & x_inc;
end if;
-- intermediary horizontal position
x_inter := x_pos + inc;
-- if first bit of x_inter is 1
-- then negative overflow occurred and
-- new x position is 0.
-- Note: x_pos and x_inter have 11 bits,
-- and because xpos has only 10, when
-- first bit becomes 1, this is considered
-- a negative number when moving left
if(x_inter(10) = '1') then
x_pos <= (others => '0');
else
x_pos <= x_inter;
end if;
-- if positive movement on x axis
else
-- if overflow occurred
if(x_overflow = '1') then
-- inc is 256
inc := "00100000000";
else
-- inc is sign extended x_inc
inc := "000" & x_inc;
end if;
-- intermediary horizontal position
x_inter := x_pos + inc;
-- if x_inter is greater than x_max
-- then positive overflow occurred and
-- new x position is x_max.
if(x_inter > ('0' & x_max)) then
x_pos <= '0' & x_max;
else
x_pos <= x_inter;
end if;
end if;
end if;
end if;
end process set_x;
-- sets the value of y_pos from another module when sety is active
-- else, computes the new y_pos from the old position when new y
-- movement detected by adding the delta movement in y_inc, or by
-- adding 256 or -256 when overflow occurs.
set_y: process(clk)
variable y_inter: std_logic_vector(10 downto 0);
variable inc: std_logic_vector(10 downto 0);
begin
if(rising_edge(clk)) then
-- if sety active, set new y_pos value
if(sety = '1') then
y_pos <= '0' & value;
-- if delta movement received from mouse
elsif(y_new = '1') then
-- if negative movement on y axis
-- Note: axes origin is upper-left corner
if(y_sign = '1') then
-- if overflow occurred
if(y_overflow = '1') then
-- inc is -256
inc := "11100000000";
else
-- inc is sign extended y_inc
inc := "111" & y_inc;
end if;
-- intermediary vertical position
y_inter := y_pos + inc;
-- if first bit of y_inter is 1
-- then negative overflow occurred and
-- new y position is 0.
-- Note: y_pos and y_inter have 11 bits,
-- and because ypos has only 10, when
-- first bit becomes 1, this is considered
-- a negative number when moving upward
if(y_inter(10) = '1') then
y_pos <= (others => '0');
else
y_pos <= y_inter;
end if;
-- if positive movement on y axis
else
-- if overflow occurred
if(y_overflow = '1') then
-- inc is 256
inc := "00100000000";
else
-- inc is sign extended y_inc
inc := "000" & y_inc;
end if;
-- intermediary vertical position
y_inter := y_pos + inc;
-- if y_inter is greater than y_max
-- then positive overflow occurred and
-- new y position is y_max.
if(y_inter > ('0' & y_max)) then
y_pos <= '0' & y_max;
else
y_pos <= y_inter;
end if;
end if;
end if;
end if;
end process set_y;
-- sets the maximum value of the x movement register, stored in x_max
-- when setmax_x is active, max value should be on value input pin
set_max_x: process(clk,rst)
begin
if(rising_edge(clk)) then
if(rst = '1') then
x_max <= DEFAULT_MAX_X;
elsif(setmax_x = '1') then
x_max <= value;
end if;
end if;
end process set_max_x;
-- sets the maximum value of the y movement register, stored in y_max
-- when setmax_y is active, max value should be on value input pin
set_max_y: process(clk,rst)
begin
if(rising_edge(clk)) then
if(rst = '1') then
y_max <= DEFAULT_MAX_Y;
elsif(setmax_y = '1') then
y_max <= value;
end if;
end if;
end process set_max_y;
-- Synchronous one process fsm to handle the communication
-- with the mouse.
-- When reset and at start-up it enters reset state
-- where it begins the procedure of initializing the mouse.
-- After initialization is complete, it waits packets from
-- the mouse.
-- Read at Behavioral decription for details.
manage_fsm: process(clk,rst)
begin
-- when reset occurs, give signals default values.
if(rst = '1') then
state <= reset;
haswheel <= '0';
x_overflow <= '0';
y_overflow <= '0';
x_sign <= '0';
y_sign <= '0';
x_inc <= (others => '0');
y_inc <= (others => '0');
x_new <= '0';
y_new <= '0';
new_event <= '0';
left_down <= '0';
middle_down <= '0';
right_down <= '0';
elsif(rising_edge(clk)) then
-- at every rising edge of the clock, this signals
-- are reset, thus assuring that they are active
-- for one clock period only if a state sets then
-- because the fsm will transition from the state
-- that set them on the next rising edge of clock.
write <= '0';
x_new <= '0';
y_new <= '0';
case state is
-- if just powered-up, reset occurred or some error in
-- transmision encountered, then fsm will transition to
-- this state. Here the RESET command (FF) is sent to the
-- mouse, and various signals receive their default values
-- From here the FSM transitions to a series of states that
-- perform the mouse initialization procedure. All this
-- state are prefixed by "reset_". After sending a byte
-- to the mouse, it respondes by sending ack (FA). All
-- states that wait ack from the mouse are postfixed by
-- "_wait_ack".
-- Read at Behavioral decription for details.
when reset =>
haswheel <= '0';
x_overflow <= '0';
y_overflow <= '0';
x_sign <= '0';
y_sign <= '0';
x_inc <= (others => '0');
y_inc <= (others => '0');
x_new <= '0';
y_new <= '0';
left_down <= '0';
middle_down <= '0';
right_down <= '0';
tx_data <= FF;
write <= '1';
state <= reset_wait_ack;
-- wait ack for the reset command.
-- when received transition to reset_wait_bat_completion.
-- if error occurs go to reset state.
when reset_wait_ack =>
if(read = '1') then
-- if received ack
if(rx_data = FA) then
state <= reset_wait_bat_completion;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_wait_ack;
end if;
-- wait for bat completion test
-- mouse should send AA if test is successful
when reset_wait_bat_completion =>
if(read = '1') then
if(rx_data = AA) then
state <= reset_wait_id;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_wait_bat_completion;
end if;
-- the mouse sends its id after performing bat test
-- the mouse id should be 00
when reset_wait_id =>
if(read = '1') then
if(rx_data = OO) then
state <= reset_set_sample_rate_200;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_wait_id;
end if;
-- with this state begins the enable wheel mouse
-- procedure. The procedure consists of setting
-- the sample rate of the mouse first 200, then 100
-- then 80. After this is done, the mouse id is
-- requested and if the mouse id is 03, then
-- mouse is in wheel mode and will send 4 byte packets
-- when reporting is enabled.
-- If the id is 00, the mouse does not have a wheel
-- and will send 3 byte packets when reporting is enabled.
-- This state issues the set_sample_rate command to the
-- mouse.
when reset_set_sample_rate_200 =>
tx_data <= SET_SAMPLE_RATE;
write <= '1';
state <= reset_set_sample_rate_200_wait_ack;
-- wait ack for set sample rate command
when reset_set_sample_rate_200_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_send_sample_rate_200;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_set_sample_rate_200_wait_ack;
end if;
-- send the desired sample rate (200 = 0xC8)
when reset_send_sample_rate_200 =>
tx_data <= "11001000"; -- 0xC8
write <= '1';
state <= reset_send_sample_rate_200_wait_ack;
-- wait ack for sending the sample rate
when reset_send_sample_rate_200_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_set_sample_rate_100;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_send_sample_rate_200_wait_ack;
end if;
-- send the sample rate command
when reset_set_sample_rate_100 =>
tx_data <= SET_SAMPLE_RATE;
write <= '1';
state <= reset_set_sample_rate_100_wait_ack;
-- wait ack for sending the sample rate command
when reset_set_sample_rate_100_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_send_sample_rate_100;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_set_sample_rate_100_wait_ack;
end if;
-- send the desired sample rate (100 = 0x64)
when reset_send_sample_rate_100 =>
tx_data <= "01100100"; -- 0x64
write <= '1';
state <= reset_send_sample_rate_100_wait_ack;
-- wait ack for sending the sample rate
when reset_send_sample_rate_100_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_set_sample_rate_80;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_send_sample_rate_100_wait_ack;
end if;
-- send set sample rate command
when reset_set_sample_rate_80 =>
tx_data <= SET_SAMPLE_RATE;
write <= '1';
state <= reset_set_sample_rate_80_wait_ack;
-- wait ack for sending the sample rate command
when reset_set_sample_rate_80_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_send_sample_rate_80;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_set_sample_rate_80_wait_ack;
end if;
-- send desired sample rate (80 = 0x50)
when reset_send_sample_rate_80 =>
tx_data <= "01010000"; -- 0x50
write <= '1';
state <= reset_send_sample_rate_80_wait_ack;
-- wait ack for sending the sample rate
when reset_send_sample_rate_80_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_read_id;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_send_sample_rate_80_wait_ack;
end if;
-- now the procedure for enabling wheel mode is done
-- the mouse id is read to determine is mouse is in
-- wheel mode.
-- Read ID command is sent to the mouse.
when reset_read_id =>
tx_data <= READ_ID;
write <= '1';
state <= reset_read_id_wait_ack;
-- wait ack for sending the read id command
when reset_read_id_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_read_id_wait_id;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_read_id_wait_ack;
end if;
-- received the mouse id
-- if the id is 00, then the mouse does not have
-- a wheel and haswheel is reset
-- if the id is 03, then the mouse is in scroll mode
-- and haswheel is set.
-- if anything else is received or an error occurred
-- then the FSM transitions to reset state.
when reset_read_id_wait_id =>
if(read = '1') then
if(rx_data = "000000000") then
-- the mouse does not have a wheel
haswheel <= '0';
state <= reset_set_resolution;
elsif(rx_data = "00000011") then -- 0x03
-- the mouse is in scroll mode
haswheel <= '1';
state <= reset_set_resolution;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_read_id_wait_id;
end if;
-- send the set resolution command to the mouse
when reset_set_resolution =>
tx_data <= SET_RESOLUTION;
write <= '1';
state <= reset_set_resolution_wait_ack;
-- wait ack for sending the set resolution command
when reset_set_resolution_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_send_resolution;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_set_resolution_wait_ack;
end if;
-- send the desired resolution (0x03 = 8 counts/mm)
when reset_send_resolution =>
tx_data <= RESOLUTION;
write <= '1';
state <= reset_send_resolution_wait_ack;
-- wait ack for sending the resolution
when reset_send_resolution_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_set_sample_rate_40;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_send_resolution_wait_ack;
end if;
-- send the set sample rate command
when reset_set_sample_rate_40 =>
tx_data <= SET_SAMPLE_RATE;
write <= '1';
state <= reset_set_sample_rate_40_wait_ack;
-- wait ack for sending the set sample rate command
when reset_set_sample_rate_40_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_send_sample_rate_40;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_set_sample_rate_40_wait_ack;
end if;
-- send the desired sampele rate.
-- 40 samples per second is sent.
when reset_send_sample_rate_40 =>
tx_data <= SAMPLE_RATE;
write <= '1';
state <= reset_send_sample_rate_40_wait_ack;
-- wait ack for sending the sample rate
when reset_send_sample_rate_40_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= reset_enable_reporting;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_send_sample_rate_40_wait_ack;
end if;
-- in this state enable reporting command is sent
-- to the mouse. Before this point, the mouse
-- does not send packets. Only after issuing this
-- command, the mouse begins sending data packets,
-- 3 byte packets if it doesn't have a wheel and
-- 4 byte packets if it is in scroll mode.
when reset_enable_reporting =>
tx_data <= ENABLE_REPORTING;
write <= '1';
state <= reset_enable_reporting_wait_ack;
-- wait ack for sending the enable reporting command
when reset_enable_reporting_wait_ack =>
if(read = '1') then
if(rx_data = FA) then
state <= read_byte_1;
else
state <= reset;
end if;
elsif(err = '1') then
state <= reset;
else
state <= reset_enable_reporting_wait_ack;
end if;
-- this is idle state of the FSM after the
-- initialization is complete.
-- Here the first byte of a packet is waited.
-- The first byte contains the state of the
-- buttons, the sign of the x and y movement
-- and overflow information about these movements
-- First byte looks like this:
-- 7 6 5 4 3 2 1 0
------------------------------------------------------
-- | Y OVF | X OVF | Y SIGN | X SIGN | 1 | M | R | L |
------------------------------------------------------
when read_byte_1 =>
-- reset new_event when back in idle state.
new_event <= '0';
-- reset last z delta movement
zpos <= (others => '0');
if(read = '1') then
-- mouse button states
left_down <= rx_data(0);
middle_down <= rx_data(2);
right_down <= rx_data(1);
-- sign of the movement data
x_sign <= rx_data(4);
-- y sign is changed to invert the y axis
-- because the mouse uses the lower-left corner
-- as axes origin and it is placed in the upper-left
-- corner by this inversion (suitable for displaying
-- a mouse cursor on the screen).
-- y movement data from the third packet must be
-- also negated.
y_sign <= not rx_data(5);
-- overflow status of the x and y movement
x_overflow <= rx_data(6);
y_overflow <= rx_data(7);
-- transition to state read_byte_2
state <= read_byte_2;
else
-- no byte received yet.
state <= read_byte_1;
end if;
-- wait the second byte of the packet
-- this byte contains the x movement counter.
when read_byte_2 =>
if(read = '1') then
-- put the delta movement in x_inc
x_inc <= rx_data;
-- signal the arrival of new x movement data.
x_new <= '1';
-- go to state read_byte_3.
state <= read_byte_3;
elsif(err = '1') then
state <= reset;
else
-- byte not received yet.
state <= read_byte_2;
end if;
-- wait the third byte of the data, that
-- contains the y data movement counter.
-- negate its value, for the axis to be
-- inverted.
-- If mouse is in scroll mode, transition
-- to read_byte_4, else go to mark_new_event
when read_byte_3 =>
if(read = '1') then
-- when y movement is 0, then ignore
if(rx_data /= "00000000") then
-- 2's complement positive numbers
-- become negative and vice versa
y_inc <= (not rx_data) + "00000001";
y_new <= '1';
end if;
-- if the mouse has a wheel then transition
-- to read_byte_4, else go to mark_new_event
if(haswheel = '1') then
state <= read_byte_4;
else
state <= mark_new_event;
end if;
elsif(err = '1') then
state <= reset;
else
state <= read_byte_3;
end if;
-- only reached when mouse is in scroll mode
-- wait for the fourth byte to arrive
-- fourth byte contains the z movement counter
-- only least significant 4 bits are relevant
-- the rest are sign extension.
when read_byte_4 =>
if(read = '1') then
-- zpos is the delta movement on z
zpos <= rx_data(3 downto 0);
-- packet completly received,
-- go to mark_new_event
state <= mark_new_event;
elsif(err = '1') then
state <= reset;
else
state <= read_byte_4;
end if;
-- set new_event high