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