]> git.sur5r.net Git - cc65/blob - libsrc/cbm510/mou/cbm510-joy.s
effdb7cc0802a75cf2ee40392ea7c7a39041669e
[cc65] / libsrc / cbm510 / mou / cbm510-joy.s
1 ;
2 ; Driver for a "joystick mouse".
3 ;
4 ; 2009-09-26, Ullrich von Bassewitz
5 ; 2013-09-05, Greg King
6 ;
7
8         .include        "zeropage.inc"
9         .include        "../extzp.inc"
10
11         .include        "mouse-kernel.inc"
12         .include        "cbm510.inc"
13
14         .macpack        generic
15
16 ; ------------------------------------------------------------------------
17 ; Header. Includes jump table
18
19 .segment        "JUMPTABLE"
20
21 HEADER:
22
23 ; Driver signature
24
25         .byte   $6d, $6f, $75           ; ASCII "mou"
26         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
27
28 ; Library reference
29
30         .addr   $0000
31
32 ; Jump table
33
34         .addr   INSTALL
35         .addr   UNINSTALL
36         .addr   HIDE
37         .addr   SHOW
38         .addr   SETBOX
39         .addr   GETBOX
40         .addr   MOVE
41         .addr   BUTTONS
42         .addr   POS
43         .addr   INFO
44         .addr   IOCTL
45         .addr   IRQ
46
47 ; Mouse driver flags
48
49         .byte   MOUSE_FLAG_LATE_IRQ
50
51 ; Callback table, set by the kernel before INSTALL is called.
52
53 CHIDE:  jmp     $0000                   ; Hide the cursor
54 CSHOW:  jmp     $0000                   ; Show the cursor
55 CMOVEX: jmp     $0000                   ; Move the cursor to x co-ord.
56 CMOVEY: jmp     $0000                   ; Move the cursor to y co-ord.
57
58
59 ;----------------------------------------------------------------------------
60 ; Constants
61
62 SCREEN_HEIGHT   = YSIZE * 8
63 SCREEN_WIDTH    = XSIZE * 8
64
65 .scope  JOY
66         UP      = %00000001
67         DOWN    = %00000010
68         LEFT    = %00000100
69         RIGHT   = %00001000
70         FIRE    = %00010000
71 .endscope
72
73 ;----------------------------------------------------------------------------
74 ; Global variables. The bounding box values are sorted so that they can be
75 ; written with the least effort in the SETBOX and GETBOX routines; so, don't
76 ; re-order them.
77
78 .bss
79
80 Vars:
81 YPos:           .res    2               ; Current mouse position, y
82 XPos:           .res    2               ; Current mouse position, x
83 XMin:           .res    2               ; X1 value of bounding box
84 YMin:           .res    2               ; Y1 value of bounding box
85 XMax:           .res    2               ; X2 value of bounding box
86 YMax:           .res    2               ; Y2 value of bounding box
87
88 ; Temporary value used in the interrupt handler
89
90 Temp:           .res    1
91
92 .rodata
93
94 ; Default values for below 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 - 1        ; XMax
103         .word   SCREEN_HEIGHT - 1       ; YMax
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 a MOUSE_ERR_xx code in .XA.
112
113 INSTALL:
114
115 ; Initiate 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         sei
128         jsr     CHIDE
129         lda     XPos
130         ldx     XPos+1
131         jsr     CMOVEX
132         lda     YPos
133         ldx     YPos+1
134         jsr     CMOVEY
135         cli
136
137 ; Done, return zero.
138
139         ldx     #>MOUSE_ERR_OK
140         txa
141         rts
142
143 ;----------------------------------------------------------------------------
144 ; UNINSTALL routine. Is called before the driver is removed from memory.
145 ; No return code required (the driver is removed from memory, on return).
146
147 UNINSTALL       := HIDE                 ; Hide cursor, on exit
148
149 ;----------------------------------------------------------------------------
150 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
151 ; a counter for calls to show/hide; and, the driver entry point is called only
152 ; if the mouse currently is visible and should get hidden. For most drivers,
153 ; no special action is required besides hiding the mouse cursor.
154 ; No return code required.
155
156 HIDE:   sei
157         jsr     CHIDE
158         cli
159         rts
160
161 ;----------------------------------------------------------------------------
162 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
163 ; a counter for calls to show/hide; and, the driver entry point is called only
164 ; if the mouse currently is hidden and should become visible. For most drivers,
165 ; no special action is required besides enabling the mouse cursor.
166 ; No return code required.
167
168 SHOW:   sei
169         jsr     CSHOW
170         cli
171         rts
172
173 ;----------------------------------------------------------------------------
174 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
175 ; from the C program, that is, a pointer to a mouse_box struct in .XA.
176 ; No checks are done if the mouse currently is inside the box; that is the job
177 ; of the caller. It is not necessary to validate the parameters; trust the
178 ; caller, and save some code here. No return code required.
179
180 SETBOX: sta     ptr1
181         stx     ptr1+1                  ; Save data pointer
182
183         ldy     #.sizeof (MOUSE_BOX) - 1
184         sei
185
186 @L1:    lda     (ptr1),y
187         sta     XMin,y
188         dey
189         bpl     @L1
190
191         cli
192         rts
193
194 ;----------------------------------------------------------------------------
195 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
196 ; come from the C program, that is, a pointer to a mouse_box struct in .XA.
197
198 GETBOX: sta     ptr1
199         stx     ptr1+1                  ; Save data pointer
200
201         ldy     #.sizeof (MOUSE_BOX) - 1
202
203 @L1:    lda     XMin,y
204         sta     (ptr1),y
205         dey
206         bpl     @L1
207
208         rts
209
210 ;----------------------------------------------------------------------------
211 ; MOVE: Move the mouse to a new position. The position is passed as it comes
212 ; from the C program, that is: x on the stack and y in .XA. The C wrapper will
213 ; remove the parameter from the stack, on return.
214 ; No checks are done if the new position is valid (within the bounding box or
215 ; the screen). No return code required.
216 ;
217
218 MOVE:   sei                             ; No interrupts
219
220         jsr     MoveY                   ; Set new y position
221
222         ldy     #1
223         lda     (sp),y
224         sta     XPos+1
225         tax
226         dey
227         lda     (sp),y
228         jsr     MoveX                   ; Move the pointer
229
230         cli                             ; Allow interrupts
231         rts
232
233 ;----------------------------------------------------------------------------
234 ; BUTTONS: Return the button mask in .XA.
235 ; Joystick 2's fire button is the  left mouse button.
236 ; Joystick 1's fire button is the right mouse button.
237
238 BUTTONS:
239         ldx     #15                    ; Switch to the system bank
240         stx     IndReg
241
242 ; Get the fire-button bits
243
244         ldy     #CIA::PRA
245         lda     (cia2),y
246
247 ; Switch back to the execution bank.
248
249         ldy     ExecReg
250         sty     IndReg
251
252 ; Joystick 2, fire button is in bit 7.
253 ; Joystick 1, fire button is in bit 6.
254
255         and     #%11000000
256         asl     a                       ; Move bits 7,6 to bits 1,0
257         rol     a
258         rol     a
259         adc     #%00001110              ; Move bit 1 to bit 4
260         and     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
261
262 ; Bits go up when buttons go down.
263
264         eor     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
265         ldx     #>0
266         rts
267
268 ;----------------------------------------------------------------------------
269 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
270 ; struct pointed to by ptr1. No return code required.
271 ;
272 ; We're cheating here to keep the code smaller: The first fields of the
273 ; mouse_info struct are identical to the mouse_pos struct; so, we just will
274 ; use _mouse_pos to fill the position fields.
275
276 INFO:   jsr     BUTTONS
277
278 ; Fill in the button state.
279
280         ldy     #MOUSE_INFO::BUTTONS
281         sta     (ptr1),y
282
283 ;       jmp     POS                     ; Fall through
284
285 ;----------------------------------------------------------------------------
286 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
287 ; No return code required.
288
289 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
290
291         sei                             ; Disable interrupts
292         lda     XPos                    ; Transfer the position
293         sta     (ptr1),y
294         lda     XPos+1
295         iny
296         sta     (ptr1),y
297         lda     YPos
298         iny
299         sta     (ptr1),y
300         lda     YPos+1
301         cli                             ; Enable interrupts
302
303         iny
304         sta     (ptr1),y                ; Store last byte
305
306         rts                             ; Done
307
308 ;----------------------------------------------------------------------------
309 ; IOCTL: Driver-defined entry point. The wrapper will pass a pointer to ioctl-
310 ; specific data in ptr1, and the ioctl code in .A.
311 ; Must return an error code in .XA.
312 ;
313
314 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL   ; We don't support ioctls, for now
315         ldx     #>MOUSE_ERR_INV_IOCTL
316         rts
317
318 ;----------------------------------------------------------------------------
319 ; IRQ: Irq.-handler entry point. Called as a subroutine, but in the IRQ context
320 ; (so, be careful). The routine MUST return carry set if the interrupt has been
321 ; 'handled' -- which means that the interrupt source is gone. Otherwise, it
322 ; MUST return carry clear.
323 ; Reads joystick 2.
324 ;
325
326 IRQ:    ldy     #15                     ; Switch to the system bank
327         sty     IndReg
328
329 ; Get the direction bits.
330
331         ldy     #CIA::PRB
332         lda     (cia2),y                ; Read joystick inputs
333
334 ; Switch back to the execution bank.
335
336         ldy     ExecReg
337         sty     IndReg
338
339 ; Joystick 2, directions in bits 7-4.
340 ; Mask the relevant bits.
341
342         and     #$F0
343         eor     #$F0                    ; All bits are inverted
344         sta     Temp
345
346 ; Check left/right.
347
348         and     #(JOY::LEFT | JOY::RIGHT) << 4
349         bze     @SkipX
350
351 ; We will cheat here, and rely on the fact that either the left OR the right
352 ; bit can be active.
353
354         and     #JOY::RIGHT << 4        ; Check RIGHT bit
355         bnz     @Right
356         lda     #<-1
357         tax
358         bnz     @AddX                   ; Branch always
359 @Right: lda     #<1
360         ldx     #>1
361
362 ; Calculate the new x co-ordinate (--> .YA).
363
364 @AddX:  add     XPos
365         tay                             ; Remember low byte
366         txa
367         adc     XPos+1
368         tax
369
370 ; Limit the x co-ordinate to the bounding box.
371
372         cpy     XMin
373         sbc     XMin+1
374         bpl     @L1
375         ldy     XMin
376         ldx     XMin+1
377         jmp     @L2
378
379 @L1:    txa
380         cpy     XMax
381         sbc     XMax+1
382         bmi     @L2
383         ldy     XMax
384         ldx     XMax+1
385 @L2:    tya
386         jsr     MoveX
387
388 ; Calculate the y movement vector.
389
390 @SkipX: lda     Temp                    ; Get joystick again
391         and     #(JOY::UP | JOY::DOWN) << 4  ; Check up/down
392         bze     @SkipY
393
394 ; We will cheat here, and rely on the fact that either the up OR the down
395 ; bit can be active.
396
397         and     #JOY::UP << 4           ; Check UP bit
398         bze     @Down
399         lda     #<-1
400         tax
401         bnz     @AddY
402 @Down:  lda     #<1
403         ldx     #>1
404
405 ; Calculate the new y co-ordinate (--> .YA).
406
407 @AddY:  add     YPos
408         tay                             ; Remember low byte
409         txa
410         adc     YPos+1
411         tax
412
413 ; Limit the y co-ordinate to the bounding box.
414
415         cpy     YMin
416         sbc     YMin+1
417         bpl     @L3
418         ldy     YMin
419         ldx     YMin+1
420         jmp     @L4
421
422 @L3:    txa
423         cpy     YMax
424         sbc     YMax+1
425         bmi     @L4
426         ldy     YMax
427         ldx     YMax+1
428 @L4:    tya
429         jsr     MoveY
430
431 ; Done
432
433 @SkipY: clc                             ; Interrupt not handled
434         rts
435
436 ; Move the mouse pointer to the new x pos.
437
438 MoveX:  sta     XPos
439         stx     XPos+1
440         jmp     CMOVEX
441
442 ; Move the mouse pointer to the new y pos.
443
444 MoveY:  sta     YPos
445         stx     YPos+1
446         jmp     CMOVEY