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