]> git.sur5r.net Git - cc65/blob - libsrc/c64/mou/c64-inkwell.s
Merge branch 'master' into lightpen
[cc65] / libsrc / c64 / mou / c64-inkwell.s
1 ;
2 ; Driver for the Inkwell Systems 170-C and 184-C lightpens.
3 ;
4 ; 2013-06-17, Greg King
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9         .include        "c64.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           ; ASCII "mou"
23         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
24
25 ; Library reference
26
27 LIBREF: .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_EARLY_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 co-ord.
53 CMOVEY: jmp     $0000                   ; Move the cursor to Y co-ord.
54
55
56 ;----------------------------------------------------------------------------
57 ; Constants
58
59 SCREEN_WIDTH    = XSIZE * 8
60 SCREEN_HEIGHT   = YSIZE * 8
61
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 ; re-order them.
67
68 .rodata
69
70 ; Default values for below variables
71 ; (We use ".proc" because we want to define both a label and a scope.)
72
73 .proc   DefVars
74         .word   0                       ; XMin
75         .word   0                       ; YMin
76         .word   SCREEN_WIDTH - 1        ; XMax
77         .word   SCREEN_HEIGHT - 1       ; YMax
78         .byte   %00000000               ; Buttons
79 .endproc
80
81 .bss
82
83 Vars:
84 XMin:           .res    2               ; X1 value of bounding box
85 YMin:           .res    2               ; Y1 value of bounding box
86 XMax:           .res    2               ; X2 value of bounding box
87 YMax:           .res    2               ; Y2 value of bounding box
88 Buttons:        .res    1               ; Button status bits
89
90 XPos:           .res    2               ; Current lightpen position, X
91 YPos:           .res    2               ; Current lightpen position, Y
92
93 OldPenX:        .res    1               ; Previous HW-counter values
94 OldPenY:        .res    1
95
96 .data
97
98 ; Default Inkwell calibration.
99 ; The first number is the width of the left border;
100 ; the second number is the actual calibration value.
101
102 XOffset:        .byte   (24 + 24) / 2   ; x-offset
103
104 ; Jump to a function that puts a new calibration value into XOffset.
105 Calibrate:      jmp     $0000
106
107
108 .code
109
110 ;----------------------------------------------------------------------------
111 ; INSTALL routine. Is called after the driver is loaded into memory. If
112 ; possible, check if the hardware is present.
113 ; Must return a MOUSE_ERR_xx code in .XA.
114
115 INSTALL:
116
117 ; Initiate variables. Just copy the default stuff over.
118
119         ldx     #.sizeof (DefVars) - 1
120 @L0:    lda     DefVars,x
121         sta     Vars,x
122         dex
123         bpl     @L0
124
125         ldx     VIC_LPEN_X
126         ldy     VIC_LPEN_Y
127         stx     OldPenX
128         sty     OldPenY
129
130 ; Call a calibration function through the library-reference.
131
132         lda     LIBREF
133         ldx     LIBREF+1
134         sta     ptr1                    ; Point to mouse_adjuster
135         stx     ptr1+1
136         ldy     #0
137         lda     (ptr1),y
138         sta     Calibrate+1             ; Point to function
139         iny
140         lda     (ptr1),y
141         sta     Calibrate+2
142         ora     Calibrate+1             ; Don't call pointer if it's NULL
143         bze     @L1
144         lda     #<XOffset               ; Function will set this variable
145         ldx     #>XOffset
146         jsr     Calibrate
147
148 ; Be sure that the lightpen cursor is invisible and at the default location.
149 ; It needs to be done here because the lightpen interrupt handler doesn't
150 ; set the lightpen position if it hasn't changed.
151
152 @L1:    jsr     CHIDE
153
154         lda     #<(SCREEN_HEIGHT / 2)
155         ldx     #>(SCREEN_HEIGHT / 2)
156         jsr     MoveY
157         lda     #<(SCREEN_WIDTH / 2)
158         ldx     #>(SCREEN_WIDTH / 2)
159         jsr     MoveX
160
161 ; Done, return zero.
162
163         lda     #MOUSE_ERR_OK
164         tax
165         rts
166
167 ;----------------------------------------------------------------------------
168 ; UNINSTALL routine. Is called before the driver is removed from memory.
169 ; No return code required (the driver is removed from memory on return).
170
171 UNINSTALL       := HIDE                 ; Hide cursor on exit
172
173 ;----------------------------------------------------------------------------
174 ; HIDE routine. Is called to hide the lightpen pointer. The mouse kernel manages
175 ; a counter for calls to show/hide, and the driver entry point is called only
176 ; if the mouse is currently visible, and should get hidden. For most drivers,
177 ; no special action is required besides hiding the lightpen cursor.
178 ; No return code required.
179
180 HIDE:   sei
181         jsr     CHIDE
182         cli
183         rts
184
185 ;----------------------------------------------------------------------------
186 ; SHOW routine. Is called to show the lightpen pointer. The mouse kernel manages
187 ; a counter for calls to show/hide, and the driver entry point is called only
188 ; if the mouse is currently hidden, and should become visible. For most drivers,
189 ; no special action is required besides enabling the lightpen cursor.
190 ; No return code required.
191
192 SHOW:   sei
193         jsr     CSHOW
194         cli
195         rts
196
197 ;----------------------------------------------------------------------------
198 ; SETBOX: Set the lightpen bounding box. The parameters are passed as they come
199 ; from the C program, that is, a pointer to a mouse_box struct in .XA.
200 ; No checks are done if the lightpen is currently inside the box, that is the job
201 ; of the caller. It is not necessary to validate the parameters; trust the
202 ; caller; and, save some code here. No return code required.
203
204 SETBOX: sta     ptr1
205         stx     ptr1+1                  ; Save data pointer
206
207         ldy     #.sizeof (MOUSE_BOX) - 1
208         sei
209
210 @L1:    lda     (ptr1),y
211         sta     XMin,y
212         dey
213         bpl     @L1
214
215         cli
216         rts
217
218 ;----------------------------------------------------------------------------
219 ; GETBOX: Return the lightpen bounding box. The parameters are passed as they
220 ; come from the C program, that is, a pointer to a mouse_box struct in .XA.
221
222 GETBOX: sta     ptr1
223         stx     ptr1+1                  ; Save data pointer
224
225         ldy     #.sizeof (MOUSE_BOX) - 1
226 @L1:    lda     XMin,y
227         sta     (ptr1),y
228         dey
229         bpl     @L1
230         rts
231
232 ;----------------------------------------------------------------------------
233 ; MOVE: Move the mouse to a new position. The position is passed as it comes
234 ; from the C program, that is: X on the stack and Y in .XA. The C wrapper will
235 ; remove the parameter from the stack on return.
236 ; No checks are done if the new position is valid (within the bounding box or
237 ; the screen). No return code required.
238 ;
239
240 MOVE:   sei                             ; No interrupts
241         jsr     MoveY
242
243         ldy     #$01
244         lda     (sp),y
245         tax
246         dey
247         lda     (sp),y
248         jsr     MoveX                   ; Move the cursor
249
250         cli                             ; Allow interrupts
251         rts
252
253 ;----------------------------------------------------------------------------
254 ; BUTTONS: Return the button mask in .XA.
255
256 BUTTONS:
257         lda     Buttons
258         ldx     #>0
259
260 ; Make the lightpen buttons look like a 1351 mouse.
261
262         asl     a
263         asl     SID_ADConv2             ; PotY
264         rol     a
265         eor     #MOUSE_BTN_RIGHT
266         and     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
267         rts
268
269 ;----------------------------------------------------------------------------
270 ; POS: Return the lightpen position in the MOUSE_POS struct pointed to by ptr1.
271 ; No return code required.
272
273 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
274
275         sei                             ; Disable interrupts
276         lda     XPos                    ; Transfer the position
277         sta     (ptr1),y
278         lda     XPos+1
279         iny
280         sta     (ptr1),y
281         lda     YPos
282         iny
283         sta     (ptr1),y
284         lda     YPos+1
285         cli                             ; Enable interrupts
286
287         iny
288         sta     (ptr1),y                ; Store last byte
289         rts
290
291 ;----------------------------------------------------------------------------
292 ; INFO: Returns lightpen position and current button mask in the MOUSE_INFO
293 ; struct pointed to by ptr1. No return code required.
294 ;
295 ; We're cheating here, to keep the code smaller: The first fields of the
296 ; mouse_info struct are identical to the mouse_pos struct; so, we'll just
297 ; call _mouse_pos to initiate the struct pointer, and fill the position
298 ; fields.
299
300 INFO:   jsr     POS
301
302 ; Fill in the button state
303
304         jsr     BUTTONS                 ; Will not touch ptr1
305         ldy     #MOUSE_INFO::BUTTONS
306         sta     (ptr1),y
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 .XA.
313 ;
314
315 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioctls, for now
316         ldx     #>MOUSE_ERR_INV_IOCTL
317         rts
318
319 ;----------------------------------------------------------------------------
320 ; IRQ: IRQ handler entry point. Called as a subroutine, but in the 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 ; Record the state of the buttons.
329 ; Try to avoid crosstalk between the keyboard and the lightpen.
330
331         ldy     #%00000000              ; Set ports A and B to input
332         sty     CIA1_DDRB
333         sty     CIA1_DDRA               ; Keyboard won't look like buttons
334         lda     CIA1_PRB                ; Read Control-Port 1
335         dec     CIA1_DDRA               ; Set port A back to output
336         eor     #%11111111              ; Bit goes up when button goes down
337         sta     Buttons
338         bze     @L0
339         lda     #%11101111              ; (Don't change bit that feeds VIC-II)
340         sta     CIA1_DDRB               ; Buttons won't look like keyboard
341         sty     CIA1_PRB                ; Set "all keys pushed"
342
343 ; Read the VIC-II lightpen registers.
344
345 @L0:    lda     VIC_LPEN_Y
346         cmp     OldPenY
347
348 ; Skip processing if nothing has changed.
349
350         beq     @SkipY
351         sta     OldPenY
352
353 ; Subtract the height of the top border, so that the lightpen co-ordinate
354 ; will match the TGI co-ordinate.
355
356         sub     #50
357         tay                             ; Remember low byte
358         ldx     #>0
359
360 ; Limit the Y co-ordinate to the bounding box.
361
362         txa
363         cpy     YMin
364         sbc     YMin+1
365         bpl     @L3
366         ldy     YMin
367         ldx     YMin+1
368         jmp     @L4
369
370 @L3:    txa
371         cpy     YMax
372         sbc     YMax+1
373         bmi     @L4
374         ldy     YMax
375         ldx     YMax+1
376
377 @L4:    tya
378         jsr     MoveY
379
380 @SkipY: lda     VIC_LPEN_X
381         cmp     OldPenX
382
383 ; Skip processing if nothing has changed.
384
385         beq     @SkipX
386         sta     OldPenX
387
388 ; Adjust the value by the calibration offset.
389
390         sub     XOffset
391
392 ; Calculate the new X co-ordinate.
393 ; The VIC-II register is eight bits; but, the screen co-ordinate is nine bits.
394 ; Therefore, the VIC-II number is doubled. Then, it points to every other pixel;
395 ; but, it can reach across the screen.
396
397         asl     a
398         tay                             ; Remember low byte
399         lda     #>0
400         rol     a
401         tax                             ; Remember high byte
402
403 ; Limit the X co-ordinate to the bounding box.
404
405         cpy     XMin
406         sbc     XMin+1
407         bpl     @L1
408         ldy     XMin
409         ldx     XMin+1
410         jmp     @L2
411
412 @L1:    txa
413         cpy     XMax
414         sbc     XMax+1
415         bmi     @L2
416         ldy     XMax
417         ldx     XMax+1
418
419 @L2:    tya
420         jsr     MoveX
421
422 ; Done
423
424 @SkipX: clc                             ; Interrupt not "handled"
425         rts
426
427 ; Move the lightpen pointer to the new Y pos.
428
429 MoveY:  sta     YPos
430         stx     YPos+1
431         jmp     CMOVEY
432
433 ; Move the lightpen pointer to the new X pos.
434
435 MoveX:  sta     XPos
436         stx     XPos+1
437         jmp     CMOVEX