]> git.sur5r.net Git - cc65/blob - libsrc/c64/mou/c64-1351.s
Fixed recent "Minor comment harmonization".
[cc65] / libsrc / c64 / mou / c64-1351.s
1 ;
2 ; Driver for the 1351 proportional mouse. Parts of the code are from
3 ; the Commodore 1351 mouse users guide.
4 ;
5 ; 2009-09-26, Ullrich von Bassewitz
6 ; 2010-02-06, Greg King
7 ;
8 ; The driver prevents the keyboard from interfering by changing the
9 ; keyboard's output port into an input port while the driver reads its
10 ; controller device.  That disables a wire that is left active by the
11 ; Kernal.  That wire is used by the STOP-key to break out of BASIC
12 ; programs -- CC65 programs don't use that feature.  The wire is shared
13 ; by these keys: STOP, "Q", Commodore, Space, "2", CTRL, Left-Arrow, and
14 ; "1".  I listed them, in order, from bit 7 over to bit 0.  The
15 ; rightmost five keys can look like joystick switches.
16 ;
17 ; The driver prevents the mouse/joystick from interfering by "blinding"
18 ; the keyboard scanner while any button/switch is active.  It changes
19 ; the input port into an output port, then stores all zero-bits in that
20 ; port's latch.  Reading from an output port sees the bitwise-AND of the
21 ; latch and the input signals.  Therefore, the scanner thinks that eight
22 ; keys are being pushed at the same time.  It doesn't know what to do
23 ; about that condition; so, it does nothing.  The driver lets the
24 ; scanner see normally, again, when no buttons/switches are active.
25 ;
26
27         .include        "zeropage.inc"
28         .include        "mouse-kernel.inc"
29         .include        "c64.inc"
30
31         .macpack        generic
32
33 ; ------------------------------------------------------------------------
34 ; Header. Includes jump table
35
36 .segment        "JUMPTABLE"
37
38 HEADER:
39
40 ; Driver signature
41
42         .byte   $6d, $6f, $75           ; "mou"
43         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
44
45 ; Library reference
46
47         .addr   $0000
48
49 ; Jump table
50
51         .addr   INSTALL
52         .addr   UNINSTALL
53         .addr   HIDE
54         .addr   SHOW
55         .addr   SETBOX
56         .addr   GETBOX
57         .addr   MOVE
58         .addr   BUTTONS
59         .addr   POS
60         .addr   INFO
61         .addr   IOCTL
62         .addr   IRQ
63
64 ; Mouse driver flags
65
66         .byte   MOUSE_FLAG_LATE_IRQ
67
68 ; Callback table, set by the kernel before INSTALL is called
69
70 CHIDE:  jmp     $0000                   ; Hide the cursor
71 CSHOW:  jmp     $0000                   ; Show the cursor
72 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
73 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
74
75
76 ;----------------------------------------------------------------------------
77 ; Constants
78
79 SCREEN_HEIGHT   = YSIZE * 8 - 1         ; (origin is zero)
80 SCREEN_WIDTH    = XSIZE * 8 - 1
81
82 ;----------------------------------------------------------------------------
83 ; Global variables. The bounding box values are sorted so that they can be
84 ; written with the least effort in the SETBOX and GETBOX routines, so don't
85 ; reorder them.
86
87 .bss
88
89 Vars:
90 OldPotX:        .res    1               ; Old hw counter values
91 OldPotY:        .res    1
92
93 XPos:           .res    2               ; Current mouse position, X
94 YPos:           .res    2               ; Current mouse position, Y
95 XMin:           .res    2               ; X1 value of bounding box
96 YMin:           .res    2               ; Y1 value of bounding box
97 XMax:           .res    2               ; X2 value of bounding box
98 YMax:           .res    2               ; Y2 value of bounding box
99 Buttons:        .res    1               ; button status bits
100
101 OldValue:       .res    1               ; Temp for MoveCheck routine
102 NewValue:       .res    1               ; Temp for MoveCheck routine
103
104 .rodata
105
106 ; Default values for above variables
107 ; (We use ".proc" because we want to define both a label and a scope.)
108
109 .proc   DefVars
110         .byte   0, 0                    ; OldPotX/OldPotY
111         .word   SCREEN_WIDTH/2          ; XPos
112         .word   SCREEN_HEIGHT/2         ; YPos
113         .word   0                       ; XMin
114         .word   0                       ; YMin
115         .word   SCREEN_WIDTH            ; XMax
116         .word   SCREEN_HEIGHT           ; YMax
117         .byte   %00000000               ; Buttons
118 .endproc
119
120 .code
121
122 ;----------------------------------------------------------------------------
123 ; INSTALL routine. Is called after the driver is loaded into memory. If
124 ; possible, check if the hardware is present.
125 ; Must return an MOUSE_ERR_xx code in a/x.
126
127 INSTALL:
128
129 ; Initialize variables. Just copy the default stuff over
130
131         ldx     #.sizeof(DefVars)-1
132 @L1:    lda     DefVars,x
133         sta     Vars,x
134         dex
135         bpl     @L1
136
137 ; Be sure the mouse cursor is invisible and at the default location. We
138 ; need to do that here, because our mouse interrupt handler doesn't set the
139 ; mouse position if it hasn't changed.
140
141         sei
142         jsr     CHIDE
143         lda     XPos
144         ldx     XPos+1
145         jsr     CMOVEX
146         lda     YPos
147         ldx     YPos+1
148         jsr     CMOVEY
149         cli
150
151 ; Done, return zero (= MOUSE_ERR_OK)
152
153         ldx     #$00
154         txa
155         rts
156
157 ;----------------------------------------------------------------------------
158 ; UNINSTALL routine. Is called before the driver is removed from memory.
159 ; No return code required (the driver is removed from memory on return).
160
161 UNINSTALL       = HIDE                  ; Hide cursor on exit
162
163 ;----------------------------------------------------------------------------
164 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
165 ; a counter for calls to show/hide, and the driver entry point is only called
166 ; if the mouse is currently visible and should get hidden. For most drivers,
167 ; no special action is required besides hiding the mouse cursor.
168 ; No return code required.
169
170 HIDE:   sei
171         jsr     CHIDE
172         cli
173         rts
174
175 ;----------------------------------------------------------------------------
176 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
177 ; a counter for calls to show/hide, and the driver entry point is only called
178 ; if the mouse is currently hidden and should become visible. For most drivers,
179 ; no special action is required besides enabling the mouse cursor.
180 ; No return code required.
181
182 SHOW:   sei
183         jsr     CSHOW
184         cli
185         rts
186
187 ;----------------------------------------------------------------------------
188 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
189 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
190 ; No checks are done if the mouse is currently inside the box, this is the job
191 ; of the caller. It is not necessary to validate the parameters, trust the
192 ; caller and save some code here. No return code required.
193
194 SETBOX: sta     ptr1
195         stx     ptr1+1                  ; Save data pointer
196
197         ldy     #.sizeof (MOUSE_BOX)-1
198         sei
199
200 @L1:    lda     (ptr1),y
201         sta     XMin,y
202         dey
203         bpl     @L1
204
205         cli
206         rts
207
208 ;----------------------------------------------------------------------------
209 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
210 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
211
212 GETBOX: sta     ptr1
213         stx     ptr1+1                  ; Save data pointer
214
215         ldy     #.sizeof (MOUSE_BOX)-1
216 @L1:    lda     XMin,y
217         sta     (ptr1),y
218         dey
219         bpl     @L1
220         rts
221
222 ;----------------------------------------------------------------------------
223 ; MOVE: Move the mouse to a new position. The position is passed as it comes
224 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
225 ; remove the parameter from the stack on return.
226 ; No checks are done if the new position is valid (within the bounding box or
227 ; the screen). No return code required.
228 ;
229
230 MOVE:   sei                             ; No interrupts
231
232         sta     YPos
233         stx     YPos+1                  ; New Y position
234         jsr     CMOVEY                  ; Set it
235
236         ldy     #$01
237         lda     (sp),y
238         sta     XPos+1
239         tax
240         dey
241         lda     (sp),y
242         sta     XPos                    ; New X position
243
244         jsr     CMOVEX                  ; Move the cursor
245
246         cli                             ; Allow interrupts
247         rts
248
249 ;----------------------------------------------------------------------------
250 ; BUTTONS: Return the button mask in a/x.
251
252 BUTTONS:
253         lda     Buttons
254         ldx     #0
255         and     #$1F
256         rts
257
258 ;----------------------------------------------------------------------------
259 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
260 ; No return code required.
261
262 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
263
264         sei                             ; Disable interrupts
265         lda     XPos                    ; Transfer the position
266         sta     (ptr1),y
267         lda     XPos+1
268         iny
269         sta     (ptr1),y
270         lda     YPos
271         iny
272         sta     (ptr1),y
273         lda     YPos+1
274         cli                             ; Enable interrupts
275
276         iny
277         sta     (ptr1),y                ; Store last byte
278
279         rts                             ; Done
280
281 ;----------------------------------------------------------------------------
282 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
283 ; struct pointed to by ptr1. No return code required.
284 ;
285 ; We're cheating here to keep the code smaller: The first fields of the
286 ; mouse_info struct are identical to the mouse_pos struct, so we will just
287 ; call _mouse_pos to initialize the struct pointer and fill the position
288 ; fields.
289
290 INFO:   jsr     POS
291
292 ; Fill in the button state
293
294         jsr     BUTTONS                 ; Will not touch ptr1
295         ldy     #MOUSE_INFO::BUTTONS
296         sta     (ptr1),y
297
298         rts
299
300 ;----------------------------------------------------------------------------
301 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
302 ; specific data in ptr1, and the ioctl code in A.
303 ; Must return an error code in a/x.
304 ;
305
306 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
307         ldx     #>MOUSE_ERR_INV_IOCTL
308         rts
309
310 ;----------------------------------------------------------------------------
311 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
312 ; (so be careful). The routine MUST return carry set if the interrupt has been
313 ; 'handled' - which means that the interrupt source is gone. Otherwise it
314 ; MUST return carry clear.
315 ;
316
317 IRQ:
318
319 ; Record the state of the buttons.
320 ; Avoid crosstalk between the keyboard and the mouse.
321
322         ldy     #%00000000              ; Set ports A and B to input
323         sty     CIA1_DDRB
324         sty     CIA1_DDRA               ; Keyboard won't look like mouse
325         lda     CIA1_PRB                ; Read Control-Port 1
326         dec     CIA1_DDRA               ; Set port A back to output
327         eor     #%11111111              ; Bit goes up when button goes down
328         sta     Buttons
329         beq     @L0                     ;(bze)
330         dec     CIA1_DDRB               ; Mouse won't look like keyboard
331         sty     CIA1_PRB                ; Set "all keys pushed"
332
333 @L0:    lda     SID_ADConv1             ; Get mouse X movement
334         ldy     OldPotX
335         jsr     MoveCheck               ; Calculate movement vector
336
337 ; Skip processing if nothing has changed
338
339         bcc     @SkipX
340         sty     OldPotX
341
342 ; Calculate the new X coordinate (--> a/y)
343
344         add     XPos
345         tay                             ; Remember low byte
346         txa
347         adc     XPos+1
348         tax
349
350 ; Limit the X coordinate to the bounding box
351
352         cpy     XMin
353         sbc     XMin+1
354         bpl     @L1
355         ldy     XMin
356         ldx     XMin+1
357         jmp     @L2
358 @L1:    txa
359
360         cpy     XMax
361         sbc     XMax+1
362         bmi     @L2
363         ldy     XMax
364         ldx     XMax+1
365 @L2:    sty     XPos
366         stx     XPos+1
367
368 ; Move the mouse pointer to the new X pos
369
370         tya
371         jsr     CMOVEX
372
373 ; Calculate the Y movement vector
374
375 @SkipX: lda     SID_ADConv2             ; Get mouse Y movement
376         ldy     OldPotY
377         jsr     MoveCheck               ; Calculate movement
378
379 ; Skip processing if nothing has changed
380
381         bcc     @SkipY
382         sty     OldPotY
383
384 ; Calculate the new Y coordinate (--> a/y)
385
386         sta     OldValue
387         lda     YPos
388         sub     OldValue
389         tay
390         stx     OldValue
391         lda     YPos+1
392         sbc     OldValue
393         tax
394
395 ; Limit the Y coordinate to the bounding box
396
397         cpy     YMin
398         sbc     YMin+1
399         bpl     @L3
400         ldy     YMin
401         ldx     YMin+1
402         jmp     @L4
403 @L3:    txa
404
405         cpy     YMax
406         sbc     YMax+1
407         bmi     @L4
408         ldy     YMax
409         ldx     YMax+1
410 @L4:    sty     YPos
411         stx     YPos+1
412
413 ; Move the mouse pointer to the new Y pos
414
415         tya
416         jsr     CMOVEY
417
418 ; Done
419
420         clc                             ; Interrupt not "handled"
421 @SkipY: rts
422
423 ; --------------------------------------------------------------------------
424 ;
425 ; Move check routine, called for both coordinates.
426 ;
427 ; Entry:        y = old value of pot register
428 ;               a = current value of pot register
429 ; Exit:         y = value to use for old value
430 ;               x/a = delta value for position
431 ;
432
433 MoveCheck:
434         sty     OldValue
435         sta     NewValue
436         ldx     #$00
437
438         sub     OldValue                ; a = mod64 (new - old)
439         and     #%01111111
440         cmp     #%01000000              ; if (a > 0)
441         bcs     @L1                     ;
442         lsr     a                       ;   a /= 2;
443         beq     @L2                     ;   if (a != 0)
444         ldy     NewValue                ;     y = NewValue
445         sec
446         rts                             ;   return
447
448 @L1:    ora     #%11000000              ; else, "or" in high-order bits
449         cmp     #$FF                    ; if (a != -1)
450         beq     @L2
451         sec
452         ror     a                       ;   a /= 2
453         dex                             ;   high byte = -1 (X = $FF)
454         ldy     NewValue
455         sec
456         rts
457
458 @L2:    txa                             ; A = $00
459         clc
460         rts
461