]> git.sur5r.net Git - cc65/blob - libsrc/c128/mou/c128-1351.s
Correctly map out ROM when needed in the "phantom keys" workaround.
[cc65] / libsrc / c128 / mou / c128-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 ; 2014-03-17, Greg King
7 ;
8
9         .include        "zeropage.inc"
10         .include        "mouse-kernel.inc"
11         .include        "c128.inc"
12
13         .macpack        generic
14
15 IRQInd  = $2FD
16
17 ; ------------------------------------------------------------------------
18 ; Header. Includes jump table
19
20 .segment        "JUMPTABLE"
21
22 HEADER:
23
24 ; Driver signature
25
26         .byte   $6d, $6f, $75           ; "mou"
27         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
28
29 ; Library reference
30
31 libref:
32         .addr   $0000
33
34 ; Jump table
35
36         .addr   INSTALL
37         .addr   UNINSTALL
38         .addr   HIDE
39         .addr   SHOW
40         .addr   SETBOX
41         .addr   GETBOX
42         .addr   MOVE
43         .addr   BUTTONS
44         .addr   POS
45         .addr   INFO
46         .addr   IOCTL
47         .addr   IRQ
48
49 ; Mouse driver flags
50
51         .byte   MOUSE_FLAG_LATE_IRQ
52
53 ; Callback table, set by the kernel before INSTALL is called
54
55 CHIDE:  jmp     $0000                   ; Hide the cursor
56 CSHOW:  jmp     $0000                   ; Show the cursor
57 CPREP:  jmp     $0000                   ; Prepare to move the cursor
58 CDRAW:  jmp     $0000                   ; Draw the cursor
59 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
60 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
61
62
63 ;----------------------------------------------------------------------------
64 ; Constants
65
66 SCREEN_HEIGHT   = 200
67 SCREEN_WIDTH    = 320
68
69 ;----------------------------------------------------------------------------
70 ; Global variables. The bounding box values are sorted so that they can be
71 ; written with the least effort in the SETBOX and GETBOX routines, so don't
72 ; reorder them.
73
74 .bss
75
76 Vars:
77 OldPotX:        .res    1               ; Old hw counter values
78 OldPotY:        .res    1
79
80 YPos:           .res    2               ; Current mouse position, Y
81 XPos:           .res    2               ; Current mouse position, X
82 XMin:           .res    2               ; X1 value of bounding box
83 YMin:           .res    2               ; Y1 value of bounding box
84 XMax:           .res    2               ; X2 value of bounding box
85 YMax:           .res    2               ; Y2 value of bounding box
86
87 OldValue:       .res    1               ; Temp for MoveCheck routine
88 NewValue:       .res    1               ; Temp for MoveCheck routine
89
90 INIT_save:      .res    1
91 Buttons:        .res    1               ; Button mask
92
93 ; Keyboard buffer fill level at start of interrupt
94
95 old_key_count:  .res    1
96
97 ; original IRQ vector
98
99 old_irq:        .res    2
100
101 .rodata
102
103 ; Default values for above variables
104 ; (We use ".proc" because we want to define both a label and a scope.)
105
106 .proc   DefVars
107         .byte   0, 0                    ; OldPotX/OldPotY
108         .word   SCREEN_HEIGHT/2         ; YPos
109         .word   SCREEN_WIDTH/2          ; XPos
110         .word   0                       ; XMin
111         .word   0                       ; YMin
112         .word   SCREEN_WIDTH - 1        ; XMax
113         .word   SCREEN_HEIGHT - 1       ; YMax
114 .endproc
115
116 .code
117
118 ;----------------------------------------------------------------------------
119 ; INSTALL routine. Is called after the driver is loaded into memory. If
120 ; possible, check if the hardware is present.
121 ; Must return an MOUSE_ERR_xx code in a/x.
122
123 INSTALL:
124
125 ; Disable the BASIC interpreter's interrupt-driven sprite-motion code.
126 ; That allows direct access to the VIC-IIe's sprite registers.
127
128         lda     INIT_STATUS
129         sta     INIT_save
130         lda     #%11000000
131         sta     INIT_STATUS
132
133 ; Initialize variables. Just copy the default stuff over
134
135         ldx     #.sizeof(DefVars)-1
136 @L1:    lda     DefVars,x
137         sta     Vars,x
138         dex
139         bpl     @L1
140
141 ; Be sure the mouse cursor is invisible and at the default location. We
142 ; need to do that here, because our mouse interrupt handler doesn't set the
143 ; mouse position if it hasn't changed.
144
145         sei
146         jsr     CHIDE
147         lda     XPos
148         ldx     XPos+1
149         jsr     CMOVEX
150         lda     YPos
151         ldx     YPos+1
152         jsr     CMOVEY
153
154 ; Initialize our IRQ magic
155
156         ; remember ROM IRQ continuation address
157         lda     IRQInd+2
158         sta     old_irq+1
159         lda     IRQInd+1
160         sta     old_irq
161
162         lda     libref
163         sta     ptr3
164         lda     libref+1
165         sta     ptr3+1
166
167         ; set ROM IRQ continuation address to point to the provided routine
168         ldy     #2
169         lda     (ptr3),y
170         sta     IRQInd+1
171         iny
172         lda     (ptr3),y
173         sta     IRQInd+2
174
175         ; set address of our IRQ callback routine
176         ; since it's called via "rts" we have to use "address-1"
177         iny
178         lda     #<(callback-1)
179         sta     (ptr3),y
180         iny
181         lda     #>(callback-1)
182         sta     (ptr3),y
183         iny
184
185         ; set ROM entry point vector
186         ; since it's called via "rts" we have to decrement it by one
187         lda     old_irq
188         sec
189         sbc     #1
190         sta     (ptr3),y
191         iny
192         lda     old_irq+1
193         sbc     #0
194         sta     (ptr3),y
195         cli
196
197 ; Done, return zero (= MOUSE_ERR_OK)
198
199         ldx     #$00
200         txa
201         rts
202
203 ;----------------------------------------------------------------------------
204 ; UNINSTALL routine. Is called before the driver is removed from memory.
205 ; No return code required (the driver is removed from memory on return).
206
207 UNINSTALL:
208         lda     old_irq
209         sei
210         sta     IRQInd+1
211         lda     old_irq+1
212         sta     IRQInd+2
213         cli
214
215         jsr     HIDE                    ; Hide cursor on exit
216         lda     INIT_save
217         sta     INIT_STATUS
218         rts
219
220 ;----------------------------------------------------------------------------
221 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
222 ; a counter for calls to show/hide, and the driver entry point is only called
223 ; if the mouse is currently visible and should get hidden. For most drivers,
224 ; no special action is required besides hiding the mouse cursor.
225 ; No return code required.
226
227 HIDE:   sei
228         jsr     CHIDE
229         cli
230         rts
231
232 ;----------------------------------------------------------------------------
233 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
234 ; a counter for calls to show/hide, and the driver entry point is only called
235 ; if the mouse is currently hidden and should become visible. For most drivers,
236 ; no special action is required besides enabling the mouse cursor.
237 ; No return code required.
238
239 SHOW:   sei
240         jsr     CSHOW
241         cli
242         rts
243
244 ;----------------------------------------------------------------------------
245 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
246 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
247 ; No checks are done if the mouse is currently inside the box, this is the job
248 ; of the caller. It is not necessary to validate the parameters, trust the
249 ; caller and save some code here. No return code required.
250
251 SETBOX: sta     ptr1
252         stx     ptr1+1                  ; Save data pointer
253
254         ldy     #.sizeof (MOUSE_BOX)-1
255         sei
256
257 @L1:    lda     (ptr1),y
258         sta     XMin,y
259         dey
260         bpl     @L1
261
262         cli
263         rts
264
265 ;----------------------------------------------------------------------------
266 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
267 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
268
269 GETBOX: sta     ptr1
270         stx     ptr1+1                  ; Save data pointer
271
272         ldy     #.sizeof (MOUSE_BOX)-1
273         sei
274
275 @L1:    lda     XMin,y
276         sta     (ptr1),y
277         dey
278         bpl     @L1
279
280         cli
281         rts
282
283 ;----------------------------------------------------------------------------
284 ; MOVE: Move the mouse to a new position. The position is passed as it comes
285 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
286 ; remove the parameter from the stack on return.
287 ; No checks are done if the new position is valid (within the bounding box or
288 ; the screen). No return code required.
289 ;
290
291 MOVE:   sei                             ; No interrupts
292
293         sta     YPos
294         stx     YPos+1                  ; New Y position
295         jsr     CMOVEY                  ; Set it
296
297         ldy     #$01
298         lda     (sp),y
299         sta     XPos+1
300         tax
301         dey
302         lda     (sp),y
303         sta     XPos                    ; New X position
304
305         jsr     CMOVEX                  ; Move the cursor
306
307         cli                             ; Allow interrupts
308         rts
309
310 ;----------------------------------------------------------------------------
311 ; BUTTONS: Return the button mask in a/x.
312
313 BUTTONS:
314         lda     Buttons
315         ldx     #$00
316         rts
317
318 ;----------------------------------------------------------------------------
319 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
320 ; No return code required.
321
322 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
323
324         sei                             ; Disable interrupts
325         lda     XPos                    ; Transfer the position
326         sta     (ptr1),y
327         lda     XPos+1
328         iny
329         sta     (ptr1),y
330         lda     YPos
331         iny
332         sta     (ptr1),y
333         lda     YPos+1
334         cli                             ; Enable interrupts
335
336         iny
337         sta     (ptr1),y                ; Store last byte
338
339         rts                             ; Done
340
341 ;----------------------------------------------------------------------------
342 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
343 ; struct pointed to by ptr1. No return code required.
344 ;
345 ; We're cheating here to keep the code smaller: The first fields of the
346 ; mouse_info struct are identical to the mouse_pos struct, so we will just
347 ; call _mouse_pos to initialize the struct pointer and fill the position
348 ; fields.
349
350 INFO:   jsr     POS
351
352 ; Fill in the button state
353
354         jsr     BUTTONS                 ; Will not touch ptr1
355         ldy     #MOUSE_INFO::BUTTONS
356         sta     (ptr1),y
357
358         rts
359
360 ;----------------------------------------------------------------------------
361 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
362 ; specific data in ptr1, and the ioctl code in A.
363 ; Must return an error code in a/x.
364 ;
365
366 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
367         ldx     #>MOUSE_ERR_INV_IOCTL
368         rts
369
370 ;----------------------------------------------------------------------------
371 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
372 ; (so be careful). The routine MUST return carry set if the interrupt has been
373 ; 'handled' - which means that the interrupt source is gone. Otherwise it
374 ; MUST return carry clear.
375 ;
376
377 IRQ:    jsr     CPREP
378         lda     KEY_COUNT
379         sta     old_key_count
380         lda     #$7F
381         sta     CIA1_PRA
382         lda     CIA1_PRB                ; Read joystick #0
383         and     #$1F
384         eor     #$1F                    ; Make all bits active high
385         sta     Buttons
386
387         lda     SID_ADConv1             ; Get mouse X movement
388         ldy     OldPotX
389         jsr     MoveCheck               ; Calculate movement vector
390         sty     OldPotX
391
392 ; Skip processing if nothing has changed
393
394         bcc     @SkipX
395
396 ; Calculate the new X coordinate (--> a/y)
397
398         add     XPos
399         tay                             ; Remember low byte
400         txa
401         adc     XPos+1
402         tax
403
404 ; Limit the X coordinate to the bounding box
405
406         cpy     XMin
407         sbc     XMin+1
408         bpl     @L1
409         ldy     XMin
410         ldx     XMin+1
411         jmp     @L2
412 @L1:    txa
413
414         cpy     XMax
415         sbc     XMax+1
416         bmi     @L2
417         ldy     XMax
418         ldx     XMax+1
419 @L2:    sty     XPos
420         stx     XPos+1
421
422 ; Move the mouse pointer to the new X pos
423
424         tya
425         jsr     CMOVEX
426
427 ; Calculate the Y movement vector
428
429 @SkipX: lda     SID_ADConv2             ; Get mouse Y movement
430         ldy     OldPotY
431         jsr     MoveCheck               ; Calculate movement
432         sty     OldPotY
433
434 ; Skip processing if nothing has changed
435
436         bcc     @SkipY
437
438 ; Calculate the new Y coordinate (--> a/y)
439
440         sta     OldValue
441         lda     YPos
442         sub     OldValue
443         tay
444         stx     OldValue
445         lda     YPos+1
446         sbc     OldValue
447         tax
448
449 ; Limit the Y coordinate to the bounding box
450
451         cpy     YMin
452         sbc     YMin+1
453         bpl     @L3
454         ldy     YMin
455         ldx     YMin+1
456         jmp     @L4
457 @L3:    txa
458
459         cpy     YMax
460         sbc     YMax+1
461         bmi     @L4
462         ldy     YMax
463         ldx     YMax+1
464 @L4:    sty     YPos
465         stx     YPos+1
466
467 ; Move the mouse pointer to the new X pos
468
469         tya
470         jsr     CMOVEY
471
472 ; Done
473
474 @SkipY: jsr     CDRAW
475         clc                             ; Interrupt not "handled"
476         rts
477
478 ; --------------------------------------------------------------------------
479 ;
480 ; Move check routine, called for both coordinates.
481 ;
482 ; Entry:        y = old value of pot register
483 ;               a = current value of pot register
484 ; Exit:         y = value to use for old value
485 ;               x/a = delta value for position
486 ;
487
488 MoveCheck:
489         sty     OldValue
490         sta     NewValue
491         ldx     #$00
492
493         sub     OldValue                ; a = mod64 (new - old)
494         and     #%01111111
495         cmp     #%01000000              ; if (a > 0)
496         bcs     @L1                     ;
497         lsr     a                       ;   a /= 2;
498         beq     @L2                     ;   if (a != 0)
499         ldy     NewValue                ;     y = NewValue
500         sec
501         rts                             ;   return
502
503 @L1:    ora     #%11000000              ; else or in high order bits
504         cmp     #$FF                    ; if (a != -1)
505         beq     @L2
506         sec
507         ror     a                       ;   a /= 2
508         dex                             ;   high byte = -1 (X = $FF)
509         ldy     NewValue
510         sec
511         rts
512
513 @L2:    txa                             ; A = $00
514         clc
515         rts
516
517 .define  OLD_BUTTONS Buttons            ; tells callback.inc where the old port status is stored
518 .include "callback.inc"