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