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