]> git.sur5r.net Git - cc65/blob - libsrc/c64/c64-1351.s
ab4732aaa6a2704c6adc6969caa4ad8f36e5831c
[cc65] / libsrc / c64 / c64-1351.s
1 ;
2 ; Driver for the 1351 proportional mouse. Parts of the code are from
3 ; the Commodore 1351 mouse users guide.
4 ;
5 ; Ullrich von Bassewitz, 2003-12-29
6 ;
7
8         .include        "zeropage.inc"
9         .include        "mouse-kernel.inc"
10         .include        "c64.inc"
11
12         .macpack        generic
13
14 ; ------------------------------------------------------------------------
15 ; Header. Includes jump table
16
17 .segment        "JUMPTABLE"
18
19 HEADER:
20
21 ; Driver signature
22
23         .byte   $6d, $6f, $75           ; "mou"
24         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
25
26 ; Jump table.
27
28         .addr   INSTALL
29         .addr   UNINSTALL
30         .addr   HIDE
31         .addr   SHOW
32         .addr   BOX
33         .addr   MOVE
34         .addr   BUTTONS
35         .addr   POS
36         .addr   INFO
37         .addr   IOCTL
38         .addr   IRQ
39
40 ; Callback table, set by the kernel before INSTALL is called
41
42 CHIDE:  jmp     $0000                   ; Hide the cursor
43 CSHOW:  jmp     $0000                   ; Show the cursor
44 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
45 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
46
47
48 ;----------------------------------------------------------------------------
49 ; Constants
50
51 SCREEN_HEIGHT   = 200
52 SCREEN_WIDTH    = 320
53
54 ;----------------------------------------------------------------------------
55 ; Global variables. The bounding box values are sorted so that they can be
56 ; written with the least effort in the BOX routine, so don't reorder them.
57
58 .bss
59
60 Vars:
61 OldPotX:        .res    1               ; Old hw counter values
62 OldPotY:        .res    1
63
64 YPos:           .res    2               ; Current mouse position, Y
65 XPos:           .res    2               ; Current mouse position, X
66 YMax:           .res    2               ; Y2 value of bounding box
67 XMax:           .res    2               ; X2 value of bounding box
68 YMin:           .res    2               ; Y1 value of bounding box
69 XMin:           .res    2               ; X1 value of bounding box
70
71 OldValue:       .res    1               ; Temp for MoveCheck routine
72 NewValue:       .res    1               ; Temp for MoveCheck routine
73
74 ; Default values for above variables
75
76 .rodata
77
78 .proc   DefVars
79         .byte   0, 0                    ; OldPotX/OldPotY
80         .word   SCREEN_HEIGHT/2         ; YPos
81         .word   SCREEN_WIDTH/2          ; XPos
82         .word   SCREEN_HEIGHT           ; YMax
83         .word   SCREEN_WIDTH            ; XMax
84         .word   0                       ; YMin
85         .word   0                       ; XMin
86 .endproc
87
88 .code
89
90 ;----------------------------------------------------------------------------
91 ; INSTALL routine. Is called after the driver is loaded into memory. If
92 ; possible, check if the hardware is present.
93 ; Must return an MOUSE_ERR_xx code in a/x.
94
95 INSTALL:
96
97 ; Initialize variables. Just copy the default stuff over
98
99         ldx     #.sizeof(DefVars)-1
100 @L1:    lda     DefVars,x
101         sta     Vars,x
102         dex
103         bpl     @L1
104
105 ; Be sure the mouse cursor is invisible and at the default location. We
106 ; need to do that here, because our mouse interrupt handler doesn't set the
107 ; mouse position if it hasn't changed.
108
109         sei
110         jsr     CHIDE
111         lda     XPos
112         ldx     XPos+1
113         jsr     CMOVEX
114         lda     YPos
115         ldx     YPos+1
116         jsr     CMOVEY
117         cli
118
119 ; Done, return zero (= MOUSE_ERR_OK)
120
121         ldx     #$00
122         txa
123         rts                             ; Run into UNINSTALL instead
124
125 ;----------------------------------------------------------------------------
126 ; UNINSTALL routine. Is called before the driver is removed from memory.
127 ; No return code required (the driver is removed from memory on return).
128
129 UNINSTALL       = HIDE                  ; Hide cursor on exit
130
131 ;----------------------------------------------------------------------------
132 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
133 ; a counter for calls to show/hide, and the driver entry point is only called
134 ; if the mouse is currently visible and should get hidden. For most drivers,
135 ; no special action is required besides hiding the mouse cursor.
136 ; No return code required.
137
138 HIDE:   sei
139         jsr     CHIDE
140         cli
141         rts
142
143 ;----------------------------------------------------------------------------
144 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
145 ; a counter for calls to show/hide, and the driver entry point is only called
146 ; if the mouse is currently hidden and should become visible. For most drivers,
147 ; no special action is required besides enabling the mouse cursor.
148 ; No return code required.
149
150 SHOW:   sei
151         jsr     CSHOW
152         cli
153         rts
154
155 ;----------------------------------------------------------------------------
156 ; BOX: Set the mouse bounding box. The parameters are passed as they come from
157 ; the C program, that is, maxy in a/x and the other parameters on the stack.
158 ; The C wrapper will remove the parameters from the stack when the driver
159 ; routine returns.
160 ; No checks are done if the mouse is currently inside the box, this is the job
161 ; of the caller. It is not necessary to validate the parameters, trust the
162 ; caller and save some code here. No return code required.
163
164 BOX:    ldy     #5
165         sei
166         sta     YMax
167         stx     YMax+1
168
169 @L1:    lda     (sp),y
170         sta     XMax,y
171         dey
172         bpl     @L1
173
174         cli
175         rts
176
177 ;----------------------------------------------------------------------------
178 ; MOVE: Move the mouse to a new position which is passed in X=ptr1, Y=a/x.
179 ; No checks are done if the new position is valid (within the bounding box or
180 ; the screen). No return code required.
181 ;
182
183 MOVE:   sei                             ; No interrupts
184
185         sta     YPos
186         stx     YPos+1                  ; New Y position
187         jsr     CMOVEY                  ; Set it
188
189         lda     ptr1
190         ldx     ptr1+1
191         sta     XPos
192         stx     XPos+1                  ; New X position
193
194         jsr     CMOVEX                  ; Move the cursor
195
196         cli                             ; Allow interrupts
197         rts
198
199 ;----------------------------------------------------------------------------
200 ; BUTTONS: Return the button mask in a/x.
201
202 BUTTONS:
203         lda     #$7F
204         sei
205         sta     CIA1_PRA
206         lda     CIA1_PRB                ; Read joystick #0
207         cli
208         ldx     #0
209         and     #$1F
210         eor     #$1F
211         rts
212
213 ;----------------------------------------------------------------------------
214 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
215 ; No return code required.
216
217 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
218
219         sei                             ; Disable interrupts
220         lda     XPos                    ; Transfer the position
221         sta     (ptr1),y
222         lda     XPos+1
223         iny
224         sta     (ptr1),y
225         lda     YPos
226         iny
227         sta     (ptr1),y
228         lda     YPos+1
229         cli                             ; Enable interrupts
230
231         iny
232         sta     (ptr1),y                ; Store last byte
233
234         rts                             ; Done
235
236 ;----------------------------------------------------------------------------
237 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
238 ; struct pointed to by ptr1. No return code required.
239 ;
240 ; We're cheating here to keep the code smaller: The first fields of the
241 ; mouse_info struct are identical to the mouse_pos struct, so we will just
242 ; call _mouse_pos to initialize the struct pointer and fill the position
243 ; fields.
244
245 INFO:   jsr     POS
246
247 ; Fill in the button state
248
249         jsr     BUTTONS                 ; Will not touch ptr1
250         ldy     #MOUSE_INFO::BUTTONS
251         sta     (ptr1),y
252
253         rts
254
255 ;----------------------------------------------------------------------------
256 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
257 ; specific data in ptr1, and the ioctl code in A.
258 ; Must return an error code in a/x.
259 ;
260
261 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
262         ldx     #>MOUSE_ERR_INV_IOCTL
263         rts
264
265 ;----------------------------------------------------------------------------
266 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
267 ; (so be careful).
268 ;
269
270 IRQ:    lda     SID_ADConv1             ; Get mouse X movement
271         ldy     OldPotX
272         jsr     MoveCheck               ; Calculate movement vector
273         sty     OldPotX
274
275 ; Skip processing if nothing has changed
276
277         bcc     @SkipX
278
279 ; Calculate the new X coordinate (--> a/y)
280
281         add     XPos
282         tay                             ; Remember low byte
283         txa
284         adc     XPos+1
285         tax
286
287 ; Limit the X coordinate to the bounding box
288
289         cpy     XMin
290         sbc     XMin+1
291         bpl     @L1
292         ldy     XMin
293         ldx     XMin+1
294         jmp     @L2
295 @L1:    txa
296
297         cpy     XMax
298         sbc     XMax+1
299         bmi     @L2
300         ldy     XMax
301         ldx     XMax+1
302 @L2:    sty     XPos
303         stx     XPos+1
304
305 ; Move the mouse pointer to the new X pos
306
307         tya
308         jsr     CMOVEX
309
310 ; Calculate the Y movement vector
311
312 @SkipX: lda     SID_ADConv2             ; Get mouse Y movement
313         ldy     OldPotY
314         jsr     MoveCheck               ; Calculate movement
315         sty     OldPotY
316
317 ; Skip processing if nothing has changed
318
319         bcc     @SkipY
320
321 ; Calculate the new Y coordinate (--> a/y)
322
323         sta     OldValue
324         lda     YPos
325         sub     OldValue
326         tay
327         stx     OldValue
328         lda     YPos+1
329         sbc     OldValue
330         tax
331
332 ; Limit the Y coordinate to the bounding box
333
334         cpy     YMin
335         sbc     YMin+1
336         bpl     @L3
337         ldy     YMin
338         ldx     YMin+1
339         jmp     @L4
340 @L3:    txa
341
342         cpy     YMax
343         sbc     YMax+1
344         bmi     @L4
345         ldy     YMax
346         ldx     YMax+1
347 @L4:    sty     YPos
348         stx     YPos+1
349
350 ; Move the mouse pointer to the new X pos
351
352         tya
353         jmp     CMOVEY
354
355 ; Done
356
357 @SkipY: rts
358
359 ; --------------------------------------------------------------------------
360 ;
361 ; Move check routine, called for both coordinates.
362 ;
363 ; Entry:        y = old value of pot register
364 ;               a = current value of pot register
365 ; Exit:         y = value to use for old value
366 ;               x/a = delta value for position
367 ;
368
369 MoveCheck:
370         sty     OldValue
371         sta     NewValue
372         ldx     #$00
373
374         sub     OldValue                ; a = mod64 (new - old)
375         and     #%01111111
376         cmp     #%01000000              ; if (a > 0)
377         bcs     @L1                     ;
378         lsr     a                       ;   a /= 2;
379         beq     @L2                     ;   if (a != 0)
380         ldy     NewValue                ;     y = NewValue
381         sec
382         rts                             ;   return
383
384 @L1:    ora     #%11000000              ; else or in high order bits
385         cmp     #$FF                    ; if (a != -1)
386         beq     @L2
387         sec
388         ror     a                       ;   a /= 2
389         dex                             ;   high byte = -1 (X = $FF)
390         ldy     NewValue
391         sec
392         rts
393
394 @L2:    txa                             ; A = $00
395         clc
396         rts
397