]> git.sur5r.net Git - cc65/blob - libsrc/c128/mouse.s
em drivers for VDC (both C128 native and C128 in C64 mode)
[cc65] / libsrc / c128 / mouse.s
1 ;
2 ; Ullrich von Bassewitz, 24.04.1999
3 ;
4 ; Routines for the 1351 proportional mouse. Parts of the code are from
5 ; the Commodore 1351 mouse users guide.
6 ;
7
8         .export         _mouse_init, _mouse_done
9         .export         _mouse_hide, _mouse_show
10         .export         _mouse_box, _mouse_info
11         .export         _mouse_move, _mouse_pos
12         .export         _mouse_buttons, _mouse_info
13         .condes         MouseIRQ, 2
14
15         .import         _readjoy
16         .import         popax, addysp1
17         .importzp       ptr1, sp
18
19         .include        "c128.inc"
20
21         .macpack        generic
22
23
24 .code
25
26 ; --------------------------------------------------------------------------
27 ;
28 ; Constants
29 ;
30
31 SPRITE_HEIGHT   = 21
32 SPRITE_WIDTH    = 24
33 SCREEN_HEIGHT   = 200
34 SCREEN_WIDTH    = 320
35 XCORR           = SPRITE_WIDTH
36
37 ; --------------------------------------------------------------------------
38 ;
39 ; unsigned char __fastcall__ mouse_init (unsigned char type);
40 ;
41
42 .proc   _mouse_init
43         lda     Initialized             ; Already initialized?
44         bne     AlreadyInitialized      ; Jump if yes
45
46 ; Initialize variables
47
48         ldx     #0
49         lda     #XCORR
50         sta     XPos
51         stx     XPos+1
52         stx     YPos
53         stx     YPos+1
54         stx     OldPotX
55         stx     OldPotY
56         stx     XMin
57         stx     XMin+1                  ; XMin = 0
58         lda     #50                     ; ## FIXME: This is the PAL value
59         sta     YCorr
60         sta     YPos
61         stx     YPos+1
62         sec
63         sbc     #SPRITE_HEIGHT          ; Sprite height in pixels
64         sta     YMin
65         stx     YMin+1                  ; YMin = 29
66         lda     #SCREEN_HEIGHT          ; Vertical screen res
67         add     YCorr                   ; Add correction factor
68         sta     YMax
69         stx     YMax+1
70         inx                             ; X = 1
71         stx     Invisible               ; Mouse *not* visible
72         lda     #<(SCREEN_WIDTH + SPRITE_WIDTH)
73         sta     XMax
74         stx     XMax+1                  ; XMax = 320 + sprite width
75
76 ; Save the old init status and reset bit 0. This will disable the BASIC
77 ; IRQ handler which will otherwise try to manage the mouse sprite on its
78 ; own
79
80         lda     INIT_STATUS
81         sta     OldInitStatus
82         and     #$FE
83         sta     INIT_STATUS
84
85 ; Mouse successfully initialized
86
87         lda     #1
88         sta     Initialized
89         rts
90
91 AlreadyInitialized:
92         lda     #0                      ; Error
93         rts
94
95 .endproc
96
97 ; --------------------------------------------------------------------------
98 ;
99 ; void mouse_done (void);
100 ;
101
102 _mouse_done:
103         lda     Initialized             ; Initialized?
104         beq     mddone                  ; Jump if no
105         lda     #0
106         sta     Initialized             ; Reset the initialized flag
107         lda     OldInitStatus           ; Load the old BASIC int bit
108         and     #$01                    ; Mask it
109         ora     INIT_STATUS             ; Restore the old state
110         sta     INIT_STATUS
111
112 ; Disable the mouse sprite
113
114 DisableSprite:
115         lda     #$FE                    ; Clear bit for sprite #0
116         sei                             ; Disable interrupts
117         and     VIC_SPR_ENA
118         sta     VIC_SPR_ENA             ; Disable sprite
119         cli                             ; Enable interrupts
120 mddone: rts
121
122
123 ; --------------------------------------------------------------------------
124 ;
125 ; void mouse_hide (void);
126 ;
127
128 .proc   _mouse_hide
129
130         lda     Invisible               ; Get the flag
131         bne     @L1                     ; Jump if already invisible
132         jsr     DisableSprite           ; Disable the mouse sprite
133 @L1:    inc     Invisible               ; Set the flag to invisible
134         rts
135
136 .endproc
137
138 ; --------------------------------------------------------------------------
139 ;
140 ; void mouse_show (void);
141 ;
142
143 .proc   _mouse_show
144
145         lda     Invisible               ; Mouse invisible?
146         beq     @L1                     ; Jump if no
147         dec     Invisible               ; Set the flag
148         bne     @L1                     ; Jump if still invisible
149
150         sei                             ; Disable interrupts
151         jsr     MoveSprite1             ; Move the sprite to it's position
152         lda     VIC_SPR_ENA             ; Get sprite enable register
153         ora     #$01                    ; Enable sprite #0
154         sta     VIC_SPR_ENA             ; Write back
155         cli                             ; Enable interrupts
156
157 @L1:    rts
158
159 .endproc
160
161 ; --------------------------------------------------------------------------
162 ;
163 ; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
164 ;
165
166 .proc   _mouse_box
167
168         ldy     #0                      ; Stack offset
169
170         add     YCorr                   ; Adjust the Y value
171         bcc     @L1
172         inx
173         clc
174 @L1:    sei                             ; Disable interrupts
175
176         sta     YMax
177         stx     YMax+1                  ; maxy
178
179         lda     (sp),y
180         adc     #XCORR
181         sta     XMax
182         iny
183         lda     (sp),y
184         adc     #$00
185         sta     XMax+1                  ; maxx
186
187         iny
188         lda     (sp),y
189         add     YCorr
190         sta     YMin
191         iny
192         lda     (sp),y
193         adc     #$00
194         sta     YMin+1                  ; miny
195
196         iny
197         lda     (sp),y
198         add     #XCORR
199         sta     XMin
200         iny
201         lda     (sp),y
202         adc     #$00
203         sta     XMin+1                  ; minx
204
205         cli                             ; Enable interrupts
206
207         jmp     addysp1                 ; Drop params, return
208
209 .endproc
210
211 ; --------------------------------------------------------------------------
212 ;
213 ; void __fastcall__ mouse_pos (struct mouse_pos* pos);
214 ; /* Return the current mouse position */
215 ;
216
217 .proc   _mouse_pos
218
219         sta     ptr1
220         stx     ptr1+1                  ; Remember the argument pointer
221
222         ldy     #0                      ; Structure offset
223         sec                             ; Needed for the SBC later
224
225         sei                             ; Disable interrupts
226         lda     XPos                    ; Transfer the position
227         sbc     #XCORR
228         sta     (ptr1),y
229         lda     XPos+1
230         sbc     #$00
231         iny
232         sta     (ptr1),y
233         lda     YPos
234         ldx     YPos+1
235         cli                             ; Restore initial interrupt state
236
237         sub     YCorr                   ; Apply the Y correction value
238         bcs     @L1
239         dex
240 @L1:    iny
241         sta     (ptr1),y                ; Store YPos
242         txa
243         iny
244         sta     (ptr1),y
245
246         rts                             ; Done
247
248 .endproc
249
250 ; --------------------------------------------------------------------------
251 ;
252 ; void __fastcall__ mouse_info (struct mouse_info* info);
253 ; /* Return the state of the mouse buttons and the position of the mouse */
254 ;
255
256 .proc   _mouse_info
257
258 ; We're cheating here to keep the code smaller: The first fields of the
259 ; mouse_info struct are identical to the mouse_pos struct, so we will just
260 ; call _mouse_pos to initialize the struct pointer and fill the position
261 ; fields.
262
263         jsr     _mouse_pos
264
265 ; Fill in the button state
266
267         jsr     _mouse_buttons          ; Will not touch ptr1
268         ldy     #4
269         sta     (ptr1),y
270
271         rts
272
273 .endproc
274
275 ; --------------------------------------------------------------------------
276 ;
277 ; void __fastcall__ mouse_move (int x, int y);
278 ;
279
280 .proc   _mouse_move
281
282         add     YCorr                   ; Add Y coordinate correction
283         bcc     @L1
284         inx
285         clc
286 @L1:    sei
287         sta     YPos
288         stx     YPos+1
289         cli
290
291         jsr     popax                   ; Get X
292         adc     #XCORR                  ; Adjust X coordinate
293         bcc     @L2
294         inx
295 @L2:    sei
296         sta     XPos
297         stx     XPos+1                  ; Set new position
298         jsr     MoveSprite              ; Move the sprite to the mouse pos
299         cli                             ; Enable interrupts
300
301         rts
302
303 .endproc
304
305 ; --------------------------------------------------------------------------
306 ;
307 ; unsigned char mouse_buttons (void);
308 ;
309
310 .proc   _mouse_buttons
311
312         lda     #$00                    ; Use port #0
313         jmp     _readjoy                ; Same as joystick
314
315 .endproc
316
317 ; --------------------------------------------------------------------------
318 ;
319 ; Mouse interrupt handler
320 ;
321
322 IRQDone:rts
323
324 MouseIRQ:
325
326         lda     Initialized             ; Mouse initialized?
327         beq     IRQDone                 ; Jump if no
328         lda     SID_ADConv1             ; Get mouse X movement
329         ldy     OldPotX
330         jsr     MoveCheck               ; Calculate movement vector
331         sty     OldPotX
332
333 ; Calculate the new X coordinate (--> a/y)
334
335         add     XPos
336         tay                             ; Remember low byte
337         txa
338         adc     XPos+1
339         tax
340
341 ; Limit the X coordinate to the bounding box
342
343         cpy     XMin
344         sbc     XMin+1
345         bpl     @L1
346         ldy     XMin
347         ldx     XMin+1
348         jmp     @L2
349 @L1:    txa
350
351         cpy     XMax
352         sbc     XMax+1
353         bmi     @L2
354         ldy     XMax
355         ldx     XMax+1
356 @L2:    sty     XPos
357         stx     XPos+1
358
359 ; Calculate the Y movement vector
360
361         lda     SID_ADConv2             ; Get mouse Y movement
362         ldy     OldPotY
363         jsr     MoveCheck               ; Calculate movement
364         sty     OldPotY
365
366 ; Calculate the new Y coordinate (--> a/y)
367
368         sta     OldValue
369         lda     YPos
370         sub     OldValue
371         tay
372         stx     OldValue
373         lda     YPos+1
374         sbc     OldValue
375         tax
376
377         cpy     YMin
378         sbc     YMin+1
379         bpl     @L3
380         ldy     YMin
381         ldx     YMin+1
382         jmp     @L4
383 @L3:    txa
384
385         cpy     YMax
386         sbc     YMax+1
387         bmi     @L4
388         ldy     YMax
389         ldx     YMax+1
390 @L4:    sty     YPos
391         stx     YPos+1
392
393 ; Move the mouse sprite to the current mouse position. Must be called
394 ; with interrupts off. MoveSprite1 is an entry without checking.
395
396 MoveSprite:
397
398         lda     Invisible               ; Mouse visible?
399         bne     Done                    ; Jump if no
400
401 ; Set the high X bit
402
403 MoveSprite1:
404         lda     VIC_SPR_HI_X            ; Get high X bits of all sprites
405         and     #$FE                    ; Clear bit for sprite #0
406         ldy     XPos+1                  ; Test Y position
407         beq     @L5
408         ora     #$01                    ; Set high X bit
409 @L5:    sta     VIC_SPR_HI_X            ; Set hi X sprite values
410
411 ; Set the low X byte
412
413         lda     XPos
414         sta     VIC_SPR0_X              ; Set low byte
415
416 ; Set the Y position
417
418         ldy     YPos+1                  ; Negative or too large?
419         bne     Done                    ; Jump if yes
420         lda     YPos
421         sta     VIC_SPR0_Y              ; Set Y position
422
423 ; Done
424
425 Done:   rts
426
427 ; --------------------------------------------------------------------------
428 ;
429 ; Move check routine, called for both coordinates.
430 ;
431 ; Entry:        y = old value of pot register
432 ;               a = current value of pot register
433 ; Exit:         y = value to use for old value
434 ;               x/a = delta value for position
435 ;
436
437 .proc   MoveCheck
438
439         sty     OldValue
440         sta     NewValue
441         ldx     #$00
442
443         sub     OldValue                ; a = mod64 (new - old)
444         and     #%01111111
445         cmp     #%01000000              ; if (a > 0)
446         bcs     @L1                     ;
447         lsr     a                       ;   a /= 2;
448         beq     @L2                     ;   if (a != 0)
449         ldy     NewValue                ;     y = NewValue
450         rts                             ;   return
451
452 @L1:    ora     #%11000000              ; else or in high order bits
453         cmp     #$FF                    ; if (a != -1)
454         beq     @L2
455         sec
456         ror     a                       ;   a /= 2
457         dex                             ;   high byte = -1 (X = $FF)
458         ldy     NewValue
459         rts
460
461 @L2:    txa                             ; A = $00
462         rts
463
464 .endproc
465
466 ; --------------------------------------------------------------------------
467 ; Data
468
469 .bss
470
471 Initialized:    .res    1               ; True if mouse initialized
472 OldInitStatus:  .res    1               ; Old IRQ flag value
473 OldValue:       .res    1               ; Temp for MoveCheck routine
474 NewValue:       .res    1               ; Temp for MoveCheck routine
475 YCorr:          .res    1               ; Correction for Y coordinate
476
477 Invisible:      .res    1               ; Is the mouse invisible?
478 OldPotX:        .res    1               ; Old hw counter values
479 OldPotY:        .res    1
480
481 XPos:           .res    2               ; Current mouse position, X
482 YPos:           .res    2               ; Current mouse position, Y
483
484 XMin:           .res    2               ; X1 value of bounding box
485 YMin:           .res    2               ; Y1 value of bounding box
486 XMax:           .res    2               ; X2 value of bounding box
487 YMax:           .res    2               ; Y2 value of bounding box
488
489