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