]> git.sur5r.net Git - cc65/blob - libsrc/atari/mou/atrjoy.s
2f77ac8dbf9147ff09778ece85fdd1a72103721d
[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        "HEADER"
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   = 191
63 SCREEN_WIDTH    = 319
64
65 .enum   JOY
66         UP      = $01
67         DOWN    = $02
68         LEFT    = $04
69         RIGHT   = $08
70 .endenum
71
72 ;----------------------------------------------------------------------------
73 ; Global variables. The bounding box values are sorted so that they can be
74 ; written with the least effort in the SETBOX and GETBOX routines, so don't
75 ; reorder them.
76
77 .bss
78
79 Vars:
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 Buttons:        .res    1               ; Button mask
87
88
89 Temp:           .res    1               ; Temporary value used in the int handler
90
91 ; Default values for above variables
92
93 .rodata
94
95 ; (We use ".proc" because we want to define both a label and a scope.)
96
97 .proc   DefVars
98         .word   SCREEN_HEIGHT/2         ; YPos
99         .word   SCREEN_WIDTH/2          ; XPos
100         .word   0                       ; XMin
101         .word   0                       ; YMin
102         .word   SCREEN_WIDTH            ; XMax
103         .word   SCREEN_HEIGHT           ; YMax
104         .byte   0                       ; Buttons
105 .endproc
106
107 .code
108
109 ;----------------------------------------------------------------------------
110 ; INSTALL routine. Is called after the driver is loaded into memory. If
111 ; possible, check if the hardware is present.
112 ; Must return an MOUSE_ERR_xx code in a/x.
113
114 INSTALL:
115
116 ; Initialize variables. Just copy the default stuff over
117
118         ldx     #.sizeof(DefVars)-1
119 @L1:    lda     DefVars,x
120         sta     Vars,x
121         dex
122         bpl     @L1
123
124 ; Make sure the mouse cursor is at the default location.
125
126         lda     XPos
127         ldx     XPos+1
128         jsr     CMOVEX
129         lda     YPos
130         ldx     YPos+1
131         jsr     CMOVEY
132
133 ; Done, return zero (= MOUSE_ERR_OK)
134
135         ldx     #$00
136         txa
137         rts
138
139 ;----------------------------------------------------------------------------
140 ; UNINSTALL routine. Is called before the driver is removed from memory.
141 ; No return code required (the driver is removed from memory on return).
142
143 UNINSTALL       = HIDE                  ; Hide cursor on exit
144
145 ;----------------------------------------------------------------------------
146 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
147 ; a counter for calls to show/hide, and the driver entry point is only called
148 ; if the mouse is currently visible and should get hidden. For most drivers,
149 ; no special action is required besides hiding the mouse cursor.
150 ; No return code required.
151
152 HIDE:   php
153         sei
154         jsr     CHIDE
155         plp
156         rts
157
158 ;----------------------------------------------------------------------------
159 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
160 ; a counter for calls to show/hide, and the driver entry point is only called
161 ; if the mouse is currently hidden and should become visible. For most drivers,
162 ; no special action is required besides enabling the mouse cursor.
163 ; No return code required.
164
165 SHOW:   php
166         sei
167         jsr     CSHOW
168         plp
169         rts
170
171 ;----------------------------------------------------------------------------
172 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
173 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
174 ; No checks are done if the mouse is currently inside the box, this is the job
175 ; of the caller. It is not necessary to validate the parameters, trust the
176 ; caller and save some code here. No return code required.
177
178 SETBOX: sta     ptr1
179         stx     ptr1+1                  ; Save data pointer
180
181         ldy     #.sizeof (MOUSE_BOX)-1
182         php
183         sei
184
185 @L1:    lda     (ptr1),y
186         sta     XMin,y
187         dey
188         bpl     @L1
189
190         plp
191         rts
192
193 ;----------------------------------------------------------------------------
194 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
195 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
196
197 GETBOX: sta     ptr1
198         stx     ptr1+1                  ; Save data pointer
199
200         ldy     #.sizeof (MOUSE_BOX)-1
201         php
202         sei
203
204 @L1:    lda     XMin,y
205         sta     (ptr1),y
206         dey
207         bpl     @L1
208
209         plp
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:   php
221         sei                             ; No interrupts
222
223         pha
224         txa
225         pha
226         jsr     CPREP
227         pla
228         tax
229         pla
230
231         sta     YPos
232         stx     YPos+1                  ; New Y position
233         jsr     CMOVEY                  ; Set it
234
235         ldy     #$01
236         lda     (sp),y
237         sta     XPos+1
238         tax
239         dey
240         lda     (sp),y
241         sta     XPos                    ; New X position
242         jsr     CMOVEX                  ; Move the cursor
243
244         jsr     CDRAW
245
246         plp                             ; Restore interrupt flag
247         rts
248
249 ;----------------------------------------------------------------------------
250 ; BUTTONS: Return the button mask in a/x.
251
252 BUTTONS:
253         lda     Buttons
254         ldx     #$00
255         rts
256
257 ;----------------------------------------------------------------------------
258 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
259 ; No return code required.
260
261 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
262
263         php
264         sei                             ; Disable interrupts
265         lda     XPos                    ; Transfer the position
266         sta     (ptr1),y
267         lda     XPos+1
268         iny
269         sta     (ptr1),y
270         lda     YPos
271         iny
272         sta     (ptr1),y
273         lda     YPos+1
274         plp                             ; Restore interrupt flag
275
276         iny
277         sta     (ptr1),y                ; Store last byte
278
279         rts                             ; Done
280
281 ;----------------------------------------------------------------------------
282 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
283 ; struct pointed to by ptr1. No return code required.
284 ;
285 ; We're cheating here to keep the code smaller: The first fields of the
286 ; mouse_info struct are identical to the mouse_pos struct, so we will just
287 ; call _mouse_pos to initialize the struct pointer and fill the position
288 ; fields.
289
290 INFO:   jsr     POS
291
292 ; Fill in the button state
293
294         lda     Buttons
295         ldy     #MOUSE_INFO::BUTTONS
296         sta     (ptr1),y
297
298         rts
299
300 ;----------------------------------------------------------------------------
301 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
302 ; specific data in ptr1, and the ioctl code in A.
303 ; Must return an error code in a/x.
304 ;
305
306 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
307         ldx     #>MOUSE_ERR_INV_IOCTL
308         rts
309
310 ;----------------------------------------------------------------------------
311 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
312 ; (so be careful). The routine MUST return carry set if the interrupt has been
313 ; 'handled' - which means that the interrupt source is gone. Otherwise it
314 ; MUST return carry clear.
315 ;
316
317 IRQ:
318
319 ; Check for a pressed button and place the result into Buttons
320
321         ldx     #0
322         lda     TRIG0                   ; joystick #0 trigger
323         bne     @L0                     ; not pressed
324         ldx     #MOUSE_BTN_LEFT
325 @L0:    stx     Buttons
326
327         lda     PORTA                   ; get joystick direction bits
328         and     #15                     ; clear joystick #1 bits
329         eor     #15
330         sta     Temp
331
332         jsr     CPREP
333
334 ; Check left/right
335
336         lda     Temp                    ; Read joystick #0
337         and     #(JOY::LEFT | JOY::RIGHT)
338         beq     @SkipX                  ;
339
340 ; We will cheat here and rely on the fact that either the left, OR the right
341 ; bit can be active
342
343         and     #JOY::RIGHT             ; Check RIGHT bit
344         bne     @Right
345         lda     #$FF
346         tax
347         bne     @AddX                   ; Branch always
348 @Right: lda     #$01
349         ldx     #$00
350
351 ; Calculate the new X coordinate (--> a/y)
352
353 @AddX:  add     XPos
354         tay                             ; Remember low byte
355         txa
356         adc     XPos+1
357         tax
358
359 ; Limit the X coordinate to the bounding box
360
361         cpy     XMin
362         sbc     XMin+1
363         bpl     @L1
364         ldy     XMin
365         ldx     XMin+1
366         jmp     @L2
367 @L1:    txa
368
369         cpy     XMax
370         sbc     XMax+1
371         bmi     @L2
372         ldy     XMax
373         ldx     XMax+1
374 @L2:    sty     XPos
375         stx     XPos+1
376
377 ; Move the mouse pointer to the new X pos
378
379         tya
380         jsr     CMOVEX
381
382 ; Calculate the Y movement vector
383
384 @SkipX: lda     Temp                    ; Read joystick #0
385         and     #(JOY::UP | JOY::DOWN)  ; Check up/down
386         beq     @SkipY                  ;
387
388 ; We will cheat here and rely on the fact that either the up, OR the down
389 ; bit can be active
390
391         lsr     a
392         bcc     @Down
393         lda     #$FF
394         tax
395         bne     @AddY
396 @Down:  lda     #$01
397         ldx     #$00
398
399 ; Calculate the new Y coordinate (--> a/y)
400
401 @AddY:  add     YPos
402         tay                             ; Remember low byte
403         txa
404         adc     YPos+1
405         tax
406
407 ; Limit the Y coordinate to the bounding box
408
409         cpy     YMin
410         sbc     YMin+1
411         bpl     @L3
412         ldy     YMin
413         ldx     YMin+1
414         jmp     @L4
415 @L3:    txa
416
417         cpy     YMax
418         sbc     YMax+1
419         bmi     @L4
420         ldy     YMax
421         ldx     YMax+1
422 @L4:    sty     YPos
423         stx     YPos+1
424
425 ; Move the mouse pointer to the new X pos
426
427         tya
428         jsr     CMOVEY
429
430 ; Done
431
432 @SkipY: jsr     CDRAW
433         clc                             ; Interrupt not "handled"
434         rts
435