]> git.sur5r.net Git - cc65/blob - libsrc/atari/mou/atrtt.s
Trakball mouse driver
[cc65] / libsrc / atari / mou / atrtt.s
1 ;
2 ; Mouse driver for Atari Trakball
3 ;
4 ; Christian Groessler, 2014-01-05
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9         .include        "atari.inc"
10
11         .macpack        generic
12
13 ; ------------------------------------------------------------------------
14 ; Header. Includes jump table
15
16 .segment        "JUMPTABLE"
17
18 HEADER:
19
20 ; Driver signature
21
22         .byte   $6d, $6f, $75           ; "mou"
23         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
24
25 ; Library reference
26
27         .addr   $0000
28
29 ; Jump table
30
31         .addr   INSTALL
32         .addr   UNINSTALL
33         .addr   HIDE
34         .addr   SHOW
35         .addr   SETBOX
36         .addr   GETBOX
37         .addr   MOVE
38         .addr   BUTTONS
39         .addr   POS
40         .addr   INFO
41         .addr   IOCTL
42         .addr   IRQ
43
44 ; Mouse driver flags
45
46         .byte   MOUSE_FLAG_LATE_IRQ
47
48 ; Callback table, set by the kernel before INSTALL is called
49
50 CHIDE:  jmp     $0000                   ; Hide the cursor
51 CSHOW:  jmp     $0000                   ; Show the cursor
52 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
53 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
54
55
56 ;----------------------------------------------------------------------------
57 ; Constants
58
59 SCREEN_HEIGHT   = 191
60 SCREEN_WIDTH    = 319
61
62 .enum   JOY
63         UP      = $01
64         DOWN    = $02
65         LEFT    = $04
66         RIGHT   = $08
67 .endenum
68
69 ;----------------------------------------------------------------------------
70 ; Global variables. The bounding box values are sorted so that they can be
71 ; written with the least effort in the SETBOX and GETBOX routines, so don't
72 ; reorder them.
73
74 .bss
75
76 Vars:
77 YPos:           .res    2               ; Current mouse position, Y
78 XPos:           .res    2               ; Current mouse position, X
79 XMin:           .res    2               ; X1 value of bounding box
80 YMin:           .res    2               ; Y1 value of bounding box
81 XMax:           .res    2               ; X2 value of bounding box
82 YMax:           .res    2               ; Y2 value of bounding box
83 Buttons:        .res    1               ; Button mask
84
85
86 visible:        .res    1
87
88 ; Default values for above variables
89
90 .rodata
91
92 .proc   DefVars
93         .word   SCREEN_HEIGHT/2         ; YPos
94         .word   SCREEN_WIDTH/2          ; XPos
95         .word   0                       ; XMin
96         .word   0                       ; YMin
97         .word   SCREEN_WIDTH            ; XMax
98         .word   SCREEN_HEIGHT           ; YMax
99         .byte   0                       ; Buttons
100 .endproc
101
102 .code
103
104 ;----------------------------------------------------------------------------
105 ; INSTALL routine. Is called after the driver is loaded into memory. If
106 ; possible, check if the hardware is present.
107 ; Must return an MOUSE_ERR_xx code in a/x.
108
109 INSTALL:
110
111 ; Initialize variables. Just copy the default stuff over
112
113         ldx     #.sizeof(DefVars)-1
114 @L1:    lda     DefVars,x
115         sta     Vars,x
116         dex
117         bpl     @L1
118
119 ; Be sure the mouse cursor is invisible and at the default location. We
120 ; need to do that here, because our mouse interrupt handler doesn't set the
121 ; mouse position if it hasn't changed.
122
123         php
124         sei
125         jsr     CHIDE
126         lda     XPos
127         ldx     XPos+1
128         jsr     CMOVEX
129         lda     YPos
130         ldx     YPos+1
131         jsr     CMOVEY
132         plp
133
134 ; Done, return zero (= MOUSE_ERR_OK)
135
136         ldx     #$00
137         txa
138         rts
139
140 ;----------------------------------------------------------------------------
141 ; UNINSTALL routine. Is called before the driver is removed from memory.
142 ; No return code required (the driver is removed from memory on return).
143
144 UNINSTALL       = HIDE                  ; Hide cursor on exit
145
146 ;----------------------------------------------------------------------------
147 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
148 ; a counter for calls to show/hide, and the driver entry point is only called
149 ; if the mouse is currently visible and should get hidden. For most drivers,
150 ; no special action is required besides hiding the mouse cursor.
151 ; No return code required.
152
153 HIDE:   dec     visible
154         php
155         sei
156         jsr     CHIDE
157         plp
158         rts
159
160 ;----------------------------------------------------------------------------
161 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
162 ; a counter for calls to show/hide, and the driver entry point is only called
163 ; if the mouse is currently hidden and should become visible. For most drivers,
164 ; no special action is required besides enabling the mouse cursor.
165 ; No return code required.
166
167 SHOW:   inc     visible
168         php
169         sei
170         jsr     CSHOW
171         plp
172         rts
173
174 ;----------------------------------------------------------------------------
175 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
176 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
177 ; No checks are done if the mouse is currently inside the box, this is the job
178 ; of the caller. It is not necessary to validate the parameters, trust the
179 ; caller and save some code here. No return code required.
180
181 SETBOX: sta     ptr1
182         stx     ptr1+1                  ; Save data pointer
183
184         ldy     #.sizeof (MOUSE_BOX)-1
185         php
186         sei
187
188 @L1:    lda     (ptr1),y
189         sta     XMin,y
190         dey
191         bpl     @L1
192
193         plp
194         rts
195
196 ;----------------------------------------------------------------------------
197 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
198 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
199
200 GETBOX: sta     ptr1
201         stx     ptr1+1                  ; Save data pointer
202
203         ldy     #.sizeof (MOUSE_BOX)-1
204         php
205         sei
206
207 @L1:    lda     XMin,y
208         sta     (ptr1),y
209         dey
210         bpl     @L1
211
212         plp
213         rts
214
215 ;----------------------------------------------------------------------------
216 ; MOVE: Move the mouse to a new position. The position is passed as it comes
217 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
218 ; remove the parameter from the stack on return.
219 ; No checks are done if the new position is valid (within the bounding box or
220 ; the screen). No return code required.
221 ;
222
223 MOVE:   php
224         sei                             ; No interrupts
225
226         pha
227         lda     visible
228         beq     @nohide
229         txa
230         pha
231         jsr     CHIDE
232         pla
233         tax
234 @nohide:pla
235
236         sta     YPos
237         stx     YPos+1                  ; New Y position
238         jsr     CMOVEY                  ; Set it
239
240         ldy     #$01
241         lda     (sp),y
242         sta     XPos+1
243         tax
244         dey
245         lda     (sp),y
246         sta     XPos                    ; New X position
247
248         jsr     CMOVEX                  ; Move the cursor
249
250         lda     visible
251         beq     @Ret
252         
253         jsr     CSHOW
254
255 @Ret:   plp                             ; Restore interrupt flag
256         rts
257
258 ;----------------------------------------------------------------------------
259 ; BUTTONS: Return the button mask in a/x.
260
261 BUTTONS:
262         lda     Buttons
263         ldx     #$00
264         rts
265
266 ;----------------------------------------------------------------------------
267 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
268 ; No return code required.
269
270 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
271
272         php
273         sei                             ; Disable interrupts
274         lda     XPos                    ; Transfer the position
275         sta     (ptr1),y
276         lda     XPos+1
277         iny
278         sta     (ptr1),y
279         lda     YPos
280         iny
281         sta     (ptr1),y
282         lda     YPos+1
283         plp                             ; Restore interrupt flag
284
285         iny
286         sta     (ptr1),y                ; Store last byte
287
288         rts                             ; Done
289
290 ;----------------------------------------------------------------------------
291 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
292 ; struct pointed to by ptr1. No return code required.
293 ;
294 ; We're cheating here to keep the code smaller: The first fields of the
295 ; mouse_info struct are identical to the mouse_pos struct, so we will just
296 ; call _mouse_pos to initialize the struct pointer and fill the position
297 ; fields.
298
299 INFO:   jsr     POS
300
301 ; Fill in the button state
302
303         lda     Buttons
304         ldy     #MOUSE_INFO::BUTTONS
305         sta     (ptr1),y
306
307         rts
308
309 ;----------------------------------------------------------------------------
310 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
311 ; specific data in ptr1, and the ioctl code in A.
312 ; Must return an error code in a/x.
313 ;
314
315 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
316         ldx     #>MOUSE_ERR_INV_IOCTL
317         rts
318
319 ;----------------------------------------------------------------------------
320 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
321 ; (so be careful). The routine MUST return carry set if the interrupt has been
322 ; 'handled' - which means that the interrupt source is gone. Otherwise it
323 ; MUST return carry clear.
324 ;
325
326 IRQ:
327
328 ; Check for a pressed button and place the result into Buttons
329
330         ldx     #0
331         stx     XPos+1
332         stx     YPos+1
333         lda     TRIG0                   ; joystick #0 trigger
334         bne     @L00                    ; not pressed
335         ldx     #MOUSE_BTN_LEFT
336 @L00:   stx     Buttons
337
338         lda     PORTA                   ; get other buttons
339         eor     #255
340         tax
341         and     #4
342         beq     @L01
343         lda     #MOUSE_BTN_LEFT
344         ora     Buttons
345         sta     Buttons
346 @L01:   txa
347         and     #8
348         beq     @L02
349         lda     #MOUSE_BTN_RIGHT
350         ora     Buttons
351         sta     Buttons
352
353 @L02:   lda     visible
354         beq     @L03
355         jsr     CHIDE
356
357 ; Get cursor position
358 ; -------------------
359 ; The touchpad is read thru the paddle potentiometers. The possible
360 ; values are 1..228. Since the maximum value is less than the X
361 ; dimension we have to "stretch" this value. In order to use only
362 ; divisions by powers of two, we use the following appoximation:
363 ; 320/227 = 1.4096
364 ; 1+1/2-1/8+1/32 = 1.4062
365 ; For Y we subtract 1/8 of it to get in the YMax ballpark.
366 ; 228-228/8=199.5
367 ; A small area in the Y dimension of the touchpad isn't used with
368 ; this approximation. The Y value is inverted, (0,0) is the bottom
369 ; left corner of the touchpad.
370
371 ; X
372
373 @L03:   ldx     PADDL0                  ; get X postion
374         dex                             ; decrement, since it's 1-based
375         stx     XPos
376         txa
377         lsr     a
378         tax
379         clc
380         adc     XPos
381         sta     XPos
382         bcc     @L04
383         inc     XPos+1
384 @L04:   txa
385         lsr     a                       ; port value / 4
386         lsr     a                       ; port value / 8
387         tax
388         sec
389         lda     XPos
390         stx     XPos
391         sbc     XPos
392         sta     XPos
393         bcs     @L05
394         dec     XPos+1
395 @L05:   txa
396         lsr     a                       ; port value / 16
397         lsr     a                       ; port value / 32
398         clc
399         adc     XPos
400         sta     XPos
401         bcc     @L06
402         inc     XPos+1
403
404 @L06:   tay
405         lda     XPos+1
406         tax
407
408 ; Limit the X coordinate to the bounding box
409
410         cpy     XMin
411         sbc     XMin+1
412         bpl     @L07
413         ldy     XMin
414         ldx     XMin+1
415         jmp     @L08
416 @L07:   txa
417
418         cpy     XMax
419         sbc     XMax+1
420         bmi     @L08
421         ldy     XMax
422         ldx     XMax+1
423 @L08:   sty     XPos
424         stx     XPos+1
425
426 ; Move the mouse pointer to the new X pos
427
428         tya
429         jsr     CMOVEX
430
431 ; Y
432
433         ldx     PADDL1                  ; get Y postion
434         dex                             ; decrement, since it's 1-based
435         stx     YPos
436         lda     #228
437         sec
438         sbc     YPos                    ; invert value
439         tax
440         lsr     a
441         lsr     a
442         lsr     a
443         sta     YPos
444         txa
445         sec
446         sbc     YPos
447         sta     YPos
448         tay
449         lda     YPos+1
450         tax
451
452 ; Limit the Y coordinate to the bounding box
453
454         cpy     YMin
455         sbc     YMin+1
456         bpl     @L09
457         ldy     YMin
458         ldx     YMin+1
459         jmp     @L10
460 @L09:   txa
461
462         cpy     YMax
463         sbc     YMax+1
464         bmi     @L10
465         ldy     YMax
466         ldx     YMax+1
467 @L10:   sty     YPos
468         stx     YPos+1
469
470 ; Move the mouse pointer to the new X pos
471
472         tya
473         jsr     CMOVEY
474
475         lda     visible
476         beq     @L11
477         jsr     CSHOW
478
479 @L11:   clc                             ; Interrupt not "handled"
480         rts
481