]> git.sur5r.net Git - cc65/blob - libsrc/c128/mou/c128-joy.s
Corrected the default upper limits of some mouse drivers' bounding box.
[cc65] / libsrc / c128 / mou / c128-joy.s
1 ;
2 ; Driver for a "joystick mouse".
3 ;
4 ; 2009-09-26, Ullrich von Bassewitz
5 ; 2014-03-17, Greg King
6 ;
7
8         .include        "zeropage.inc"
9         .include        "mouse-kernel.inc"
10         .include        "c128.inc"
11
12         .macpack        generic
13
14 ; ------------------------------------------------------------------------
15 ; Header. Includes jump table
16
17 .segment        "JUMPTABLE"
18
19 HEADER:
20
21 ; Driver signature
22
23         .byte   $6d, $6f, $75           ; "mou"
24         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
25
26 ; Library reference
27
28         .addr   $0000
29
30 ; Jump table
31
32         .addr   INSTALL
33         .addr   UNINSTALL
34         .addr   HIDE
35         .addr   SHOW
36         .addr   SETBOX
37         .addr   GETBOX
38         .addr   MOVE
39         .addr   BUTTONS
40         .addr   POS
41         .addr   INFO
42         .addr   IOCTL
43         .addr   IRQ
44
45 ; Mouse driver flags
46
47         .byte   MOUSE_FLAG_LATE_IRQ
48
49 ; Callback table, set by the kernel before INSTALL is called
50
51 CHIDE:  jmp     $0000                   ; Hide the cursor
52 CSHOW:  jmp     $0000                   ; Show the cursor
53 CPREP:  jmp     $0000                   ; Prepare to move the cursor
54 CDRAW:  jmp     $0000                   ; Draw the cursor
55 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
56 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
57
58
59 ;----------------------------------------------------------------------------
60 ; Constants
61
62 SCREEN_HEIGHT   = 200
63 SCREEN_WIDTH    = 320
64
65 .enum   JOY
66         UP      = $01
67         DOWN    = $02
68         LEFT    = $04
69         RIGHT   = $08
70         FIRE    = $10
71 .endenum
72
73 ;----------------------------------------------------------------------------
74 ; Global variables. The bounding box values are sorted so that they can be
75 ; written with the least effort in the SETBOX and GETBOX routines, so don't
76 ; reorder them.
77
78 .bss
79
80 Vars:
81 YPos:           .res    2               ; Current mouse position, Y
82 XPos:           .res    2               ; Current mouse position, X
83 XMin:           .res    2               ; X1 value of bounding box
84 YMin:           .res    2               ; Y1 value of bounding box
85 XMax:           .res    2               ; X2 value of bounding box
86 YMax:           .res    2               ; Y2 value of bounding box
87 Buttons:        .res    1               ; Button mask
88
89 INIT_save:      .res    1
90
91 ; Temporary value used in the int handler
92
93 Temp:           .res    1
94
95 .rodata
96
97 ; Default values for above variables
98 ; (We use ".proc" because we want to define both a label and a scope.)
99
100 .proc   DefVars
101         .word   SCREEN_HEIGHT/2         ; YPos
102         .word   SCREEN_WIDTH/2          ; XPos
103         .word   0                       ; XMin
104         .word   0                       ; YMin
105         .word   SCREEN_WIDTH - 1        ; XMax
106         .word   SCREEN_HEIGHT - 1       ; YMax
107         .byte   0                       ; Buttons
108 .endproc
109
110 .code
111
112 ;----------------------------------------------------------------------------
113 ; INSTALL routine. Is called after the driver is loaded into memory. If
114 ; possible, check if the hardware is present.
115 ; Must return an MOUSE_ERR_xx code in a/x.
116
117 INSTALL:
118
119 ; Disable the BASIC interpreter's interrupt-driven sprite-motion code.
120 ; That allows direct access to the VIC-IIe's sprite registers.
121
122         lda     INIT_STATUS
123         sta     INIT_save
124         lda     #%11000000
125         sta     INIT_STATUS
126
127 ; Initialize variables. Just copy the default stuff over
128
129         ldx     #.sizeof(DefVars)-1
130 @L1:    lda     DefVars,x
131         sta     Vars,x
132         dex
133         bpl     @L1
134
135 ; Be sure the mouse cursor is invisible and at the default location. We
136 ; need to do that here, because our mouse interrupt handler doesn't set the
137 ; mouse position if it hasn't changed.
138
139         sei
140         jsr     CHIDE
141         lda     XPos
142         ldx     XPos+1
143         jsr     CMOVEX
144         lda     YPos
145         ldx     YPos+1
146         jsr     CMOVEY
147         cli
148
149 ; Done, return zero (= MOUSE_ERR_OK)
150
151         ldx     #$00
152         txa
153         rts
154
155 ;----------------------------------------------------------------------------
156 ; UNINSTALL routine. Is called before the driver is removed from memory.
157 ; No return code required (the driver is removed from memory on return).
158
159 UNINSTALL:
160         jsr     HIDE                    ; Hide cursor on exit
161         lda     INIT_save
162         sta     INIT_STATUS
163         rts
164
165 ;----------------------------------------------------------------------------
166 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
167 ; a counter for calls to show/hide, and the driver entry point is only called
168 ; if the mouse is currently visible and should get hidden. For most drivers,
169 ; no special action is required besides hiding the mouse cursor.
170 ; No return code required.
171
172 HIDE:   sei
173         jsr     CHIDE
174         cli
175         rts
176
177 ;----------------------------------------------------------------------------
178 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
179 ; a counter for calls to show/hide, and the driver entry point is only called
180 ; if the mouse is currently hidden and should become visible. For most drivers,
181 ; no special action is required besides enabling the mouse cursor.
182 ; No return code required.
183
184 SHOW:   sei
185         jsr     CSHOW
186         cli
187         rts
188
189 ;----------------------------------------------------------------------------
190 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
191 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
192 ; No checks are done if the mouse is currently inside the box, this is the job
193 ; of the caller. It is not necessary to validate the parameters, trust the
194 ; caller and save some code here. No return code required.
195
196 SETBOX: sta     ptr1
197         stx     ptr1+1                  ; Save data pointer
198
199         ldy     #.sizeof (MOUSE_BOX)-1
200         sei
201
202 @L1:    lda     (ptr1),y
203         sta     XMin,y
204         dey
205         bpl     @L1
206
207         cli
208         rts
209
210 ;----------------------------------------------------------------------------
211 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
212 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
213
214 GETBOX: sta     ptr1
215         stx     ptr1+1                  ; Save data pointer
216
217         ldy     #.sizeof (MOUSE_BOX)-1
218         sei
219
220 @L1:    lda     XMin,y
221         sta     (ptr1),y
222         dey
223         bpl     @L1
224
225         cli
226         rts
227
228 ;----------------------------------------------------------------------------
229 ; MOVE: Move the mouse to a new position. The position is passed as it comes
230 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
231 ; remove the parameter from the stack on return.
232 ; No checks are done if the new position is valid (within the bounding box or
233 ; the screen). No return code required.
234 ;
235
236 MOVE:   sei                             ; No interrupts
237
238         sta     YPos
239         stx     YPos+1                  ; New Y position
240         jsr     CMOVEY                  ; Set it
241
242         ldy     #$01
243         lda     (sp),y
244         sta     XPos+1
245         tax
246         dey
247         lda     (sp),y
248         sta     XPos                    ; New X position
249
250         jsr     CMOVEX                  ; Move the cursor
251
252         cli                             ; Allow interrupts
253         rts
254
255 ;----------------------------------------------------------------------------
256 ; BUTTONS: Return the button mask in a/x.
257
258 BUTTONS:
259         lda     Buttons
260         ldx     #$00
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         lda     Buttons
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     #$7F
324         sta     CIA1_PRA
325         lda     CIA1_PRB                ; Read joystick #0
326         and     #$1F
327         eor     #$1F                    ; Make all bits active high
328         sta     Temp
329
330 ; Check for a pressed button and place the result into Buttons
331
332         ldx     #$00                    ; Assume no button pressed
333         and     #JOY::FIRE              ; Check fire button
334         beq     @L0                     ; Jump if not pressed
335         ldx     #MOUSE_BTN_LEFT         ; Left (only) button is pressed
336 @L0:    stx     Buttons
337
338 ; Check left/right
339
340         lda     Temp                    ; Read joystick #0
341         and     #(JOY::LEFT | JOY::RIGHT)
342         beq     @SkipX                  ;
343
344 ; We will cheat here and rely on the fact that either the left, OR the right
345 ; bit can be active
346
347         and     #JOY::RIGHT             ; Check RIGHT bit
348         bne     @Right
349         lda     #$FF
350         tax
351         bne     @AddX                   ; Branch always
352 @Right: lda     #$01
353         ldx     #$00
354
355 ; Calculate the new X coordinate (--> a/y)
356
357 @AddX:  add     XPos
358         tay                             ; Remember low byte
359         txa
360         adc     XPos+1
361         tax
362
363 ; Limit the X coordinate to the bounding box
364
365         cpy     XMin
366         sbc     XMin+1
367         bpl     @L1
368         ldy     XMin
369         ldx     XMin+1
370         jmp     @L2
371 @L1:    txa
372
373         cpy     XMax
374         sbc     XMax+1
375         bmi     @L2
376         ldy     XMax
377         ldx     XMax+1
378 @L2:    sty     XPos
379         stx     XPos+1
380
381 ; Move the mouse pointer to the new X pos
382
383         tya
384         jsr     CMOVEX
385
386 ; Calculate the Y movement vector
387
388 @SkipX: lda     Temp                    ; Read joystick #0
389         and     #(JOY::UP | JOY::DOWN)  ; Check up/down
390         beq     @SkipY                  ;
391
392 ; We will cheat here and rely on the fact that either the up, OR the down
393 ; bit can be active
394
395         lsr     a                       ; Check UP bit
396         bcc     @Down
397         lda     #$FF
398         tax
399         bne     @AddY
400 @Down:  lda     #$01
401         ldx     #$00
402
403 ; Calculate the new Y coordinate (--> a/y)
404
405 @AddY:  add     YPos
406         tay                             ; Remember low byte
407         txa
408         adc     YPos+1
409         tax
410
411 ; Limit the Y coordinate to the bounding box
412
413         cpy     YMin
414         sbc     YMin+1
415         bpl     @L3
416         ldy     YMin
417         ldx     YMin+1
418         jmp     @L4
419 @L3:    txa
420
421         cpy     YMax
422         sbc     YMax+1
423         bmi     @L4
424         ldy     YMax
425         ldx     YMax+1
426 @L4:    sty     YPos
427         stx     YPos+1
428
429 ; Move the mouse pointer to the new X pos
430
431         tya
432         jsr     CMOVEY
433
434 ; Done
435
436 @SkipY: jsr     CDRAW
437         clc                             ; Interrupt not "handled"
438         rts