]> git.sur5r.net Git - cc65/blob - libsrc/atari/mou/atrjoy.s
Add "joystick mouse" driver and default mouse callback routine (not
[cc65] / libsrc / atari / mou / atrjoy.s
1 ;
2 ; Driver for a "joystick mouse".
3 ;
4 ; C128 version: Ullrich von Bassewitz, 2004-04-05, 2009-09-26
5 ; Adapted to Atari: Christian Groessler, 2014-01-02
6 ;
7
8         .include        "zeropage.inc"
9         .include        "mouse-kernel.inc"
10         .include        "atari.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 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
54 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
55
56
57 ;----------------------------------------------------------------------------
58 ; Constants
59
60 SCREEN_HEIGHT   = 191
61 SCREEN_WIDTH    = 319
62
63 .enum   JOY
64         UP      = $01
65         DOWN    = $02
66         LEFT    = $04
67         RIGHT   = $08
68 .endenum
69
70 ;----------------------------------------------------------------------------
71 ; Global variables. The bounding box values are sorted so that they can be
72 ; written with the least effort in the SETBOX and GETBOX routines, so don't
73 ; reorder them.
74
75 .bss
76
77 Vars:
78 YPos:           .res    2               ; Current mouse position, Y
79 XPos:           .res    2               ; Current mouse position, X
80 XMin:           .res    2               ; X1 value of bounding box
81 YMin:           .res    2               ; Y1 value of bounding box
82 XMax:           .res    2               ; X2 value of bounding box
83 YMax:           .res    2               ; Y2 value of bounding box
84 Buttons:        .res    1               ; Button mask
85
86
87 Temp:           .res    1               ; Temporary value used in the int handler
88 visible:        .res    1
89
90 ; Default values for above variables
91
92 .rodata
93
94 .proc   DefVars
95         .word   SCREEN_HEIGHT/2         ; YPos
96         .word   SCREEN_WIDTH/2          ; XPos
97         .word   0                       ; XMin
98         .word   0                       ; YMin
99         .word   SCREEN_WIDTH            ; XMax
100         .word   SCREEN_HEIGHT           ; YMax
101         .byte   0                       ; Buttons
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 ; Initialize variables. Just copy the default stuff over
114
115         ldx     #.sizeof(DefVars)-1
116 @L1:    lda     DefVars,x
117         sta     Vars,x
118         dex
119         bpl     @L1
120
121 ; Be sure the mouse cursor is invisible and at the default location. We
122 ; need to do that here, because our mouse interrupt handler doesn't set the
123 ; mouse position if it hasn't changed.
124
125         sei
126         jsr     CHIDE
127         lda     XPos
128         ldx     XPos+1
129         jsr     CMOVEX
130         lda     YPos
131         ldx     YPos+1
132         jsr     CMOVEY
133         cli
134
135 ; Done, return zero (= MOUSE_ERR_OK)
136
137         ldx     #$00
138         txa
139         rts
140
141 ;----------------------------------------------------------------------------
142 ; UNINSTALL routine. Is called before the driver is removed from memory.
143 ; No return code required (the driver is removed from memory on return).
144
145 UNINSTALL       = HIDE                  ; Hide cursor on exit
146
147 ;----------------------------------------------------------------------------
148 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
149 ; a counter for calls to show/hide, and the driver entry point is only called
150 ; if the mouse is currently visible and should get hidden. For most drivers,
151 ; no special action is required besides hiding the mouse cursor.
152 ; No return code required.
153
154 HIDE:   dec     visible
155         sei
156         jsr     CHIDE
157         cli
158         rts
159
160 ;----------------------------------------------------------------------------
161 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
162 ; a counter for calls to show/hide, and the driver entry point is only called
163 ; if the mouse is currently hidden and should become visible. For most drivers,
164 ; no special action is required besides enabling the mouse cursor.
165 ; No return code required.
166
167 SHOW:   inc     visible
168         sei
169         jsr     CSHOW
170         cli
171         rts
172
173 ;----------------------------------------------------------------------------
174 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
175 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
176 ; No checks are done if the mouse is currently inside the box, this is the job
177 ; of the caller. It is not necessary to validate the parameters, trust the
178 ; caller and save some code here. No return code required.
179
180 SETBOX: sta     ptr1
181         stx     ptr1+1                  ; Save data pointer
182
183         ldy     #.sizeof (MOUSE_BOX)-1
184         sei
185
186 @L1:    lda     (ptr1),y
187         sta     XMin,y
188         dey
189         bpl     @L1
190
191         cli
192         rts
193
194 ;----------------------------------------------------------------------------
195 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
196 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
197
198 GETBOX: sta     ptr1
199         stx     ptr1+1                  ; Save data pointer
200
201         ldy     #.sizeof (MOUSE_BOX)-1
202         sei
203
204 @L1:    lda     XMin,y
205         sta     (ptr1),y
206         dey
207         bpl     @L1
208
209         cli
210         rts
211
212 ;----------------------------------------------------------------------------
213 ; MOVE: Move the mouse to a new position. The position is passed as it comes
214 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
215 ; remove the parameter from the stack on return.
216 ; No checks are done if the new position is valid (within the bounding box or
217 ; the screen). No return code required.
218 ;
219
220 MOVE:   sei                             ; No interrupts
221
222         pha
223         txa
224         pha
225         jsr     CHIDE
226         pla
227         tax
228         pla
229
230         sta     YPos
231         stx     YPos+1                  ; New Y position
232         jsr     CMOVEY                  ; Set it
233
234         ldy     #$01
235         lda     (sp),y
236         sta     XPos+1
237         tax
238         dey
239         lda     (sp),y
240         sta     XPos                    ; New X position
241
242         jsr     CMOVEX                  ; Move the cursor
243
244         lda     visible
245         beq     @Ret
246         
247         jsr     CSHOW
248
249 @Ret:   cli                             ; Allow interrupts
250         rts
251
252 ;----------------------------------------------------------------------------
253 ; BUTTONS: Return the button mask in a/x.
254
255 BUTTONS:
256         lda     Buttons
257         ldx     #$00
258         rts
259
260 ;----------------------------------------------------------------------------
261 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
262 ; No return code required.
263
264 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
265
266         sei                             ; Disable interrupts
267         lda     XPos                    ; Transfer the position
268         sta     (ptr1),y
269         lda     XPos+1
270         iny
271         sta     (ptr1),y
272         lda     YPos
273         iny
274         sta     (ptr1),y
275         lda     YPos+1
276         cli                             ; Enable interrupts
277
278         iny
279         sta     (ptr1),y                ; Store last byte
280
281         rts                             ; Done
282
283 ;----------------------------------------------------------------------------
284 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
285 ; struct pointed to by ptr1. No return code required.
286 ;
287 ; We're cheating here to keep the code smaller: The first fields of the
288 ; mouse_info struct are identical to the mouse_pos struct, so we will just
289 ; call _mouse_pos to initialize the struct pointer and fill the position
290 ; fields.
291
292 INFO:   jsr     POS
293
294 ; Fill in the button state
295
296         lda     Buttons
297         ldy     #MOUSE_INFO::BUTTONS
298         sta     (ptr1),y
299
300         rts
301
302 ;----------------------------------------------------------------------------
303 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
304 ; specific data in ptr1, and the ioctl code in A.
305 ; Must return an error code in a/x.
306 ;
307
308 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
309         ldx     #>MOUSE_ERR_INV_IOCTL
310 hlprts: rts
311
312 ;----------------------------------------------------------------------------
313 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
314 ; (so be careful). The routine MUST return carry set if the interrupt has been
315 ; 'handled' - which means that the interrupt source is gone. Otherwise it
316 ; MUST return carry clear.
317 ;
318
319 IRQ:
320
321 ; Check for a pressed button and place the result into Buttons
322
323         ldx     #0
324         lda     TRIG0                   ; joystick #0 trigger
325         bne     @L0                     ; not pressed
326         ldx     #MOUSE_BTN_LEFT
327 @L0:    stx     Buttons
328
329         lda     PORTA                   ; get joystick direction bits
330         and     #15                     ; clear joystick #1 bits
331         eor     #15
332         sta     Temp
333         clc
334         beq     hlprts                  ; no movement, do nothing
335
336         jsr     CHIDE
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
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: lda     visible
437         beq     @Done
438
439         jsr     CSHOW
440
441 @Done:  clc                             ; Interrupt not "handled"
442         rts
443