]> git.sur5r.net Git - cc65/blob - libsrc/c64/c64-joymouse.s
Changed the mouse API: Introduced a new flag byte that contains information
[cc65] / libsrc / c64 / c64-joymouse.s
1 ;
2 ; Driver for a "joystick mouse".
3 ;
4 ; Ullrich von Bassewitz, 2004-03-29
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9         .include        "c64.inc"
10
11         .macpack        generic
12
13 ; ------------------------------------------------------------------------
14 ; Header. Includes jump table
15
16 .segment        "JUMPTABLE"
17
18 HEADER:
19
20 ; Driver signature
21
22         .byte   $6d, $6f, $75           ; "mou"
23         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
24
25 ; Jump table.
26
27         .addr   INSTALL
28         .addr   UNINSTALL
29         .addr   HIDE
30         .addr   SHOW
31         .addr   BOX
32         .addr   MOVE
33         .addr   BUTTONS
34         .addr   POS
35         .addr   INFO
36         .addr   IOCTL
37         .addr   IRQ
38
39 ; Mouse driver flags
40
41         .byte   MOUSE_FLAG_LATE_IRQ
42
43 ; Callback table, set by the kernel before INSTALL is called
44
45 CHIDE:  jmp     $0000                   ; Hide the cursor
46 CSHOW:  jmp     $0000                   ; Show the cursor
47 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
48 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
49
50
51 ;----------------------------------------------------------------------------
52 ; Constants
53
54 SCREEN_HEIGHT   = 200
55 SCREEN_WIDTH    = 320
56
57 .enum   JOY
58         UP      = $01
59         DOWN    = $02
60         LEFT    = $04
61         RIGHT   = $08
62         FIRE    = $10
63 .endenum
64
65 ;----------------------------------------------------------------------------
66 ; Global variables. The bounding box values are sorted so that they can be
67 ; written with the least effort in the BOX routine, so don't reorder them.
68
69 .bss
70
71 Vars:
72 YPos:           .res    2               ; Current mouse position, Y
73 XPos:           .res    2               ; Current mouse position, X
74 YMax:           .res    2               ; Y2 value of bounding box
75 XMax:           .res    2               ; X2 value of bounding box
76 YMin:           .res    2               ; Y1 value of bounding box
77 XMin:           .res    2               ; X1 value of bounding box
78 Buttons:        .res    1               ; Button mask
79
80 ; Temporary value used in the int handler
81
82 Temp:           .res    1
83
84 ; Default values for above variables
85
86 .rodata
87
88 .proc   DefVars
89         .word   SCREEN_HEIGHT/2         ; YPos
90         .word   SCREEN_WIDTH/2          ; XPos
91         .word   SCREEN_HEIGHT           ; YMax
92         .word   SCREEN_WIDTH            ; XMax
93         .word   0                       ; YMin
94         .word   0                       ; XMin
95         .byte   0                       ; Buttons
96 .endproc
97
98 .code
99
100 ;----------------------------------------------------------------------------
101 ; INSTALL routine. Is called after the driver is loaded into memory. If
102 ; possible, check if the hardware is present.
103 ; Must return an MOUSE_ERR_xx code in a/x.
104
105 INSTALL:
106
107 ; Initialize variables. Just copy the default stuff over
108
109         ldx     #.sizeof(DefVars)-1
110 @L1:    lda     DefVars,x
111         sta     Vars,x
112         dex
113         bpl     @L1
114
115 ; Be sure the mouse cursor is invisible and at the default location. We
116 ; need to do that here, because our mouse interrupt handler doesn't set the
117 ; mouse position if it hasn't changed.
118
119         sei
120         jsr     CHIDE
121         lda     XPos
122         ldx     XPos+1
123         jsr     CMOVEX
124         lda     YPos
125         ldx     YPos+1
126         jsr     CMOVEY
127         cli
128
129 ; Done, return zero (= MOUSE_ERR_OK)
130
131         ldx     #$00
132         txa
133         rts
134
135 ;----------------------------------------------------------------------------
136 ; UNINSTALL routine. Is called before the driver is removed from memory.
137 ; No return code required (the driver is removed from memory on return).
138
139 UNINSTALL       = HIDE                  ; Hide cursor on exit
140
141 ;----------------------------------------------------------------------------
142 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
143 ; a counter for calls to show/hide, and the driver entry point is only called
144 ; if the mouse is currently visible and should get hidden. For most drivers,
145 ; no special action is required besides hiding the mouse cursor.
146 ; No return code required.
147
148 HIDE:   sei
149         jsr     CHIDE
150         cli
151         rts
152
153 ;----------------------------------------------------------------------------
154 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
155 ; a counter for calls to show/hide, and the driver entry point is only called
156 ; if the mouse is currently hidden and should become visible. For most drivers,
157 ; no special action is required besides enabling the mouse cursor.
158 ; No return code required.
159
160 SHOW:   sei
161         jsr     CSHOW
162         cli
163         rts
164
165 ;----------------------------------------------------------------------------
166 ; BOX: Set the mouse bounding box. The parameters are passed as they come from
167 ; the C program, that is, maxy in a/x and the other parameters on the stack.
168 ; The C wrapper will remove the parameters from the stack when the driver
169 ; routine returns.
170 ; No checks are done if the mouse is currently inside the box, this is the job
171 ; of the caller. It is not necessary to validate the parameters, trust the
172 ; caller and save some code here. No return code required.
173
174 BOX:    ldy     #5
175         sei
176         sta     YMax
177         stx     YMax+1
178
179 @L1:    lda     (sp),y
180         sta     XMax,y
181         dey
182         bpl     @L1
183
184         cli
185         rts
186
187 ;----------------------------------------------------------------------------
188 ; MOVE: Move the mouse to a new position. The position is passed as it comes
189 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
190 ; remove the parameter from the stack on return.
191 ; No checks are done if the new position is valid (within the bounding box or
192 ; the screen). No return code required.
193 ;
194
195 MOVE:   sei                             ; No interrupts
196
197         sta     YPos
198         stx     YPos+1                  ; New Y position
199         jsr     CMOVEY                  ; Set it
200
201         ldy     #$01
202         lda     (sp),y
203         sta     XPos+1
204         tax
205         dey
206         lda     (sp),y
207         sta     XPos                    ; New X position
208
209         jsr     CMOVEX                  ; Move the cursor
210
211         cli                             ; Allow interrupts
212         rts
213
214 ;----------------------------------------------------------------------------
215 ; BUTTONS: Return the button mask in a/x.
216
217 BUTTONS:
218         lda     Buttons
219         ldx     #$00
220         rts
221
222 ;----------------------------------------------------------------------------
223 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
224 ; No return code required.
225
226 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
227
228         sei                             ; Disable interrupts
229         lda     XPos                    ; Transfer the position
230         sta     (ptr1),y
231         lda     XPos+1
232         iny
233         sta     (ptr1),y
234         lda     YPos
235         iny
236         sta     (ptr1),y
237         lda     YPos+1
238         cli                             ; Enable interrupts
239
240         iny
241         sta     (ptr1),y                ; Store last byte
242
243         rts                             ; Done
244
245 ;----------------------------------------------------------------------------
246 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
247 ; struct pointed to by ptr1. No return code required.
248 ;
249 ; We're cheating here to keep the code smaller: The first fields of the
250 ; mouse_info struct are identical to the mouse_pos struct, so we will just
251 ; call _mouse_pos to initialize the struct pointer and fill the position
252 ; fields.
253
254 INFO:   jsr     POS
255
256 ; Fill in the button state
257
258         lda     Buttons
259         ldy     #MOUSE_INFO::BUTTONS
260         sta     (ptr1),y
261
262         rts
263
264 ;----------------------------------------------------------------------------
265 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
266 ; specific data in ptr1, and the ioctl code in A.
267 ; Must return an error code in a/x.
268 ;
269
270 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
271         ldx     #>MOUSE_ERR_INV_IOCTL
272         rts
273
274 ;----------------------------------------------------------------------------
275 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
276 ; (so be careful). The routine MUST return carry set if the interrupt has been
277 ; 'handled' - which means that the interrupt source is gone. Otherwise it
278 ; MUST return carry clear.
279 ;
280
281 IRQ:    lda     #$7F
282         sta     CIA1_PRA
283         lda     CIA1_PRB                ; Read joystick #0
284         and     #$1F
285         eor     #$1F                    ; Make all bits active high
286         sta     Temp
287
288 ; Check for a pressed button and place the result into Buttons
289
290         ldx     #$00                    ; Assume no button pressed
291         and     #JOY::FIRE              ; Check fire button
292         beq     @L0                     ; Jump if not pressed
293         ldx     #MOUSE_BTN_LEFT         ; Left (only) button is pressed
294 @L0:    stx     Buttons
295
296 ; Check left/right
297
298         lda     Temp                    ; Read joystick #0
299         and     #(JOY::LEFT | JOY::RIGHT)
300         beq     @SkipX                  ;
301
302 ; We will cheat here and rely on the fact that either the left, OR the right
303 ; bit can be active
304
305         and     #JOY::RIGHT             ; Check RIGHT bit
306         bne     @Right
307         lda     #$FF
308         tax
309         bne     @AddX                   ; Branch always
310 @Right: lda     #$01
311         ldx     #$00
312
313 ; Calculate the new X coordinate (--> a/y)
314
315 @AddX:  add     XPos
316         tay                             ; Remember low byte
317         txa
318         adc     XPos+1
319         tax
320
321 ; Limit the X coordinate to the bounding box
322
323         cpy     XMin
324         sbc     XMin+1
325         bpl     @L1
326         ldy     XMin
327         ldx     XMin+1
328         jmp     @L2
329 @L1:    txa
330
331         cpy     XMax
332         sbc     XMax+1
333         bmi     @L2
334         ldy     XMax
335         ldx     XMax+1
336 @L2:    sty     XPos
337         stx     XPos+1
338
339 ; Move the mouse pointer to the new X pos
340
341         tya
342         jsr     CMOVEX
343
344 ; Calculate the Y movement vector
345
346 @SkipX: lda     Temp                    ; Read joystick #0
347         and     #(JOY::UP | JOY::DOWN)  ; Check up/down
348         beq     @SkipY                  ;
349
350 ; We will cheat here and rely on the fact that either the up, OR the down
351 ; bit can be active
352
353         lsr     a                       ; Check UP bit
354         bcc     @Down
355         lda     #$FF
356         tax
357         bne     @AddY
358 @Down:  lda     #$01
359         ldx     #$00
360
361 ; Calculate the new Y coordinate (--> a/y)
362
363 @AddY:  add     YPos
364         tay                             ; Remember low byte
365         txa
366         adc     YPos+1
367         tax
368
369 ; Limit the Y coordinate to the bounding box
370
371         cpy     YMin
372         sbc     YMin+1
373         bpl     @L3
374         ldy     YMin
375         ldx     YMin+1
376         jmp     @L4
377 @L3:    txa
378
379         cpy     YMax
380         sbc     YMax+1
381         bmi     @L4
382         ldy     YMax
383         ldx     YMax+1
384 @L4:    sty     YPos
385         stx     YPos+1
386
387 ; Move the mouse pointer to the new X pos
388
389         tya
390         jsr     CMOVEY
391
392 ; Done
393
394 @SkipY: clc                             ; Interrupt not handled
395         rts
396