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