]> git.sur5r.net Git - cc65/blob - libsrc/c128/mou/c128-pot.s
Merge pull request #249 from polluks/master
[cc65] / libsrc / c128 / mou / c128-pot.s
1 ;
2 ; Driver for a potentiometer "mouse", e.g. Koala Pad
3 ;
4 ; 2006-08-20, Stefan Haubenthal
5 ; 2009-09-26, Ullrich von Bassewitz
6 ; 2014-04-26, Christian Groessler
7 ; 2014-05-05, Greg King
8 ;
9
10         .include        "zeropage.inc"
11         .include        "mouse-kernel.inc"
12         .include        "c128.inc"
13
14         .macpack        generic
15         .macpack        module
16
17
18 ; ------------------------------------------------------------------------
19 ; Header. Includes jump table
20
21         module_header   _c128_pot_mou
22
23 HEADER:
24
25 ; Driver signature
26
27         .byte   $6d, $6f, $75           ; "mou"
28         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
29
30 ; Library reference
31
32 libref: .addr   $0000
33
34 ; Jump table
35
36         .addr   INSTALL
37         .addr   UNINSTALL
38         .addr   HIDE
39         .addr   SHOW
40         .addr   SETBOX
41         .addr   GETBOX
42         .addr   MOVE
43         .addr   BUTTONS
44         .addr   POS
45         .addr   INFO
46         .addr   IOCTL
47         .addr   IRQ
48
49 ; Mouse driver flags
50
51         .byte   MOUSE_FLAG_LATE_IRQ
52
53 ; Callback table, set by the kernel before INSTALL is called
54
55 CHIDE:  jmp     $0000                   ; Hide the cursor
56 CSHOW:  jmp     $0000                   ; Show the cursor
57 CPREP:  jmp     $0000                   ; Prepare to move the cursor
58 CDRAW:  jmp     $0000                   ; Draw the cursor
59 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
60 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
61
62
63 ;----------------------------------------------------------------------------
64 ; Constants
65
66 SCREEN_HEIGHT   = 200
67 SCREEN_WIDTH    = 320
68
69 .enum   JOY
70         UP      = $01
71         DOWN    = $02
72         LEFT    = $04
73         RIGHT   = $08
74         FIRE    = $10
75 .endenum
76
77 ;----------------------------------------------------------------------------
78 ; Global variables. The bounding box values are sorted so that they can be
79 ; written with the least effort in the SETBOX and GETBOX routines, so don't
80 ; reorder them.
81
82 .bss
83
84 Vars:
85 YPos:           .res    2               ; Current mouse position, Y
86 XPos:           .res    2               ; Current mouse position, X
87 XMin:           .res    2               ; X1 value of bounding box
88 YMin:           .res    2               ; Y1 value of bounding box
89 XMax:           .res    2               ; X2 value of bounding box
90 YMax:           .res    2               ; Y2 value of bounding box
91 Buttons:        .res    1               ; Button mask
92
93 INIT_save:      .res    1
94
95 ; Keyboard buffer fill level at start of interrupt
96
97 old_key_count:  .res    1
98
99 ; Original IRQ vector
100
101 old_irq:        .res    2
102
103 .rodata
104
105 ; Default values for above variables
106 ; (We use ".proc" because we want to define both a label and a scope.)
107
108 .proc   DefVars
109         .word   SCREEN_HEIGHT/2         ; YPos
110         .word   SCREEN_WIDTH/2          ; XPos
111         .word   0                       ; XMin
112         .word   0                       ; YMin
113         .word   SCREEN_WIDTH - 1        ; XMax
114         .word   SCREEN_HEIGHT - 1       ; YMax
115         .byte   0                       ; Buttons
116 .endproc
117
118 .code
119
120 ;----------------------------------------------------------------------------
121 ; INSTALL routine. Is called after the driver is loaded into memory. If
122 ; possible, check if the hardware is present.
123 ; Must return an MOUSE_ERR_xx code in a/x.
124
125 INSTALL:
126
127 ; Disable the BASIC interpreter's interrupt-driven sprite-motion code.
128 ; That allows direct access to the VIC-IIe's sprite registers.
129
130         lda     INIT_STATUS
131         sta     INIT_save
132         lda     #%11000000
133         sta     INIT_STATUS
134
135 ; Initialize variables. Just copy the default stuff over
136
137         ldx     #.sizeof(DefVars)-1
138 @L1:    lda     DefVars,x
139         sta     Vars,x
140         dex
141         bpl     @L1
142
143 ; Be sure the mouse cursor is invisible and at the default location. We
144 ; need to do that here, because our mouse interrupt handler doesn't set the
145 ; mouse position if it hasn't changed.
146
147         sei
148         jsr     CHIDE
149         lda     XPos
150         ldx     XPos+1
151         jsr     CMOVEX
152         lda     YPos
153         ldx     YPos+1
154         jsr     CMOVEY
155
156 ; Initiate our IRQ magic.
157
158         ; Remember the ROM IRQ continuation address.
159         ldx     IRQInd+2
160         lda     IRQInd+1
161         stx     old_irq+1
162         sta     old_irq
163
164         lda     libref
165         ldx     libref+1
166         sta     ptr3
167         stx     ptr3+1
168
169         ; Set the ROM IRQ continuation address to point to the provided routine.
170         ldy     #2
171         lda     (ptr3),y
172         sta     IRQInd+1
173         iny
174         lda     (ptr3),y
175         sta     IRQInd+2
176
177         ; Set the address of our IRQ callback routine.
178         ; Because it's called via "rts", we must use "address-1".
179         iny
180         lda     #<(callback-1)
181         sta     (ptr3),y
182         iny
183         lda     #>(callback-1)
184         sta     (ptr3),y
185
186         ; Set the ROM entry-point vector.
187         ; Because it's called via "rts", we must decrement it by one.
188         iny
189         lda     old_irq
190         sub     #<1
191         sta     (ptr3),y
192         iny
193         lda     old_irq+1
194         sbc     #>1
195         sta     (ptr3),y
196         cli
197
198 ; Done, return zero (= MOUSE_ERR_OK)
199
200         ldx     #$00
201         txa
202         rts
203
204 ;----------------------------------------------------------------------------
205 ; UNINSTALL routine. Is called before the driver is removed from memory.
206 ; No return code required (the driver is removed from memory on return).
207
208 UNINSTALL:
209         lda     old_irq
210         ldx     old_irq+1
211         sei
212         sta     IRQInd+1
213         stx     IRQInd+2
214         ;cli                            ; This will be done at end of HIDE
215
216         jsr     HIDE                    ; Hide cursor on exit
217         lda     INIT_save
218         sta     INIT_STATUS
219         rts
220
221 ;----------------------------------------------------------------------------
222 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
223 ; a counter for calls to show/hide, and the driver entry point is only called
224 ; if the mouse is currently visible and should get hidden. For most drivers,
225 ; no special action is required besides hiding the mouse cursor.
226 ; No return code required.
227
228 HIDE:   sei
229         jsr     CHIDE
230         cli
231         rts
232
233 ;----------------------------------------------------------------------------
234 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
235 ; a counter for calls to show/hide, and the driver entry point is only called
236 ; if the mouse is currently hidden and should become visible. For most drivers,
237 ; no special action is required besides enabling the mouse cursor.
238 ; No return code required.
239
240 SHOW:   sei
241         jsr     CSHOW
242         cli
243         rts
244
245 ;----------------------------------------------------------------------------
246 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
247 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
248 ; No checks are done if the mouse is currently inside the box, this is the job
249 ; of the caller. It is not necessary to validate the parameters, trust the
250 ; caller and save some code here. No return code required.
251
252 SETBOX: sta     ptr1
253         stx     ptr1+1                  ; Save data pointer
254
255         ldy     #.sizeof (MOUSE_BOX)-1
256         sei
257
258 @L1:    lda     (ptr1),y
259         sta     XMin,y
260         dey
261         bpl     @L1
262
263         cli
264         rts
265
266 ;----------------------------------------------------------------------------
267 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
268 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
269
270 GETBOX: sta     ptr1
271         stx     ptr1+1                  ; Save data pointer
272
273         ldy     #.sizeof (MOUSE_BOX)-1
274         sei
275
276 @L1:    lda     XMin,y
277         sta     (ptr1),y
278         dey
279         bpl     @L1
280
281         cli
282         rts
283
284 ;----------------------------------------------------------------------------
285 ; MOVE: Move the mouse to a new position. The position is passed as it comes
286 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
287 ; remove the parameter from the stack on return.
288 ; No checks are done if the new position is valid (within the bounding box or
289 ; the screen). No return code required.
290 ;
291
292 MOVE:   sei                             ; No interrupts
293
294         sta     YPos
295         stx     YPos+1                  ; New Y position
296         jsr     CMOVEY                  ; Set it
297
298         ldy     #$01
299         lda     (sp),y
300         sta     XPos+1
301         tax
302         dey
303         lda     (sp),y
304         sta     XPos                    ; New X position
305
306         jsr     CMOVEX                  ; Move the cursor
307
308         cli                             ; Allow interrupts
309         rts
310
311 ;----------------------------------------------------------------------------
312 ; BUTTONS: Return the button mask in a/x.
313
314 BUTTONS:
315         lda     Buttons
316         ldx     #$00
317
318 ; Make the buttons look like a 1351 mouse.
319
320         and     #JOY::LEFT | JOY::RIGHT
321         lsr     a
322         lsr     a
323         ;clc                            ; ("lsr" shifted zero into carry flag)
324         adc     #%00001110              ; Shift bit 1 over to bit 4
325         and     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
326         rts
327
328 ;----------------------------------------------------------------------------
329 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
330 ; No return code required.
331
332 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
333
334         sei                             ; Disable interrupts
335         lda     XPos                    ; Transfer the position
336         sta     (ptr1),y
337         lda     XPos+1
338         iny
339         sta     (ptr1),y
340         lda     YPos
341         iny
342         sta     (ptr1),y
343         lda     YPos+1
344         cli                             ; Enable interrupts
345
346         iny
347         sta     (ptr1),y                ; Store last byte
348
349         rts                             ; Done
350
351 ;----------------------------------------------------------------------------
352 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
353 ; struct pointed to by ptr1. No return code required.
354 ;
355 ; We're cheating here to keep the code smaller: The first fields of the
356 ; mouse_info struct are identical to the mouse_pos struct, so we will just
357 ; call _mouse_pos to initialize the struct pointer and fill the position
358 ; fields.
359
360 INFO:   jsr     POS
361
362 ; Fill in the button state
363
364         jsr     BUTTONS
365         ldy     #MOUSE_INFO::BUTTONS
366         sta     (ptr1),y
367
368         rts
369
370 ;----------------------------------------------------------------------------
371 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
372 ; specific data in ptr1, and the ioctl code in A.
373 ; Must return an error code in a/x.
374 ;
375
376 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioctls for now
377         ldx     #>MOUSE_ERR_INV_IOCTL
378         rts
379
380 ;----------------------------------------------------------------------------
381 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
382 ; (so be careful).
383 ;
384
385 IRQ:    jsr     CPREP
386         lda     KEY_COUNT
387         sta     old_key_count
388         lda     #$7F
389         sta     CIA1_PRA
390         lda     CIA1_PRB                ; Read port #1
391         eor     #%11111111              ; Make all bits active high
392         sta     Buttons
393
394         ldx     #%01000000              ; Read port 1 paddles
395         stx     CIA1_PRA
396         ldy     #<256
397 :       dey
398         bne     :-
399         ldx     SID_ADConv1
400         stx     XPos
401         ldx     SID_ADConv2
402         stx     YPos
403
404         lda     #$FF
405         tax
406         bne     @AddX                   ; Branch always
407         lda     #$01
408         ldx     #$00
409
410 ; Calculate the new X coordinate (--> a/y)
411
412 @AddX:  add     XPos
413         tay                             ; Remember low byte
414         txa
415         adc     XPos+1
416         tax
417
418 ; Limit the X coordinate to the bounding box
419
420         cpy     XMin
421         sbc     XMin+1
422         bpl     @L1
423         ldy     XMin
424         ldx     XMin+1
425         jmp     @L2
426 @L1:    txa
427
428         cpy     XMax
429         sbc     XMax+1
430         bmi     @L2
431         ldy     XMax
432         ldx     XMax+1
433 @L2:    sty     XPos
434         stx     XPos+1
435
436 ; Move the mouse pointer to the new X pos
437
438         tya
439         jsr     CMOVEX
440
441         lda     #$FF
442         tax
443         bne     @AddY
444 @Down:  lda     #$01
445         ldx     #$00
446
447 ; Calculate the new Y coordinate (--> a/y)
448
449 @AddY:  add     YPos
450         tay                             ; Remember low byte
451         txa
452         adc     YPos+1
453         tax
454
455 ; Limit the Y coordinate to the bounding box
456
457         cpy     YMin
458         sbc     YMin+1
459         bpl     @L3
460         ldy     YMin
461         ldx     YMin+1
462         jmp     @L4
463 @L3:    txa
464
465         cpy     YMax
466         sbc     YMax+1
467         bmi     @L4
468         ldy     YMax
469         ldx     YMax+1
470 @L4:    sty     YPos
471         stx     YPos+1
472
473 ; Move the mouse pointer to the new X pos
474
475         tya
476         jsr     CMOVEY
477         jsr     CDRAW
478         clc                             ; Interrupt not "handled"
479         rts
480
481 .define OLD_BUTTONS Buttons             ; Tells callback.inc where the old port status is stored
482 .include        "callback.inc"