; Driver for the 1351 proportional mouse. Parts of the code are from
; the Commodore 1351 mouse users guide.
;
-; Ullrich von Bassewitz, 2003-12-29
+; Ullrich von Bassewitz, 2003-12-29, 2009-09-26
;
.include "zeropage.inc"
.addr UNINSTALL
.addr HIDE
.addr SHOW
- .addr BOX
+ .addr SETBOX
+ .addr GETBOX
.addr MOVE
.addr BUTTONS
.addr POS
.addr IOCTL
.addr IRQ
-; Data that is visible to the outside. Initialized by the kernel.
+; Mouse driver flags
-XPos: .word 0 ; Current mouse position, X
-YPos: .word 0 ; Current mouse position, Y
+ .byte MOUSE_FLAG_LATE_IRQ
; Callback table, set by the kernel before INSTALL is called
SCREEN_WIDTH = 320
;----------------------------------------------------------------------------
-;
-; Global variables
-;
+; Global variables. The bounding box values are sorted so that they can be
+; written with the least effort in the SETBOX and GETBOX routines, so don't
+; reorder them.
.bss
OldPotX: .res 1 ; Old hw counter values
OldPotY: .res 1
+YPos: .res 2 ; Current mouse position, Y
+XPos: .res 2 ; Current mouse position, X
XMin: .res 2 ; X1 value of bounding box
YMin: .res 2 ; Y1 value of bounding box
XMax: .res 2 ; X2 value of bounding box
.proc DefVars
.byte 0, 0 ; OldPotX/OldPotY
- .word 0, 0 ; XMin/YMin
+ .word SCREEN_HEIGHT/2 ; YPos
+ .word SCREEN_WIDTH/2 ; XPos
+ .word 0 ; XMin
+ .word 0 ; YMin
.word SCREEN_WIDTH ; XMax
.word SCREEN_HEIGHT ; YMax
.endproc
dex
bpl @L1
+; Be sure the mouse cursor is invisible and at the default location. We
+; need to do that here, because our mouse interrupt handler doesn't set the
+; mouse position if it hasn't changed.
+
+ sei
+ jsr CHIDE
+ lda XPos
+ ldx XPos+1
+ jsr CMOVEX
+ lda YPos
+ ldx YPos+1
+ jsr CMOVEY
+ cli
+
; Done, return zero (= MOUSE_ERR_OK)
- inx ; X = 0
+ ldx #$00
txa
-; rts ; Run into UNINSTALL instead
+ rts ; Run into UNINSTALL instead
;----------------------------------------------------------------------------
; UNINSTALL routine. Is called before the driver is removed from memory.
; No return code required (the driver is removed from memory on return).
-UNINSTALL:
- rts
+UNINSTALL = HIDE ; Hide cursor on exit
;----------------------------------------------------------------------------
; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
; no special action is required besides hiding the mouse cursor.
; No return code required.
-HIDE = CHIDE
+HIDE: sei
+ jsr CHIDE
+ cli
+ rts
;----------------------------------------------------------------------------
; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
; no special action is required besides enabling the mouse cursor.
; No return code required.
-SHOW = CSHOW
+SHOW: sei
+ jsr CSHOW
+ cli
+ rts
;----------------------------------------------------------------------------
-; BOX: Set the mouse bounding box. No checks are done if the mouse is
-; currently inside the box, this is the job of the caller. It is not necessary
-; to validate the parameters, trust the caller and save some code here.
-; No return code required.
+; SETBOX: Set the mouse bounding box. The parameters are passed as they come
+; from the C program, that is, a pointer to a mouse_box struct in a/x.
+; No checks are done if the mouse is currently inside the box, this is the job
+; of the caller. It is not necessary to validate the parameters, trust the
+; caller and save some code here. No return code required.
+
+SETBOX: sta ptr1
+ stx ptr1+1 ; Save data pointer
+
+ ldy #.sizeof (MOUSE_BOX)-1
+ sei
+
+@L1: lda (ptr1),y
+ sta XMin,y
+ dey
+ bpl @L1
-BOX:
+ cli
rts
;----------------------------------------------------------------------------
-; MOVE: Move the mouse to a new position which is passed in X=ptr1, Y=a/x.
+; GETBOX: Return the mouse bounding box. The parameters are passed as they
+; come from the C program, that is, a pointer to a mouse_box struct in a/x.
+
+GETBOX: sta ptr1
+ stx ptr1+1 ; Save data pointer
+
+ ldy #.sizeof (MOUSE_BOX)-1
+ sei
+
+@L1: lda XMin,y
+ sta (ptr1),y
+ dey
+ bpl @L1
+
+ cli
+ rts
+
+;----------------------------------------------------------------------------
+; MOVE: Move the mouse to a new position. The position is passed as it comes
+; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
+; remove the parameter from the stack on return.
; No checks are done if the new position is valid (within the bounding box or
; the screen). No return code required.
;
stx YPos+1 ; New Y position
jsr CMOVEY ; Set it
- lda ptr1
- ldx ptr1+1
- sta XPos
- stx XPos+1 ; New X position
+ ldy #$01
+ lda (sp),y
+ sta XPos+1
+ tax
+ dey
+ lda (sp),y
+ sta XPos ; New X position
jsr CMOVEX ; Move the cursor
;----------------------------------------------------------------------------
; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
-; (so be careful).
+; (so be careful). The routine MUST return carry set if the interrupt has been
+; 'handled' - which means that the interrupt source is gone. Otherwise it
+; MUST return carry clear.
;
IRQ: lda SID_ADConv1 ; Get mouse X movement
; Skip processing if nothing has changed
- tay
- beq @SkipX
+ bcc @SkipX
; Calculate the new X coordinate (--> a/y)
; Move the mouse pointer to the new X pos
tya
- jsr CMOVEY
+ jsr CMOVEX
; Calculate the Y movement vector
@SkipX: lda SID_ADConv2 ; Get mouse Y movement
- ldy OldPotY
- jsr MoveCheck ; Calculate movement
- sty OldPotY
+ ldy OldPotY
+ jsr MoveCheck ; Calculate movement
+ sty OldPotY
; Skip processing if nothing has changed
- tay
- beq @SkipY
+ bcc @SkipY
; Calculate the new Y coordinate (--> a/y)
; Limit the Y coordinate to the bounding box
cpy YMin
- sbc YMin+1
- bpl @L3
+ sbc YMin+1
+ bpl @L3
ldy YMin
ldx YMin+1
jmp @L4
ldy YMax
ldx YMax+1
@L4: sty YPos
- stx YPos+1
+ stx YPos+1
; Move the mouse pointer to the new X pos
tya
- jsr CMOVEX
+ jsr CMOVEY
; Done
+ clc ; Interrupt not handled
@SkipY: rts
; --------------------------------------------------------------------------
sta NewValue
ldx #$00
- sub OldValue ; a = mod64 (new - old)
+ sub OldValue ; a = mod64 (new - old)
and #%01111111
- cmp #%01000000 ; if (a > 0)
- bcs @L1 ;
- lsr a ; a /= 2;
- beq @L2 ; if (a != 0)
- ldy NewValue ; y = NewValue
- rts ; return
-
-@L1: ora #%11000000 ; else or in high order bits
- cmp #$FF ; if (a != -1)
+ cmp #%01000000 ; if (a > 0)
+ bcs @L1 ;
+ lsr a ; a /= 2;
+ beq @L2 ; if (a != 0)
+ ldy NewValue ; y = NewValue
+ sec
+ rts ; return
+
+@L1: ora #%11000000 ; else or in high order bits
+ cmp #$FF ; if (a != -1)
beq @L2
sec
- ror a ; a /= 2
- dex ; high byte = -1 (X = $FF)
+ ror a ; a /= 2
+ dex ; high byte = -1 (X = $FF)
ldy NewValue
+ sec
rts
-@L2: txa ; A = $00
+@L2: txa ; A = $00
+ clc
rts