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