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