]> git.sur5r.net Git - cc65/blob - libsrc/apple2/apple2-stdmou.s
e07246fec014bc298d171c6ae4399279aec6eb59
[cc65] / libsrc / apple2 / apple2-stdmou.s
1 ;
2 ; Driver for the AppleMouse II Card.
3 ;
4 ; Oliver Schmidt, 03.09.2005
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9
10 ; ------------------------------------------------------------------------
11
12 SETMOUSE        = $12   ; Sets mouse mode
13 SERVEMOUSE      = $13   ; Services mouse interrupt
14 READMOUSE       = $14   ; Reads mouse position
15 CLEARMOUSE      = $15   ; Clears mouse position to 0 (for delta mode)
16 POSMOUSE        = $16   ; Sets mouse position to a user-defined pos
17 CLAMPMOUSE      = $17   ; Sets mouse bounds in a window
18 HOMEMOUSE       = $18   ; Sets mouse to upper-left corner of clamp win
19 INITMOUSE       = $19   ; Resets mouse clamps to default values and
20                         ; sets mouse position to 0,0
21
22 pos1_lo         := $0478
23 pos1_hi         := $0578
24 pos2_lo         := $04F8
25 pos2_hi         := $05F8
26 status          := $0778
27
28 ; ------------------------------------------------------------------------
29
30         .segment        "JUMPTABLE"
31
32         ; Driver signature
33         .byte   $6D, $6F, $75           ; "mou"
34         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
35
36         ; Jump table.
37         .addr   INSTALL
38         .addr   UNINSTALL
39         .addr   HIDE
40         .addr   SHOW
41         .addr   BOX
42         .addr   MOVE
43         .addr   BUTTONS
44         .addr   POS
45         .addr   INFO
46         .addr   IOCTL
47         .addr   IRQ
48
49         ; Mouse driver flags
50         .byte   MOUSE_FLAG_EARLY_IRQ
51
52         ; Callback table, set by the kernel before INSTALL is called
53 CHIDE:  jmp     $0000                   ; Hide the cursor
54 CSHOW:  jmp     $0000                   ; Show the cursor
55 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
56 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
57
58 ; ------------------------------------------------------------------------
59
60         .bss
61
62 slot:   .res    1
63 visible:.res    1
64
65 ; ------------------------------------------------------------------------
66
67         .rodata
68
69 offsets:.byte   $05             ; Pascal 1.0 ID byte
70         .byte   $07             ; Pascal 1.0 ID byte
71         .byte   $0B             ; Pascal 1.1 generic signature byte
72         .byte   $0C             ; Device signature byte
73
74 values: .byte   $38             ; Fixed
75         .byte   $18             ; Fixed
76         .byte   $01             ; Fixed
77         .byte   $20             ; X-Y pointing device type 0
78
79 size    = * - values
80
81 ; ------------------------------------------------------------------------
82
83         .data
84
85 info:   .word   279 / 2         ; MOUSE_INFO::MOUSE_POS::XCOORD
86         .word   191 / 2         ; MOUSE_INFO::MOUSE_POS::YCOORD
87         .byte   %00000000       ; MOUSE_INFO::BUTTONS
88
89 firmware:
90         ; Lookup and patch firmware address lobyte
91 lookup: ldy     $FF00,x         ; Patched at runtime
92         sty     jump+1          ; Modify code below
93
94         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
95         ; "Enter all mouse routines (...) with the X register set to $Cn
96         ;  and Y register set to $n0, where n = the slot number."
97 xparam: ldx     #$FF            ; Patched at runtime
98 yparam: ldy     #$FF            ; Patched at runtime
99
100 jump:   jmp     $FFFF           ; Patched at runtime
101
102 ; ------------------------------------------------------------------------
103
104         .code
105
106 ; INSTALL: Is called after the driver is loaded into memory. If possible,
107 ; check if the hardware is present. Must return an MOUSE_ERR_xx code in A/X.
108 INSTALL:
109         lda     #<$C000
110         sta     ptr1
111         lda     #>$C000
112         sta     ptr1+1
113
114         ; Search for AppleMouse II firmware in slots 1 - 7
115 next:   inc     ptr1+1
116         lda     ptr1+1
117         cmp     #>$C800
118         bcc     :+
119
120         ; Mouse firmware not found
121         lda     #<MOUSE_ERR_NO_DEVICE
122         ldx     #>MOUSE_ERR_NO_DEVICE
123         rts
124
125         ; Check Pascal 1.1 Firmware Protocol ID bytes
126 :       ldx     #size - 1
127 :       ldy     offsets,x
128         lda     values,x
129         cmp     (ptr1),y
130         bne     next
131         dex
132         bpl     :-
133
134         ; Get and patch firmware address hibyte
135         lda     ptr1+1
136         sta     lookup+2
137         sta     xparam+1
138         sta     jump+2
139
140         ; Convert to and save slot number
141         and     #$0F
142         sta     slot
143
144         ; Convert to and patch I/O register index
145         asl
146         asl
147         asl
148         asl
149         sta     yparam+1
150
151         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
152         ; "Disable interrupts when calling any mouse routine."
153         sei
154
155         ; Reset mouse hardware
156         ldx     #INITMOUSE
157         jsr     firmware
158
159         ; Turn mouse on
160         lda     #%00000001
161         ldx     #SETMOUSE
162         jsr     firmware
163
164         ; Set initial mouse clamps
165         lda     #<279
166         ldx     #>279
167         sta     pos2_lo
168         stx     pos2_hi
169         lda     #$00            ; Set x clamps
170         sta     pos1_lo
171         sta     pos1_hi
172         ldx     #CLAMPMOUSE
173         jsr     firmware
174         lda     #<191
175         ldx     #>191
176         sta     pos2_lo
177         stx     pos2_hi
178         lda     #$01            ; Set y clamps
179         ldx     #CLAMPMOUSE
180         jsr     firmware
181
182         ; Set initial mouse position
183         ldx     slot
184         lda     #<(279 / 2)
185         sta     pos1_lo,x
186         lda     #>(279 / 2)
187         sta     pos1_hi,x
188         lda     #<(191 / 2)
189         sta     pos2_lo,x
190         lda     #>(191 / 2)
191         sta     pos2_hi,x
192         ldx     #POSMOUSE
193         jsr     firmware
194
195         ; Turn VBL interrupt on
196         lda     #%00001001
197         ldx     #SETMOUSE
198 common: jsr     firmware
199
200         ; Enable interrupts and return success
201         cli
202         lda     #<MOUSE_ERR_OK
203         ldx     #>MOUSE_ERR_OK
204         rts
205
206 ; UNINSTALL: Is called before the driver is removed from memory.
207 ; No return code required (the driver is removed from memory on return).
208 UNINSTALL:
209         ; Hide cursor
210         sei
211         jsr     CHIDE
212
213         ; Turn mouse off
214         lda     #%00000000
215         ldx     #SETMOUSE
216         bne     common          ; Branch always
217
218 ; HIDE: Is called to hide the mouse cursor. The mouse kernel manages a
219 ; counter for calls to show/hide, and the driver entry point is only called
220 ; if the mouse is currently visible and should get hidden. For most drivers,
221 ; no special action is required besides hiding the mouse cursor.
222 ; No return code required.
223 HIDE:
224         dec     visible
225         sei
226         jsr     CHIDE
227         cli
228         rts
229
230 ; SHOW: Is called to show the mouse cursor. The mouse kernel manages a
231 ; counter for calls to show/hide, and the driver entry point is only called
232 ; if the mouse is currently hidden and should become visible. For most drivers,
233 ; no special action is required besides enabling the mouse cursor.
234 ; No return code required.
235 SHOW:
236         inc     visible
237         rts
238
239 ; BOX: Set the mouse bounding box. The parameters are passed as they come from
240 ; the C program, that is, maxy in A/X and the other parameters on the stack.
241 ; The C wrapper will remove the parameters from the stack when the driver
242 ; routine returns.
243 ; No checks are done if the mouse is currently inside the box, this is the job
244 ; of the caller. It is not necessary to validate the parameters, trust the
245 ; caller and save some code here. No return code required.
246 BOX:
247         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
248         ; "Disable interrupts before placing position information in the screen holes."
249         sei
250
251         ; Set high clamp
252         sta     pos2_lo
253         txa
254
255         ldx     #$01            ; Set y clamps
256         ldy     #$00            ; Start at top of stack
257         jsr     :+
258
259         ldx     #$00            ; Set x clamps
260         ldy     #$00            ; Start at top of stack
261
262         ; Set high clamp
263         lda     (sp),y
264         iny
265         sei
266         sta     pos2_lo
267         lda     (sp),y
268         iny
269 :       sta     pos2_hi
270
271         ; Skip one parameter
272         iny
273         iny
274
275         ; Set low clamp
276         lda     (sp),y
277         iny
278         sta     pos1_lo
279         lda     (sp),y
280         sta     pos1_hi
281
282         txa
283         ldx     #CLAMPMOUSE
284         bne     common          ; Branch always
285
286 ; MOVE: Move the mouse to a new position. The position is passed as it comes
287 ; from the C program, that is: x on the stack and y in A/X. The C wrapper will
288 ; remove the parameter from the stack on return.
289 ; No checks are done if the new position is valid (within the bounding box or
290 ; the screen). No return code required.
291 MOVE:
292         ldy     slot
293         sei
294
295         ; Set y
296         sta     pos2_lo,y
297         txa
298         sta     pos2_hi,y
299
300         tya
301         tax
302         ldy     #$00            ; Start at top of stack
303
304         ; Set x
305         lda     (sp),y
306         iny
307         sta     pos1_lo,x
308         lda     (sp),y
309         sta     pos1_hi,x
310
311         ; Update cursor
312         jsr     update
313
314         ldx     #POSMOUSE
315         bne     common          ; Branch always
316
317 ; BUTTONS: Return the button mask in A/X.
318 BUTTONS:
319         lda     info + MOUSE_INFO::BUTTONS
320         ldx     #$00
321         rts
322
323 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
324 ; No return code required.
325 POS:
326         ldx     #.sizeof(MOUSE_POS)-1
327         bne     copy            ; Branch always
328
329 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
330 ; struct pointed to by ptr1. No return code required.
331 INFO:
332         ldx     #.sizeof(MOUSE_INFO)-1
333 copy:   txa
334         tay
335         sei
336 :       lda     info,x
337         sta     (ptr1),y
338         dex
339         dey
340         bpl     :-
341         cli
342         rts
343
344 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
345 ; specific data in ptr1, and the ioctl code in A.
346 ; Must return an MOUSE_ERR_xx code in A/X.
347 IOCTL:
348         lda     #<MOUSE_ERR_INV_IOCTL
349         ldx     #>MOUSE_ERR_INV_IOCTL
350         rts
351
352 ; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
353 ; registers are already saved, no parameters are passed, but the carry flag
354 ; is clear on entry. The routine must return with carry set if the interrupt
355 ; was handled, otherwise with carry clear.
356 IRQ:
357         ; Check for mouse interrupt
358         ldx     #SERVEMOUSE
359         jsr     firmware
360         bcc     :+
361         clc                     ; Interrupt not handled
362         rts
363
364 :       ldx     #READMOUSE
365         jsr     firmware
366
367         ; Get status
368         ldy     slot
369         lda     status,y
370         tax                     ; Save status
371
372         ; Extract button down values
373         asl                     ;  C = Button 0 is currently down
374         and     #%00100000      ; !Z = Button 1 is currently down
375
376         ; Set button mask
377         beq     :+
378         lda     #MOUSE_BTN_RIGHT
379 :       bcc     :+
380         ora     #MOUSE_BTN_LEFT
381 :       sta     info + MOUSE_INFO::BUTTONS
382
383         ; Check for mouse movement
384         txa                     ; Restore status
385         and     #%00100000      ; X or Y changed since last READMOUSE
386         beq     :+
387
388         ; Remove the cursor at the old position
389 update: jsr     CHIDE
390
391         ; Get and set the new X position
392         ldy     slot
393         lda     pos1_lo,y
394         ldx     pos1_hi,y
395         sta     info + MOUSE_POS::XCOORD
396         stx     info + MOUSE_POS::XCOORD+1
397         jsr     CMOVEX
398
399         ; Get and set the new Y position
400         ldy     slot
401         lda     pos2_lo,y
402         ldx     pos2_hi,y
403         sta     info + MOUSE_POS::YCOORD
404         stx     info + MOUSE_POS::YCOORD+1
405         jsr     CMOVEY
406
407         ; Check for visibility
408 :       lda     visible
409         beq     :+
410
411         ; Draw the cursor at the new position
412         jsr     CSHOW
413 :       sec                     ; Interrupt handled
414         rts