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