]> git.sur5r.net Git - cc65/blob - libsrc/cbm510/mou/cbm510-joy.s
9381cf7616b9ae9238ef02422a57838aba5332e5
[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 ; Default values for above variables
93
94 .rodata
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 - 1        ; XMax
102         .word   SCREEN_HEIGHT - 1       ; YMax
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 a MOUSE_ERR_xx code in .XA.
111
112 INSTALL:
113
114 ; Initiate 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.
137
138         ldx     #>MOUSE_ERR_OK
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 called only
151 ; if the mouse currently is 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 called only
163 ; if the mouse currently is 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 .XA.
175 ; No checks are done if the mouse currently is inside the box; that 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 .XA.
196
197 GETBOX: sta     ptr1
198         stx     ptr1+1                  ; Save data pointer
199
200         ldy     #.sizeof (MOUSE_BOX) - 1
201
202 @L1:    lda     XMin,y
203         sta     (ptr1),y
204         dey
205         bpl     @L1
206
207         rts
208
209 ;----------------------------------------------------------------------------
210 ; MOVE: Move the mouse to a new position. The position is passed as it comes
211 ; from the C program, that is: x on the stack and y in .XA. The C wrapper will
212 ; remove the parameter from the stack, on return.
213 ; No checks are done if the new position is valid (within the bounding box or
214 ; the screen). No return code required.
215 ;
216
217 MOVE:   sei                             ; No interrupts
218
219         jsr     MoveY                   ; Set new y position
220
221         ldy     #1
222         lda     (sp),y
223         sta     XPos+1
224         tax
225         dey
226         lda     (sp),y
227         jsr     MoveX                   ; Move the pointer
228
229         cli                             ; Allow interrupts
230         rts
231
232 ;----------------------------------------------------------------------------
233 ; BUTTONS: Return the button mask in .XA.
234 ; Joystick 2's fire button is the  left mouse button.
235 ; Joystick 1's fire button is the right mouse button.
236
237 BUTTONS:
238         ldx     #15                    ; Switch to the system bank
239         stx     IndReg
240
241 ; Get the fire-button bits
242
243         ldy     #CIA::PRA
244         lda     (cia2),y
245
246 ; Switch back to the execution bank.
247
248         ldy     ExecReg
249         sty     IndReg
250
251 ; Joystick 2, fire button is in bit 7.
252 ; Joystick 1, fire button is in bit 6.
253
254         and     #%11000000
255         asl     a                       ; Move bits 7,6 to bits 1,0
256         rol     a
257         rol     a
258         adc     #%00001110              ; Move bit 1 to bit 4
259         and     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
260
261 ; Bits go up when buttons go down.
262
263         eor     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
264         ldx     #>0
265         rts
266
267 ;----------------------------------------------------------------------------
268 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
269 ; struct pointed to by ptr1. No return code required.
270 ;
271 ; We're cheating here to keep the code smaller: The first fields of the
272 ; mouse_info struct are identical to the mouse_pos struct; so, we just will
273 ; use _mouse_pos to fill the position fields.
274
275 INFO:   jsr     BUTTONS
276
277 ; Fill in the button state.
278
279         ldy     #MOUSE_INFO::BUTTONS
280         sta     (ptr1),y
281
282 ;       jmp     POS                     ; Fall through
283
284 ;----------------------------------------------------------------------------
285 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
286 ; No return code required.
287
288 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
289
290         sei                             ; Disable interrupts
291         lda     XPos                    ; Transfer the position
292         sta     (ptr1),y
293         lda     XPos+1
294         iny
295         sta     (ptr1),y
296         lda     YPos
297         iny
298         sta     (ptr1),y
299         lda     YPos+1
300         cli                             ; Enable interrupts
301
302         iny
303         sta     (ptr1),y                ; Store last byte
304
305         rts                             ; Done
306
307 ;----------------------------------------------------------------------------
308 ; IOCTL: Driver-defined entry point. The wrapper will pass a pointer to ioctl-
309 ; specific data in ptr1, and the ioctl code in .A.
310 ; Must return an error code in .XA.
311 ;
312
313 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL   ; We don't support ioctls, for now
314         ldx     #>MOUSE_ERR_INV_IOCTL
315         rts
316
317 ;----------------------------------------------------------------------------
318 ; IRQ: Irq.-handler entry point. Called as a subroutine, but in the IRQ context
319 ; (so, be careful). The routine MUST return carry set if the interrupt has been
320 ; 'handled' -- which means that the interrupt source is gone. Otherwise, it
321 ; MUST return carry clear.
322 ; Reads joystick 2.
323 ;
324
325 IRQ:    ldy     #15                     ; Switch to the system bank
326         sty     IndReg
327
328 ; Get the direction bits.
329
330         ldy     #CIA::PRB
331         lda     (cia2),y                ; Read joystick inputs
332
333 ; Switch back to the execution bank.
334
335         ldy     ExecReg
336         sty     IndReg
337
338 ; Joystick 2, directions in bits 7-4.
339 ; Mask the relevant bits.
340
341         and     #$F0
342         eor     #$F0                    ; All bits are inverted
343         sta     Temp
344
345 ; Check left/right.
346
347         and     #(JOY::LEFT | JOY::RIGHT) << 4
348         bze     @SkipX
349
350 ; We will cheat here, and rely on the fact that either the left OR the right
351 ; bit can be active.
352
353         and     #JOY::RIGHT << 4        ; Check RIGHT bit
354         bnz     @Right
355         lda     #<-1
356         tax
357         bnz     @AddX                   ; Branch always
358 @Right: lda     #<1
359         ldx     #>1
360
361 ; Calculate the new x co-ordinate (--> .YA).
362
363 @AddX:  add     XPos
364         tay                             ; Remember low byte
365         txa
366         adc     XPos+1
367         tax
368
369 ; Limit the x co-ordinate to the bounding box.
370
371         cpy     XMin
372         sbc     XMin+1
373         bpl     @L1
374         ldy     XMin
375         ldx     XMin+1
376         jmp     @L2
377
378 @L1:    txa
379         cpy     XMax
380         sbc     XMax+1
381         bmi     @L2
382         ldy     XMax
383         ldx     XMax+1
384 @L2:    tya
385         jsr     MoveX
386
387 ; Calculate the y movement vector.
388
389 @SkipX: lda     Temp                    ; Get joystick again
390         and     #(JOY::UP | JOY::DOWN) << 4  ; Check up/down
391         bze     @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         and     #JOY::UP << 4           ; Check UP bit
397         bze     @Down
398         lda     #<-1
399         tax
400         bnz     @AddY
401 @Down:  lda     #<1
402         ldx     #>1
403
404 ; Calculate the new y co-ordinate (--> .YA).
405
406 @AddY:  add     YPos
407         tay                             ; Remember low byte
408         txa
409         adc     YPos+1
410         tax
411
412 ; Limit the y co-ordinate 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
421 @L3:    txa
422         cpy     YMax
423         sbc     YMax+1
424         bmi     @L4
425         ldy     YMax
426         ldx     YMax+1
427 @L4:    tya
428         jsr     MoveY
429
430 ; Done
431
432 @SkipY: clc                             ; Interrupt not handled
433         rts
434
435 ; Move the mouse pointer to the new x pos.
436
437 MoveX:  sta     XPos
438         stx     XPos+1
439         jmp     CMOVEX
440
441 ; Move the mouse pointer to the new y pos.
442
443 MoveY:  sta     YPos
444         stx     YPos+1
445         jmp     CMOVEY