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