]> git.sur5r.net Git - cc65/blob - libsrc/apple2/apple2-stdmou.s
Minor update by Oliver Schmidt
[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 info:   .tag    MOUSE_INFO
63 slot:   .res    1
64 visible:.res    1
65
66 ; ------------------------------------------------------------------------
67
68         .rodata
69
70 offsets:.byte   $05             ; Pascal 1.0 ID byte
71         .byte   $07             ; Pascal 1.0 ID byte
72         .byte   $0B             ; Pascal 1.1 generic signature byte
73         .byte   $0C             ; Device signature byte
74
75 values: .byte   $38             ; Fixed
76         .byte   $18             ; Fixed
77         .byte   $01             ; Fixed
78         .byte   $20             ; X-Y pointing device type 0
79
80 size    = * - values
81
82 ; ------------------------------------------------------------------------
83
84         .data
85
86 firmware:
87         ; Lookup and patch firmware address lobyte
88 lookup: ldy     $FF00,x         ; Patched at runtime
89         sty     jump+1          ; Modify code below
90
91         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
92         ; "Enter all mouse routines (...) with the X register set to $Cn
93         ;  and Y register set to $n0, where n = the slot number."
94 xparam: ldx     #$FF            ; Patched at runtime
95 yparam: ldy     #$FF            ; Patched at runtime
96
97 jump:   jmp     $FFFF           ; Patched at runtime
98
99 ; ------------------------------------------------------------------------
100
101         .code
102
103 ; INSTALL: Is called after the driver is loaded into memory. If possible,
104 ; check if the hardware is present. Must return an MOUSE_ERR_xx code in A/X.
105 INSTALL:
106         lda     #<$C000
107         sta     ptr1
108         lda     #>$C000
109         sta     ptr1+1
110
111         ; Search for AppleMouse II firmware in slots 1 - 7
112 next:   inc     ptr1+1
113         lda     ptr1+1
114         cmp     #>$C800
115         bcc     :+
116
117         ; Mouse firmware not found
118         lda     #<MOUSE_ERR_NO_DEVICE
119         ldx     #>MOUSE_ERR_NO_DEVICE
120         rts
121
122         ; Check Pascal 1.1 Firmware Protocol ID bytes
123 :       ldx     #size - 1
124 :       ldy     offsets,x
125         lda     values,x
126         cmp     (ptr1),y
127         bne     next
128         dex
129         bpl     :-
130
131         ; Get and patch firmware address hibyte
132         lda     ptr1+1
133         sta     lookup+2
134         sta     xparam+1
135         sta     jump+2
136
137         ; Convert to and save slot number
138         and     #$0F
139         sta     slot
140
141         ; Convert to and patch I/O register index
142         asl
143         asl
144         asl
145         asl
146         sta     yparam+1
147
148         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
149         ; "Disable interrupts when calling any mouse routine."
150         sei
151
152         ; Reset mouse hardware
153         ldx     #INITMOUSE
154         jsr     firmware
155
156         ; Turn mouse on
157         lda     #%00000001
158         ldx     #SETMOUSE
159         jsr     firmware
160
161         ; Set initial mouse clamps
162         lda     #<279
163         ldx     #>279
164         sta     pos2_lo
165         stx     pos2_hi
166         lda     #$00            ; Set x clamps
167         sta     pos1_lo
168         sta     pos1_hi
169         ldx     #CLAMPMOUSE
170         jsr     firmware
171         lda     #<191
172         ldx     #>191
173         sta     pos2_lo
174         stx     pos2_hi
175         lda     #$01            ; Set y clamps
176         ldx     #CLAMPMOUSE
177         jsr     firmware
178
179         ; Set initial mouse position
180         ldx     slot
181         lda     #<(279 / 2)
182         sta     pos1_lo,x
183         lda     #>(279 / 2)
184         sta     pos1_hi,x
185         lda     #<(191 / 2)
186         sta     pos2_lo,x
187         lda     #>(191 / 2)
188         sta     pos2_hi,x
189         ldx     #POSMOUSE
190         jsr     firmware
191
192         ; Update cursor
193         jsr     update
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