Inital commit

This commit is contained in:
Quinn Dunki 2015-07-14 18:21:27 -07:00
commit a7943b50ec
15 changed files with 1088 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
mousedemo.lst

BIN
AppleCommander.jar Normal file

Binary file not shown.

32
Makefile Normal file
View File

@ -0,0 +1,32 @@
#
# Makefile
# Mouse driver
#
# Created by Quinn Dunki on 7/14/15.
# One Girl, One Laptop Productions
# http://www.quinndunki.com
# http://www.quinndunki.com/blondihacks
#
CL65=cl65
AC=AppleCommander.jar
ADDR=6000
PGM=mousedemo
all: $(PGM)
$(PGM):
@PATH=$(PATH):/usr/local/bin; $(CL65) -t apple2enh --start-addr $(ADDR) -l$(PGM).lst $(PGM).s
java -jar $(AC) -d $(PGM).dsk $(PGM)
java -jar $(AC) -p $(PGM).dsk $(PGM) BIN 0x$(ADDR) < $(PGM)
rm -f $(PGM)
rm -f $(PGM).o
osascript V2Make.scpt $(PROJECT_DIR) $(PGM)
clean:
rm -f $(PGM)
rm -f $(PGM).o

View File

@ -0,0 +1,199 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXFileReference section */
70355B941B55977F00D79881 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
70355B951B55977F00D79881 /* mouse.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = mouse.s; sourceTree = "<group>"; };
70355B961B55977F00D79881 /* mousedemo.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = mousedemo.s; sourceTree = "<group>"; };
70355B971B55977F00D79881 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
70355B981B5597EC00D79881 /* macros.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = macros.s; sourceTree = "<group>"; };
70355B991B5597EC00D79881 /* switches.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = switches.s; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
70355B891B55975C00D79881 = {
isa = PBXGroup;
children = (
70355B971B55977F00D79881 /* README.md */,
70355B941B55977F00D79881 /* Makefile */,
70355B981B5597EC00D79881 /* macros.s */,
70355B991B5597EC00D79881 /* switches.s */,
70355B951B55977F00D79881 /* mouse.s */,
70355B961B55977F00D79881 /* mousedemo.s */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXLegacyTarget section */
70355B8E1B55975C00D79881 /* Mouse */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "$(ACTION)";
buildConfigurationList = 70355B911B55975C00D79881 /* Build configuration list for PBXLegacyTarget "Mouse" */;
buildPhases = (
);
buildToolPath = /usr/bin/make;
dependencies = (
);
name = Mouse;
passBuildSettingsInEnvironment = 1;
productName = Mouse;
};
/* End PBXLegacyTarget section */
/* Begin PBXProject section */
70355B8A1B55975C00D79881 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0640;
ORGANIZATIONNAME = "Quinn Dunki";
TargetAttributes = {
70355B8E1B55975C00D79881 = {
CreatedOnToolsVersion = 6.4;
};
};
};
buildConfigurationList = 70355B8D1B55975C00D79881 /* Build configuration list for PBXProject "Mouse" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 70355B891B55975C00D79881;
projectDirPath = "";
projectRoot = "";
targets = (
70355B8E1B55975C00D79881 /* Mouse */,
);
};
/* End PBXProject section */
/* Begin XCBuildConfiguration section */
70355B8F1B55975C00D79881 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
70355B901B55975C00D79881 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};
name = Release;
};
70355B921B55975C00D79881 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEBUGGING_SYMBOLS = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
70355B931B55975C00D79881 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
70355B8D1B55975C00D79881 /* Build configuration list for PBXProject "Mouse" */ = {
isa = XCConfigurationList;
buildConfigurations = (
70355B8F1B55975C00D79881 /* Debug */,
70355B901B55975C00D79881 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
70355B911B55975C00D79881 /* Build configuration list for PBXLegacyTarget "Mouse" */ = {
isa = XCConfigurationList;
buildConfigurations = (
70355B921B55975C00D79881 /* Debug */,
70355B931B55975C00D79881 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
/* End XCConfigurationList section */
};
rootObject = 70355B8A1B55975C00D79881 /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Mouse.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0640"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "70355B8E1B55975C00D79881"
BuildableName = "Mouse"
BlueprintName = "Mouse"
ReferencedContainer = "container:Mouse.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "70355B8E1B55975C00D79881"
BuildableName = "Mouse"
BlueprintName = "Mouse"
ReferencedContainer = "container:Mouse.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "70355B8E1B55975C00D79881"
BuildableName = "Mouse"
BlueprintName = "Mouse"
ReferencedContainer = "container:Mouse.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Mouse.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>70355B8E1B55975C00D79881</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

19
README.md Normal file
View File

@ -0,0 +1,19 @@
*Mouse Driver for Apple II computers*
Supports the Apple //e Enhanced with a mouse card in any slot. Also supports Apple //c and //c+. May work on Apple IIgs as well.
<br><br><br>
Known issues
------------
- Hitting Reset during a WeeGUI application will leave your Apple II in an unsafe state.
- Calling WGEraseView on a view that shares border rendering with other views will require manually redrawing those views.
- Included sample ASMDEMO has a slight tendancy to step on ProDOS's buffers. This is mostly harmless.
To Do:
------

BIN
V2Make.scpt Normal file

Binary file not shown.

120
macros.s Normal file
View File

@ -0,0 +1,120 @@
;
; macros.s
; Generally useful macros for 6502 code
;
; Created by Quinn Dunki on 8/15/14.
; Copyright (c) 2014 One Girl, One Laptop Productions. All rights reserved.
;
; Macros
.macro SETSWITCH name ; Sets the named softswitch (assumes write method)
sta name
.endmacro
.macro SAVE_AXY ; Saves all registers
pha
phx
phy
.endmacro
.macro RESTORE_AXY ; Restores all registers
ply
plx
pla
.endmacro
.macro SAVE_AY ; Saves accumulator and Y index
pha
phy
.endmacro
.macro RESTORE_AY ; Restores accumulator and Y index
ply
pla
.endmacro
.macro SAVE_AX ; Saves accumulator and X index
pha
phx
.endmacro
.macro RESTORE_AX ; Restores accumulator and X index
plx
pla
.endmacro
.macro SAVE_XY ; Saves X and Y index
phx
phy
.endmacro
.macro RESTORE_XY ; Restores X and Y index
ply
plx
.endmacro
.macro SAVE_ZPP ; Saves Zero Page locations we use for parameters
lda PARAM0
pha
lda PARAM1
pha
lda PARAM2
pha
lda PARAM3
pha
.endmacro
.macro RESTORE_ZPP ; Restores Zero Page locations we use for parameters
pla
sta PARAM3
pla
sta PARAM2
pla
sta PARAM1
pla
sta PARAM0
.endmacro
.macro SAVE_ZPS ; Saves Zero Page locations we use for scratch
lda SCRATCH0
pha
lda SCRATCH1
pha
.endmacro
.macro RESTORE_ZPS ; Restores Zero Page locations we use for scratch
pla
sta SCRATCH1
pla
sta SCRATCH0
.endmacro
.macro PARAM16 addr
lda #<addr
sta PARAM0
lda #>addr
sta PARAM1
.endmacro
.macro CALL16 func,addr
PARAM16 addr
jsr func
.endmacro

505
mouse.s Normal file
View File

@ -0,0 +1,505 @@
;
; mouse.s
; Mouse driver for Apple //e Enhanced with mouse card (any slot), or Apple //c(+)
;
; Created by Quinn Dunki on 7/14/15.
; Copyright (c) 2014 One Girl, One Laptop Productions. All rights reserved.
;
.include "macros.s"
.include "switches.s"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mouse clamping values. These are set to a convenient one-byte
; range, but you can change to suit your application. If you
; change them, also change the scaling math below (search for SCALING)
; Hardware produces values 0-1023 in both dimensions if not clamped
SCALE_X_IIE = $027f ; 640-1
SCALE_Y_IIE = $02e0 ; 736
; //c tracks much slower, so smaller clamps and no scaling works better
SCALE_X_IIC = $004f ; 8-1
SCALE_Y_IIC = $0017 ; 24-1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ProDOS ROM entry points and constants
;
PRODOS_MLI = $bf00
ALLOC_INTERRUPT = $40
DEALLOC_INTERRUPT = $41
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mouse firmware ROM entry points and constants
;
; These mouse firmware entry points are offsets from the firmware
; entry point of the slot, and also indirect.
SETMOUSE = $12
SERVEMOUSE = $13
READMOUSE = $14
CLEARMOUSE = $15
POSMOUSE = $16
CLAMPMOUSE = $17
HOMEMOUSE = $18
INITMOUSE = $19
MOUSTAT = $0778 ; + Slot Num
MOUSE_XL = $0478 ; + Slot Num
MOUSE_XH = $0578 ; + Slot Num
MOUSE_YL = $04f8 ; + Slot Num
MOUSE_YH = $05f8 ; + Slot Num
MOUSE_CLAMPL = $04f8 ; Upper mouse clamp (LSB). Slot independent.
MOUSE_CLAMPH = $05f8 ; Upper mouse clamp (MSB). Slot independent.
MOUSE_ZEROL = $0478 ; Zero value of mouse (LSB). Slot independent.
MOUSE_ZEROH = $0578 ; Zero value of mouse (MSB). Slot independent.
MOUSTAT_MASK_BUTTONINT = %00000100
MOUSTAT_MASK_MOVEINT = %00000010
MOUSTAT_MASK_DOWN = %10000000
MOUSTAT_MASK_WASDOWN = %01000000
MOUSTAT_MASK_MOVED = %00100000
MOUSEMODE_OFF = $00 ; Mouse off
MOUSEMODE_PASSIVE = $01 ; Passive mode (polling only)
MOUSEMODE_MOVEINT = $03 ; Interrupts on movement
MOUSEMODE_BUTINT = $05 ; Interrupts on button
MOUSEMODE_COMBINT = $07 ; Interrupts on movement and button
; Mouse firmware is all indirectly called, because
; it moved around a lot in different Apple II ROM
; versions. This macro helps abstracts this for us.
.macro CALLMOUSE name
ldx #name
jsr WGCallMouse
.endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGEnableMouse
; Prepares the mouse for use
;
WGEnableMouse:
pha
SETSWITCH PAGE2OFF
; Find slot number and calculate the various indirections needed
jsr WGFindMouse
bcs WGEnableMouse_Error
; Note if we're a //e or //c, because mouse tracking and interrupts are different
lda $fbb3
cmp #$06
bne WGEnableMouse_Error ; II or II+? Sorry...
lda $fbc0
bne WGEnableMouse_IIe
lda #1
sta WG_APPLEIIC
WGEnableMouse_IIe:
; Install our interrupt handler via ProDOS (play nice!)
jsr PRODOS_MLI
.byte ALLOC_INTERRUPT
.addr WG_PRODOS_ALLOC
bne WGEnableMouse_Error ; ProDOS will return here with Z clear on error
; Initialize the mouse
stz WG_MOUSEPOS_X
stz WG_MOUSEPOS_Y
stz WG_MOUSEBG
CALLMOUSE INITMOUSE
bcs WGEnableMouse_Error ; Firmware sets carry if mouse is not available
CALLMOUSE CLEARMOUSE
lda #MOUSEMODE_COMBINT ; Enable combination interrupt mode
CALLMOUSE SETMOUSE
; Set the mouse's zero postion to (1,1), since we're in text screen space
stz MOUSE_ZEROH
lda #0
sta MOUSE_ZEROL
lda #1
CALLMOUSE CLAMPMOUSE
lda #0
CALLMOUSE CLAMPMOUSE
; Scale the mouse's range into something easy to do math with,
; while retaining as much range of motion and precision as possible
lda WG_APPLEIIC
bne WGEnableMouse_ConfigIIc ; Sorry //c, no scaling for you
lda #<SCALE_X_IIE
sta MOUSE_CLAMPL
lda #>SCALE_X_IIE
sta MOUSE_CLAMPH
lda #0
CALLMOUSE CLAMPMOUSE
lda #<SCALE_Y_IIE
sta MOUSE_CLAMPL
lda #>SCALE_Y_IIE
sta MOUSE_CLAMPH
lda #1
CALLMOUSE CLAMPMOUSE
bra WGEnableMouse_Activate
WGEnableMouse_Error:
stz WG_MOUSEACTIVE
WGEnableMouse_done: ; Exit point here for branch range
pla
rts
WGEnableMouse_ConfigIIc: ; //c's tracking is weird. Need to clamp to a much smaller range
lda #<SCALE_X_IIC
sta MOUSE_CLAMPL
lda #>SCALE_X_IIC
sta MOUSE_CLAMPH
lda #0
CALLMOUSE CLAMPMOUSE
lda #<SCALE_Y_IIC
sta MOUSE_CLAMPL
lda #>SCALE_Y_IIC
sta MOUSE_CLAMPH
lda #1
CALLMOUSE CLAMPMOUSE
WGEnableMouse_Activate:
lda #1
sta WG_MOUSEACTIVE
cli ; Once all setup is done, it's safe to enable interrupts
bra WGEnableMouse_done
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGDisableMouse
; Shuts off the mouse when we're done with it
;
WGDisableMouse:
pha
SETSWITCH PAGE2OFF
lda WG_MOUSEACTIVE ; Never activated the mouse
beq WGDisableMouse_done
lda MOUSEMODE_OFF
CALLMOUSE SETMOUSE
stz WG_MOUSEACTIVE
; Remove our interrupt handler via ProDOS (done playing nice!)
lda WG_PRODOS_ALLOC+1 ; Copy interrupt ID that ProDOS gave us
sta WG_PRODOS_DEALLOC+1
jsr PRODOS_MLI
.byte DEALLOC_INTERRUPT
.addr WG_PRODOS_DEALLOC
jsr WGUndrawPointer ; Be nice if we're disabled during a program
WGDisableMouse_done:
pla
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGCallMouse
; Calls a mouse firmware routine. Here's where we handle all
; the layers of indirection needed to call mouse firmware. The
; firmware moved in ROM several times over the life of the
; Apple II, so it's kind of a hassle to call it.
; X: Name of routine (firmware offset constant)
; Side effects: Clobbers all registers
WGCallMouse:
stx WGCallMouse+4 ; Use self-modifying code to smooth out some indirection
; This load address is overwritten by the above code, AND by the mouse set
; up code, to make sure we have the right slot entry point and firmware
; offset
ldx $c400 ; Self-modifying code!
stx WG_MOUSE_JUMPL ; Get low byte of final jump from firmware
php ; Note that mouse firmware is not re-entrant,
sei ; so we must disable interrupts inside them
jsr WGCallMouse_redirect
plp ; Restore interrupts to previous state
rts
WGCallMouse_redirect:
ldx WG_MOUSE_JUMPH
ldy WG_MOUSE_SLOTSHIFTED
jmp (WG_MOUSE_JUMPL)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGFindMouse
; Figures out which slot (//e) or port (//c) the mouse is in.
; It moved around a lot over the years. Sets it to 0 if no mouse
; could be found
; OUT C: Set if no mouse could be found
WGFindMouse:
SAVE_AX
ldx #7
WGFindMouse_loop:
txa ; Compute slot firmware locations for this loop
ora #$c0
sta WGFindMouse_loopModify+2 ; Self-modifying code!
sta WGFindMouse_loopModify+9
sta WGFindMouse_loopModify+16
sta WGFindMouse_loopModify+23
sta WGFindMouse_loopModify+30
WGFindMouse_loopModify:
; Check for the magic 5-byte pattern that gives away the mouse card
lda $c005 ; These addresses are modified in place on
cmp #$38 ; each loop iteration
bne WGFindMouse_nextSlot
lda $c007
cmp #$18
bne WGFindMouse_nextSlot
lda $c00b
cmp #$01
bne WGFindMouse_nextSlot
lda $c00c
cmp #$20
bne WGFindMouse_nextSlot
lda $c0fb
cmp #$d6
bne WGFindMouse_nextSlot
bra WGFindMouse_found
WGFindMouse_nextSlot:
dex
bmi WGFindMouse_none
bra WGFindMouse_loop
WGFindMouse_found:
; Found it! Now configure all our indirection lookups
stx WG_MOUSE_SLOT
lda #$c0
ora WG_MOUSE_SLOT
sta WG_MOUSE_JUMPH
sta WGCallMouse+5 ; Self-modifying code!
txa
asl
asl
asl
asl
sta WG_MOUSE_SLOTSHIFTED
clc
bra WGFindMouse_done
WGFindMouse_none:
stz WG_MOUSE_SLOT
sec
WGFindMouse_done:
RESTORE_AX
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGMouseInterruptHandler
; Handles interrupts that may be related to the mouse
; This is a ProDOS-compliant interrupt handling routine, and
; should be installed and removed via ProDOS as needed.
;
; IMPORTANT: This routine is NOT MLI-reentrant, which means MLI
; calls can NOT be made within this handler. See page 108 of the
; ProDOS 8 Technical Reference Manual if this feature needs to be
; added.
;
WGMouseInterruptHandler:
cld ; ProDOS interrupt handlers must open with this
SAVE_AXY
CALLMOUSE SERVEMOUSE
bcs WGMouseInterruptHandler_disregard
php
sei
lda PAGE2 ; Need to preserve text bank, because we may interrupt rendering
pha
SETSWITCH PAGE2OFF
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Check interrupt status bits first, because READMOUSE clears them
and #MOUSTAT_MASK_BUTTONINT
bne WGMouseInterruptHandler_button
jsr WGUndrawPointer ; Erase the old mouse pointer
; Read the mouse state. Note that interrupts need to remain
; off until after the data is copied.
CALLMOUSE READMOUSE
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Movement/button status bits are now valid
sta WG_MOUSE_STAT
lda WG_APPLEIIC
bne WGMouseInterruptHandler_IIc
; Read mouse position and transform it into screen space
; SCALING: If you change the clamps, change this division from
; 1024 to match your new values.
lsr MOUSE_XH,x
ror MOUSE_XL,x
lsr MOUSE_XH,x
ror MOUSE_XL,x
lsr MOUSE_XH,x
ror MOUSE_XL,x
lda MOUSE_XL,x
sta WG_MOUSEPOS_X
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lsr MOUSE_YH,x
ror MOUSE_YL,x
lda MOUSE_YL,x
sta WG_MOUSEPOS_Y
bra WGMouseInterruptHandler_draw
WGMouseInterruptHandler_IIc: ; IIc tracks much slower, so don't scale
lda MOUSE_XL,x
sta WG_MOUSEPOS_X
lda MOUSE_YL,x
sta WG_MOUSEPOS_Y
WGMouseInterruptHandler_draw:
jsr WGDrawPointer ; Redraw the pointer
bra WGMouseInterruptHandler_intDone
WGMouseInterruptHandler_disregard:
; Carry will still be set here, to notify ProDOS that
; this interrupt was not ours
RESTORE_AXY
rts
WGMouseInterruptHandler_button:
CALLMOUSE READMOUSE
ldx WG_MOUSE_SLOT
lda MOUSTAT,x ; Movement/button status bits are now valid
sta WG_MOUSE_STAT
bit WG_MOUSE_STAT ; Check for rising edge of button state
bpl WGMouseInterruptHandler_intDone
bvs WGMouseInterruptHandler_intDone ; Held, so ignore (//c only, but more elegant code to leave in for both)
; Button went down, so make a note of location for later
lda WG_MOUSEPOS_X
sta WG_MOUSECLICK_X
lda WG_MOUSEPOS_Y
sta WG_MOUSECLICK_Y
WGMouseInterruptHandler_intDone:
pla ; Restore text bank
bpl WGMouseInterruptHandler_intDoneBankOff
SETSWITCH PAGE2ON
bra WGMouseInterruptHandler_done
WGMouseInterruptHandler_intDoneBankOff:
SETSWITCH PAGE2OFF
WGMouseInterruptHandler_done:
RESTORE_AXY
plp
clc ; Notify ProDOS this was our interrupt
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGUndrawPointer
; Unplots the mouse pointer at current location
; Stub for your use
;
WGUndrawPointer:
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WGDrawPointer
; Plots the mouse pointer at current location
; Stub for your use
;
WGDrawPointer:
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Mouse API state
;
; Useful things you can poll in your code:
WG_MOUSEACTIVE:
.byte 0
WG_MOUSEPOS_X:
.byte 39
WG_MOUSEPOS_Y:
.byte 11
WG_MOUSECLICK_X:
.byte $ff
WG_MOUSECLICK_Y:
.byte 0
; Internal state for the driver (no touchy!)
WG_MOUSE_STAT:
.byte 0
WG_MOUSEBG:
.byte 0
WG_APPLEIIC:
.byte 0
WG_MOUSE_JUMPL:
.byte 0
WG_MOUSE_JUMPH:
.byte 0
WG_MOUSE_SLOT:
.byte 0
WG_MOUSE_SLOTSHIFTED:
.byte 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ProDOS system call parameter blocks
;
WG_PRODOS_ALLOC:
.byte 2
.byte 0 ; ProDOS returns an ID number for the interrupt here
.addr WGMouseInterruptHandler
WG_PRODOS_DEALLOC:
.byte 1
.byte 0 ; To be filled with ProDOS ID number

BIN
mousedemo.dsk Normal file

Binary file not shown.

74
mousedemo.s Normal file
View File

@ -0,0 +1,74 @@
;
; mousedemo.s
; Mouse driver sample application
;
; Created by Quinn Dunki on 7/14/15.
; Copyright (c) 2015 One Girl, One Laptop Productions. All rights reserved.
;
.org $6000
COUT = $fded
PRBYTE = $fdda
main: ; BRUN lands here
jsr WGEnableMouse
loop:
; Print current mouse position
lda #'X' + $80
jsr COUT
lda #'=' + $80
jsr COUT
lda WG_MOUSEPOS_X
jsr PRBYTE
lda #' ' + $80
jsr COUT
lda #'Y' + $80
jsr COUT
lda #'=' + $80
jsr COUT
lda WG_MOUSEPOS_Y
jsr PRBYTE
lda WG_MOUSECLICK_X
bmi lineDone
lda #' ' + $80
jsr COUT
lda #'!' + $80
jsr COUT
lda #$ff
sta WG_MOUSECLICK_X
lineDone:
lda #13 + $80
jsr COUT
; Check for any key to quit
lda KBD
bpl loop ; No key pending
; Clean up and return to BASIC
sta KBDSTRB ; Clear strobe
jsr WGDisableMouse
rts
.include "mouse.s"
; Suppress some linker warnings - Must be the last thing in the file
; This is because Quinn doesn't really know how to use ca65 properly
.SEGMENT "ZPSAVE"
.SEGMENT "EXEHDR"
.SEGMENT "STARTUP"
.SEGMENT "INIT"
.SEGMENT "LOWCODE"

32
switches.s Normal file
View File

@ -0,0 +1,32 @@
;
; switches.s
; Softswitches for Apple ][
;
; Created by Quinn Dunki on 8/15/14.
; Copyright (c) 2014 One Girl, One Laptop Productions. All rights reserved.
;
PAGE2 = $c01c ; Read bit 7
PAGE2OFF = $c054 ; Read/Write
PAGE2ON = $c055 ; Read/Write
COL80 = $c01f ; Read bit 7
COL80OFF = $c00c ; Write
COL80ON = $c00d ; Write
STORE80 = $c018 ; Read bit 7
STORE80OFF = $c000 ; Write
STORE80ON = $c001 ; Write
TEXT = $c01a ; Read bit 7
TEXTOFF = $c050 ; Read/Write
TEXTON = $C051 ; Read/Write
KBD = $c000 ; Read
KBDSTRB = $c010 ; Read/Write
RDVBLBAR = $C019 ; Read bit 7 (active low)
OURCH = $057b ; 80 col cursor position (H)
OURCV = $05fb ; 80 col cursor position (V)