spun mouse rom to its own .asm file; fixed PR# and IN# behavior in the mouse driver

This commit is contained in:
Jorj Bauer 2021-01-13 22:03:30 -05:00
parent e63b21d7c0
commit 7028e1dfd2
8 changed files with 436 additions and 174 deletions

View File

@ -20,7 +20,7 @@ SDLSRCS=sdl/sdl-speaker.cpp sdl/sdl-display.cpp sdl/sdl-keyboard.cpp sdl/sdl-pad
SDLOBJS=sdl/sdl-speaker.o sdl/sdl-display.o sdl/sdl-keyboard.o sdl/sdl-paddles.o nix/nix-filemanager.o sdl/aiie.o sdl/sdl-printer.o nix/nix-clock.o nix/nix-prefs.o nix/debugger.o nix/disassembler.o sdl/sdl-mouse.o
ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h apple/hd32-rom.h
ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h apple/hd32-rom.h apple/mouse-rom.h
.PHONY: roms clean
@ -39,8 +39,8 @@ test: $(TSRC)
./testharness -f tests/65C02_extended_opcodes_test.bin -s 0x400 && \
./testharness -f tests/65c02-all.bin -s 0x200
roms: apple2e.rom disk.rom parallel.rom HDDRVR.BIN
./util/genrom.pl apple2e.rom disk.rom parallel.rom HDDRVR.BIN
roms: apple2e.rom disk.rom parallel.rom HDDRVR.BIN mouse.rom
./util/genrom.pl apple2e.rom disk.rom parallel.rom HDDRVR.BIN mouse.rom
apple/applemmu-rom.h: roms
@ -48,6 +48,8 @@ apple/diskii-rom.h: roms
apple/parallel-rom.h: roms
apple/mouse-rom.h: roms
clean:
rm -f *.o *~ */*.o */*~ testharness.basic testharness.verbose testharness.extended testharness apple/diskii-rom.h apple/applemmu-rom.h apple/parallel-rom.h aiie-sdl *.d */*.d

36
apple/manual-linker.pl Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/perl
# The ca65 assembler honors .ORG statements - but the ld65 assembler
# then destroys them. I haven't figured out how to make its config
# do what I want yet, so this is brute force...
#
# This script takes the listing output from ca65 and generates the
# final binary object, like so:
#
# ca65 --target apple2enh mouserom.asm --listing mouserom.lst --list-bytes 50
# ./manual-linker.pl < mouserom.lst > out.bin
use strict;
use warnings;
my @memory;
while (<STDIN>) {
chomp;
if (/^(......)\s\s[12]\s\s(.+)/) {
my $addr = hex($1);
my $rest = $2;
my @data;
while ($rest =~ /^([0-9A-F][0-9A-F])\s+(.+)/) {
$memory[$addr] = hex($1);
$addr++;
$rest = $2;
}
}
}
# Specifcally, memory $C400..$C4FF gets dumped
foreach my $i (0xC400..0xC4FF) {
$memory[$i] ||= 0;
print chr($memory[$i]);
}

39
apple/mouse-rom.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef TEENSYDUINO
#define PROGMEM
#endif
static
uint8_t romData[256] PROGMEM = {
0x2C, 0x58, 0xFF, 0x70, 0x1B, 0x38, 0x90, 0x18,
0xB8, 0x50, 0x15, 0x01, 0x20, 0x68, 0x68, 0x68,
0x68, 0x00, 0x60, 0x6A, 0x7B, 0x80, 0x85, 0x8A,
0x93, 0x98, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
0x48, 0x98, 0x48, 0x8A, 0x48, 0x08, 0x78, 0x20,
0x58, 0xFF, 0xBA, 0xBD, 0x00, 0x01, 0xAA, 0x0A,
0x0A, 0x0A, 0x0A, 0xA8, 0x28, 0x50, 0x0F, 0xA5,
0x38, 0xD0, 0x0D, 0x8A, 0x45, 0x39, 0xD0, 0x08,
0xA9, 0x05, 0x85, 0x38, 0xD0, 0x0B, 0xB0, 0x09,
0x68, 0xAA, 0x68, 0xEA, 0x68, 0x99, 0x80, 0xC0,
0x60, 0x99, 0x81, 0xC0, 0x68, 0xBD, 0x38, 0x06,
0xAA, 0x68, 0xA8, 0x68, 0xBD, 0x00, 0x02, 0x60,
0xC9, 0x0A, 0xB0, 0x04, 0x8D, 0xCF, 0xC0, 0x60,
0x38, 0x60, 0x48, 0x78, 0x8D, 0xCE, 0xC0, 0xA2,
0x04, 0xBD, 0xB8, 0x06, 0x29, 0x0E, 0xD0, 0x01,
0x38, 0x68, 0x60, 0x8D, 0xCB, 0xC0, 0x18, 0x60,
0x8D, 0xCA, 0xC0, 0x18, 0x60, 0x8D, 0xC9, 0xC0,
0x18, 0x60, 0xC9, 0x02, 0xB0, 0xDA, 0x8D, 0xCD,
0xC0, 0x18, 0x60, 0x8D, 0xC8, 0xC0, 0x18, 0x60,
0x8D, 0xCC, 0xC0, 0x18, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xD6, 0x00, 0x00, 0x00, 0x01,
};

View File

@ -2,8 +2,15 @@
#include <string.h>
#include "globals.h"
// This ROM is part of the Aiie source code, but it was compiled and
// bundled as a binary. If you want to see what it's doing, take a
// look at mouserom.asm.
#include "mouse-rom.h"
enum {
SW_W_INIT = 0x00,
SW_W_INITPR = 0x00,
SW_W_HANDLEIN = 0x01,
SW_R_HOMEMOUSE = 0x08,
SW_R_POSMOUSE = 0x09,
SW_R_CLEARMOUSE = 0x0A,
@ -14,11 +21,6 @@ enum {
SW_W_SETMOUSE = 0x0F
};
// The first 3 soft switch bits technically should pass directly to
// the PIA6821. In practice, so far, I've only seen the first (SW_W_INIT)
// used when PR#4 is invoked to initialize the mouse interface from DOS,
// so for the moment I'll just catch that specifically.
enum {
ST_MOUSEENABLE = 0x01,
ST_INTMOUSE = 0x02,
@ -58,12 +60,32 @@ void Mouse::Reset()
{
}
void Mouse::performHack()
{
char buf[20];
uint16_t xpos, ypos;
g_mouse->getPosition(&xpos, &ypos);
bool curButton = g_mouse->getButton();
static bool prevButton = false;
bool isKeyPressed = ((AppleMMU *)(g_vm->getMMU()))->readDirect(0xC010, 0) & 0x80 ? true : false;
uint8_t buttonPressData = (curButton ? 1 : 3) + (prevButton ? 0 : 1);
sprintf(buf, "%d,%d,%s%d\015", xpos, ypos,
isKeyPressed ? "-" : "",
buttonPressData);
for (int i=0; i<strlen(buf); i++) {
g_vm->getMMU()->write(0x200 + i, buf[i] | 0x80);
}
// Put the string length in 0x638+$c0+n == $6FC for slot #4.
// The caller will pick that up and return it as the length of the buffer,
// which that caller will interpret as the next byte it has to display to
// the screen in the GETLN call; and since it's a return, it will display
// *nothing* and start parsing the string immediately.
g_vm->getMMU()->write(0x6fc, strlen(buf)-1);
}
uint8_t Mouse::readSwitches(uint8_t s)
{
switch (s) {
default:
printf("mouse: unknown switch read 0x%X\n", s);
};
return 0xFF;
}
@ -74,6 +96,17 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v)
* modify any state inside the VM directly -- but it's important (per docs)
* that we return A, X, and Y as they were when we were called. So these
* are all now writes, which don't modify A/X/Y. */
case SW_W_INITPR:
v &= 0x01;
//printf("Simple init: value is 0x%X\n", v);
g_vm->getMMU()->write(0x7f8 + 4, v);
break;
case SW_W_HANDLEIN:
performHack();
break;
case SW_R_HOMEMOUSE:
g_mouse->setPosition( (g_vm->getMMU()->read(0x578) << 8) | g_vm->getMMU()->read(0x478),
(g_vm->getMMU()->read(0x5F8) << 8) | g_vm->getMMU()->read(0x4F8)
@ -127,12 +160,6 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v)
g_vm->getMMU()->write(0x6B8+4, interruptsTriggered); // hack to appease ROM
interruptsTriggered = 0;
break;
case SW_W_INIT:
v &= 0x03; // just the low 3 bits apparently?
// printf("Simple init: value is 0x%X\n", v);
status = v;
g_vm->getMMU()->write(0x7f8 + 4, v);
break;
case SW_W_CLAMPMOUSE:
{
uint16_t lowval = (g_vm->getMMU()->read(0x578) << 8) | (g_vm->getMMU()->read(0x478));
@ -165,168 +192,24 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v)
void Mouse::loadROM(uint8_t *toWhere)
{
/* This is a custom-built ROM which hands off control to the C++ code via
* soft switch writes. It's hard-coded to work with the mouse in Slot 4.
*
* ; $c400 is the entry point for PR#4
* $C400 2C 58 FF BIT $FF58
* $C403 70 1B BVS IOHandler
* ; $c405 is the entry point for IN#4 when we set KSW
* $C405 38 SEC
* $C406 90 18 BCC IOHandler
* $C408 B8 CLV
* $C409 50 15 BVC IOHandler ; always branch
* $C40B 01 20 8D 8D 8D ; data (ID bytes & such)
* $C410 8D 00 60 68 76 7B 80 85 ; data (lookup table of entrypoints)
* $C418 8F 94 8D 8D 8D 8D 8D 8D ; data (lookup table of entrypoints)
* ; IOHandler ORG $c420
* $C420 48 PHA ; save registers on stack
* $C421 98 TYA
* $C422 48 PHA
* $C423 8A TXA
* $C424 48 PHA
* $C425 08 PHP
* $C426 78 SEI ; disable interrupts
* $C427 20 58 FF JSR $FF58 ; JSR to this well-known location that has
* $C42A BA TSX ; an RTS (normally). Then when we get
* $C42B BD 00 01 LDA $100,X ; back, pull our address off the stack
* $C42E AA TAX ; and save the high byte in X
* $C42F 0A ASL
* $C430 0A ASL
* $C431 0A ASL
* $C432 0A ASL
* $C433 A8 TAY ; and (high byte << 4) in Y
* $C434 28 PLP ; restore interrupt state
* $C435 50 0F BVC $C446
* $C437 A5 38 LDA $0
* $C439 D0 0D BNE $C448
* $C43B 8A TXA
* $C43C 45 39 EOR $0
* $C43E D0 08 BNE $C448
* $C440 A9 05 LDA #$0
* $C442 85 38 STA $0
* $C444 D0 0B BNE SendInputToDOS
* $C446 B0 09 BCS SendInputToDOS
* $C448 68 PLA ; restore registers
* $C449 AA TAX
* $C44A 68 PLA
* $C44B EA NOP
* $C44C 68 PLA
* $C44D EA NOP
* $C44E EA NOP
* $C44F EA NOP
* $C450 60 RTS
* ; SendInputToDOS ORG $c451
* $C451 EA NOP
* $C452 EA NOP
* $C453 EA NOP
* $C454 68 PLA
* $C455 BD 38 06 LDA $638,X ; X is $C4, so this is $6F8+n - which is
* $C458 AA TAX ; a reserved hole
* $C459 68 PLA
* $C45A A8 TAY
* $C45B 68 PLA
* $C45C BD 00 02 LDA $200,X ; keyboard buffer output
* $C45F 60 RTS
* ; SetMouse ORG $c460
* $C460 C9 10 CMP #$0
* $C462 B0 29 BCS ExitWithError
* $C464 8D CF C0 STA $C0CF ; soft switch 0x0F invokes SetMouse
* $C467 60 RTS
* ; ServeMouse ORG $c468
* $C468 48 PHA
* $C469 18 CLC ; use CLC/BCC to force relative jump
* $C46A 90 2D BCC ServeMouseWorker
* ; ServeMouseExit ORG $c46c
* $C46C BD B8 06 LDA $6B8,X ; check what interrupts we say we serviced
* $C46F 29 0E AND #$0
* $C471 D0 01 BNE $C474 ; if we serviced any, leave carry clear
* $C473 38 SEC ; but set carry if we serviced none
* $C474 68 PLA
* $C475 60 RTS
* ; ReadMouse ORG $c476
* $C476 8D CB C0 STA $C0CB ; soft switch 0x0B
* $C479 18 CLC
* $C47A 60 RTS
* ; ClearMouse ORG $c47b
* $C47B 8D CA C0 STA $C0CA ; soft switch 0x0A
* $C47E 18 CLC
* $C47F 60 RTS
* ; PosMouse ORG $c480
* $C480 8D C9 C0 STA $C0C9 ; soft switch 0x09
* $C483 18 CLC
* $C484 60 RTS
* ; ClampMouse ORG $c485
* $C485 C9 02 CMP #$0
* $C487 B0 04 BCS $C48D
* $C489 8D CD C0 STA $C0CD ; soft switch 0x0D
* $C48C 60 RTS
* ; ExitWithError ORG $c48d
* $C48D 38 SEC ; the spec says carry is set on errors
* $C48E 60 RTS
* ; HomeMouse ORG $c48f
* $C48F 8D C8 C0 STA $C0C8 ; soft switch 0x08
* $C492 18 CLC
* $C493 60 RTS
* ; InitMouse ORG $c494
* $C494 8D CC C0 STA $C0CC ; soft switch 0x0C
* $C497 18 CLC
* $C498 60 RTS
* ; ServeMouseWorker ORG $c499
* $C499 78 SEI ; disable interrupts
* $C49A 8D CE C0 STA $C0CE ; soft switch 0x0E
* $C49D A2 04 LDX #$0
* $C49F 18 CLC
* $C4A0 90 CA BCC ServeMouseExit ; force relative jump
* ; $C4A2..C4FA is dead space (all $FF)
* $C4FB D6 FF FF FF 01 ; data (ID bytes)
*/
uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, // C400
0xb8, 0x50, 0x15, 0x01, 0x20, 0x8d, 0x8d, 0x8d,
0x8d, 0x00, 0x60, 0x68, 0x76, 0x7b, 0x80, 0x85, // C410
0x8f, 0x94, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
0x48, 0x98, 0x48, 0x8a, 0x48, 0x08, 0x78, 0x20, // C420
0x58, 0xFF, 0xBA, 0xBD, 0x00, 0x01, 0xAA, 0x0A,
0x0A, 0x0A, 0x0A, 0xA8, 0x28, 0x50, 0x0F, 0xA5, // C430
0x38, 0xd0, 0x0d, 0x8a, 0x45, 0x39, 0xd0, 0x08,
0xa9, 0x05, 0x85, 0x38, 0xd0, 0x0b, 0xb0, 0x09, // C440
0x68, 0xaa, 0x68, 0xea, 0x68, 0xea, 0xea, 0xea,
0x60, 0xea, 0xea, 0xea, 0x68, 0xbd, 0x38, 0x06, // C450
0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60,
0xc9, 0x10, 0xb0, 0x29, 0x8d, 0xcf, 0xc0, 0x60, // C460
0x48, 0x18, 0x90, 0x2d, 0xbd, 0xb8, 0x06, 0x29,
0x0e, 0xd0, 0x01, 0x38, 0x68, 0x60, 0x8d, 0xcb, // C470
0xc0, 0x18, 0x60, 0x8d, 0xca, 0xc0, 0x18, 0x60,
0x8d, 0xc9, 0xc0, 0x18, 0x60, 0xc9, 0x02, 0xb0, // C480
0x04, 0x8d, 0xcd, 0xc0, 0x60, 0x38, 0x60, 0x8d,
0xc8, 0xc0, 0x18, 0x60, 0x8d, 0xcc, 0xc0, 0x18, // C490
0x60, 0x78, 0x8d, 0xce, 0xc0, 0xa2, 0x04, 0x18,
0x90, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C4A0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4B0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4C0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4D0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4E0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4F0
0xff, 0xff, 0xff, 0xd6, 0xff, 0xff, 0xff, 0x01 };
memcpy(toWhere, rom, 256);
#ifdef TEENSYDUINO
println("loading Mouse rom");
for (uint16_t i=0; i<=0xFF; i++) {
toWhere[i] = pgm_read_byte(&romData[i]);
}
#else
printf("loading HD32 rom\n");
memcpy(toWhere, romData, 256);
#endif
}
bool Mouse::hasExtendedRom()
{
return true;
return false;
}
void Mouse::loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset)
{
// There's no extended ROM needed, b/c we do the extended ROM work
// directly in C++
}
void Mouse::maintainMouse(int64_t cycleCount)

View File

@ -31,6 +31,8 @@ class Mouse : public Slot {
bool isEnabled();
void performHack();
private:
uint8_t status;
uint8_t interruptsTriggered;

146
apple/mouserom.asm Normal file
View File

@ -0,0 +1,146 @@
.ORG $C400
Entry:
BIT $FF58 ; well-known RTS location - where RTS is $60
BVS PREntry ; always branches (used to relocatably branch)
.ORG $C405
INEntry:
SEC
BCC PREntry ; never happens, but has a magic ID byte @ C407 == 18
CLV
BVC PREntry ; always branches
;; lookup table
.ORG $C40B
.byte $01 ; magic identifier
.byte $20 ; magic identifier
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte $00
.byte .LOBYTE(SetMouse)
.byte .LOBYTE(ServeMouse)
.byte .LOBYTE(ReadMouse)
.byte .LOBYTE(ClearMouse)
.byte .LOBYTE(PosMouse)
.byte .LOBYTE(ClampMouse)
.byte .LOBYTE(HomeMouse)
.byte .LOBYTE(InitMouse)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.byte .LOBYTE(ExitWithError)
.ORG $C420
PREntry:
PHA ; save Y, X, A, S on the stack
TYA
PHA
TXA
PHA
PHP
SEI ; turn off interrupts while we find our address via the stack
JSR $FF58 ; well-known RTS
TSX ; grab stack pointer
LDA $0100,X ; inspect the stack frame
TAX ; now A and X hold the high byte of the return address to *us*
ASL ; A <<= 4
ASL
ASL
ASL
TAY ; so Y = $n0, while X = $Cn for whatever slot we're in
PLP ; pull Status off the stack
BVC lastChance
LDA $38 ; We're being invoked in an IN# context, not a PR# context.
BNE PopAndReturn ; if $38/$39 don't point to us, then exit
TXA
EOR $39 ; is $39 == $Cn?
BNE PopAndReturn
InstallInHandler:
LDA #$05 ; Update IN handler to point to $Cn05 instead of $Cn00, so we know we've
STA $38 ;initialized it
BNE INHandler
lastChance:
BCS INHandler
PopAndReturn:
PLA
TAX
PLA
NOP
PLA
STA $c080,Y ; call soft-switch #0 for our slot to set mouse state
RTS
INHandler:
STA $c081,Y ; call soft-switch #1 for our slot to fill the keyboard buffer w/ mouse info
PLA
LDA $0638,X ; pull the string length from this magic screen hole (X == $Cn)
TAX ; which we'll return to the caller in X
PLA ; restore Y
TAY
PLA ; restore A
LDA $200,X ; Grab the last character entered in to the buffer by the magic switch call
RTS
SetMouse:
CMP #$0A ; values >= 10 are invalid
BCS ExitWithError
STA $C0CF ; soft switch 0x0F, hard-coded slot 4 for now
RTS
ExitWithError:
SEC ; the spec says carry is set on errors
RTS
ServeMouse:
PHA
SEI ; disable interrupts while we find out about interrupts
STA $C0CE ; soft switch 0x0E, hard-coded slot 4 for now
LDX #$04
LDA $6B8,X ; check what interrupts we serviced
AND #$0E
BNE _sm1 ; if we serviced any, leave carry clear
SEC ; ... but set carry if we serviced none
_sm1:
PLA
RTS
ReadMouse:
STA $C0CB ; soft switch 0x0B, hard-coded slot 4 for now
CLC
RTS
ClearMouse:
STA $C0CA ; soft switch 0x0A, hard-coded slot 4 for now
CLC
RTS
PosMouse:
STA $C0C9 ; soft switch 0x09, hard-coded slot 4 for now
CLC
RTS
ClampMouse:
CMP #$02
BCS ExitWithError
STA $C0CD ; soft switch 0x0D, hard-coded slot 4 for now
CLC
RTS
HomeMouse:
STA $C0C8 ; soft switch 0x08, hard-coded slot 4 for now
CLC
RTS
InitMouse:
STA $C0CC ; soft switch 0x0C, hard-coded slot 4 for now
CLC
RTS
.ORG $C4FB
.byte $D6 ; magic identifier
.ORG $C4FF
.byte $01 ; version

151
apple/mouserom.lst Normal file
View File

@ -0,0 +1,151 @@
ca65 V2.18 - N/A
Main file : mouserom.asm
Current file: mouserom.asm
000000r 1 .ORG $C400
00C400 1 Entry:
00C400 1 2C 58 FF BIT $FF58 ; well-known RTS location - where RTS is $60
00C403 1 70 1B BVS PREntry ; always branches (used to relocatably branch)
00C405 1
00C405 1 .ORG $C405
00C405 1 INEntry:
00C405 1 38 SEC
00C406 1 90 18 BCC PREntry ; never happens, but has a magic ID byte @ C407 == 18
00C408 1 B8 CLV
00C409 1 50 15 BVC PREntry ; always branches
00C40B 1
00C40B 1 ;; lookup table
00C40B 1 .ORG $C40B
00C40B 1 01 .byte $01 ; magic identifier
00C40C 1 20 .byte $20 ; magic identifier
00C40D 1 68 .byte .LOBYTE(ExitWithError)
00C40E 1 68 .byte .LOBYTE(ExitWithError)
00C40F 1 68 .byte .LOBYTE(ExitWithError)
00C410 1 68 .byte .LOBYTE(ExitWithError)
00C411 1 00 .byte $00
00C412 1 60 .byte .LOBYTE(SetMouse)
00C413 1 6A .byte .LOBYTE(ServeMouse)
00C414 1 7B .byte .LOBYTE(ReadMouse)
00C415 1 80 .byte .LOBYTE(ClearMouse)
00C416 1 85 .byte .LOBYTE(PosMouse)
00C417 1 8A .byte .LOBYTE(ClampMouse)
00C418 1 93 .byte .LOBYTE(HomeMouse)
00C419 1 98 .byte .LOBYTE(InitMouse)
00C41A 1 68 .byte .LOBYTE(ExitWithError)
00C41B 1 68 .byte .LOBYTE(ExitWithError)
00C41C 1 68 .byte .LOBYTE(ExitWithError)
00C41D 1 68 .byte .LOBYTE(ExitWithError)
00C41E 1 68 .byte .LOBYTE(ExitWithError)
00C41F 1 68 .byte .LOBYTE(ExitWithError)
00C420 1
00C420 1 .ORG $C420
00C420 1 PREntry:
00C420 1 48 PHA ; save Y, X, A, S on the stack
00C421 1 98 TYA
00C422 1 48 PHA
00C423 1 8A TXA
00C424 1 48 PHA
00C425 1 08 PHP
00C426 1 78 SEI ; turn off interrupts while we find our address via the stack
00C427 1 20 58 FF JSR $FF58 ; well-known RTS
00C42A 1 BA TSX ; grab stack pointer
00C42B 1 BD 00 01 LDA $0100,X ; inspect the stack frame
00C42E 1 AA TAX ; now A and X hold the high byte of the return address to *us*
00C42F 1 0A ASL ; A <<= 4
00C430 1 0A ASL
00C431 1 0A ASL
00C432 1 0A ASL
00C433 1 A8 TAY ; so Y = $n0, while X = $Cn for whatever slot we're in
00C434 1 28 PLP ; pull Status off the stack
00C435 1 50 0F BVC lastChance
00C437 1 A5 38 LDA $38 ; We're being invoked in an IN# context, not a PR# context.
00C439 1 D0 0D BNE PopAndReturn ; if $38/$39 don't point to us, then exit
00C43B 1 8A TXA
00C43C 1 45 39 EOR $39 ; is $39 == $Cn?
00C43E 1 D0 08 BNE PopAndReturn
00C440 1 InstallInHandler:
00C440 1 A9 05 LDA #$05 ; Update IN handler to point to $Cn05 instead of $Cn00, so we know we've
00C442 1 85 38 STA $38 ;initialized it
00C444 1 D0 0B BNE INHandler
00C446 1 lastChance:
00C446 1 B0 09 BCS INHandler
00C448 1 PopAndReturn:
00C448 1 68 PLA
00C449 1 AA TAX
00C44A 1 68 PLA
00C44B 1 EA NOP
00C44C 1 68 PLA
00C44D 1 99 80 C0 STA $c080,Y ; call soft-switch #0 for our slot to set mouse state
00C450 1 60 RTS
00C451 1 INHandler:
00C451 1 99 81 C0 STA $c081,Y ; call soft-switch #1 for our slot to fill the keyboard buffer w/ mouse info
00C454 1 68 PLA
00C455 1 BD 38 06 LDA $0638,X ; pull the string length from this magic screen hole (X == $Cn)
00C458 1 AA TAX ; which we'll return to the caller in X
00C459 1 68 PLA ; restore Y
00C45A 1 A8 TAY
00C45B 1 68 PLA ; restore A
00C45C 1 BD 00 02 LDA $200,X ; Grab the last character entered in to the buffer by the magic switch call
00C45F 1 60 RTS
00C460 1
00C460 1 SetMouse:
00C460 1 C9 0A CMP #$0A ; values >= 10 are invalid
00C462 1 B0 04 BCS ExitWithError
00C464 1 8D CF C0 STA $C0CF ; soft switch 0x0F, hard-coded slot 4 for now
00C467 1 60 RTS
00C468 1
00C468 1 ExitWithError:
00C468 1 38 SEC ; the spec says carry is set on errors
00C469 1 60 RTS
00C46A 1
00C46A 1 ServeMouse:
00C46A 1 48 PHA
00C46B 1 78 SEI ; disable interrupts while we find out about interrupts
00C46C 1 8D CE C0 STA $C0CE ; soft switch 0x0E, hard-coded slot 4 for now
00C46F 1 A2 04 LDX #$04
00C471 1 BD B8 06 LDA $6B8,X ; check what interrupts we serviced
00C474 1 29 0E AND #$0E
00C476 1 D0 01 BNE _sm1 ; if we serviced any, leave carry clear
00C478 1 38 SEC ; ... but set carry if we serviced none
00C479 1 _sm1:
00C479 1 68 PLA
00C47A 1 60 RTS
00C47B 1
00C47B 1 ReadMouse:
00C47B 1 8D CB C0 STA $C0CB ; soft switch 0x0B, hard-coded slot 4 for now
00C47E 1 18 CLC
00C47F 1 60 RTS
00C480 1
00C480 1 ClearMouse:
00C480 1 8D CA C0 STA $C0CA ; soft switch 0x0A, hard-coded slot 4 for now
00C483 1 18 CLC
00C484 1 60 RTS
00C485 1
00C485 1 PosMouse:
00C485 1 8D C9 C0 STA $C0C9 ; soft switch 0x09, hard-coded slot 4 for now
00C488 1 18 CLC
00C489 1 60 RTS
00C48A 1
00C48A 1 ClampMouse:
00C48A 1 C9 02 CMP #$02
00C48C 1 B0 DA BCS ExitWithError
00C48E 1 8D CD C0 STA $C0CD ; soft switch 0x0D, hard-coded slot 4 for now
00C491 1 18 CLC
00C492 1 60 RTS
00C493 1
00C493 1 HomeMouse:
00C493 1 8D C8 C0 STA $C0C8 ; soft switch 0x08, hard-coded slot 4 for now
00C496 1 18 CLC
00C497 1 60 RTS
00C498 1
00C498 1 InitMouse:
00C498 1 8D CC C0 STA $C0CC ; soft switch 0x0C, hard-coded slot 4 for now
00C49B 1 18 CLC
00C49C 1 60 RTS
00C49D 1
00C49D 1 .ORG $C4FB
00C4FB 1 D6 .byte $D6 ; magic identifier
00C4FC 1 .ORG $C4FF
00C4FF 1 01 .byte $01 ; version
00C500 1
00C500 1

View File

@ -7,16 +7,19 @@ my $romfile = shift || die "Must provide the path to an Apple //e ROM image";
my $diskrom = shift || die "Must also provide the path to an Apple //e Disk II ROM image";
my $parallelrom = shift || die "Must also provide the path to an Apple // parallel card ROM image";
my $hdrom = shift || die "Must also provide the path to the AppleWin HDDRVR.BIN";
my $mouserom = shift || die "Also need the path to a mouse.rom image";
validate($romfile, 32768, "an Apple //e ROM image");
validate($diskrom, 256, "a DiskII ROM image");
validate($parallelrom, 256, "a parallel card ROM image");
validate($hdrom, 256, "HDDRVR.BIN from AppleWin");
validate($mouserom, 256, "mouse.rom, compiled as part of Aiie");
dumpRom($romfile, "apple/applemmu-rom.h", "romData", 32768);
dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256);
dumpRom($parallelrom, "apple/parallel-rom.h", "romData", 256);
dumpRom($hdrom, "apple/hd32-rom.h", "romData", 256);
dumpRom($mouserom, "apple/mouse-rom.h", "romData", 256);
exit 0;
sub validate {