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