]> git.ozlabs.org Git - minimigmac.git/blob - fpga/ps2_mouse.v
Add GPL v2
[minimigmac.git] / fpga / ps2_mouse.v
1 `timescale 1ns / 100ps
2
3 /*
4  * PS2 Mouse to Mac interface module
5  */
6 module ps2_mouse(input  sysclk,
7                  input  reset,
8
9                  inout  ps2dat,
10                  inout  ps2clk,
11                  
12                  output reg x1,
13                  output reg y1,
14                  output reg x2,
15                  output reg y2,
16                  output reg button,
17                  
18                  output reg [15:0] debug
19 );
20         wire            istrobe;
21         wire [7:0]      ibyte;
22         wire            timeout;
23         wire            oack;
24         reg [7:0]       obyte;
25         reg             oreq;
26         reg [2:0]       state;
27         reg [2:0]       next;
28         reg [7:0]       nbyte;
29         reg             nreq;
30         reg [9:0]       xacc;
31         reg [9:0]       yacc;
32         reg             xsign;
33         reg             ysign;
34         reg [11:0]      clkdiv;
35         wire            tick;   
36         wire[1:0]       dbg_lowstate;
37         
38         ps2 ps20(.sysclk(sysclk),
39                  .reset(reset),
40                  .ps2dat(ps2dat),
41                  .ps2clk(ps2clk),
42                  .istrobe(istrobe),
43                  .ibyte(ibyte),
44                  .oreq(oreq),
45                  .obyte(obyte),
46                  .oack(oack),
47                  .timeout(timeout),
48                  .dbg_state(dbg_lowstate));
49         
50         /* State machine:
51          *
52          *  - at state_init: wait for BAT reply
53          *     * 0xaa                   -> state_id
54          *     * 0xfa      -> send 0xff -> state_init
55          *     * bad reply -> send 0xff -> state_init
56          *     * timeout   -> send 0xff -> state_init
57          * 
58          *  - at state_id: wait for device_id
59          *     * 0x00      -> send 0xf4 -> state_setup
60          *     * bad reply -> send 0xff -> state_init
61          *     * timeout   -> send 0xff -> state_init
62          * 
63          *  - at state_setup: wait for enable data reporting ack
64          *     * 0xfa                   -> state_byte0
65          *     * bad reply -> send 0xff -> state_init
66          *     * timeout   -> send 0xff -> state_init
67          * 
68          *  - at state_byte0: wait for data byte 0
69          *     * data                   -> state_byte1
70          *     * data                   -> state_byte1
71          *     * timeout   -> send 0xff -> state_init
72          * 
73          *  - at state_byte1: wait for data byte 1
74          *     * data                   -> state_byte2
75          *     * timeout   -> send 0xff -> state_init
76          *
77          *  - at state_byte2: wait for data byte 2
78          *     * data                   -> state_byte0
79          *     * timeout   -> send 0xff -> state_init
80          */
81         localparam ps2m_state_init      = 0;
82         localparam ps2m_state_id        = 1;
83         localparam ps2m_state_setup     = 2;
84         localparam ps2m_state_byte0     = 3;
85         localparam ps2m_state_byte1     = 4;
86         localparam ps2m_state_byte2     = 5;
87
88         /* Unlike my other modules, here I'll play with a big fat
89          * combo logic. The outputs are:
90          *  - oreq   : triggers sending of a byte. Set based on either
91          *             timeout or istrobe, and as such only set for a
92          *             clock.
93          *  - next   : next state
94          *  - obyte  : next byte to send
95          */
96         always@(timeout or state or istrobe or ibyte) begin
97                 nreq = 0;
98                 next = state;
99                 nbyte = 8'hff;
100                 if (timeout) begin
101                         next = ps2m_state_init;
102                         nreq = 1;                       
103                 end else if (istrobe)
104                   case(state)
105                           ps2m_state_init: begin
106                                   if (ibyte == 8'haa)
107                                     next = ps2m_state_id;
108                                   else if (ibyte != 8'hfa)
109                                     nreq = 1;
110                           end
111                           ps2m_state_id: begin
112                                   nreq = 1;
113                                   if (ibyte == 8'h00) begin
114                                           nbyte = 8'hf4;
115                                           next = ps2m_state_setup;
116                                   end else
117                                     next = ps2m_state_init;
118                           end
119                           ps2m_state_setup: begin
120                                   if (ibyte == 8'hfa)
121                                     next = ps2m_state_byte0;
122                                   else begin
123                                           nreq = 1;
124                                           next = ps2m_state_init;
125                                   end
126                           end
127                           ps2m_state_byte0: next = ps2m_state_byte1;
128                           ps2m_state_byte1: next = ps2m_state_byte2;
129                           ps2m_state_byte2: next = ps2m_state_byte0;
130                   endcase
131         end
132
133         /* State related latches. We latch oreq and obyte, we don't
134          * necessarily have to but that avoids back to back
135          * receive/send at the low level which can upset things
136          */
137         always@(posedge sysclk or posedge reset)
138                 if (reset)
139                   state <= ps2m_state_init;
140                 else
141                   state <= next;
142         always@(posedge sysclk or posedge reset)
143                 if (reset)
144                   oreq <= 0;
145                 else
146                   oreq <= nreq;
147         always@(posedge sysclk or posedge reset)
148                 if (reset)
149                   obyte <= 0;
150                 else
151                   obyte <= nbyte;
152
153         /* Capture button state */
154         always@(posedge sysclk or posedge reset)
155                 if (reset)
156                   button <= 1;
157                 else if (istrobe && state == ps2m_state_byte0)
158                   button <= ~ibyte[0];          
159
160         /* Clock divider to flush accumulators */
161         always@(posedge sysclk or posedge reset)
162                 if (reset)
163                   clkdiv <= 0;
164                 else
165                   clkdiv <= clkdiv + 1;
166         assign tick = clkdiv == 0;
167
168         /* Toggle output lines base on accumulator */
169         always@(posedge sysclk or posedge reset) begin
170                 if (reset) begin
171                         x1 <= 0;
172                         x2 <= 0;
173                 end else if (tick && xacc != 0) begin
174                         x1 <= ~x1;
175                         x2 <= ~x1 ^ ~xacc[9];
176                 end
177         end
178         always@(posedge sysclk or posedge reset) begin
179                 if (reset) begin
180                         y1 <= 0;
181                         y2 <= 0;
182                 end else if (tick && yacc != 0) begin
183                         y1 <= ~y1;
184                         y2 <= ~y1 ^ ~yacc[9];
185                 end
186         end
187
188         /* Capture sign bits */
189         always@(posedge sysclk or posedge reset) begin
190                 if (reset) begin
191                         xsign <= 0;
192                         ysign <= 0;                     
193                 end else if (istrobe && state == ps2m_state_byte0) begin
194                         xsign <= ibyte[4];
195                         ysign <= ibyte[5];
196                 end
197         end
198
199         /* Movement accumulators. Needs tuning ! */
200         always@(posedge sysclk or posedge reset) begin
201                 if (reset)
202                   xacc <= 0;
203                 else begin
204                         /* Add movement, convert to a 10-bit number if not over */
205                         if (istrobe && state == ps2m_state_byte1 && xacc[8] == xacc[9])
206                                 xacc <= xacc + { xsign, xsign, ibyte };
207                         else
208                           /* Decrement */
209                           if (tick && xacc != 0)
210                             xacc <= xacc + { {9{~xsign}}, 1'b1 };
211                 end
212         end
213         
214         always@(posedge sysclk or posedge reset) begin
215                 if (reset)
216                   yacc <= 0;
217                 else begin
218                         /* Add movement, convert to a 10-bit number if not over*/
219                         if (istrobe && state == ps2m_state_byte2 && yacc[8] == yacc[9])
220                                 yacc <= yacc + { ysign, ysign, ibyte };
221                         else
222                           /* Decrement */
223                           if (tick && yacc != 0)
224                             yacc <= yacc + { {9{~ysign}}, 1'b1 };
225                 end
226         end
227
228         /* Some debug signals for my own sanity */
229         always@(posedge sysclk or posedge reset) begin
230                 if (reset)
231                   debug <= 0;
232                 else begin
233                         if (istrobe)
234                           debug[15:8] <= ibyte;
235                         debug[7:0] <= { ps2clk, ps2dat, dbg_lowstate, 1'b0,
236                                         state };
237                 end
238         end
239 endmodule