diff --git a/Makefile b/Makefile index 1997de9..19314dc 100755 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/apple/manual-linker.pl b/apple/manual-linker.pl new file mode 100755 index 0000000..5b24361 --- /dev/null +++ b/apple/manual-linker.pl @@ -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 () { + 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]); +} diff --git a/apple/mouse-rom.h b/apple/mouse-rom.h new file mode 100644 index 0000000..ba2b739 --- /dev/null +++ b/apple/mouse-rom.h @@ -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, +}; diff --git a/apple/mouse.cpp b/apple/mouse.cpp index b0923cb..aa29c91 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -2,8 +2,15 @@ #include #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; igetMMU()->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) diff --git a/apple/mouse.h b/apple/mouse.h index bafa602..96ccd71 100644 --- a/apple/mouse.h +++ b/apple/mouse.h @@ -31,6 +31,8 @@ class Mouse : public Slot { bool isEnabled(); + void performHack(); + private: uint8_t status; uint8_t interruptsTriggered; diff --git a/apple/mouserom.asm b/apple/mouserom.asm new file mode 100644 index 0000000..a176d24 --- /dev/null +++ b/apple/mouserom.asm @@ -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 + diff --git a/apple/mouserom.lst b/apple/mouserom.lst new file mode 100644 index 0000000..a5699ea --- /dev/null +++ b/apple/mouserom.lst @@ -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 diff --git a/util/genrom.pl b/util/genrom.pl index 867f2b0..ee8eaff 100755 --- a/util/genrom.pl +++ b/util/genrom.pl @@ -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 {