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