412 lines
8.7 KiB
ArmAsm
412 lines
8.7 KiB
ArmAsm
|
;
|
||
|
; Driver for the AppleMouse II Card.
|
||
|
;
|
||
|
; Oliver Schmidt, 03.09.2005
|
||
|
;
|
||
|
|
||
|
.include "zeropage.inc"
|
||
|
.include "mouse-kernel.inc"
|
||
|
|
||
|
; ------------------------------------------------------------------------
|
||
|
|
||
|
SETMOUSE = $12 ; Sets mouse mode
|
||
|
SERVEMOUSE = $13 ; Services mouse interrupt
|
||
|
READMOUSE = $14 ; Reads mouse position
|
||
|
CLEARMOUSE = $15 ; Clears mouse position to 0 (for delta mode)
|
||
|
POSMOUSE = $16 ; Sets mouse position to a user-defined pos
|
||
|
CLAMPMOUSE = $17 ; Sets mouse bounds in a window
|
||
|
HOMEMOUSE = $18 ; Sets mouse to upper-left corner of clamp win
|
||
|
INITMOUSE = $19 ; Resets mouse clamps to default values and
|
||
|
; sets mouse position to 0,0
|
||
|
|
||
|
pos1_lo := $0478
|
||
|
pos1_hi := $0578
|
||
|
pos2_lo := $04F8
|
||
|
pos2_hi := $05F8
|
||
|
status := $0778
|
||
|
|
||
|
; ------------------------------------------------------------------------
|
||
|
|
||
|
.segment "JUMPTABLE"
|
||
|
|
||
|
; Driver signature
|
||
|
.byte $6D, $6F, $75 ; "mou"
|
||
|
.byte MOUSE_API_VERSION ; Mouse driver API version number
|
||
|
|
||
|
; Jump table.
|
||
|
.addr INSTALL
|
||
|
.addr UNINSTALL
|
||
|
.addr HIDE
|
||
|
.addr SHOW
|
||
|
.addr BOX
|
||
|
.addr MOVE
|
||
|
.addr BUTTONS
|
||
|
.addr POS
|
||
|
.addr INFO
|
||
|
.addr IOCTL
|
||
|
.addr IRQ
|
||
|
|
||
|
; Callback table, set by the kernel before INSTALL is called
|
||
|
CHIDE: jmp $0000 ; Hide the cursor
|
||
|
CSHOW: jmp $0000 ; Show the cursor
|
||
|
CMOVEX: jmp $0000 ; Move the cursor to X coord
|
||
|
CMOVEY: jmp $0000 ; Move the cursor to Y coord
|
||
|
|
||
|
; ------------------------------------------------------------------------
|
||
|
|
||
|
.bss
|
||
|
|
||
|
slot: .res 1
|
||
|
visible:.res 1
|
||
|
|
||
|
; ------------------------------------------------------------------------
|
||
|
|
||
|
.rodata
|
||
|
|
||
|
offsets:.byte $05 ; Pascal 1.0 ID byte
|
||
|
.byte $07 ; Pascal 1.0 ID byte
|
||
|
.byte $0B ; Pascal 1.1 generic signature byte
|
||
|
.byte $0C ; Device signature byte
|
||
|
|
||
|
values: .byte $38 ; Fixed
|
||
|
.byte $18 ; Fixed
|
||
|
.byte $01 ; Fixed
|
||
|
.byte $20 ; X-Y pointing device type 0
|
||
|
|
||
|
size = * - values
|
||
|
|
||
|
; ------------------------------------------------------------------------
|
||
|
|
||
|
.data
|
||
|
|
||
|
info: .word 279 / 2 ; MOUSE_INFO::MOUSE_POS::XCOORD
|
||
|
.word 191 / 2 ; MOUSE_INFO::MOUSE_POS::YCOORD
|
||
|
.byte %00000000 ; MOUSE_INFO::BUTTONS
|
||
|
|
||
|
firmware:
|
||
|
; Lookup and patch firmware address lobyte
|
||
|
lookup: ldy $FF00,x ; Patched at runtime
|
||
|
sty jump+1 ; Modify code below
|
||
|
|
||
|
; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
|
||
|
; "Enter all mouse routines (...) with the X register set to $Cn
|
||
|
; and Y register set to $n0, where n = the slot number."
|
||
|
xparam: ldx #$FF ; Patched at runtime
|
||
|
yparam: ldy #$FF ; Patched at runtime
|
||
|
|
||
|
jump: jmp $FFFF ; Patched at runtime
|
||
|
|
||
|
; ------------------------------------------------------------------------
|
||
|
|
||
|
.code
|
||
|
|
||
|
; INSTALL: Is called after the driver is loaded into memory. If possible,
|
||
|
; check if the hardware is present. Must return an MOUSE_ERR_xx code in A/X.
|
||
|
INSTALL:
|
||
|
lda #<$C000
|
||
|
sta ptr1
|
||
|
lda #>$C000
|
||
|
sta ptr1+1
|
||
|
|
||
|
; Search for AppleMouse II firmware in slots 1 - 7
|
||
|
next: inc ptr1+1
|
||
|
lda ptr1+1
|
||
|
cmp #>$C800
|
||
|
bcc :+
|
||
|
|
||
|
; Mouse firmware not found
|
||
|
lda #<MOUSE_ERR_NO_DEVICE
|
||
|
ldx #>MOUSE_ERR_NO_DEVICE
|
||
|
rts
|
||
|
|
||
|
; Check Pascal 1.1 Firmware Protocol ID bytes
|
||
|
: ldx #size - 1
|
||
|
: ldy offsets,x
|
||
|
lda values,x
|
||
|
cmp (ptr1),y
|
||
|
bne next
|
||
|
dex
|
||
|
bpl :-
|
||
|
|
||
|
; Get and patch firmware address hibyte
|
||
|
lda ptr1+1
|
||
|
sta lookup+2
|
||
|
sta xparam+1
|
||
|
sta jump+2
|
||
|
|
||
|
; Convert to and save slot number
|
||
|
and #$0F
|
||
|
sta slot
|
||
|
|
||
|
; Convert to and patch I/O register index
|
||
|
asl
|
||
|
asl
|
||
|
asl
|
||
|
asl
|
||
|
sta yparam+1
|
||
|
|
||
|
; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
|
||
|
; "Disable interrupts when calling any mouse routine."
|
||
|
sei
|
||
|
|
||
|
; Reset mouse hardware
|
||
|
ldx #INITMOUSE
|
||
|
jsr firmware
|
||
|
|
||
|
; Turn mouse on
|
||
|
lda #%00000001
|
||
|
ldx #SETMOUSE
|
||
|
jsr firmware
|
||
|
|
||
|
; Set initial mouse clamps
|
||
|
lda #<279
|
||
|
ldx #>279
|
||
|
sta pos2_lo
|
||
|
stx pos2_hi
|
||
|
lda #$00 ; Set x clamps
|
||
|
sta pos1_lo
|
||
|
sta pos1_hi
|
||
|
ldx #CLAMPMOUSE
|
||
|
jsr firmware
|
||
|
lda #<191
|
||
|
ldx #>191
|
||
|
sta pos2_lo
|
||
|
stx pos2_hi
|
||
|
lda #$01 ; Set y clamps
|
||
|
ldx #CLAMPMOUSE
|
||
|
jsr firmware
|
||
|
|
||
|
; Set initial mouse position
|
||
|
ldx slot
|
||
|
lda #<(279 / 2)
|
||
|
sta pos1_lo,x
|
||
|
lda #>(279 / 2)
|
||
|
sta pos1_hi,x
|
||
|
lda #<(191 / 2)
|
||
|
sta pos2_lo,x
|
||
|
lda #>(191 / 2)
|
||
|
sta pos2_hi,x
|
||
|
ldx #POSMOUSE
|
||
|
jsr firmware
|
||
|
|
||
|
; Turn VBL interrupt on
|
||
|
lda #%00001001
|
||
|
ldx #SETMOUSE
|
||
|
common: jsr firmware
|
||
|
|
||
|
; Enable interrupts and return success
|
||
|
cli
|
||
|
lda #<MOUSE_ERR_OK
|
||
|
ldx #>MOUSE_ERR_OK
|
||
|
rts
|
||
|
|
||
|
; UNINSTALL: Is called before the driver is removed from memory.
|
||
|
; No return code required (the driver is removed from memory on return).
|
||
|
UNINSTALL:
|
||
|
; Hide cursor
|
||
|
sei
|
||
|
jsr CHIDE
|
||
|
|
||
|
; Turn mouse off
|
||
|
lda #%00000000
|
||
|
ldx #SETMOUSE
|
||
|
bne common ; Branch always
|
||
|
|
||
|
; HIDE: Is called to hide the mouse cursor. The mouse kernel manages a
|
||
|
; counter for calls to show/hide, and the driver entry point is only called
|
||
|
; if the mouse is currently visible and should get hidden. For most drivers,
|
||
|
; no special action is required besides hiding the mouse cursor.
|
||
|
; No return code required.
|
||
|
HIDE:
|
||
|
dec visible
|
||
|
sei
|
||
|
jsr CHIDE
|
||
|
cli
|
||
|
rts
|
||
|
|
||
|
; SHOW: Is called to show the mouse cursor. The mouse kernel manages a
|
||
|
; counter for calls to show/hide, and the driver entry point is only called
|
||
|
; if the mouse is currently hidden and should become visible. For most drivers,
|
||
|
; no special action is required besides enabling the mouse cursor.
|
||
|
; No return code required.
|
||
|
SHOW:
|
||
|
inc visible
|
||
|
rts
|
||
|
|
||
|
; BOX: Set the mouse bounding box. The parameters are passed as they come from
|
||
|
; the C program, that is, maxy in A/X and the other parameters on the stack.
|
||
|
; The C wrapper will remove the parameters from the stack when the driver
|
||
|
; routine returns.
|
||
|
; 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.
|
||
|
BOX:
|
||
|
; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
|
||
|
; "Disable interrupts before placing position information in the screen holes."
|
||
|
sei
|
||
|
|
||
|
; Set high clamp
|
||
|
sta pos2_lo
|
||
|
txa
|
||
|
|
||
|
ldx #$01 ; Set y clamps
|
||
|
ldy #$00 ; Start at top of stack
|
||
|
jsr :+
|
||
|
|
||
|
ldx #$00 ; Set x clamps
|
||
|
ldy #$00 ; Start at top of stack
|
||
|
|
||
|
; Set high clamp
|
||
|
lda (sp),y
|
||
|
iny
|
||
|
sei
|
||
|
sta pos2_lo
|
||
|
lda (sp),y
|
||
|
iny
|
||
|
: sta pos2_hi
|
||
|
|
||
|
; Skip one parameter
|
||
|
iny
|
||
|
iny
|
||
|
|
||
|
; Set low clamp
|
||
|
lda (sp),y
|
||
|
iny
|
||
|
sta pos1_lo
|
||
|
lda (sp),y
|
||
|
sta pos1_hi
|
||
|
|
||
|
txa
|
||
|
ldx #CLAMPMOUSE
|
||
|
bne common ; Branch always
|
||
|
|
||
|
; 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.
|
||
|
MOVE:
|
||
|
ldy slot
|
||
|
sei
|
||
|
|
||
|
; Set y
|
||
|
sta pos2_lo,y
|
||
|
txa
|
||
|
sta pos2_hi,y
|
||
|
|
||
|
tya
|
||
|
tax
|
||
|
ldy #$00 ; Start at top of stack
|
||
|
|
||
|
; Set x
|
||
|
lda (sp),y
|
||
|
iny
|
||
|
sta pos1_lo,x
|
||
|
lda (sp),y
|
||
|
sta pos1_hi,x
|
||
|
|
||
|
; Update cursor
|
||
|
jsr update
|
||
|
|
||
|
ldx #POSMOUSE
|
||
|
bne common ; Branch always
|
||
|
|
||
|
; BUTTONS: Return the button mask in A/X.
|
||
|
BUTTONS:
|
||
|
lda info + MOUSE_INFO::BUTTONS
|
||
|
ldx #$00
|
||
|
rts
|
||
|
|
||
|
; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
|
||
|
; No return code required.
|
||
|
POS:
|
||
|
ldx #.sizeof(MOUSE_POS)-1
|
||
|
bne copy ; Branch always
|
||
|
|
||
|
; INFO: Returns mouse position and current button mask in the MOUSE_INFO
|
||
|
; struct pointed to by ptr1. No return code required.
|
||
|
INFO:
|
||
|
ldx #.sizeof(MOUSE_INFO)-1
|
||
|
copy: txa
|
||
|
tay
|
||
|
sei
|
||
|
: lda info,x
|
||
|
sta (ptr1),y
|
||
|
dex
|
||
|
dey
|
||
|
bpl :-
|
||
|
cli
|
||
|
rts
|
||
|
|
||
|
; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
|
||
|
; specific data in ptr1, and the ioctl code in A.
|
||
|
; Must return an MOUSE_ERR_xx code in A/X.
|
||
|
IOCTL:
|
||
|
lda #<MOUSE_ERR_INV_IOCTL
|
||
|
ldx #>MOUSE_ERR_INV_IOCTL
|
||
|
rts
|
||
|
|
||
|
; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
|
||
|
; registers are already saved, no parameters are passed, but the carry flag
|
||
|
; is clear on entry. The routine must return with carry set if the interrupt
|
||
|
; was handled, otherwise with carry clear.
|
||
|
IRQ:
|
||
|
; Check for mouse interrupt
|
||
|
ldx #SERVEMOUSE
|
||
|
jsr firmware
|
||
|
bcc :+
|
||
|
clc ; Interrupt not handled
|
||
|
rts
|
||
|
|
||
|
: ldx #READMOUSE
|
||
|
jsr firmware
|
||
|
|
||
|
; Get status
|
||
|
ldy slot
|
||
|
lda status,y
|
||
|
tax ; Save status
|
||
|
|
||
|
; Extract button down values
|
||
|
asl ; C = Button 0 is currently down
|
||
|
and #%00100000 ; !Z = Button 1 is currently down
|
||
|
|
||
|
; Set button mask
|
||
|
beq :+
|
||
|
lda #MOUSE_BTN_RIGHT
|
||
|
: bcc :+
|
||
|
ora #MOUSE_BTN_LEFT
|
||
|
: sta info + MOUSE_INFO::BUTTONS
|
||
|
|
||
|
; Check for mouse movement
|
||
|
txa ; Restore status
|
||
|
and #%00100000 ; X or Y changed since last READMOUSE
|
||
|
beq :+
|
||
|
|
||
|
; Remove the cursor at the old position
|
||
|
update: jsr CHIDE
|
||
|
|
||
|
; Get and set the new X position
|
||
|
ldy slot
|
||
|
lda pos1_lo,y
|
||
|
ldx pos1_hi,y
|
||
|
sta info + MOUSE_POS::XCOORD
|
||
|
stx info + MOUSE_POS::XCOORD+1
|
||
|
jsr CMOVEX
|
||
|
|
||
|
; Get and set the new Y position
|
||
|
ldy slot
|
||
|
lda pos2_lo,y
|
||
|
ldx pos2_hi,y
|
||
|
sta info + MOUSE_POS::YCOORD
|
||
|
stx info + MOUSE_POS::YCOORD+1
|
||
|
jsr CMOVEY
|
||
|
|
||
|
; Check for visibility
|
||
|
: lda visible
|
||
|
beq :+
|
||
|
|
||
|
; Draw the cursor at the new position
|
||
|
jsr CSHOW
|
||
|
: sec ; Interrupt handled
|
||
|
rts
|