]> git.sur5r.net Git - cc65/blob - libsrc/c128/mou/c128-joy.s
add gotox, gotoy, and gotoxy
[cc65] / libsrc / c128 / mou / c128-joy.s
1 ;
2 ; Driver for a "joystick mouse".
3 ;
4 ; Ullrich von Bassewitz, 2004-04-05, 2009-09-26
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9         .include        "c128.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 ; Library reference
26
27         .addr   $0000
28
29 ; Jump table
30
31         .addr   INSTALL
32         .addr   UNINSTALL
33         .addr   HIDE
34         .addr   SHOW
35         .addr   SETBOX
36         .addr   GETBOX
37         .addr   MOVE
38         .addr   BUTTONS
39         .addr   POS
40         .addr   INFO
41         .addr   IOCTL
42         .addr   IRQ
43
44 ; Mouse driver flags
45
46         .byte   MOUSE_FLAG_LATE_IRQ
47
48 ; Callback table, set by the kernel before INSTALL is called
49
50 CHIDE:  jmp     $0000                   ; Hide the cursor
51 CSHOW:  jmp     $0000                   ; Show the cursor
52 CPREP:  jmp     $0000                   ; Prepare to move the cursor
53 CDRAW:  jmp     $0000                   ; Draw the cursor
54 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
55 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
56
57
58 ;----------------------------------------------------------------------------
59 ; Constants
60
61 SCREEN_HEIGHT   = 200
62 SCREEN_WIDTH    = 320
63
64 .enum   JOY
65         UP      = $01
66         DOWN    = $02
67         LEFT    = $04
68         RIGHT   = $08
69         FIRE    = $10
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 ; Temporary value used in the int handler
89
90 Temp:           .res    1
91
92 .rodata
93
94 ; Default values for above variables
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 ; Be sure the mouse cursor is invisible and at the default location. We
125 ; need to do that here, because our mouse interrupt handler doesn't set the
126 ; mouse position if it hasn't changed.
127
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         cli
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:   sei
158         jsr     CHIDE
159         cli
160         rts
161
162 ;----------------------------------------------------------------------------
163 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
164 ; a counter for calls to show/hide, and the driver entry point is only called
165 ; if the mouse is currently hidden and should become visible. For most drivers,
166 ; no special action is required besides enabling the mouse cursor.
167 ; No return code required.
168
169 SHOW:   sei
170         jsr     CSHOW
171         cli
172         rts
173
174 ;----------------------------------------------------------------------------
175 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
176 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
177 ; No checks are done if the mouse is currently inside the box, this is the job
178 ; of the caller. It is not necessary to validate the parameters, trust the
179 ; caller and save some code here. No return code required.
180
181 SETBOX: sta     ptr1
182         stx     ptr1+1                  ; Save data pointer
183
184         ldy     #.sizeof (MOUSE_BOX)-1
185         sei
186
187 @L1:    lda     (ptr1),y
188         sta     XMin,y
189         dey
190         bpl     @L1
191
192         cli
193         rts
194
195 ;----------------------------------------------------------------------------
196 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
197 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
198
199 GETBOX: sta     ptr1
200         stx     ptr1+1                  ; Save data pointer
201
202         ldy     #.sizeof (MOUSE_BOX)-1
203         sei
204
205 @L1:    lda     XMin,y
206         sta     (ptr1),y
207         dey
208         bpl     @L1
209
210         cli
211         rts
212
213 ;----------------------------------------------------------------------------
214 ; MOVE: Move the mouse to a new position. The position is passed as it comes
215 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
216 ; remove the parameter from the stack on return.
217 ; No checks are done if the new position is valid (within the bounding box or
218 ; the screen). No return code required.
219 ;
220
221 MOVE:   sei                             ; No interrupts
222
223         sta     YPos
224         stx     YPos+1                  ; New Y position
225         jsr     CMOVEY                  ; Set it
226
227         ldy     #$01
228         lda     (sp),y
229         sta     XPos+1
230         tax
231         dey
232         lda     (sp),y
233         sta     XPos                    ; New X position
234
235         jsr     CMOVEX                  ; Move the cursor
236
237         cli                             ; Allow interrupts
238         rts
239
240 ;----------------------------------------------------------------------------
241 ; BUTTONS: Return the button mask in a/x.
242
243 BUTTONS:
244         lda     Buttons
245         ldx     #$00
246         rts
247
248 ;----------------------------------------------------------------------------
249 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
250 ; No return code required.
251
252 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
253
254         sei                             ; Disable interrupts
255         lda     XPos                    ; Transfer the position
256         sta     (ptr1),y
257         lda     XPos+1
258         iny
259         sta     (ptr1),y
260         lda     YPos
261         iny
262         sta     (ptr1),y
263         lda     YPos+1
264         cli                             ; Enable interrupts
265
266         iny
267         sta     (ptr1),y                ; Store last byte
268
269         rts                             ; Done
270
271 ;----------------------------------------------------------------------------
272 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
273 ; struct pointed to by ptr1. No return code required.
274 ;
275 ; We're cheating here to keep the code smaller: The first fields of the
276 ; mouse_info struct are identical to the mouse_pos struct, so we will just
277 ; call _mouse_pos to initialize the struct pointer and fill the position
278 ; fields.
279
280 INFO:   jsr     POS
281
282 ; Fill in the button state
283
284         lda     Buttons
285         ldy     #MOUSE_INFO::BUTTONS
286         sta     (ptr1),y
287
288         rts
289
290 ;----------------------------------------------------------------------------
291 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
292 ; specific data in ptr1, and the ioctl code in A.
293 ; Must return an error code in a/x.
294 ;
295
296 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
297         ldx     #>MOUSE_ERR_INV_IOCTL
298         rts
299
300 ;----------------------------------------------------------------------------
301 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
302 ; (so be careful). The routine MUST return carry set if the interrupt has been
303 ; 'handled' - which means that the interrupt source is gone. Otherwise it
304 ; MUST return carry clear.
305 ;
306
307 IRQ:    jsr     CPREP
308         lda     #$7F
309         sta     CIA1_PRA
310         lda     CIA1_PRB                ; Read joystick #0
311         and     #$1F
312         eor     #$1F                    ; Make all bits active high
313         sta     Temp
314
315 ; Check for a pressed button and place the result into Buttons
316
317         ldx     #$00                    ; Assume no button pressed
318         and     #JOY::FIRE              ; Check fire button
319         beq     @L0                     ; Jump if not pressed
320         ldx     #MOUSE_BTN_LEFT         ; Left (only) button is pressed
321 @L0:    stx     Buttons
322
323 ; Check left/right
324
325         lda     Temp                    ; Read joystick #0
326         and     #(JOY::LEFT | JOY::RIGHT)
327         beq     @SkipX                  ;
328
329 ; We will cheat here and rely on the fact that either the left, OR the right
330 ; bit can be active
331
332         and     #JOY::RIGHT             ; Check RIGHT bit
333         bne     @Right
334         lda     #$FF
335         tax
336         bne     @AddX                   ; Branch always
337 @Right: lda     #$01
338         ldx     #$00
339
340 ; Calculate the new X coordinate (--> a/y)
341
342 @AddX:  add     XPos
343         tay                             ; Remember low byte
344         txa
345         adc     XPos+1
346         tax
347
348 ; Limit the X coordinate to the bounding box
349
350         cpy     XMin
351         sbc     XMin+1
352         bpl     @L1
353         ldy     XMin
354         ldx     XMin+1
355         jmp     @L2
356 @L1:    txa
357
358         cpy     XMax
359         sbc     XMax+1
360         bmi     @L2
361         ldy     XMax
362         ldx     XMax+1
363 @L2:    sty     XPos
364         stx     XPos+1
365
366 ; Move the mouse pointer to the new X pos
367
368         tya
369         jsr     CMOVEX
370
371 ; Calculate the Y movement vector
372
373 @SkipX: lda     Temp                    ; Read joystick #0
374         and     #(JOY::UP | JOY::DOWN)  ; Check up/down
375         beq     @SkipY                  ;
376
377 ; We will cheat here and rely on the fact that either the up, OR the down
378 ; bit can be active
379
380         lsr     a                       ; Check UP bit
381         bcc     @Down
382         lda     #$FF
383         tax
384         bne     @AddY
385 @Down:  lda     #$01
386         ldx     #$00
387
388 ; Calculate the new Y coordinate (--> a/y)
389
390 @AddY:  add     YPos
391         tay                             ; Remember low byte
392         txa
393         adc     YPos+1
394         tax
395
396 ; Limit the Y coordinate to the bounding box
397
398         cpy     YMin
399         sbc     YMin+1
400         bpl     @L3
401         ldy     YMin
402         ldx     YMin+1
403         jmp     @L4
404 @L3:    txa
405
406         cpy     YMax
407         sbc     YMax+1
408         bmi     @L4
409         ldy     YMax
410         ldx     YMax+1
411 @L4:    sty     YPos
412         stx     YPos+1
413
414 ; Move the mouse pointer to the new X pos
415
416         tya
417         jsr     CMOVEY
418
419 ; Done
420
421 @SkipY: jsr     CDRAW
422         clc                             ; Interrupt not "handled"
423         rts