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