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