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