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