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