]> git.sur5r.net Git - cc65/blob - libsrc/c64/mou/c64-inkwell.s
Merge remote-tracking branch 'upstream/master'
[cc65] / libsrc / c64 / mou / c64-inkwell.s
1 ;
2 ; Driver for the Inkwell Systems 170-C and 184-C lightpens.
3 ;
4 ; 2013-07-01, 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     #1
137         lda     (ptr1),y
138         bze     @L1                     ; Don't call pointer if it's NULL
139         sta     Calibrate+2             ; Point to function
140         dey
141         lda     (ptr1),y
142         sta     Calibrate+1
143         lda     #<XOffset               ; Function will set this variable
144         ldx     #>XOffset
145         jsr     Calibrate
146
147 ; Be sure that the lightpen cursor is invisible and at the default location.
148 ; It needs to be done here because the lightpen interrupt handler doesn't
149 ; set the lightpen position if it hasn't changed.
150
151 @L1:    sei
152         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         cli
161
162 ; Done, return zero.
163
164         lda     #MOUSE_ERR_OK
165         tax
166         rts
167
168 ;----------------------------------------------------------------------------
169 ; UNINSTALL routine. Is called before the driver is removed from memory.
170 ; No return code required (the driver is removed from memory on return).
171
172 UNINSTALL       := HIDE                 ; Hide cursor on exit
173
174 ;----------------------------------------------------------------------------
175 ; HIDE routine. Is called to hide the lightpen pointer. The mouse kernel manages
176 ; a counter for calls to show/hide, and the driver entry point is called only
177 ; if the mouse is currently visible, and should get hidden. For most drivers,
178 ; no special action is required besides hiding the lightpen cursor.
179 ; No return code required.
180
181 HIDE:   sei
182         jsr     CHIDE
183         cli
184         rts
185
186 ;----------------------------------------------------------------------------
187 ; SHOW routine. Is called to show the lightpen pointer. The mouse kernel manages
188 ; a counter for calls to show/hide, and the driver entry point is called only
189 ; if the mouse is currently hidden, and should become visible. For most drivers,
190 ; no special action is required besides enabling the lightpen cursor.
191 ; No return code required.
192
193 SHOW:   sei
194         jsr     CSHOW
195         cli
196         rts
197
198 ;----------------------------------------------------------------------------
199 ; SETBOX: Set the lightpen bounding box. The parameters are passed as they come
200 ; from the C program, that is, a pointer to a mouse_box struct in .XA.
201 ; No checks are done if the lightpen is currently inside the box, that is the job
202 ; of the caller. It is not necessary to validate the parameters; trust the
203 ; caller; and, save some code here. No return code required.
204
205 SETBOX: sta     ptr1
206         stx     ptr1+1                  ; Save data pointer
207
208         ldy     #.sizeof (MOUSE_BOX) - 1
209         sei
210
211 @L1:    lda     (ptr1),y
212         sta     XMin,y
213         dey
214         bpl     @L1
215
216         cli
217         rts
218
219 ;----------------------------------------------------------------------------
220 ; GETBOX: Return the lightpen bounding box. The parameters are passed as they
221 ; come from the C program, that is, a pointer to a mouse_box struct in .XA.
222
223 GETBOX: sta     ptr1
224         stx     ptr1+1                  ; Save data pointer
225
226         ldy     #.sizeof (MOUSE_BOX) - 1
227 @L1:    lda     XMin,y
228         sta     (ptr1),y
229         dey
230         bpl     @L1
231         rts
232
233 ;----------------------------------------------------------------------------
234 ; MOVE: Move the mouse to a new position. The position is passed as it comes
235 ; from the C program, that is: X on the stack and Y in .XA. The C wrapper will
236 ; remove the parameter from the stack on return.
237 ; No checks are done if the new position is valid (within the bounding box or
238 ; the screen). No return code required.
239 ;
240
241 MOVE:   sei                             ; No interrupts
242         jsr     MoveY
243
244         ldy     #$01
245         lda     (sp),y
246         tax
247         dey
248         lda     (sp),y
249         jsr     MoveX                   ; Move the cursor
250
251         cli                             ; Allow interrupts
252         rts
253
254 ;----------------------------------------------------------------------------
255 ; BUTTONS: Return the button mask in .XA.
256
257 BUTTONS:
258         lda     Buttons
259         ldx     #>0
260
261 ; Make the lightpen buttons look like a 1351 mouse.
262
263         asl     a
264         asl     SID_ADConv2             ; PotY
265         rol     a
266         eor     #MOUSE_BTN_RIGHT
267         and     #MOUSE_BTN_LEFT | MOUSE_BTN_RIGHT
268         rts
269
270 ;----------------------------------------------------------------------------
271 ; POS: Return the lightpen position in the MOUSE_POS struct pointed to by ptr1.
272 ; No return code required.
273
274 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
275
276         sei                             ; Disable interrupts
277         lda     XPos                    ; Transfer the position
278         sta     (ptr1),y
279         lda     XPos+1
280         iny
281         sta     (ptr1),y
282         lda     YPos
283         iny
284         sta     (ptr1),y
285         lda     YPos+1
286         cli                             ; Enable interrupts
287
288         iny
289         sta     (ptr1),y                ; Store last byte
290         rts
291
292 ;----------------------------------------------------------------------------
293 ; INFO: Returns lightpen position and current button mask in the MOUSE_INFO
294 ; struct pointed to by ptr1. No return code required.
295 ;
296 ; We're cheating here, to keep the code smaller: The first fields of the
297 ; mouse_info struct are identical to the mouse_pos struct; so, we'll just
298 ; call _mouse_pos to initiate the struct pointer, and fill the position
299 ; fields.
300
301 INFO:   jsr     POS
302
303 ; Fill in the button state
304
305         jsr     BUTTONS                 ; Will not touch ptr1
306         ldy     #MOUSE_INFO::BUTTONS
307         sta     (ptr1),y
308         rts
309
310 ;----------------------------------------------------------------------------
311 ; IOCTL: Driver-defined entry point. The wrapper will pass a pointer to ioctl-
312 ; specific data in ptr1, and the ioctl code in .A.
313 ; Must return an error code in .XA.
314 ;
315
316 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioctls, for now
317         ldx     #>MOUSE_ERR_INV_IOCTL
318         rts
319
320 ;----------------------------------------------------------------------------
321 ; IRQ: IRQ handler entry point. Called as a subroutine, but in the IRQ context
322 ; (so, be careful). The routine MUST return carry set if the interrupt has been
323 ; 'handled' -- which means that the interrupt source is gone. Otherwise, it
324 ; MUST return carry clear.
325 ;
326
327 IRQ:
328
329 ; Record the state of the buttons.
330 ; Try to avoid crosstalk between the keyboard and the lightpen.
331
332         ldy     #%00000000              ; Set ports A and B to input
333         sty     CIA1_DDRB
334         sty     CIA1_DDRA               ; Keyboard won't look like buttons
335         lda     CIA1_PRB                ; Read Control-Port 1
336         dec     CIA1_DDRA               ; Set port A back to output
337         eor     #%11111111              ; Bit goes up when button goes down
338         sta     Buttons
339         bze     @L0
340         lda     #%11101111              ; (Don't change bit that feeds VIC-II)
341         sta     CIA1_DDRB               ; Buttons won't look like keyboard
342         sty     CIA1_PRB                ; Set "all keys pushed"
343
344 ; Read the VIC-II lightpen registers.
345
346 @L0:    lda     VIC_LPEN_Y
347         cmp     OldPenY
348
349 ; Skip processing if nothing has changed.
350
351         beq     @SkipY
352         sta     OldPenY
353
354 ; Subtract the height of the top border, so that the lightpen co-ordinate
355 ; will match the TGI co-ordinate.
356
357         sub     #50
358         tay                             ; Remember low byte
359         ldx     #>0
360
361 ; Limit the Y co-ordinate to the bounding box.
362
363         txa
364         cpy     YMin
365         sbc     YMin+1
366         bpl     @L3
367         ldy     YMin
368         ldx     YMin+1
369         jmp     @L4
370
371 @L3:    txa
372         cpy     YMax
373         sbc     YMax+1
374         bmi     @L4
375         ldy     YMax
376         ldx     YMax+1
377
378 @L4:    tya
379         jsr     MoveY
380
381 @SkipY: lda     VIC_LPEN_X
382         cmp     OldPenX
383
384 ; Skip processing if nothing has changed.
385
386         beq     @SkipX
387         sta     OldPenX
388
389 ; Adjust the value by the calibration offset.
390
391         sub     XOffset
392
393 ; Calculate the new X co-ordinate.
394 ; The VIC-II register is eight bits; but, the screen co-ordinate is nine bits.
395 ; Therefore, the VIC-II number is doubled. Then, it points to every other pixel;
396 ; but, it can reach across the screen.
397
398         asl     a
399         tay                             ; Remember low byte
400         lda     #>0
401         rol     a
402         tax                             ; Remember high byte
403
404 ; Limit the X co-ordinate to the bounding box.
405
406         cpy     XMin
407         sbc     XMin+1
408         bpl     @L1
409         ldy     XMin
410         ldx     XMin+1
411         jmp     @L2
412
413 @L1:    txa
414         cpy     XMax
415         sbc     XMax+1
416         bmi     @L2
417         ldy     XMax
418         ldx     XMax+1
419
420 @L2:    tya
421         jsr     MoveX
422
423 ; Done
424
425 @SkipX: clc                             ; Interrupt not "handled"
426         rts
427
428 ; Move the lightpen pointer to the new Y pos.
429
430 MoveY:  sta     YPos
431         stx     YPos+1
432         jmp     CMOVEY
433
434 ; Move the lightpen pointer to the new X pos.
435
436 MoveX:  sta     XPos
437         stx     XPos+1
438         jmp     CMOVEX