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