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