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