From fe46c4ab529054e1086d9134749f5e741160c7fc Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Tue, 29 Dec 2020 09:12:33 -0500 Subject: [PATCH 01/23] importing old mouse work to new teensy 4.1 --- Makefile | 6 ++-- apple/applemmu.cpp | 88 ++++++++++++++++++++++++++++++---------------- apple/applevm.cpp | 3 ++ apple/applevm.h | 2 ++ apple/mouse.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++ apple/mouse.h | 31 ++++++++++++++++ apple/pia6821.cpp | 43 ++++++++++++++++++++++ apple/pia6821.h | 31 ++++++++++++++++ apple/slot.h | 3 ++ util/genrom.pl | 3 ++ vmram.cpp | 12 +++++-- vmram.h | 6 ++-- 12 files changed, 276 insertions(+), 38 deletions(-) create mode 100644 apple/mouse.cpp create mode 100644 apple/mouse.h create mode 100644 apple/pia6821.cpp create mode 100644 apple/pia6821.h diff --git a/Makefile b/Makefile index dcf8e35..886e889 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ TSRC=cpu.cpp util/testharness.cpp COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp -COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o +COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o apple/pia6821.o FBSRCS=linuxfb/linux-speaker.cpp linuxfb/fb-display.cpp linuxfb/linux-keyboard.cpp linuxfb/fb-paddles.cpp nix/nix-filemanager.cpp linuxfb/aiie.cpp linuxfb/linux-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp @@ -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 -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 MouseInterface.rom .PHONY: roms clean @@ -40,7 +40,7 @@ test: $(TSRC) ./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 + ./util/genrom.pl apple2e.rom disk.rom parallel.rom HDDRVR.BIN MouseInterface.rom apple/applemmu-rom.h: roms diff --git a/apple/applemmu.cpp b/apple/applemmu.cpp index 899cd3f..63f0464 100644 --- a/apple/applemmu.cpp +++ b/apple/applemmu.cpp @@ -52,8 +52,9 @@ page 0-1 4 pages (1k) [altzp] 0xC1-0xCF 15 * 2 pages = 30 pages (7.5k) [intcxrom, slotLatch] 0xD0 - 0xDF 16 * 5 pages = 80 pages (20k) [altzp, bank2, {r,w}bsr] 0xE0 - 0xFF 32 * 3 pages = 96 pages (24k) [altzp, {r,w}bsr] +... plus 8 additional pages for the mouse ROM -= 147.75k (591 pages) stored off-chip += 147.75k (591 pages) stored off-chip (+ 8 more) Current read page table [512 bytes] in real ram Current write page table [512 bytes] in real ram @@ -84,10 +85,11 @@ enum { MP_60 = 192, // 0x60 - 0xBF * 2 = 192; 192..383 MP_C1 = 384, // start of 0xC1-0xCF * 2 page variants = 30; 384-413 - MP_D0 = 414, // start of 0xD0-0xDF * 5 page variants = 80; 414-493 - MP_E0 = 493, // start of 0xE0-0xFF * 3 page variants = 96; 494-589 - MP_C0 = 590 - // = 591 pages in all (147.75k) + MP_C8 = 398, // 0xc8 - 0xcf, 3 page variants = 24; 398 - 421 + MP_D0 = 422, // start of 0xD0-0xDF * 5 page variants = 80; 422 - 501 + MP_E0 = 502, // start of 0xE0-0xFF * 3 page variants = 96; 502 - 597 + MP_C0 = 598 + // = 599 pages in all (149.75k) }; @@ -115,10 +117,14 @@ static uint16_t _pageNumberForRam(uint8_t highByte, uint8_t variant) if (highByte == 0xc0) { return MP_C0; } - if (highByte <= 0xCF) { - // 0xC1-0xCF 15 * 2 pages = 30 pages (7.5k) + if (highByte <= 0xC7) { + // 0xC1 - 0xC7 return ((highByte - 0xC1) * 2 + variant + MP_C1); } + if (highByte <= 0xCF) { + // bank-switched ROM. 0 = built-in; 1 = 80-column (slot 3); 2 = mouse (slot 4) + return ((highByte - 0xC8) * 3 + variant + MP_C8); + } if (highByte <= 0xDF) { // 0xD0 - 0xDF 16 * 5 pages = 80 pages (20k) @@ -917,6 +923,8 @@ void AppleMMU::resetRAM() // Load system ROM for (uint16_t i=0x80; i<=0xFF; i++) { + uint16_t page0 = _pageNumberForRam(i, 0); + uint16_t page1 = _pageNumberForRam(i, 1); for (uint16_t k=0; k<0x100; k++) { uint16_t idx = ((i-0x80) << 8) | k; #ifdef TEENSYDUINO @@ -924,30 +932,22 @@ void AppleMMU::resetRAM() #else uint8_t v = romData[idx]; #endif - for (int j=0; j<5; j++) { - // For the ROM section from 0xc100 .. 0xcfff, we load in to - // an alternate page space (INTCXROM). - - uint16_t page0 = _pageNumberForRam(i, 0); - - if (i >= 0xc1 && i <= 0xcf) { - // If we want to convince the VM we've got 128k of RAM, we - // need to load C3 ROM in page 0 (but not 1, meaning there's - // a board installed); and C800.CFFF in both page [0] and [1] - // (meaning there's an extended 80-column ROM available, - // that is also physically in the slot). - // Everything else goes in page [1]. - - uint16_t page1 = _pageNumberForRam(i, 1); - - if (i == 0xc3) { - g_ram.writeByte((page0 << 8) | (k & 0xFF), v); - } - else if (i >= 0xc8) { + // The space from 0xC1 through 0xCF is ROM image territory. We + // load the C3 ROM in to page 0, but not in page 1; and then we + // load C800.CFFF to both the main ROM (page 0) and the C3 aux ROM + // (page 1) to convince the VM that we've got 128k of RAM and an + // 80-column card. + if (i >= 0xc1 && i <= 0xcf) { + if (i == 0xc3) { + // C300..C3FF => built-in ROM + g_ram.writeByte((page0 << 8) | (k & 0xFF), v); + } else if (i >= 0xc8) { + // C800..CFFF => built-in ROM and slot 3 extended ROM + if (i >= 0xc1 && i <= 0xcf) { g_ram.writeByte((page0 << 8) | (k & 0xFF), v); g_ram.writeByte((page1 << 8) | (k & 0xFF), v); - } - else { + } else { + // C000..C2FF and C400..C7FF are main ROM g_ram.writeByte((page1 << 8) | (k & 0xFF), v); } } else { @@ -962,12 +962,33 @@ void AppleMMU::resetRAM() for (uint8_t slotnum = 1; slotnum <= 7; slotnum++) { uint16_t page0 = _pageNumberForRam(0xC0 + slotnum, 0); if (slots[slotnum]) { + // Load the primary ROM for this peripheral (0xCsXX..0xCsFF) uint8_t tmpBuf[256]; memset(tmpBuf, 0, sizeof(tmpBuf)); slots[slotnum]->loadROM(tmpBuf); for (int i=0; i<256; i++) { g_ram.writeByte( (page0 << 8) + i, tmpBuf[i] ); } + + // See if there's an extended 2k ROM for this peripheral (0xC800..0xCFFF) + if (slots[slotnum]->hasExtendedRom()) { + for (int j=0; j<8; j++) { + // Load each of the 256 byte chunks separately to its own VMRam page + uint16_t slotPage = 0; + if (slotnum == 4) { + slotPage = _pageNumberForRam(0xC8 + j, 2); + } else { +#ifndef TEENSYDUINO + fprintf(stderr, "ERROR: unsupported extended ROM peripheral in slot %d\n", slotnum); + exit(1); +#endif + } + if (slotPage) { + uint8_t *p = g_ram.memPtr(slotPage << 8); + slots[slotnum]->loadExtendedRom(p, j * 256); + } + } + } } } @@ -1066,12 +1087,17 @@ void AppleMMU::updateMemoryPages() // If slotLatch is set (!= -1), then we are mapping 2k of ROM // for a given peripheral to C800..CFFF. if (slotLatch != -1) { - // FIXME: the only peripheral we support this with right now is - // the 80-column card. + // FIXME: this is a hacky mess. Slot 3 (the 80-col card) is + // supported as "page 1"; and Slot 4 (the mouse card) is + // supported as "page 2". if (slotLatch == 3) { for (int i=0xc8; i <= 0xcf; i++) { readPages[i] = _pageNumberForRam(i, 1); } + } else if (slotLatch == 4) { + for (int i=0xc8; i<=0xcf; i++) { + readPages[i] = _pageNumberForRam(i, 2); + } } } diff --git a/apple/applevm.cpp b/apple/applevm.cpp index b925d2b..b0c822c 100644 --- a/apple/applevm.cpp +++ b/apple/applevm.cpp @@ -32,6 +32,9 @@ AppleVM::AppleVM() hd32 = new HD32((AppleMMU *)mmu); ((AppleMMU *)mmu)->setSlot(7, hd32); + + mouse = new Mouse(); + ((AppleMMU *)mmu)->setSlot(4, mouse); } AppleVM::~AppleVM() diff --git a/apple/applevm.h b/apple/applevm.h index a595d7a..65e02f4 100644 --- a/apple/applevm.h +++ b/apple/applevm.h @@ -7,6 +7,7 @@ #include "hd32.h" #include "vmkeyboard.h" #include "parallelcard.h" +#include "mouse.h" #include "vm.h" class AppleVM : public VM { @@ -39,6 +40,7 @@ class AppleVM : public VM { protected: VMKeyboard *keyboard; ParallelCard *parallel; + Mouse *mouse; }; diff --git a/apple/mouse.cpp b/apple/mouse.cpp new file mode 100644 index 0000000..aea25b3 --- /dev/null +++ b/apple/mouse.cpp @@ -0,0 +1,86 @@ +#include "mouse.h" +#include +#include "mouse-rom.h" + +Mouse::Mouse() +{ +} + +Mouse::~Mouse() +{ +} + +bool Mouse::Serialize(int8_t fd) +{ + return true; +} + +bool Mouse::Deserialize(int8_t fd) +{ + return true; +} + +void Mouse::Reset() +{ +} + +uint8_t Mouse::readSwitches(uint8_t s) +{ + return 0xFF; +} + +void Mouse::writeSwitches(uint8_t s, uint8_t v) +{ + printf("unknown switch 0x%X\n", s); +} + +void Mouse::loadROM(uint8_t *toWhere) +{ + uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, + 0xb8, 0x50, 0x15, 0x01, 0x20, 0xae, 0xae, 0xae, + 0xae, 0x00, 0x6d, 0x75, 0x8e, 0x9f, 0xa4, 0x86, + 0xa9, 0x97, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x10, 0xb0, + 0x3f, 0x99, 0x82, 0xc0, 0x60, 0x48, 0x18, 0x90, + 0x39, 0x99, 0x83, 0xc0, 0xbd, 0xb8, 0x06, 0x29, + + 0x0E, 0xD0, 0x01, 0x38, 0x68, 0x60, 0xc9, 0x02, + 0xb0, 0x26, 0x99, 0x83, 0xc0, 0x60, 0xa9, 0x04, + 0x99, 0x83, 0xc0, 0x18, 0xea, 0xea, 0x60, 0xea, + 0xa9, 0x02, 0x99, 0x83, 0xc0, 0x18, 0x60, 0xea, + 0xa9, 0x05, 0xd0, 0xf6, 0xea, 0xa9, 0x06, 0xd0, + 0xf1, 0xea, 0xa9, 0x07, 0xd0, 0xec, 0xa2, 0x03, + 0x38, 0x60, 0x08, 0xa5, 0x00, 0x48, 0xa9, 0x60, + 0x85, 0x00, 0x78, 0x20, 0x00, 0x00, 0xba, 0x68, + 0x85, 0x00, 0xbd, 0x00, 0x01, 0x28, 0xaa, 0x0a, + 0x0a, 0x0a, 0x0a, 0xa8, 0xa9, 0x03, 0x18, 0x90, + 0xa8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xd6, 0xff, 0xff, 0xff, 0x01 }; + memcpy(toWhere, rom, 256); +} + +bool Mouse::hasExtendedRom() +{ + return true; +} + +void Mouse::loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset) +{ + printf("loading extended rom for the mouse\n"); + for (int i=0; i<256; i++) { + toWhere[i] = romData[i + byteOffset]; + } +} diff --git a/apple/mouse.h b/apple/mouse.h new file mode 100644 index 0000000..fcc330b --- /dev/null +++ b/apple/mouse.h @@ -0,0 +1,31 @@ +#ifndef __APPLEMOUSE_H +#define __APPLEMOUSE_H + +#ifdef TEENSYDUINO +#include +#else +#include +#include +#endif + +#include "applemmu.h" +#include "slot.h" + +class Mouse : public Slot { + public: + Mouse(); + virtual ~Mouse(); + + virtual bool Serialize(int8_t fd); + virtual bool Deserialize(int8_t fd); + + virtual void Reset(); // used by BIOS cold-boot + virtual uint8_t readSwitches(uint8_t s); + virtual void writeSwitches(uint8_t s, uint8_t v); + virtual void loadROM(uint8_t *toWhere); + + virtual bool hasExtendedRom(); + virtual void loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset); +}; + +#endif diff --git a/apple/pia6821.cpp b/apple/pia6821.cpp new file mode 100644 index 0000000..bb26c53 --- /dev/null +++ b/apple/pia6821.cpp @@ -0,0 +1,43 @@ +#include "pia6821.h" + +PIA6821::PIA6821() +{ +} + +PIA6821::~PIA6821() +{ +} + +uint8_t PIA6821::read(uint8_t addr) +{ + uint8_t rv; + + switch (addr) { + case DDRA: + if (cra & 0x04) { // DDR or Peripherial Interface access control + // peripheral + // rv = readPeripheralA(); + // FIXME continue here + } else { + rv = ddra; + } + break; + case CTLA: + rv = cra; + break; + case DDRB: + if (crb & 0x04) { + // rv = readPeripheralB(); + // FIXME continue here + } else { + rv = ddrb; + } + break; + case CTLB: + rv = crb; + break; + } + + return rv; +} + diff --git a/apple/pia6821.h b/apple/pia6821.h new file mode 100644 index 0000000..9317d63 --- /dev/null +++ b/apple/pia6821.h @@ -0,0 +1,31 @@ +#ifndef _PIA6821_H +#define _PIA6821_H + +#include + +// http://webpages.charter.net/coinopcauldron/piaarticle.html + +#define DDRA 0 +#define CTLA 1 +#define DDRB 2 +#define CTLB 3 + +class PIA6821 { + public: + PIA6821(); + ~PIA6821(); + + uint8_t read(uint8_t addr); + + + private: + uint8_t porta, portb; + uint8_t ddra, ddrb; + uint8_t cra, crb; // control registers + /* + 2 ports - porta, portb + */ + +}; + +#endif diff --git a/apple/slot.h b/apple/slot.h index e394e06..fedf709 100644 --- a/apple/slot.h +++ b/apple/slot.h @@ -22,6 +22,9 @@ class Slot { virtual void writeSwitches(uint8_t s, uint8_t v) = 0; virtual void loadROM(uint8_t *toWhere) = 0; + + virtual bool hasExtendedRom() { return false; }; + virtual void loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset) {}; }; #endif diff --git a/util/genrom.pl b/util/genrom.pl index 867f2b0..b5ecaf2 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 the 2k Mouse rom"; 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, 2048, "2k Mouse extended ROM image"); 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($hdrom, "apple/mouse-rom.h", "romData", 2048); exit 0; sub validate { diff --git a/vmram.cpp b/vmram.cpp index a4f99d8..cb07178 100644 --- a/vmram.cpp +++ b/vmram.cpp @@ -8,9 +8,10 @@ #include "globals.h" #ifdef TEENSYDUINO -EXTMEM uint8_t preallocatedRam[591*256]; +EXTMEM uint8_t preallocatedRam[599*256]; #else -uint8_t preallocatedRam[591*256]; +#include +uint8_t preallocatedRam[599*256]; #endif #ifndef TEENSYDUINO @@ -44,6 +45,13 @@ void VMRam::writeByte(uint32_t addr, uint8_t value) preallocatedRam[addr] = value; } +uint8_t *VMRam::memPtr(uint32_t addr) +{ + printf("Asked for preallocated RAM pointer at 0x%X\n", addr); + printf("Base is 0x%llX\n", (unsigned long long) preallocatedRam); + return &preallocatedRam[addr]; +} + bool VMRam::Serialize(int8_t fd) { uint32_t size = sizeof(preallocatedRam); diff --git a/vmram.h b/vmram.h index 1d3e158..38af993 100644 --- a/vmram.h +++ b/vmram.h @@ -15,13 +15,15 @@ class VMRam { uint8_t readByte(uint32_t addr); void writeByte(uint32_t addr, uint8_t value); + uint8_t *memPtr(uint32_t addr); + bool Serialize(int8_t fd); bool Deserialize(int8_t fd); bool Test(); private: - // We need 591 pages of 256 bytes for the //e. + // We need 599 pages of 256 bytes for the //e. // // This previously used a split memory model where some of this was // in internal ram and some was external - and while that's not true @@ -37,7 +39,7 @@ class VMRam { // Pages 4-7 are 0x200 - 0x3FF. We want those in RAM too (text pages). // Has to be static if we're using the EXTMEM sectioning, so it's now in vmram.cpp :/ - //EXTMEM uint8_t preallocatedRam[591*256]; + //EXTMEM uint8_t preallocatedRam[599*256]; }; From 0468bf43c5d4f26412d9f1429066b6367b452a36 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Fri, 8 Jan 2021 19:25:08 -0500 Subject: [PATCH 02/23] more normalization and commenting --- apple/applemmu.cpp | 64 +++++++++------- apple/mouse.cpp | 181 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 27 deletions(-) diff --git a/apple/applemmu.cpp b/apple/applemmu.cpp index 63f0464..2ba4005 100644 --- a/apple/applemmu.cpp +++ b/apple/applemmu.cpp @@ -61,8 +61,15 @@ Current write page table [512 bytes] in real ram */ -// This has a split memory model so more often addressed pages can be -// in internal memory, and an external memory can hold others. +// All the pages. Because we don't have enough RAM for both the +// display's DMA and the Apple's 148k (128k + ROM space), we're using +// an external SRAM for some of this. Anything that's accessed very +// often should be in the *low* pages, b/c those are in internal +// Teensy RAM. When we run out of preallocated RAM (cf. vmram.h), we +// fall over to an external 256kB SRAM (which is much slower). +// +// Zero page (and its alts) are the most used pages (the stack is in +// page 1). // // We want the video display pages in real RAM as much as possible, // since blits wind up touching so much of it. If we can keep that in @@ -79,20 +86,19 @@ enum { MP_ZP = 0, // page 0/1 * 2 page variants = 4; 0..3 MP_4 = 4, // 0x04 - 0x07 (text display pages) * 2 variants = 8; 4..11 MP_20 = 12, // 0x20 - 0x5F * 2 variants = 128; 12..139 - // Pages that can go to external RAM if needed: + // Pages that can go to external SRAM: MP_2 = 140, // 0x02 - 0x03 * 2 variants = 4; 140..143 MP_8 = 144, // 0x08 - 0x1F * 2 = 48; 144..191 MP_60 = 192, // 0x60 - 0xBF * 2 = 192; 192..383 - MP_C1 = 384, // start of 0xC1-0xCF * 2 page variants = 30; 384-413 - MP_C8 = 398, // 0xc8 - 0xcf, 3 page variants = 24; 398 - 421 + MP_C1 = 384, // start of 0xC1-0xC7 * 2 page variants = 14; 384-397 + MP_C8 = 398, // 0xc8 - 0xcf, 3 page variants = 24; 398 - 421 MP_D0 = 422, // start of 0xD0-0xDF * 5 page variants = 80; 422 - 501 MP_E0 = 502, // start of 0xE0-0xFF * 3 page variants = 96; 502 - 597 - MP_C0 = 598 + MP_C0 = 598 // = 599 pages in all (149.75k) }; - static uint16_t _pageNumberForRam(uint8_t highByte, uint8_t variant) { if (highByte <= 1) { @@ -118,14 +124,13 @@ static uint16_t _pageNumberForRam(uint8_t highByte, uint8_t variant) return MP_C0; } if (highByte <= 0xC7) { - // 0xC1 - 0xC7 + // 0xC1-0xC7 return ((highByte - 0xC1) * 2 + variant + MP_C1); } if (highByte <= 0xCF) { // bank-switched ROM. 0 = built-in; 1 = 80-column (slot 3); 2 = mouse (slot 4) return ((highByte - 0xC8) * 3 + variant + MP_C8); } - if (highByte <= 0xDF) { // 0xD0 - 0xDF 16 * 5 pages = 80 pages (20k) return ((highByte - 0xD0) * 5 + variant + MP_D0); @@ -229,6 +234,8 @@ bool AppleMMU::Deserialize(int8_t fd) return true; } + + void AppleMMU::Reset() { resetRAM(); @@ -925,6 +932,7 @@ void AppleMMU::resetRAM() for (uint16_t i=0x80; i<=0xFF; i++) { uint16_t page0 = _pageNumberForRam(i, 0); uint16_t page1 = _pageNumberForRam(i, 1); + for (uint16_t k=0; k<0x100; k++) { uint16_t idx = ((i-0x80) << 8) | k; #ifdef TEENSYDUINO @@ -932,28 +940,30 @@ void AppleMMU::resetRAM() #else uint8_t v = romData[idx]; #endif - // The space from 0xC1 through 0xCF is ROM image territory. We - // load the C3 ROM in to page 0, but not in page 1; and then we - // load C800.CFFF to both the main ROM (page 0) and the C3 aux ROM + + // The space from 0xc1 through 0xcf is ROM image territory. We + // load the C3 ROM in to page 0, but not page 1; and then we + // load c800.CFFF to both main ROM (page 0) and the C3 aux ROM // (page 1) to convince the VM that we've got 128k of RAM and an // 80-column card. + if (i >= 0xc1 && i <= 0xcf) { if (i == 0xc3) { // C300..C3FF => built-in ROM g_ram.writeByte((page0 << 8) | (k & 0xFF), v); - } else if (i >= 0xc8) { - // C800..CFFF => built-in ROM and slot 3 extended ROM - if (i >= 0xc1 && i <= 0xcf) { - g_ram.writeByte((page0 << 8) | (k & 0xFF), v); - g_ram.writeByte((page1 << 8) | (k & 0xFF), v); - } else { - // C000..C2FF and C400..C7FF are main ROM - g_ram.writeByte((page1 << 8) | (k & 0xFF), v); - } - } else { - // Everything else goes in page 0. - g_ram.writeByte((page0 << 8) | (k & 0xFF), v); } + else if (i >= 0xc8) { + // C800..CFFF => built-in ROM and slot 3 extended ROM + g_ram.writeByte((page0 << 8) | (k & 0xFF), v); + g_ram.writeByte((page1 << 8) | (k & 0xFF), v); + } + else { + // C000..C2FF and C400..c7FF are main ROM + g_ram.writeByte((page1 << 8) | (k & 0xFF), v); + } + } else { + // Everything else goes in page 0. + g_ram.writeByte((page0 << 8) | (k & 0xFF), v); } } } @@ -1088,14 +1098,14 @@ void AppleMMU::updateMemoryPages() // for a given peripheral to C800..CFFF. if (slotLatch != -1) { // FIXME: this is a hacky mess. Slot 3 (the 80-col card) is - // supported as "page 1"; and Slot 4 (the mouse card) is - // supported as "page 2". + // supported, as page "1"; and Slot 4 (the mouse card) is + // supported as page "2". if (slotLatch == 3) { for (int i=0xc8; i <= 0xcf; i++) { readPages[i] = _pageNumberForRam(i, 1); } } else if (slotLatch == 4) { - for (int i=0xc8; i<=0xcf; i++) { + for (int i=0xc8; i <= 0xcf; i++) { readPages[i] = _pageNumberForRam(i, 2); } } diff --git a/apple/mouse.cpp b/apple/mouse.cpp index aea25b3..9eacc91 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -36,6 +36,187 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v) void Mouse::loadROM(uint8_t *toWhere) { + /* ROM Disassembly: +C400- 2C 58 FF BIT $FF58 ; test bits in FF58 w/ A +C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $20 on boot-up +C405- 38 SEC +C406- 90 18 BCC $C420 ; no-op; unless called @ $C406 directly? + +C408- B8 CLV ; clear overflow +C409- 50 15 BVC $C420 ; always branches + +; unused... ? more lookup table... ? +C40B- 01 20 ORA ($20,X) +C40D- AE AE AE LDX $AEAE + +; This is the lookup table for entry addresses +C410- AE +C411- 00 +C412- 6D ;(setmouse @ c46d) +C413- 75 ;(servemouse @ C475) +C414- 8E ;(readmouse @ C48E) +C415- 9F ;(clearmouse @ C49F) +C416- A4 ;(posmouse @ C4A4) +C417- 86 ;(clampmouse @ C486) +C418- A9 ;(homemouse @ C4A9) +C419- 97 ;(initmouse @ C497) +C41A- AE +C41B- AE +C41C- AE ;(semi-documented: sets mouse frequency handler to 60 or 50 hz) +C41D- AE +C41E- AE +C41F- AE + +; Main +C420- 48 PHA ; push accumulator to stack +C421- 98 TYA +C422- 48 PHA ; push Y to stack +C423- 8A TXA +C424- 48 PHA ; push X to stack +C424- 48 PHA +C425- 08 PHP ; push status to stack +C426- 78 SEI ; disable interrupts + +; This JSR $FF58 is a trick to get the address we're calling from. By +; default, $FF58 contains a RTS (until patched as the DOS '&' vector, +; or ProDOS does something similar). As long as this executes before +; the DOS takes over, it's safe; but if we're doing this after ProDOS +; loads, a 64k machine might have garbage after the language card RAM +; is loaded here. A safer alternative would be something like +; LDA #$60 ; Write an RTS ($60) to a temporary memory +; STA WORK ; address, and then +; JSR WORK ; jump to it +; TSX +; LDA $100, X ; grab the return address off the stack + +C427- 20 58 FF JSR $FF58 +C42A- BA TSX +C42B- BD 00 01 LDA $0100,X +C42E- AA TAX +C42F- 0A ASL +C430- 0A ASL +C431- 0A ASL +C432- 0A ASL +C433- A8 TAY +C434- 28 PLP ; restore status from stack +C435- 50 0F BVC $C446 ; overflow is clear if ... ? +C437- A5 38 LDA $38 ; >> what's in $38? +C439- D0 0D BNE $C448 ; restore stack & return +C43B- 8A TXA +C43C- 45 39 EOR $39 ; >> what's in $39? +C43E- D0 08 BNE $C448 ; restore stack & return +C440- A9 05 LDA #$05 +C442- 85 38 STA $38 ; ($38) = $05 +C442- 85 38 STA $38 +C444- D0 0B BNE $C451 + +C446- B0 09 BCS $C451 ; carry set if ... ? +C448- 68 PLA ; pull X from stack +C449- AA TAX +C44A- 68 PLA ; pull Y from stack, but +C44B- EA NOP ; throw it away +C44C- 68 PLA ; pull A from stack +C44D- 99 80 C0 STA $C080,Y ; LC RAM bank2, read and wr-protect +C450- 60 RTS + +C451- 99 81 C0 STA $C081,Y ; LC RAM bank 2, read ROM +C454- 68 PLA ; +C455- BD 38 06 LDA $0638,X +C458- AA TAX +C459- 68 PLA +C45A- A8 TAY +C45B- 68 PLA +C45C- BD 00 02 LDA $0200,X ; keyboard character buffer? +C45F- 60 RTS + +C460- 00 BRK +C461- 00 BRK +C462- 00 BRK +C463- 00 BRK +C464- 00 BRK +C465- 00 BRK +C466- 00 BRK +C467- 00 BRK +C468- 00 BRK +C469- 00 BRK +C46A- 00 BRK +C46B- 00 BRK +C46C- 00 BRK + +; SetMouse +C46D- C9 10 CMP #$10 ; interrupt on VBL + interrupt on mouse move? +C46F- B0 3F BCS $C4B0 ; RTS if A >= 0x10 +C471- 99 82 C0 STA $C082,Y ; LC RAM bank 2, read ROM, wr-protect RAM +C474- 60 RTS +; ServeMouse +C475- 48 PHA +C476- 18 CLC +C477- 90 39 BCC $C4B2 ; always branches +; ServeMouse cleanup and exit +C479- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM +C47C- BD B8 06 LDA $06B8,X +C47F- 29 0E AND #$0E +C481- D0 01 BNE $C484 +C483- 38 SEC +C484- 68 PLA +C485- 60 RTS +; ClampMouse +C486- C9 02 CMP #$02 +C488- B0 26 BCS $C4B0 ; RTS if 2 <= the A register +C48A- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM +C48D- 60 RTS +; ReadMouse +C48E- A9 04 LDA #$04 +C490- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM +C493- 18 CLC +C494- EA NOP +C495- EA NOP +C496- 60 RTS +; InitMouse +C497- EA NOP +C498- A9 02 LDA #$02 +C49A- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM +C49D- 18 CLC +C49E- 60 RTS +; ClearMouse +C49F- EA NOP +C4A0- A9 05 LDA #$05 +C4A2- D0 F6 BNE $C49A +; PosMouse +C4A4- EA NOP +C4A5- A9 06 LDA #$06 +C4A7- D0 F1 BNE $C49A +; HomeMouse +C4A9- EA NOP +C4AA- A9 07 LDA #$07 +C4AC- D0 EC BNE $C49A +C4AE- A2 03 LDX #$03 +C4B0- 38 SEC +C4B1- 60 RTS +; ServeMouse main worker +C4B2- 08 PHP +C4B3- A5 00 LDA $00 +C4B5- 48 PHA +C4B6- A9 60 LDA #$60 +C4B8- 85 00 STA $00 +C4BA- 78 SEI +C4BB- 20 00 00 JSR $0000 +C4BE- BA TSX +C4BF- 68 PLA +C4C0- 85 00 STA $00 +C4C2- BD 00 01 LDA $0100,X +C4C5- 28 PLP +C4C6- AA TAX +C4C7- 0A ASL +C4C8- 0A ASL +C4C9- 0A ASL +C4CA- 0A ASL +C4CB- A8 TAY +C4CC- A9 03 LDA #$03 +C4CE- 18 CLC +C4CF- 90 A8 BCC $C479 ; always branches + + */ uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, 0xb8, 0x50, 0x15, 0x01, 0x20, 0xae, 0xae, 0xae, 0xae, 0x00, 0x6d, 0x75, 0x8e, 0x9f, 0xa4, 0x86, From 826e5d14c549ad0037fcd1dd1dc3df4500e68108 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Fri, 8 Jan 2021 19:41:12 -0500 Subject: [PATCH 03/23] expand reboot options (and make them understandable) --- bios.cpp | 79 +++++++++++++++++++++++++++++++++++++++----------------- bios.h | 1 + 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/bios.cpp b/bios.cpp index aca9185..63dd6c2 100644 --- a/bios.cpp +++ b/bios.cpp @@ -50,23 +50,24 @@ enum { enum { ACT_EXIT = 1, ACT_RESET = 2, - ACT_COLDBOOT = 3, - ACT_MONITOR = 4, - ACT_DISPLAYTYPE = 5, - ACT_DEBUG = 6, - ACT_DISK1 = 7, - ACT_DISK2 = 8, - ACT_HD1 = 9, - ACT_HD2 = 10, - ACT_VOLPLUS = 11, - ACT_VOLMINUS = 12, - ACT_SUSPEND = 13, - ACT_RESTORE = 14, - ACT_PADX_INV = 15, - ACT_PADY_INV = 16, - ACT_PADDLES = 17, - ACT_SPEED = 18, - ACT_ABOUT = 19, + ACT_REBOOT = 3, + ACT_REBOOTANDEJECT = 4, + ACT_MONITOR = 5, + ACT_DISPLAYTYPE = 6, + ACT_DEBUG = 7, + ACT_DISK1 = 8, + ACT_DISK2 = 9, + ACT_HD1 = 10, + ACT_HD2 = 11, + ACT_VOLPLUS = 12, + ACT_VOLMINUS = 13, + ACT_SUSPEND = 14, + ACT_RESTORE = 15, + ACT_PADX_INV = 16, + ACT_PADY_INV = 17, + ACT_PADDLES = 18, + ACT_SPEED = 19, + ACT_ABOUT = 20, }; #define NUM_TITLES 4 @@ -75,7 +76,8 @@ const uint8_t titleWidths[NUM_TITLES] = {45, 28, 80, 45 }; const uint8_t aiieActions[] = { ACT_ABOUT }; -const uint8_t vmActions[] = { ACT_EXIT, ACT_RESET, ACT_COLDBOOT, ACT_MONITOR, +const uint8_t vmActions[] = { ACT_EXIT, ACT_RESET, ACT_REBOOT, ACT_REBOOTANDEJECT, + ACT_MONITOR, ACT_DEBUG, ACT_SUSPEND, ACT_RESTORE }; const uint8_t hardwareActions[] = { ACT_DISPLAYTYPE, ACT_SPEED, ACT_PADX_INV, ACT_PADY_INV, @@ -289,7 +291,12 @@ uint16_t BIOS::VmMenuHandler(bool needsRedraw, bool performAction) case ACT_RESET: WarmReset(); return BIOS_DONE; - case ACT_COLDBOOT: + case ACT_REBOOT: + // Reboot, but don't eject disks + RebootAsIs(); + return BIOS_DONE; + case ACT_REBOOTANDEJECT: + // Power off and on, ejecting disks ColdReboot(); return BIOS_DONE; case ACT_MONITOR: @@ -666,6 +673,28 @@ void BIOS::WarmReset() g_cpu->Reset(); } +void BIOS::RebootAsIs() +{ + // g_vm->Reset() will eject disks. We don't want to do that, so we need to + // grab the inserted disk names; reset the VM; then restore the disks. + const char *disk6s1 = ((AppleVM *)g_vm)->DiskName(0); + const char *disk6s2 = ((AppleVM *)g_vm)->DiskName(1); + const char *hdd1 = ((AppleVM *)g_vm)->HDName(0); + const char *hdd2 = ((AppleVM *)g_vm)->HDName(1); + + g_vm->Reset(); + g_cpu->Reset(); + + if (disk6s1) + ((AppleVM *)g_vm)->insertDisk(0, disk6s1); + if (disk6s2) + ((AppleVM *)g_vm)->insertDisk(1, disk6s2); + if (hdd1) + ((AppleVM *)g_vm)->insertHD(0, hdd1); + if (hdd2) + ((AppleVM *)g_vm)->insertHD(2, hdd2); +} + void BIOS::ColdReboot() { g_vm->Reset(); @@ -678,7 +707,8 @@ bool BIOS::isActionActive(int8_t action) switch (action) { case ACT_EXIT: case ACT_RESET: - case ACT_COLDBOOT: + case ACT_REBOOT: + case ACT_REBOOTANDEJECT: case ACT_MONITOR: case ACT_DISPLAYTYPE: case ACT_SPEED: @@ -776,10 +806,13 @@ void BIOS::DrawVMMenu() strcpy(buf, "Resume"); break; case ACT_RESET: - strcpy(buf, "Reset"); + strcpy(buf, "Reset (press Reset key)"); break; - case ACT_COLDBOOT: - strcpy(buf, "Cold Reboot"); + case ACT_REBOOT: + strcpy(buf, "Reboot (reboot emulator)"); + break; + case ACT_REBOOTANDEJECT: + strcpy(buf, "Reboot and eject disks"); break; case ACT_MONITOR: strcpy(buf, "Drop to Monitor"); diff --git a/bios.h b/bios.h index 0f9ab8a..48f6fbd 100644 --- a/bios.h +++ b/bios.h @@ -42,6 +42,7 @@ class BIOS { int8_t getCurrentMenuAction(); void WarmReset(); + void RebootAsIs(); void ColdReboot(); uint16_t DrawDiskNames(uint8_t page, int8_t selection, const char *filter); From c0f105807c7267ef806e4fead78c6803ae4bc4d8 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Fri, 8 Jan 2021 19:56:05 -0500 Subject: [PATCH 04/23] initialize cpu speed state in the bios menu so it shows the correct value --- bios.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/bios.cpp b/bios.cpp index 63dd6c2..1c24bff 100644 --- a/bios.cpp +++ b/bios.cpp @@ -173,6 +173,7 @@ bool BIOS::loop() bool hitReturn = false; uint16_t rv; + bool changingMenu = false; if (g_keyboard->kbhit()) { switch (g_keyboard->read()) { case PK_DARR: @@ -187,11 +188,13 @@ bool BIOS::loop() selectedMenuItem = 0; selectedMenu++; selectedMenu %= NUM_TITLES; + changingMenu = true; needsRedraw = true; break; case PK_LARR: selectedMenuItem = 0; selectedMenu--; + changingMenu = true; if (selectedMenu < 0) { selectedMenu = NUM_TITLES-1; } @@ -205,6 +208,29 @@ bool BIOS::loop() break; } } + + if (changingMenu && selectedMenu == BIOS_HARDWARE) { + // Need to initialize the CPU speed from g_speed + switch (g_speed) { + case 1023000: + currentCPUSpeedIndex = CPUSPEED_FULL; + break; + case 1023000/2: + currentCPUSpeedIndex = CPUSPEED_HALF; + break; + case 1023000*2: + currentCPUSpeedIndex = CPUSPEED_DOUBLE; + break; + case 1023000*4: + currentCPUSpeedIndex = CPUSPEED_QUAD; + break; + default: + // Dunno what happened, but we'll default back to full (normal) speed + currentCPUSpeedIndex = CPUSPEED_FULL; + g_speed = 1023000; + break; + } + } switch (selectedMenu) { case BIOS_AIIE: From 5c701b9418989e8fea2383a9fc67fe59990f0b2b Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sat, 9 Jan 2021 07:14:14 -0500 Subject: [PATCH 05/23] use the apple font for the BIOS (reduce memory footprint, make prettier) --- apple/font.h | 155 ++++++++++++++++++++++---------------- bios-font.h | 107 -------------------------- bios.cpp | 51 +++++++------ physicaldisplay.h | 2 +- sdl/sdl-display.cpp | 35 +++++---- sdl/sdl-display.h | 2 +- teensy/bios-font.h | 1 - teensy/teensy-display.cpp | 46 +++++++---- teensy/teensy-display.h | 2 +- 9 files changed, 174 insertions(+), 227 deletions(-) delete mode 100644 bios-font.h delete mode 120000 teensy/bios-font.h diff --git a/apple/font.h b/apple/font.h index f39f3b4..5e3173d 100644 --- a/apple/font.h +++ b/apple/font.h @@ -132,137 +132,137 @@ const unsigned char ucase_glyphs[512] = const unsigned char lcase_glyphs[256] = { - /* : 0x60 */ + /* : 0x60 \ */ 0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - /* : 0x61 */ + /* : 0x61 a */ 0x00, 0x00, 0x1c, 0x20, 0x3c, 0x22, 0x3c, 0x00, - /* : 0x62 */ + /* : 0x62 b */ 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, - /* : 0x63 */ + /* : 0x63 c */ 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, - /* : 0x64 */ + /* : 0x64 d */ 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, - /* : 0x65 */ + /* : 0x65 e */ 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x3c, 0x00, - /* : 0x66 */ + /* : 0x66 f */ 0x18, 0x24, 0x04, 0x0e, 0x04, 0x04, 0x04, 0x00, - /* : 0x67 */ + /* : 0x67 g */ 0x00, 0x00, 0x1c, 0x22, 0x22, 0x3c, 0x20, 0x1c, - /* : 0x68 */ + /* : 0x68 h */ 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, - /* : 0x69 */ + /* : 0x69 i */ 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, - /* : 0x6a */ + /* : 0x6a j */ 0x10, 0x00, 0x18, 0x10, 0x10, 0x10, 0x12, 0x0c, - /* : 0x6b */ + /* : 0x6b k */ 0x02, 0x02, 0x22, 0x12, 0x0e, 0x12, 0x22, 0x00, - /* : 0x6c */ + /* : 0x6c l */ 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, - /* : 0x6d */ + /* : 0x6d m */ 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x2a, 0x00, - /* : 0x6e */ + /* : 0x6e n */ 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, - /* : 0x6f */ + /* : 0x6f o */ 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, - /* : 0x70 */ + /* : 0x70 p */ 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, - /* : 0x71 */ + /* : 0x71 q */ 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x20, - /* : 0x72 */ + /* : 0x72 r */ 0x00, 0x00, 0x3a, 0x06, 0x02, 0x02, 0x02, 0x00, - /* : 0x73 */ + /* : 0x73 s */ 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, - /* : 0x74 */ + /* : 0x74 t */ 0x04, 0x04, 0x3e, 0x04, 0x04, 0x24, 0x18, 0x00, - /* : 0x75 */ + /* : 0x75 u */ 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, - /* : 0x76 */ + /* : 0x76 v */ 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, - /* : 0x77 */ + /* : 0x77 w */ 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, - /* : 0x78 */ + /* : 0x78 x */ 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, - /* : 0x79 */ + /* : 0x79 y */ 0x00, 0x00, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x1c, - /* : 0x7a */ + /* : 0x7a z */ 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, - /* : 0x7b */ + /* : 0x7b { */ 0x38, 0x0c, 0x0c, 0x06, 0x0c, 0x0c, 0x38, 0x00, - /* : 0x7c */ + /* : 0x7c flat colon */ 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, - /* : 0x7d */ + /* : 0x7d } */ 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, - /* : 0x7e */ + /* : 0x7e ~ */ 0x2c, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* : 0x7f */ + /* : 0x7f delete block */ 0x00, 0x2a, 0x14, 0x2a, 0x14, 0x2a, 0x00, 0x00 }; const unsigned char mousetext_glyphs[256] = { - /* : 0x00 */ + /* : 0x00 closed apple */ 0x10, 0x08, 0x36, 0x7f, 0x3f, 0x3f, 0x7e, 0x36, - /* : 0x01 */ + /* : 0x01 open apple */ 0x10, 0x08, 0x36, 0x41, 0x21, 0x21, 0x4a, 0x36, - /* : 0x02 */ + /* : 0x02 mouse pointer arrow */ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x36, 0x42, - /* : 0x03 */ + /* : 0x03 hourglass */ 0x7f, 0x22, 0x14, 0x08, 0x08, 0x14, 0x22, 0x7f, - /* : 0x04 */ + /* : 0x04 checkmark */ 0x00, 0x40, 0x20, 0x11, 0x0a, 0x04, 0x04, 0x00, - /* : 0x05 */ + /* : 0x05 inverted checkmark */ 0x7f, 0x3f, 0x5f, 0x6e, 0x75, 0x7b, 0x7b, 0x7f, - /* : 0x06 */ + /* : 0x06 left half of running person */ 0x70, 0x60, 0x7e, 0x31, 0x79, 0x30, 0x3f, 0x02, - /* : 0x07 */ + /* : 0x07 right half of running person */ 0x00, 0x18, 0x07, 0x00, 0x07, 0x0c, 0x08, 0x70, - /* : 0x08 */ + /* : 0x08 left arrow */ 0x08, 0x04, 0x02, 0x7f, 0x02, 0x04, 0x08, 0x00, - /* : 0x09 */ + /* : 0x09 ... */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, - /* : 0x0a */ + /* : 0x0a down arrow */ 0x08, 0x08, 0x08, 0x08, 0x49, 0x2a, 0x1c, 0x08, - /* : 0x0b */ + /* : 0x0b up arrow */ 0x08, 0x1c, 0x2a, 0x49, 0x08, 0x08, 0x08, 0x08, - /* : 0x0c */ + /* : 0x0c overscore */ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* : 0x0d */ + /* : 0x0d carriage return arrow */ 0x40, 0x40, 0x40, 0x44, 0x46, 0x7f, 0x06, 0x04, - /* : 0x0e */ + /* : 0x0e solid block */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - /* : 0x0f */ + /* : 0x0f inline left arrow */ 0x13, 0x18, 0x1c, 0x7e, 0x1c, 0x18, 0x10, 0x6f, - /* : 0x10 */ + /* : 0x10 inline right arrow */ 0x64, 0x0c, 0x1c, 0x3f, 0x1c, 0x0c, 0x04, 0x7b, - /* : 0x11 */ + /* : 0x11 inline down arrow */ 0x40, 0x48, 0x08, 0x7f, 0x3e, 0x1c, 0x48, 0x40, - /* : 0x12 */ + /* : 0x12 inline up arrow */ 0x40, 0x48, 0x1c, 0x3e, 0x7f, 0x08, 0x48, 0x40, - /* : 0x13 */ + /* : 0x13 dash */ 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, - /* : 0x14 */ + /* : 0x14 left/bottom border */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, - /* : 0x15 */ + /* : 0x15 right arrow */ 0x08, 0x10, 0x20, 0x7f, 0x20, 0x10, 0x08, 0x00, - /* : 0x16 */ + /* : 0x16 delete char 1 */ 0x2a, 0x55, 0x2a, 0x55, 0x2a, 0x55, 0x2a, 0x55, - /* : 0x17 */ + /* : 0x17 delete char 2 */ 0x55, 0x2a, 0x55, 0x2a, 0x55, 0x2a, 0x55, 0x2a, - /* : 0x18 */ + /* : 0x18 left half of folder */ 0x00, 0x3e, 0x41, 0x01, 0x01, 0x01, 0x7f, 0x00, - /* : 0x19 */ + /* : 0x19 right half of folder */ 0x00, 0x00, 0x3f, 0x40, 0x40, 0x40, 0x7f, 0x00, - /* : 0x1a */ + /* : 0x1a right border */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - /* : 0x1b */ + /* : 0x1b diamond */ 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00, - /* : 0x1c */ + /* : 0x1c top and bottom border */ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, - /* : 0x1d */ + /* : 0x1d crosshairs */ 0x14, 0x14, 0x77, 0x00, 0x77, 0x14, 0x14, 0x00, - /* : 0x1e */ + /* : 0x1e top/right/bottom border with center dot */ 0x7f, 0x40, 0x40, 0x4c, 0x4c, 0x40, 0x40, 0x7f, - /* : 0x1f */ + /* : 0x1f left border */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; @@ -333,3 +333,30 @@ const unsigned char interface_glyphs[256] = /* : 0x1F ----------------------- glyph_nonactionable */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +// Generic utility for anything trying to turn those glyph maps into +// characters based on ASCII input +static const unsigned char *asciiToAppleGlyph(unsigned char c) +{ + if (c < 32) { + return &ucase_glyphs[32]; // space + } else if (c <= 63) { + // space through ? + return &ucase_glyphs[(c-32+32)*8]; + } else if (c <= 95) { + // @ through Z to _ + return &ucase_glyphs[(c-64)*8]; + } else if (c <= 127) { + // Direct mapping of lcase_glyphs: ` through z to del + return &lcase_glyphs[(c-96)*8]; + } else if (c <= 159) { + // map in the 32 mousetext_glyphs + return &mousetext_glyphs[(c-128)*8]; + } else if (c <= 191) { + // map in the 32 interface_glyphs + return &interface_glyphs[(c-160)*8]; + } else { + return &ucase_glyphs[32]; // space + } +} + diff --git a/bios-font.h b/bios-font.h deleted file mode 100644 index f0756b6..0000000 --- a/bios-font.h +++ /dev/null @@ -1,107 +0,0 @@ -// SmallFont.c from UTFT library -// Font Size : 8x12 -// Memory usage : 1144 bytes -// # characters : 95 - -#ifndef TEENSYDUINO - #define PROGMEM -#endif - -// xsize: 8; ysize: 0x0C; offset: 0x20; numchars: 0x5F -uint8_t BiosFont[1140] PROGMEM={ -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // -0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, // ! -0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " -0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00, // # -0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00, // $ -0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00, // % -0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00, // & -0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' -0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00, // ( -0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00, // ) -0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00, // * -0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00, // + -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80, // , -0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, // - -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, // . -0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00, // / -0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // 0 -0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // 1 -0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00, // 2 -0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00, // 3 -0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00, // 4 -0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00, // 5 -0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00, // 6 -0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00, // 7 -0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00, // 8 -0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00, // 9 -0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00, // : -0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00, // ; -0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // < -0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, // = -0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, // > -0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, // ? -0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00, // @ -0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00, // A -0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00, // B -0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00, // C -0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00, // D -0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00, // E -0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00, // F -0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00, // G -0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00, // H -0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // I -0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00, // J -0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00, // K -0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00, // L -0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // M -0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00, // N -0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // O -0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00, // P -0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00, // Q -0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00, // R -0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00, // S -0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // T -0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00, // U -0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00, // V -0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00, // W -0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00, // X -0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // Y -0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00, // Z -0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, // [ -0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00, // -0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, // ] -0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, // _ -0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' -0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00, // a -0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00, // b -0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00, // c -0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00, // d -0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00, // e -0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00, // f -0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38, // g -0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00, // h -0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, // i -0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0, // j -0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00, // k -0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // l -0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // m -0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00, // n -0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00, // o -0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0, // p -0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C, // q -0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00, // r -0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00, // s -0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00, // t -0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00, // u -0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00, // v -0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00, // w -0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00, // x -0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0, // y -0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00, // z -0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00, // { -0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // | -0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00, // } -0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ -}; diff --git a/bios.cpp b/bios.cpp index 1c24bff..df0effd 100644 --- a/bios.cpp +++ b/bios.cpp @@ -6,6 +6,7 @@ #include "physicalkeyboard.h" #include "physicaldisplay.h" #include "cpu.h" +#include "appledisplay.h" #ifdef TEENSYDUINO #include @@ -32,6 +33,8 @@ uint16_t numCacheEntries = 0; char fileFilter[16]; // FIXME length & Strcpy -> strncpy uint16_t fileSelectionFor; // define what the returned name is for +#define LINEHEIGHT 10 + // menu screen enums enum { BIOS_AIIE = 0, @@ -129,9 +132,9 @@ void BIOS::DrawMenuBar() for (int i=0; idrawUIPixel(xpos+x, 0, 0xFFFF); - g_display->drawUIPixel(xpos+x, 16, 0xFFFF); + g_display->drawUIPixel(xpos+x, 10, 0xFFFF); } - for (int y=0; y<=16; y++) { + for (int y=0; y<=10; y++) { g_display->drawUIPixel(xpos, y, 0xFFFF); g_display->drawUIPixel(xpos + titleWidths[i] + 2*XPADDING, y, 0xFFFF); } @@ -275,7 +278,7 @@ uint16_t BIOS::AiieMenuHandler(bool needsRedraw, bool performAction) selectedMenuItem %= sizeof(aiieActions); if (needsRedraw || localRedraw) { - g_display->clrScr(); + g_display->clrScr(c_darkblue); DrawMenuBar(); DrawAiieMenu(); g_display->flush(); @@ -300,7 +303,7 @@ uint16_t BIOS::VmMenuHandler(bool needsRedraw, bool performAction) selectedMenuItem %= sizeof(vmActions); if (needsRedraw || localRedraw) { - g_display->clrScr(); + g_display->clrScr(c_darkblue); DrawMenuBar(); DrawVMMenu(); @@ -334,7 +337,7 @@ uint16_t BIOS::VmMenuHandler(bool needsRedraw, bool performAction) localRedraw = true; return BIOS_VM; case ACT_SUSPEND: - g_display->clrScr(); + g_display->clrScr(c_darkblue); g_display->drawString(M_SELECTED, 80, 100,"Suspending VM..."); g_display->flush(); // CPU is already suspended, so this is safe... @@ -342,7 +345,7 @@ uint16_t BIOS::VmMenuHandler(bool needsRedraw, bool performAction) localRedraw = true; return BIOS_VM; case ACT_RESTORE: - g_display->clrScr(); + g_display->clrScr(c_darkblue); g_display->drawString(M_SELECTED, 80, 100,"Resuming VM..."); g_display->flush(); ((AppleVM *)g_vm)->Resume("suspend.vm"); @@ -363,7 +366,7 @@ uint16_t BIOS::HardwareMenuHandler(bool needsRedraw, bool performAction) selectedMenuItem %= sizeof(hardwareActions); if (needsRedraw || localRedraw) { - g_display->clrScr(); + g_display->clrScr(c_darkblue); DrawMenuBar(); DrawHardwareMenu(); g_display->flush(); @@ -451,7 +454,7 @@ uint16_t BIOS::DisksMenuHandler(bool needsRedraw, bool performAction) selectedMenuItem %= sizeof(diskActions); if (needsRedraw || localRedraw) { - g_display->clrScr(); + g_display->clrScr(c_darkblue); DrawMenuBar(); DrawDisksMenu(); g_display->flush(); @@ -519,7 +522,7 @@ uint16_t BIOS::AboutScreenHandler(bool needsRedraw, bool performAction) selectedMenuItem = 0; if (needsRedraw || localRedraw) { - g_display->clrScr(); + g_display->clrScr(c_darkblue); g_display->drawString(M_SELECTED, 0, @@ -569,7 +572,7 @@ uint16_t BIOS::PaddlesScreenHandler(bool needsRedraw, bool performAction) if (needsRedraw || localRedraw) { char buf[50]; - g_display->clrScr(); + g_display->clrScr(c_darkblue); sprintf(buf, "Paddle X: %d ", lastPaddleX); g_display->drawString(M_NORMAL, 0, 12, buf); sprintf(buf, "Paddle Y: %d ", lastPaddleY); @@ -776,9 +779,9 @@ void BIOS::DrawAiieMenu() } if (isActionActive(aiieActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + 14 * i, + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); } } @@ -852,9 +855,9 @@ void BIOS::DrawVMMenu() } if (isActionActive(vmActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); } } } @@ -931,9 +934,9 @@ void BIOS::DrawHardwareMenu() } if (isActionActive(hardwareActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); } } @@ -1001,9 +1004,9 @@ void BIOS::DrawDisksMenu() } if (isActionActive(diskActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + 14 * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); } } } @@ -1046,7 +1049,7 @@ void BIOS::stripDirectory() uint16_t BIOS::DrawDiskNames(uint8_t page, int8_t selection, const char *filter) { uint16_t fileCount = GatherFilenames(page, filter); - g_display->clrScr(); + g_display->clrScr(c_darkblue); g_display->drawString(M_NORMAL, 0, 12, "BIOS Configuration - pick disk"); if (page == 0) { @@ -1058,18 +1061,18 @@ uint16_t BIOS::DrawDiskNames(uint8_t page, int8_t selection, const char *filter) uint8_t i; for (i=0; idrawString((i == selection-1) ? M_SELECTED : M_NORMAL, 10, 50 + 14 * (i+1), fileDirectory[i]); + g_display->drawString((i == selection-1) ? M_SELECTED : M_NORMAL, 10, 50 + LINEHEIGHT * (i+1), fileDirectory[i]); } else { - g_display->drawString((i == selection-1) ? M_SELECTDISABLED : M_DISABLED, 10, 50+14*(i+1), "-"); + g_display->drawString((i == selection-1) ? M_SELECTDISABLED : M_DISABLED, 10, 50+LINEHEIGHT*(i+1), "-"); } } // FIXME: this doesn't accurately say whether or not there *are* more. if (fileCount < BIOS_MAXFILES) { - g_display->drawString((i+1 == selection) ? M_SELECTDISABLED : M_DISABLED, 10, 50 + 14 * (i+1), ""); + g_display->drawString((i+1 == selection) ? M_SELECTDISABLED : M_DISABLED, 10, 50 + LINEHEIGHT * (i+1), ""); } else { - g_display->drawString(i+1 == selection ? M_SELECTED : M_NORMAL, 10, 50 + 14 * (i+1), ""); + g_display->drawString(i+1 == selection ? M_SELECTED : M_NORMAL, 10, 50 + LINEHEIGHT * (i+1), ""); } g_display->flush(); @@ -1089,7 +1092,7 @@ uint16_t BIOS::cacheAllEntries(const char *filter) strcpy(cachedFilter, filter); // This could be a lengthy process, so... - g_display->clrScr(); + g_display->clrScr(c_darkblue); g_display->drawString(M_SELECTED, 0, 0, diff --git a/physicaldisplay.h b/physicaldisplay.h index b8644e2..47bc7e3 100644 --- a/physicaldisplay.h +++ b/physicaldisplay.h @@ -26,7 +26,7 @@ class PhysicalDisplay { virtual void drawUIPixel(uint16_t x, uint16_t y, uint16_t color) = 0; - virtual void clrScr() = 0; + virtual void clrScr(uint8_t coloridx) = 0; // methods to draw in to the buffer - not directly to the screen. diff --git a/sdl/sdl-display.cpp b/sdl/sdl-display.cpp index caf80e5..3ffbce3 100644 --- a/sdl/sdl-display.cpp +++ b/sdl/sdl-display.cpp @@ -1,13 +1,19 @@ #include // isgraph #include "sdl-display.h" -#include "bios-font.h" #include "images.h" #include "globals.h" #include "applevm.h" #include "apple/appleui.h" +// FIXME should be able to omit this include and relay on the xterns, which +// would prove it's linking properly +#include "apple/font.h" +extern const unsigned char ucase_glyphs[512]; +extern const unsigned char lcase_glyphs[256]; +extern const unsigned char mousetext_glyphs[256]; +extern const unsigned char interface_glyphs[256]; #define SCREENINSET_X (18*SDLDISPLAY_SCALE) #define SCREENINSET_Y (13*SDLDISPLAY_SCALE) @@ -173,12 +179,8 @@ void SDLDisplay::drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t void SDLDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) { int8_t xsize = 8, - ysize = 0x0C, - offset = 0x20; - uint16_t temp; - - c -= offset;// font starts with a space - + ysize = 0x07; + uint16_t offPixel, onPixel; switch (mode) { case M_NORMAL: @@ -200,20 +202,19 @@ void SDLDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) break; } - temp=(c*ysize); - // This does not scale, because drawPixel scales. + + // This does not scale when drawing, because drawPixel scales. + const unsigned char *ch = asciiToAppleGlyph(c); for (int8_t y_off = 0; y_off <= ysize; y_off++) { - uint8_t ch = BiosFont[temp]; for (int8_t x_off = 0; x_off <= xsize; x_off++) { - if (ch & (1 << (7-x_off))) { + if (*ch & (1 << (x_off))) { drawUIPixel(x + x_off, y + y_off, onPixel); } else { drawUIPixel(x + x_off, y + y_off, offPixel); } } - temp++; + ch++; } - } void SDLDisplay::drawString(uint8_t mode, uint16_t x, uint8_t y, const char *str) @@ -227,9 +228,13 @@ void SDLDisplay::drawString(uint8_t mode, uint16_t x, uint8_t y, const char *str } } -void SDLDisplay::clrScr() +void SDLDisplay::clrScr(uint8_t coloridx) { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // set to white + const uint8_t *rgbptr = &loresPixelColors[0][0]; + if (coloridx <= 16) + rgbptr = loresPixelColors[coloridx]; + + SDL_SetRenderDrawColor(renderer, rgbptr[0], rgbptr[1], rgbptr[2], 255); // select a color SDL_RenderClear(renderer); // clear it to the selected color SDL_RenderPresent(renderer); // perform the render } diff --git a/sdl/sdl-display.h b/sdl/sdl-display.h index 8d3439c..2f15ad8 100644 --- a/sdl/sdl-display.h +++ b/sdl/sdl-display.h @@ -34,7 +34,7 @@ class SDLDisplay : public PhysicalDisplay { virtual void drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c); virtual void drawString(uint8_t mode, uint16_t x, uint8_t y, const char *str); - virtual void clrScr(); + virtual void clrScr(uint8_t coloridx); virtual void cachePixel(uint16_t x, uint16_t y, uint8_t color); virtual void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color); diff --git a/teensy/bios-font.h b/teensy/bios-font.h deleted file mode 120000 index c09ff71..0000000 --- a/teensy/bios-font.h +++ /dev/null @@ -1 +0,0 @@ -../bios-font.h \ No newline at end of file diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index b0daa91..87d87eb 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -3,8 +3,15 @@ #include "teensy-display.h" -#include "bios-font.h" #include "appleui.h" +// FIXME should be able to omit this include and relay on the xterns, which +// would prove it's linking properly +#include "font.h" +extern const unsigned char ucase_glyphs[512]; +extern const unsigned char lcase_glyphs[256]; +extern const unsigned char mousetext_glyphs[256]; +extern const unsigned char interface_glyphs[256]; + #include #define _clock 75000000 @@ -126,9 +133,27 @@ void TeensyDisplay::redraw() } } -void TeensyDisplay::clrScr() +void TeensyDisplay::clrScr(uint8_t coloridx) { - memset(dmaBuffer, 0x00, sizeof(dmaBuffer)); + if (coloridx == c_black) { + memset(dmaBuffer, 0x00, sizeof(dmaBuffer)); + } else if (coloridx == c_white) { + memset(dmaBuffer, 0xFF, sizeof(dmaBuffer)); + } else { + const uint8_t *rgbptr = &loresPixelColors[0][0]; + if (coloridx <= 16) + rgbptr = loresPixelColors[coloridx]; + uint16_t color16 = ((rgbptr[0] & 0xF8) << 8) | + ((rgbptr[1] & 0xFC) << 3) | + ((rgbptr[2] & 0xF8) >> 3); + // This could be faster - make one line, then memcpy the line to the other + // lines? + for (uint8_t y=0; y Date: Sat, 9 Jan 2021 07:56:31 -0500 Subject: [PATCH 06/23] fixups for teensy display --- teensy/teensy-display.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index 87d87eb..4f1152f 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -37,7 +37,9 @@ extern const unsigned char interface_glyphs[256]; #include "globals.h" #include "applevm.h" -DMAMEM uint16_t dmaBuffer[240][320]; // 240 rows, 320 columns +#define PHYSMAXX 320 +#define PHYSMAXY 240 +DMAMEM uint16_t dmaBuffer[PHYSMAXY][PHYSMAXX]; // 240 rows, 320 columns #define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3)) #define _565toR(c) ( ((c) & 0xF800) >> 8 ) @@ -140,16 +142,13 @@ void TeensyDisplay::clrScr(uint8_t coloridx) } else if (coloridx == c_white) { memset(dmaBuffer, 0xFF, sizeof(dmaBuffer)); } else { - const uint8_t *rgbptr = &loresPixelColors[0][0]; - if (coloridx <= 16) - rgbptr = loresPixelColors[coloridx]; - uint16_t color16 = ((rgbptr[0] & 0xF8) << 8) | - ((rgbptr[1] & 0xFC) << 3) | - ((rgbptr[2] & 0xF8) >> 3); + uint16_t color16 = loresPixelColors[c_black]; + if (coloridx < 16) + color16 = loresPixelColors[coloridx]; // This could be faster - make one line, then memcpy the line to the other // lines? - for (uint8_t y=0; y= nextMessageTime) { if (overlayMessage[0]) { - drawString(M_SELECTDISABLED, 1, 240 - 16 - 12, overlayMessage); + drawString(M_SELECTDISABLED, 1, PHYSMAXY - 16 - 12, overlayMessage); } nextMessageTime = millis() + 1000; } @@ -231,9 +230,9 @@ void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) // This does not scale when drawing, because drawPixel scales. const unsigned char *ch = asciiToAppleGlyph(c); for (int8_t y_off = 0; y_off <= ysize; y_off++) { - if (y + y_off < 240) { // FIXME constant + if (y + y_off < PHYSMAXY) { for (int8_t x_off = 0; x_off <= xsize; x_off++) { - if (x+x_off < 320) { // FIXME constant + if (x+x_off < PHYSMAXX) { if (*ch & (1 << (x_off))) { dmaBuffer[y+y_off][x+x_off] = onPixel; } else { @@ -252,8 +251,8 @@ void TeensyDisplay::drawString(uint8_t mode, uint16_t x, uint8_t y, const char * for (int8_t i=0; i= 320) break; // FIXME constant + x += xsize; + if (x >= PHYSMAXX) break; } } @@ -289,7 +288,6 @@ void TeensyDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color) void TeensyDisplay::cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorA, uint8_t colorB) { - // FIXME: Convert 4-bit colors to 16-bit colors? dmaBuffer[y+VOFFSET][x+ HOFFSET] = loresPixelColors[colorB&0xF]; dmaBuffer[y+VOFFSET][x+1+HOFFSET] = loresPixelColors[colorA&0xF]; } From d2c4b983469605a1aa7925d642f48bb5399de574 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sat, 9 Jan 2021 10:48:15 -0500 Subject: [PATCH 07/23] cleanups for file selection --- bios.cpp | 134 +++++++++++++++++++++++++++---------------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/bios.cpp b/bios.cpp index df0effd..69d4837 100644 --- a/bios.cpp +++ b/bios.cpp @@ -34,6 +34,9 @@ char fileFilter[16]; // FIXME length & Strcpy -> strncpy uint16_t fileSelectionFor; // define what the returned name is for #define LINEHEIGHT 10 +#define MENUINDENT 10 +#define MAXFILESPERPAGE BIOS_MAXFILES +#define FILEMENUSTARTAT (LINEHEIGHT+1) // menu screen enums enum { @@ -132,9 +135,9 @@ void BIOS::DrawMenuBar() for (int i=0; idrawUIPixel(xpos+x, 0, 0xFFFF); - g_display->drawUIPixel(xpos+x, 10, 0xFFFF); + g_display->drawUIPixel(xpos+x, LINEHEIGHT, 0xFFFF); } - for (int y=0; y<=10; y++) { + for (int y=0; y<=LINEHEIGHT; y++) { g_display->drawUIPixel(xpos, y, 0xFFFF); g_display->drawUIPixel(xpos + titleWidths[i] + 2*XPADDING, y, 0xFFFF); } @@ -658,45 +661,6 @@ uint16_t BIOS::SelectFileScreenHandler(bool needsRedraw, bool performAction) return BIOS_SELECTFILE; } -/* -bool BIOS::runUntilDone() -{ - // Reset the cache - cachedPath[0] = 0; - numCacheEntries = 0; - - g_filemanager->getRootPath(rootPath, sizeof(rootPath)); - - // FIXME: abstract these constant speeds - currentCPUSpeedIndex = CPUSPEED_FULL; - if (g_speed == 1023000/2) - currentCPUSpeedIndex = CPUSPEED_HALF; - if (g_speed == 1023000*2) - currentCPUSpeedIndex = CPUSPEED_DOUBLE; - if (g_speed == 1023000*4) - currentCPUSpeedIndex = CPUSPEED_QUAD; - - int8_t prevAction = ACT_EXIT; - while (1) { - switch (prevAction = GetAction(prevAction)) { - - *** - // ConfigurePaddles(); -*** - } - } - - done: - // Undo whatever damage we've done to the screen - g_display->redraw(); - AiieRect r = { 0, 0, 191, 279 }; - g_display->blit(r); - - // return true if any persistent setting changed that we want to store in eeprom - return true; -} -*/ - void BIOS::WarmReset() { g_cpu->Reset(); @@ -779,9 +743,9 @@ void BIOS::DrawAiieMenu() } if (isActionActive(aiieActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, MENUINDENT, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, MENUINDENT, 20 + LINEHEIGHT * i, buf); } } @@ -855,9 +819,9 @@ void BIOS::DrawVMMenu() } if (isActionActive(vmActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, MENUINDENT, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, MENUINDENT, 20 + LINEHEIGHT * i, buf); } } } @@ -934,9 +898,9 @@ void BIOS::DrawHardwareMenu() } if (isActionActive(hardwareActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, MENUINDENT, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, MENUINDENT, 20 + LINEHEIGHT * i, buf); } } @@ -1004,9 +968,9 @@ void BIOS::DrawDisksMenu() } if (isActionActive(diskActions[i])) { - g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTED : M_NORMAL, MENUINDENT, 20 + LINEHEIGHT * i, buf); } else { - g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + LINEHEIGHT * i, buf); + g_display->drawString(selectedMenuItem == i ? M_SELECTDISABLED : M_DISABLED, MENUINDENT, 20 + LINEHEIGHT * i, buf); } } } @@ -1039,7 +1003,6 @@ void BIOS::stripDirectory() } // We're either at the previous directory, or we've nulled out the whole thing. - if (rootPath[0] == '\0') { // Never go beyond this strcpy(rootPath, "/"); @@ -1050,29 +1013,66 @@ uint16_t BIOS::DrawDiskNames(uint8_t page, int8_t selection, const char *filter) { uint16_t fileCount = GatherFilenames(page, filter); g_display->clrScr(c_darkblue); - g_display->drawString(M_NORMAL, 0, 12, "BIOS Configuration - pick disk"); - - if (page == 0) { - g_display->drawString(selection == 0 ? M_SELECTDISABLED : M_DISABLED, 10, 50, ""); - } else { - g_display->drawString(selection == 0 ? M_SELECTED : M_NORMAL, 10, 50, ""); + const char *title="BIOS Configuration - pick disk image"; + g_display->drawString(M_NORMAL, 0, 0, title); + + for (int x=0; xdrawUIPixel(x, LINEHEIGHT-1, 0xFFFF); } + uint8_t vpos = FILEMENUSTARTAT; + g_display->drawString(page==0 ? (selection == 0 ? M_SELECTDISABLED : M_DISABLED) : + (selection == 0 ? M_SELECTED : M_NORMAL), + MENUINDENT, vpos, ""); + vpos += LINEHEIGHT * 1.5; + + bool endsHere = false; uint8_t i; - for (i=0; idrawString((i == selection-1) ? M_SELECTED : M_NORMAL, 10, 50 + LINEHEIGHT * (i+1), fileDirectory[i]); - } else { - g_display->drawString((i == selection-1) ? M_SELECTDISABLED : M_DISABLED, 10, 50+LINEHEIGHT*(i+1), "-"); - } + for (i=0; idrawString( + (i < fileCount) ? ((i == selection-1) ? M_SELECTED : M_NORMAL) : + (i == selection-1) ? M_SELECTDISABLED : M_DISABLED, + + MENUINDENT, vpos, + + name); + vpos += LINEHEIGHT; + + if (strlen(fileDirectory[i]) > 39) { + // Break the string at 39 characters and start drawing the second line indented more + char restOfString[BIOS_MAXPATH-39+1]; + strcpy(restOfString, (char *)&name[39]); + g_display->drawString( + (i < fileCount) ? ((i == selection-1) ? M_SELECTED : M_NORMAL) : + (i == selection-1) ? M_SELECTDISABLED : M_DISABLED, + + MENUINDENT+15, + vpos, + + restOfString); + vpos += LINEHEIGHT; + + } + if (i >= fileCount) + endsHere = true; } - // FIXME: this doesn't accurately say whether or not there *are* more. - if (fileCount < BIOS_MAXFILES) { - g_display->drawString((i+1 == selection) ? M_SELECTDISABLED : M_DISABLED, 10, 50 + LINEHEIGHT * (i+1), ""); + vpos += LINEHEIGHT/2; + if (endsHere || fileCount < BIOS_MAXFILES) { + g_display->drawString((i+1 == selection) ? M_SELECTDISABLED : M_DISABLED, + MENUINDENT, vpos, + ""); } else { - g_display->drawString(i+1 == selection ? M_SELECTED : M_NORMAL, 10, 50 + LINEHEIGHT * (i+1), ""); + g_display->drawString(i+1 == selection ? M_SELECTED : M_NORMAL, + MENUINDENT, vpos, + ""); } g_display->flush(); @@ -1144,7 +1144,7 @@ void BIOS::sortCachedEntries() uint16_t BIOS::GatherFilenames(uint8_t pageOffset, const char *filter) { - uint8_t startNum = 10 * pageOffset; + uint8_t startNum = MAXFILESPERPAGE * pageOffset; uint8_t count = 0; // number we're including in our listing uint16_t numEntriesTotal = cacheAllEntries(filter); From 5c6354e025716982bccfa06d3d496eecf52970cf Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sat, 9 Jan 2021 11:30:19 -0500 Subject: [PATCH 08/23] fix disk behavior on bios reboot --- bios.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/bios.cpp b/bios.cpp index 69d4837..181f39f 100644 --- a/bios.cpp +++ b/bios.cpp @@ -670,22 +670,27 @@ void BIOS::RebootAsIs() { // g_vm->Reset() will eject disks. We don't want to do that, so we need to // grab the inserted disk names; reset the VM; then restore the disks. - const char *disk6s1 = ((AppleVM *)g_vm)->DiskName(0); - const char *disk6s2 = ((AppleVM *)g_vm)->DiskName(1); - const char *hdd1 = ((AppleVM *)g_vm)->HDName(0); - const char *hdd2 = ((AppleVM *)g_vm)->HDName(1); - + char *disk6s1 = strdup(((AppleVM *)g_vm)->DiskName(0) ? ((AppleVM *)g_vm)->DiskName(0) : ""); + char *disk6s2 = strdup(((AppleVM *)g_vm)->DiskName(1) ? ((AppleVM *)g_vm)->DiskName(1) : ""); + char *hdd1 = strdup(((AppleVM *)g_vm)->HDName(0) ? ((AppleVM *)g_vm)->HDName(0) : ""); + char *hdd2 = strdup(((AppleVM *)g_vm)->HDName(1) ? ((AppleVM *)g_vm)->HDName(1) : ""); + g_vm->Reset(); g_cpu->Reset(); - if (disk6s1) + if (disk6s1[0]) ((AppleVM *)g_vm)->insertDisk(0, disk6s1); - if (disk6s2) + if (disk6s2[0]) ((AppleVM *)g_vm)->insertDisk(1, disk6s2); - if (hdd1) + if (hdd1[0]) ((AppleVM *)g_vm)->insertHD(0, hdd1); - if (hdd2) + if (hdd2[0]) ((AppleVM *)g_vm)->insertHD(2, hdd2); + + free(disk6s1); + free(disk6s2); + free(hdd1); + free(hdd2); } void BIOS::ColdReboot() From 0df32dbeba27645191bf3161bcea7e320450894c Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sat, 9 Jan 2021 12:15:12 -0500 Subject: [PATCH 09/23] improve BIOS about screen --- bios.cpp | 76 ++++++++++++++++++++++++++++++++++++++- globals.h | 3 +- sdl/sdl-display.cpp | 4 +++ teensy/teensy-display.cpp | 4 +++ 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/bios.cpp b/bios.cpp index 181f39f..84735be 100644 --- a/bios.cpp +++ b/bios.cpp @@ -527,6 +527,13 @@ uint16_t BIOS::AboutScreenHandler(bool needsRedraw, bool performAction) if (needsRedraw || localRedraw) { g_display->clrScr(c_darkblue); + // Draw a black area where we're going to "boot" a fake //e for the about screen. Don't put the whole graphic around it so it's obvious it's not a //e. + for (uint8_t y=12; y<12+192; y++) { + for (uint16_t x=20; x<280+20; x++) { + g_display->drawUIPixel( x, y, 0x0000 ); + } + } + /* g_display->drawString(M_SELECTED, 0, 0, @@ -544,13 +551,80 @@ uint16_t BIOS::AboutScreenHandler(bool needsRedraw, bool performAction) 0, 200, "Press return"); - + */ g_display->flush(); localRedraw = false; } + const char *str = + " " + " Aiie! " + " " + " " + " " + " " + " " + " " + " ... an Apple //e emulator " + " written by " + " Jorj Bauer " + " " + " " + " " + " (c) 2017-2021 Jorj Bauer " + " " + " " + " Source code is available at " + " github.com/JorjBauer/aiie/ " + " " + " " + " " + " Press ... " // intentionally short so cursor stays here + ; + + static uint16_t ptr = 0; + static bool didFinish = false; + + if (!didFinish) { + // Draw the next character + bool didOne = false; + while (!didOne || ptr < 35*2) { // draw the first 2 lines in one go, no matter what + char charToDraw = str[ptr]; + didOne = true; + int xpos = ptr % 35; + int ypos = (int)(ptr / 35); + if (charToDraw != ' ') { + // First 2 lines have a blue background on any text; others are black + g_display->drawCharacter(ptr < 70 ? M_NORMAL : M_PLAIN, xpos * 8 + 20, ypos * 8 + 12, charToDraw); + } + ptr++; + if (ptr >= strlen(str)) { + didFinish = true; + } else { + if (charToDraw == ' ') { + // Just blep the spaces to the screen toot-sweet + didOne = false; + } + } + } + } else { + // Flash the cursor until the user exits + static bool cursorOn = false; + static bool flopTime = false; + flopTime = !flopTime; + if (flopTime) { + cursorOn = !cursorOn; + } + int xpos = strlen(str) % 35; + int ypos = (int)(strlen(str) / 35); + g_display->drawCharacter(M_PLAIN, xpos * 8 + 20, ypos * 8 + 12, cursorOn ? 127 : 32); + } + g_display->flush(); + if (performAction) { + ptr = 0; + didFinish = false; return BIOS_AIIE; } diff --git a/globals.h b/globals.h index e995cc2..d8fda9a 100644 --- a/globals.h +++ b/globals.h @@ -19,7 +19,8 @@ enum { M_NORMAL = 0, M_SELECTED = 1, M_DISABLED = 2, - M_SELECTDISABLED = 3 + M_SELECTDISABLED = 3, + M_PLAIN = 4 }; // debug modes diff --git a/sdl/sdl-display.cpp b/sdl/sdl-display.cpp index 3ffbce3..0132751 100644 --- a/sdl/sdl-display.cpp +++ b/sdl/sdl-display.cpp @@ -200,6 +200,10 @@ void SDLDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) onPixel = 0x7BEF; offPixel = 0xFFE0; break; + case M_PLAIN: + onPixel = 0xFFFF; + offPixel = 0x0000; + break; } diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index 4f1152f..3d38079 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -225,6 +225,10 @@ void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) onPixel = 0x7BEF; offPixel = 0xFFE0; break; + case M_PLAIN: + onPixel = 0xFFFF; + offPixel = 0x0000; + break; } // This does not scale when drawing, because drawPixel scales. From 2eb24f9b3f641f7d459c70b9ae9505b8ef036a76 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sat, 9 Jan 2021 21:32:40 -0500 Subject: [PATCH 10/23] fix suspend/resume --- apple/applemmu.cpp | 83 ++++++++-------- apple/applevm.cpp | 79 +++++++-------- apple/applevm.h | 4 +- apple/diskii.cpp | 177 +++++++++++----------------------- apple/hd32.cpp | 109 ++++++++------------- apple/woz-serializer.cpp | 74 ++++++-------- cpu.cpp | 87 +++++++---------- globals.cpp | 4 + globals.h | 4 + nix/nix-filemanager.cpp | 40 +++++--- teensy/fscompat.h | 6 +- teensy/iocompat.h | 12 +++ teensy/teensy-filemanager.cpp | 13 ++- vm.h | 4 +- vmram.cpp | 44 ++++----- 15 files changed, 310 insertions(+), 430 deletions(-) create mode 100644 teensy/iocompat.h diff --git a/apple/applemmu.cpp b/apple/applemmu.cpp index 2ba4005..84216e2 100644 --- a/apple/applemmu.cpp +++ b/apple/applemmu.cpp @@ -12,10 +12,13 @@ #include "physicalspeaker.h" #include "cpu.h" +#include "serialize.h" + #include "globals.h" #ifdef TEENSYDUINO #include "teensy-clock.h" +#include "iocompat.h" #else #include "nix-clock.h" #endif @@ -166,24 +169,23 @@ AppleMMU::~AppleMMU() bool AppleMMU::Serialize(int8_t fd) { - uint8_t buf[13] = { MMUMAGIC, - (uint8_t)((switches >> 8) & 0xFF), - (uint8_t)((switches ) & 0xFF), - auxRamRead ? 1 : 0, - auxRamWrite ? 1 : 0, - bank2 ? 1 : 0, - readbsr ? 1 : 0, - writebsr ? 1 : 0, - altzp ? 1 : 0, - intcxrom ? 1 : 0, - slot3rom ? 1 : 0, - slotLatch, - preWriteFlag ? 1 : 0 }; - if (g_filemanager->write(fd, buf, 13) != 13) - return false; + serializeMagic(MMUMAGIC); + serialize16(switches); + serialize8(auxRamRead ? 1 : 0); + serialize8(auxRamWrite ? 1 : 0); + serialize8(bank2 ? 1 : 0); + serialize8(readbsr ? 1 : 0); + serialize8(writebsr ? 1 : 0); + serialize8(altzp ? 1 : 0); + serialize8(intcxrom ? 1 : 0); + serialize8(slot3rom ? 1 : 0); + serialize8(slotLatch); + serialize8(preWriteFlag ? 1 : 0); - if (!g_ram.Serialize(fd)) - return false; + if (!g_ram.Serialize(fd)) { + printf("Failed to serialize RAM\n"); + goto err; + } // readPages & writePages don't need suspending, but we will need to // recalculate after resume @@ -191,47 +193,42 @@ bool AppleMMU::Serialize(int8_t fd) // Not suspending/resuming slots b/c they're a fixed configuration // in this project. Should probably checksum them though. FIXME. - if (g_filemanager->write(fd, buf, 1) != 1) - return false; - + serializeMagic(MMUMAGIC); return true; + + err: + return false; } bool AppleMMU::Deserialize(int8_t fd) { - uint8_t buf[13]; + deserializeMagic(MMUMAGIC); - if (g_filemanager->read(fd, buf, 13) != 13) - return false; + deserialize16(switches); + serialize8(auxRamRead); + serialize8(auxRamWrite); + serialize8(bank2); + serialize8(readbsr); + serialize8(writebsr); + serialize8(altzp); + serialize8(intcxrom); + serialize8(slot3rom); + serialize8(slotLatch); + serialize8(preWriteFlag); - if (buf[0] != MMUMAGIC) - return false; - - switches = (buf[1] << 8) | buf[2]; - auxRamRead = buf[3]; - auxRamWrite = buf[4]; - bank2 = buf[5]; - readbsr = buf[6]; - writebsr = buf[7]; - altzp = buf[8]; - intcxrom = buf[9]; - slot3rom = buf[10]; - slotLatch = buf[11]; - preWriteFlag = buf[12]; - if (!g_ram.Deserialize(fd)) { - return false; + goto err; } - if (g_filemanager->read(fd, buf, 1) != 1) - return false; - if (buf[0] != MMUMAGIC) - return false; + deserializeMagic(MMUMAGIC); // Reset readPages[] and writePages[] and the display resetDisplay(); return true; + + err: + return false; } diff --git a/apple/applevm.cpp b/apple/applevm.cpp index b0c822c..3fc0d2c 100644 --- a/apple/applevm.cpp +++ b/apple/applevm.cpp @@ -6,10 +6,13 @@ #include "applekeyboard.h" #include "physicalkeyboard.h" +#include "serialize.h" + #include "globals.h" #ifdef TEENSYDUINO #include "teensy-println.h" +#include "iocompat.h" #endif #include @@ -43,83 +46,75 @@ AppleVM::~AppleVM() delete parallel; } -void AppleVM::Suspend(const char *fn) +bool AppleVM::Suspend(const char *fn) { /* Open a new suspend file via the file manager; tell all our objects to serialize in to it; close the file */ - int8_t fh = g_filemanager->openFile(fn); - if (fh == -1) { + int8_t fd = g_filemanager->openFile(fn); + if (fd == -1) { // Unable to open; skip suspend - return; + printf("failed to open suspend file\n"); + return false; } /* Header */ - if (g_filemanager->write(fh, suspendHdr, strlen(suspendHdr)) != strlen(suspendHdr)) - return; + serializeString(suspendHdr); /* Tell all of the peripherals to suspend */ - if (g_cpu->Serialize(fh) && - disk6->Serialize(fh) && - hd32->Serialize(fh) + if (g_cpu->Serialize(fd) && + disk6->Serialize(fd) && + hd32->Serialize(fd) ) { -#ifdef TEENSYDUINO - println("All serialized successfully"); -#else printf("All serialized successfully\n"); -#endif } - g_filemanager->closeFile(fh); + g_filemanager->closeFile(fd); + return true; + + err: + g_filemanager->closeFile(fd); + return false; } -void AppleVM::Resume(const char *fn) +bool AppleVM::Resume(const char *fn) { /* Open the given suspend file via the file manager; tell all our objects to deserialize from it; close the file */ - int8_t fh = g_filemanager->openFile(fn); - if (fh == -1) { + int8_t fd = g_filemanager->openFile(fn); + if (fd == -1) { // Unable to open; skip resume -#ifdef TEENSYDUINO - print("Unable to open resume file "); - println(fn); -#else - printf("Unable to open resume file\n"); -#endif - g_filemanager->closeFile(fh); - return; + printf("Unable to open resume file '%s'\n", fn); + goto err; } /* Header */ - uint8_t c; - for (int i=0; iread(fh, &c, 1) != 1 || - c != suspendHdr[i]) { - /* Failed to read correct header; abort */ - g_filemanager->closeFile(fh); - return; - } + deserializeString(debugBuf); + if (strcmp(debugBuf, suspendHdr)) { + printf("Bad file header while resuming\n"); + goto err; } /* Tell all of the peripherals to resume */ - if (g_cpu->Deserialize(fh) && - disk6->Deserialize(fh) && - hd32->Deserialize(fh) + if (g_cpu->Deserialize(fd) && + disk6->Deserialize(fd) && + hd32->Deserialize(fd) ) { -#ifdef TEENSYDUINO - println("Deserialization successful"); -#else printf("All deserialized successfully\n"); -#endif } else { -#ifndef TEENSYDUINO printf("Deserialization failed\n"); +#ifndef TEENSYDUINO exit(1); #endif + goto err; } - g_filemanager->closeFile(fh); + g_filemanager->closeFile(fd); + return true; + err: + g_filemanager->closeFile(fd); + return false; } // fixme: make member vars diff --git a/apple/applevm.h b/apple/applevm.h index 65e02f4..57759b1 100644 --- a/apple/applevm.h +++ b/apple/applevm.h @@ -15,8 +15,8 @@ class AppleVM : public VM { AppleVM(); virtual ~AppleVM(); - void Suspend(const char *fn); - void Resume(const char *fn); + bool Suspend(const char *fn); + bool Resume(const char *fn); void cpuMaintenance(int64_t cycles); diff --git a/apple/diskii.cpp b/apple/diskii.cpp index 16177d1..42f9288 100644 --- a/apple/diskii.cpp +++ b/apple/diskii.cpp @@ -3,6 +3,7 @@ #ifdef TEENSYDUINO #include #include "teensy-println.h" +#include "iocompat.h" #else #include #include @@ -16,6 +17,8 @@ #include "globals.h" #include "appleui.h" +#include "serialize.h" + #include "diskii-rom.h" #define DISKIIMAGIC 0xAA @@ -57,171 +60,101 @@ DiskII::~DiskII() bool DiskII::Serialize(int8_t fd) { - uint8_t buf[27] = { DISKIIMAGIC, - readWriteLatch, - sequencer, - dataRegister, - writeMode, - writeProt, - selectedDisk }; + serializeMagic(DISKIIMAGIC); + serialize8(readWriteLatch); + serialize8(sequencer); + serialize8(dataRegister); + serialize8(writeMode); + serialize8(writeProt); + serialize8(selectedDisk); - if (g_filemanager->write(fd, buf, 7) != 7) { - return false; - } - for (int i=0; i<2; i++) { - uint8_t ptr = 0; - buf[ptr++] = curHalfTrack[i]; - buf[ptr++] = curWozTrack[i]; - buf[ptr++] = curPhase[i]; - buf[ptr++] = ((driveSpinupCycles[i] >> 56) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] >> 48) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] >> 40) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] >> 32) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] >> 24) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] >> 16) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] >> 8) & 0xFF); - buf[ptr++] = ((driveSpinupCycles[i] ) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 56) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 48) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 40) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 32) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 24) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 16) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] >> 8) & 0xFF); - buf[ptr++] = ((deliveredDiskBits[i] ) & 0xFF); - buf[ptr++] = (diskIsSpinningUntil[i] >> 56) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] >> 48) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] >> 40) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] >> 32) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] >> 24) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] >> 16) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] >> 8) & 0xFF; - buf[ptr++] = (diskIsSpinningUntil[i] ) & 0xFF; - // Safety check: keeping the hard-coded 27 and comparing against ptr. - // If we change the 27, also need to change the size of buf[] above - if (g_filemanager->write(fd, buf, 27) != ptr) { - return false; - } + serialize8(curHalfTrack[i]); + serialize8(curWozTrack[i]); + serialize8(curPhase[i]); + serialize64(driveSpinupCycles[i]); + serialize64(deliveredDiskBits[i]); + serialize64(diskIsSpinningUntil[i]); if (disk[i]) { // Make sure we have flushed the disk images disk[i]->flush(); flushAt[i] = 0; // and there's no need to re-flush them now - buf[0] = 1; - if (g_filemanager->write(fd, buf, 1) != 1) - return false; + serialize8(1); // FIXME: this ONLY works for builds using the filemanager to read // the disk image, so it's broken until we port Woz to do that! const char *fn = disk[i]->diskName(); - if (g_filemanager->write(fd, fn, strlen(fn)+1) != strlen(fn)+1) // include null terminator - return false; + serializeString(fn); if (!disk[i]->Serialize(fd)) - return false; + goto err; } else { - buf[0] = 0; - if (g_filemanager->write(fd, buf, 0) != 1) - return false; + serialize8(0); } } - buf[0] = DISKIIMAGIC; - if (g_filemanager->write(fd, buf, 1) != 1) - return false; + serializeMagic(DISKIIMAGIC); return true; + err: + return false; } bool DiskII::Deserialize(int8_t fd) { - uint8_t buf[MAXPATH]; - if (g_filemanager->read(fd, buf, 7) != 7) - return false; - if (buf[0] != DISKIIMAGIC) - return false; + deserializeMagic(DISKIIMAGIC); - readWriteLatch = buf[1]; - sequencer = buf[2]; - dataRegister = buf[3]; - writeMode = buf[4]; - writeProt = buf[5]; - selectedDisk = buf[6]; + deserialize8(readWriteLatch); + deserialize8(sequencer); + deserialize8(dataRegister); + deserialize8(writeMode); + deserialize8(writeProt); + deserialize8(selectedDisk); for (int i=0; i<2; i++) { - uint8_t ptr = 0; - if (g_filemanager->read(fd, buf, 27) != 27) - return false; + deserialize8(curHalfTrack[i]); + deserialize8(curWozTrack[i]); + deserialize8(curPhase[i]); - curHalfTrack[i] = buf[ptr++]; - curWozTrack[i] = buf[ptr++]; - curPhase[i] = buf[ptr++]; + deserialize64(driveSpinupCycles[i]); + deserialize64(deliveredDiskBits[i]); + deserialize64(diskIsSpinningUntil[i]); - driveSpinupCycles[i] = buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; - - deliveredDiskBits[i] = buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; - - diskIsSpinningUntil[i] = buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; - diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++]; + uint8_t hasDisk; + deserialize8(hasDisk); - if (disk[i]) - delete disk[i]; - if (g_filemanager->read(fd, buf, 1) != 1) - return false; - if (buf[0]) { + if (disk[i]) delete disk[i]; + if (hasDisk) { disk[i] = new WozSerializer(); - ptr = 0; // FIXME: MAXPATH check! - while (1) { - if (g_filemanager->read(fd, &buf[ptr++], 1) != 1) - return false; - if (buf[ptr-1] == 0) - break; - } - if (buf[0]) { - // Important we don't read all the tracks, so we can also flush - // writes back to the fd... - disk[i]->readFile((char *)buf, false, T_AUTO); // FIXME error checking + char fn[MAXPATH]; + deserializeString(fn); + if (fn[0]) { + printf("Restoring disk image named '%s'\n", fn); + disk[i]->readFile((char *)fn, false, T_AUTO); // FIXME error checking } else { // ERROR: there's a disk but we don't have the path to its image? - return false; + printf("Failed to read inserted disk name for disk %d\n", i); + goto err; } - if (!disk[i]->Deserialize(fd)) - return false; + if (!disk[i]->Deserialize(fd)) { + printf("Failed to deserialize disk %d\n", i); + goto err; + } } else { disk[i] = NULL; } } - if (g_filemanager->read(fd, buf, 1) != 1) - return false; - if (buf[0] != DISKIIMAGIC) - return false; + deserializeMagic(DISKIIMAGIC); return true; + + err: + return false; } void DiskII::Reset() diff --git a/apple/hd32.cpp b/apple/hd32.cpp index 4837d39..f05030c 100644 --- a/apple/hd32.cpp +++ b/apple/hd32.cpp @@ -12,6 +12,7 @@ #ifdef TEENSYDUINO #include #include "teensy-println.h" +#include "iocompat.h" #else #include #include @@ -23,6 +24,8 @@ #include "applemmu.h" // for FLOATING +#include "serialize.h" + #include "globals.h" #include "hd32-rom.h" @@ -66,92 +69,58 @@ HD32::~HD32() bool HD32::Serialize(int8_t fd) { - uint8_t buf[19] = { HD32MAGIC, - driveSelected, - unitSelected, - command, - enabled, - errorState[0], - errorState[1], - (uint8_t)((memBlock[0] >> 8) & 0xFF), - (uint8_t)((memBlock[0] ) & 0xFF), - (uint8_t)((memBlock[1] >> 8) & 0xFF), - (uint8_t)((memBlock[1] ) & 0xFF), - (uint8_t)((cursor[0] >> 24) & 0xFF), - (uint8_t)((cursor[0] >> 16) & 0xFF), - (uint8_t)((cursor[0] >> 8) & 0xFF), - (uint8_t)((cursor[0] ) & 0xFF), - (uint8_t)((cursor[1] >> 24) & 0xFF), - (uint8_t)((cursor[1] >> 16) & 0xFF), - (uint8_t)((cursor[1] >> 8) & 0xFF), - (uint8_t)((cursor[1] ) & 0xFF) - }; - if (g_filemanager->write(fd, buf, 19) != 10) - return false; + serializeMagic(HD32MAGIC); + serialize8(driveSelected); + serialize8(unitSelected); + serialize8(command); + serialize8(enabled); + serialize8(errorState[0]); + serialize8(errorState[1]); + serialize16(memBlock[0]); + serialize16(memBlock[1]); + serialize32(cursor[0]); + serialize32(cursor[1]); for (int i=0; i<2; i++) { const char *fn = diskName(i); - if (g_filemanager->write(fd, fn, strlen(fn)+1) != strlen(fn)+1) { - return false; - } + serializeString(fn); } + serializeMagic(HD32MAGIC); + return true; - buf[0] = HD32MAGIC; - return (g_filemanager->write(fd, buf, 1) == 1); + err: + return false; } bool HD32::Deserialize(int8_t fd) { - uint8_t buf[255]; - if (g_filemanager->read(fd, buf, 19) != 19) { - return false; - } - if (buf[0] != HD32MAGIC) - return false; - - driveSelected = buf[1]; - unitSelected = buf[2]; - command = buf[3]; - enabled = buf[4]; - errorState[0] = buf[5]; - errorState[1] = buf[6]; - memBlock[0] = buf[7]; - memBlock[0] <<= 8; memBlock[0] |= buf[8]; - memBlock[1] = buf[9]; - memBlock[1] <<= 8; memBlock[1] |= buf[10]; - cursor[0] = buf[11]; - cursor[0] <<= 8; cursor[0] |= buf[12]; - cursor[0] <<= 8; cursor[0] |= buf[13]; - cursor[0] <<= 8; cursor[0] |= buf[14]; - cursor[1] = buf[15]; - cursor[1] <<= 8; cursor[1] |= buf[16]; - cursor[1] <<= 8; cursor[1] |= buf[17]; - cursor[1] <<= 8; cursor[1] |= buf[18]; + deserializeMagic(HD32MAGIC); + deserialize8(driveSelected); + deserialize8(unitSelected); + deserialize8(command); + deserialize8(enabled); + deserialize8(errorState[0]); + deserialize8(errorState[1]); + deserialize16(memBlock[0]); + deserialize16(memBlock[1]); + deserialize32(cursor[0]); + deserialize32(cursor[1]); + cachedBlockNum = -1; // just invalidate the cache; it will reload... for (int i=0; i<2; i++) { - uint32_t ptr = 0; - // FIXME: MAXPATH check! - while (1) { - if (g_filemanager->read(fd, &buf[ptr++], 1) != 1) - return false; - if (buf[ptr-1] == 0) - break; - } - if (strlen((char *)buf)) { - // FIXME: this tromps on error and some other vars ... that we just restored - insertDisk(i, (char *)buf); - } + char buf[MAXPATH]; + deserializeString(buf); + // FIXME: this tromps on error and some other vars ... that we just restored + insertDisk(i, (char *)buf); } - if (g_filemanager->read(fd, buf, 1) != 1) - return false; - - if (buf[0] != HD32MAGIC) - return false; - + deserializeMagic(HD32MAGIC); + return true; + err: + return false; } void HD32::Reset() diff --git a/apple/woz-serializer.cpp b/apple/woz-serializer.cpp index 926182a..890d3eb 100644 --- a/apple/woz-serializer.cpp +++ b/apple/woz-serializer.cpp @@ -1,6 +1,12 @@ #include "woz-serializer.h" #include "globals.h" +#include "serialize.h" + +#ifdef TEENSYDUINO +#include "iocompat.h" +#endif + #define WOZMAGIC 0xD5 WozSerializer::WozSerializer() : Woz(0,0) @@ -20,60 +26,36 @@ bool WozSerializer::Serialize(int8_t fd) // If we're being asked to serialize, make sure we've flushed any data first flush(); - uint8_t buf[17] = { WOZMAGIC, - (trackPointer >> 24) & 0xFF, - (trackPointer >> 16) & 0xFF, - (trackPointer >> 8) & 0xFF, - (trackPointer ) & 0xFF, - (trackBitCounter >> 24) & 0xFF, - (trackBitCounter >> 16) & 0xFF, - (trackBitCounter >> 8) & 0xFF, - (trackBitCounter ) & 0xFF, - (lastReadPointer >> 24) & 0xFF, - (lastReadPointer >> 16) & 0xFF, - (lastReadPointer >> 8) & 0xFF, - (lastReadPointer ) & 0xFF, - trackByte, - trackBitIdx, - trackLoopCounter, - WOZMAGIC }; - if (g_filemanager->write(fd, buf, 17) != 17) - return false; + serializeMagic(WOZMAGIC); + serialize32(trackPointer); + serialize32(trackBitCounter); + serialize32(lastReadPointer); + serialize8(trackByte); + serialize8(trackBitIdx); + serialize8(trackLoopCounter); + serializeMagic(WOZMAGIC); return true; + + err: + return false; } bool WozSerializer::Deserialize(int8_t fd) { // Before deserializing, the caller has to re-load the right disk image! - uint8_t buf[17]; - if (g_filemanager->read(fd, buf, 17) != 17) - return false; - - if (buf[0] != WOZMAGIC) - return false; - - trackPointer = buf[1]; - trackPointer <<= 8; trackPointer |= buf[2]; - trackPointer <<= 8; trackPointer |= buf[3]; - trackPointer <<= 8; trackPointer |= buf[4]; - - trackBitCounter = buf[5]; - trackBitCounter <<= 8; trackBitCounter |= buf[6]; - trackBitCounter <<= 8; trackBitCounter |= buf[7]; - trackBitCounter <<= 8; trackBitCounter |= buf[8]; - - lastReadPointer = buf[9]; - lastReadPointer <<= 8; lastReadPointer |= buf[10]; - lastReadPointer <<= 8; lastReadPointer |= buf[11]; - lastReadPointer <<= 8; lastReadPointer |= buf[12]; - - trackByte = buf[13]; - trackBitIdx = buf[14]; - trackLoopCounter = buf[15]; - if (buf[16] != WOZMAGIC) - return false; + deserializeMagic(WOZMAGIC); + deserialize32(trackPointer); + deserialize32(trackBitCounter); + deserialize32(lastReadPointer); + deserialize8(trackByte); + deserialize8(trackBitIdx); + deserialize8(trackLoopCounter); + deserializeMagic(WOZMAGIC); return true; + + err: + return false; } diff --git a/cpu.cpp b/cpu.cpp index 7738457..532a3b1 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -7,10 +7,13 @@ #include #include "mmu.h" +#include "serialize.h" + #include "globals.h" #ifdef TEENSYDUINO #include "teensy-println.h" +#include "iocompat.h" #endif // define DEBUGSTEPS to show disassembly of each instruction as it's processed @@ -320,74 +323,54 @@ Cpu::~Cpu() mmu = NULL; } -bool Cpu::Serialize(int8_t fh) +bool Cpu::Serialize(int8_t fd) { - uint8_t buf[13] = { CPUMAGIC, - (uint8_t)((pc >> 8) & 0xFF), - (uint8_t)((pc ) & 0xFF), - sp, - a, - x, - y, - flags, - (uint8_t)((cycles >> 24) & 0xFF), - (uint8_t)((cycles >> 16) & 0xFF), - (uint8_t)((cycles >> 8) & 0xFF), - (uint8_t)((cycles ) & 0xFF), - irqPending ? (uint8_t)1 : (uint8_t)0 }; + serializeMagic(CPUMAGIC); + serialize16(pc); + serialize8(sp); + serialize8(a); + serialize8(x); + serialize8(y); + serialize8(flags); + serialize32(cycles); + serialize8(irqPending ? 1 : 0); - if (g_filemanager->write(fh, buf, 13) != 13) - return false; - - if (!mmu->Serialize(fh)) { -#ifndef TEENSYDUINO + if (!mmu->Serialize(fd)) { printf("MMU serialization failed\n"); -#else - println("MMU serialization failed"); -#endif - return false; + goto err; } - - if (g_filemanager->write(fh, buf, 1) != 1) - return false; + serializeMagic(CPUMAGIC); return true; + + err: + return false; } -bool Cpu::Deserialize(int8_t fh) +bool Cpu::Deserialize(int8_t fd) { - uint8_t buf[13]; - if (g_filemanager->read(fh, buf, 13) != 13) - return false; - if (buf[0] != CPUMAGIC) - return false; - pc = (buf[1] << 8) | buf[2]; - sp = buf[3]; - a = buf[4]; - x = buf[5]; - y = buf[6]; - flags = buf[7]; - - cycles = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; - - irqPending = buf[12]; - - if (!mmu->Deserialize(fh)) { -#ifndef TEENSYDUINO + deserializeMagic(CPUMAGIC); + deserialize16(pc); + deserialize8(sp); + deserialize8(a); + deserialize8(x); + deserialize8(y); + deserialize8(flags); + deserialize32(cycles); + deserialize8(irqPending); + + if (!mmu->Deserialize(fd)) { printf("MMU deserialization failed\n"); -#endif return false; } - if (g_filemanager->read(fh, buf, 1) != 1) - return false; - if (buf[0] != CPUMAGIC) - return false; + deserializeMagic(CPUMAGIC); -#ifndef TEENSYDUINO printf("CPU deserialization complete\n"); -#endif return true; + + err: + return false; } void Cpu::Reset() diff --git a/globals.cpp b/globals.cpp index e9e683d..e614a4c 100644 --- a/globals.cpp +++ b/globals.cpp @@ -19,3 +19,7 @@ bool g_invertPaddleX = false; bool g_invertPaddleY = false; char debugBuf[255]; + +#ifdef TEENSYDUINO +char fsbuf[200]; +#endif diff --git a/globals.h b/globals.h index d8fda9a..5edd239 100644 --- a/globals.h +++ b/globals.h @@ -56,4 +56,8 @@ extern bool g_invertPaddleY; extern char debugBuf[255]; +#ifdef TEENSYDUINO +extern char fsbuf[200]; +#endif + #endif diff --git a/nix/nix-filemanager.cpp b/nix/nix-filemanager.cpp index 9793d16..5b8b5bc 100644 --- a/nix/nix-filemanager.cpp +++ b/nix/nix-filemanager.cpp @@ -194,33 +194,43 @@ void NixFileManager::seekToEnd(int8_t fd) int NixFileManager::write(int8_t fd, const void *buf, int nbyte) { - if (fd < 0 || fd >= numCached) + if (fd < 0 || fd >= numCached) { + printf("invalid fd (out of range)\n"); return -1; + } - if (cachedNames[fd][0] == 0) + if (cachedNames[fd][0] == 0) { + printf("invalid fd (not opened)\n"); return -1; + } uint32_t pos = fileSeekPositions[fd]; // open, seek, write, close. - bool ret = false; + ssize_t rv = 0; int ffd = ::open(cachedNames[fd], O_WRONLY|O_CREAT, 0644); - if (ffd != -1) { - if (::lseek(ffd, pos, SEEK_SET) == -1) { - close(ffd); - return -1; - } - ssize_t rv = ::write(ffd, buf, nbyte); - if (rv != nbyte) { - printf("error writing: %d; wanted to write %d got %d\n", errno, nbyte, ret); - } - close(ffd); - } else { + if (ffd == -1) { printf("Failed to open '%s' for writing: %d\n", cachedNames[fd], errno); + close(ffd); + return -1; } + + if (::lseek(ffd, pos, SEEK_SET) == -1) { + printf("failed to open and seek\n"); + close(ffd); + return -1; + } + + rv = ::write(ffd, buf, nbyte); + if (rv != nbyte) { + printf("error writing: %d; wanted to write %d got %ld\n", errno, nbyte, rv); + } + + close(ffd); + fileSeekPositions[fd]+=nbyte; - return ret; + return (int)rv; }; int NixFileManager::read(int8_t fd, void *buf, int nbyte) diff --git a/teensy/fscompat.h b/teensy/fscompat.h index 0fc0830..1fd1a8a 100644 --- a/teensy/fscompat.h +++ b/teensy/fscompat.h @@ -16,8 +16,4 @@ #define read(filedes,buf,nbyte) g_filemanager->read(filedes,buf,nbyte) #define lseek(filedes,offset,whence) g_filemanager->lseek(filedes,offset,whence) -static char fsbuf[200]; -#define printf(x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();} -#define fprintf(f, x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();} -#define perror(x) {Serial.println(x);Serial.flush(); Serial.send_now();} - +#include "iocompat.h" diff --git a/teensy/iocompat.h b/teensy/iocompat.h new file mode 100644 index 0000000..94531ce --- /dev/null +++ b/teensy/iocompat.h @@ -0,0 +1,12 @@ +#ifndef __IOCOMPAT_H +#define __IOCOMPAT_H + +#include "globals.h" +#include + +#define printf(x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();} +#define fprintf(f, x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();} +#define perror(x) {Serial.println(x);Serial.flush(); Serial.send_now();} + + +#endif diff --git a/teensy/teensy-filemanager.cpp b/teensy/teensy-filemanager.cpp index 44b4f48..5c24a80 100644 --- a/teensy/teensy-filemanager.cpp +++ b/teensy/teensy-filemanager.cpp @@ -9,7 +9,7 @@ static SdFat sd; static FsFile cacheFile; static FsFile outerDir; - +#include "iocompat.h" TeensyFileManager::TeensyFileManager() { @@ -179,14 +179,15 @@ bool TeensyFileManager::_prepCache(int8_t fd) } // Open the new one - cacheFile.open(cachedNames[fd], O_RDWR); + cacheFile.open(cachedNames[fd], O_CREAT|O_RDWR); if (!cacheFile) { + printf("failed to open cacheFile\n"); return false; } cacheFd = fd; // cache is live } - return true; // FIXME error handling + return true; } void TeensyFileManager::getRootPath(char *toWhere, int8_t maxLen) @@ -225,10 +226,12 @@ int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte) { // open, seek, write, close. if (fd < 0 || fd >= numCached) { + printf("no fd\n"); return -1; } if (cachedNames[fd][0] == 0) { + printf("no name\n"); return -1; } @@ -237,15 +240,16 @@ int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte) uint32_t pos = fileSeekPositions[fd]; if (!cacheFile.seek(pos)) { + printf("can't seek to %d\n", pos); return -1; } if (cacheFile.write((const uint8_t *)buf, (size_t)nbyte) != (size_t)nbyte) { + printf("can't write\n"); return -1; } fileSeekPositions[fd] += nbyte; - cacheFile.close(); return nbyte; }; @@ -266,6 +270,7 @@ int TeensyFileManager::read(int8_t fd, void *buf, int nbyte) if (!cacheFile.seek(pos)) { return -1; } + fileSeekPositions[fd] += nbyte; if (cacheFile.read(buf, nbyte) != nbyte) { diff --git a/vm.h b/vm.h index c98a02a..6eebc11 100644 --- a/vm.h +++ b/vm.h @@ -16,8 +16,8 @@ class VM { VM() { mmu=NULL; vmdisplay = NULL; hasIRQ = false;} virtual ~VM() { if (mmu) delete mmu; if (vmdisplay) delete vmdisplay; } - virtual void Suspend(const char *fn) = 0; - virtual void Resume(const char *fn) = 0; + virtual bool Suspend(const char *fn) = 0; + virtual bool Resume(const char *fn) = 0; virtual void SetMMU(MMU *mmu) { this->mmu = mmu; } virtual MMU *getMMU() { return mmu; } diff --git a/vmram.cpp b/vmram.cpp index cb07178..236de94 100644 --- a/vmram.cpp +++ b/vmram.cpp @@ -5,6 +5,7 @@ #include "vmram.h" #include +#include "serialize.h" #include "globals.h" #ifdef TEENSYDUINO @@ -55,46 +56,35 @@ uint8_t *VMRam::memPtr(uint32_t addr) bool VMRam::Serialize(int8_t fd) { uint32_t size = sizeof(preallocatedRam); - uint8_t buf[5] = { RAMMAGIC, - (uint8_t)((size >> 24) & 0xFF), - (uint8_t)((size >> 16) & 0xFF), - (uint8_t)((size >> 8) & 0xFF), - (uint8_t)((size ) & 0xFF) }; - if (g_filemanager->write(fd, buf, 5) != 5) - return false; + serializeMagic(RAMMAGIC); + serialize32(size); if (g_filemanager->write(fd, preallocatedRam, sizeof(preallocatedRam)) != sizeof(preallocatedRam)) - return false; - - if (g_filemanager->write(fd, buf, 1) != 1) - return false; + goto err; + + serializeMagic(RAMMAGIC); return true; + + err: + return false; } bool VMRam::Deserialize(int8_t fd) { - uint8_t buf[5]; - if (g_filemanager->read(fd, buf, 5) != 5) - return false; - - if (buf[0] != RAMMAGIC) - return false; - - uint32_t size = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4]; - - if (size != sizeof(preallocatedRam)) - return false; + deserializeMagic(RAMMAGIC); + uint32_t size; + deserialize32(size); if (g_filemanager->read(fd, preallocatedRam, size) != size) - return false; + goto err; - if (g_filemanager->read(fd, buf, 1) != 1) - return false; - if (buf[0] != RAMMAGIC) - return false; + deserializeMagic(RAMMAGIC); return true; + + err: + return false; } bool VMRam::Test() From f5985c2ca6fc4233b9dca64641d600df2e7ee6ee Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sun, 10 Jan 2021 00:47:56 -0500 Subject: [PATCH 11/23] debugging fixes --- teensy/teensy.ino | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/teensy/teensy.ino b/teensy/teensy.ino index f99180a..36f39e1 100644 --- a/teensy/teensy.ino +++ b/teensy/teensy.ino @@ -13,6 +13,7 @@ #include "appleui.h" #include "teensy-prefs.h" #include "teensy-println.h" +#include "smalloc.h" //#define DEBUG_TIMING @@ -240,21 +241,38 @@ void setup() // FIXME: move these memory-related functions elsewhere... // This only gives you an estimated free mem size. It's not perfect. -uint32_t FreeRamEstimate() +uint32_t FreeIntRamEstimate() { - uint32_t stackTop; uint32_t heapTop; - // current position of the stack. - stackTop = (uint32_t) &stackTop; + // The Teensy 4.1 has different memory regions; the stack grows down + // from the top of RAM1, and the heap gros up from the start of + // RAM2. The end of RAM2 is 0x20280000, so if we malloc a byte we + // should be able to calculate a gross estimate (ignoring memory + // holes created by fragmentation of course). - // current position of heap. void* hTop = malloc(1); heapTop = (uint32_t) hTop; free(hTop); - // The difference is the free, available ram. - return stackTop - heapTop; + return 0x20280000 - heapTop; +} + +uint32_t FreeExtRamEstimate() +{ + // EXTMEM uses a different thing entirely - the smalloc library is + // embedded in TeensyDuino (as of this writing) and we should be + // able to query it to see how much ram exists, is in use, and is + // free. However, at some point this will break, and we'll have to + // figure out what new library Teensyduino moved to... + + size_t total = 0, totalUser = 0, freespace = 0; + int blocks; // number of blocks allocated + sm_malloc_stats_pool(&extmem_smalloc_pool, &total, &totalUser, &freespace, &blocks); + + // total and totalUser always seem to be 0. So is blocks. But freespace might be real? + + return freespace; } #include "malloc.h" @@ -302,8 +320,13 @@ void runDisplay(uint32_t now) if (now >= microsForNext) { refreshCount++; microsForNext = microsAtStart + (1000000.0*((float)refreshCount/(float)TARGET_FPS)); - - doDebugging(lastFps); + + { static uint32_t nextDebugTime = 0; + if (millis() > nextDebugTime) { + doDebugging(lastFps); + nextDebugTime = millis() + 1000; + } + } if (!g_biosInterrupt) { g_ui->blit(); @@ -500,7 +523,7 @@ void doDebugging(uint32_t lastFps) g_display->debugMsg(debugBuf); break; case D_SHOWMEMFREE: - sprintf(debugBuf, "%lu %u", FreeRamEstimate(), heapSize()); + sprintf(debugBuf, "%lu %lu", FreeIntRamEstimate(), FreeExtRamEstimate()); g_display->debugMsg(debugBuf); break; case D_SHOWPADDLES: From 3a254f83f1a3598fccb884cd4609392f0effb03e Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sun, 10 Jan 2021 07:34:57 -0500 Subject: [PATCH 12/23] remove single cached track hack; convert to EXTMEM on the Teensy 4 --- apple/woz.cpp | 65 +++++++-------------------------------------------- apple/woz.h | 1 - 2 files changed, 9 insertions(+), 57 deletions(-) diff --git a/apple/woz.cpp b/apple/woz.cpp index 9fa62bf..3f0b36e 100644 --- a/apple/woz.cpp +++ b/apple/woz.cpp @@ -5,14 +5,15 @@ #include "version.h" #include "fscompat.h" -extern uint32_t FreeRamEstimate(); - // Block number we start packing data bits after (Woz 2.0 images) #define STARTBLOCK 3 #ifdef TEENSYDUINO #define SKIPCHECKSUM -#define STATICALLOC +#define malloc extmem_malloc +#define free extmem_free +#define calloc extmem_calloc +#define realloc extmem_realloc #endif #define PREP_SECTION(fd, t) { \ @@ -59,18 +60,12 @@ Woz::~Woz() fd = -1; } -#ifdef STATICALLOC - for (int i=0; i<160; i++) { - tracks[i].trackData = NULL; - } -#else for (int i=0; i<160; i++) { if (tracks[i].trackData) { free(tracks[i].trackData); tracks[i].trackData = NULL; } } -#endif if (metaData) { free(metaData); metaData = NULL; @@ -661,18 +656,12 @@ bool Woz::loadMissingTrackFromImage(uint8_t datatrack) // autoFlushTrackData==true (trying to limit memory use) if (autoFlushTrackData == true) { flush(); -#ifdef STATICALLOC - for (int i=0; i<160; i++) { - tracks[i].trackData = NULL; - } -#else for (int i=0; i<160; i++) { if (tracks[i].trackData) { free(tracks[i].trackData); tracks[i].trackData = NULL; } } -#endif } // Based on the source image type, load the data track we're looking for if (imageType == T_WOZ) { @@ -699,16 +688,12 @@ bool Woz::loadMissingTrackFromImage(uint8_t datatrack) return false; } -#ifdef STATICALLOC - tracks[datatrack].trackData = singleCachedTrack; - memset(singleCachedTrack, 0, sizeof(singleCachedTrack)); -#else tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); if (!tracks[datatrack].trackData) { fprintf(stderr, "Failed to malloc track data\n"); return false; } -#endif + tracks[datatrack].startingBlock = STARTBLOCK + 13*phystrack; // make it look like it came from a WOZ2 image tracks[datatrack].blockCount = 13; uint32_t sizeInBits = nibblizeTrack(tracks[datatrack].trackData, sectorData, imageType, phystrack); @@ -725,15 +710,11 @@ bool Woz::loadMissingTrackFromImage(uint8_t datatrack) // If the source was a NIB file, then the datatrack is directly // mapped 1:1 to the physical track uint8_t phystrack = datatrack; // used for clarity of which kind of track we mean, below -#ifdef STATICALLOC - tracks[datatrack].trackData = singleCachedTrack; - memset(singleCachedTrack, 0, sizeof(singleCachedTrack)); -#else tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); if (!tracks[datatrack].trackData) { return false; } -#endif + lseek(fd, NIBTRACKSIZE * phystrack, SEEK_SET); read(fd, tracks[datatrack].trackData, NIBTRACKSIZE); // FIXME: no error checking @@ -751,10 +732,6 @@ bool Woz::loadMissingTrackFromImage(uint8_t datatrack) bool Woz::readDskFile(const char *filename, bool preloadTracks, uint8_t subtype) { -#ifdef STATICALLOC - preloadTracks = false; -#endif - bool retval = false; autoFlushTrackData = !preloadTracks; imageType = subtype; @@ -778,16 +755,12 @@ bool Woz::readDskFile(const char *filename, bool preloadTracks, uint8_t subtype) goto done; } uint8_t datatrack = quarterTrackMap[phystrack*4]; -#ifdef STATICALLOC - tracks[datatrack].trackData = singleCachedTrack; - memset(singleCachedTrack, 0, sizeof(singleCachedTrack)); -#else tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); if (!tracks[datatrack].trackData) { fprintf(stderr, "Failed to malloc track data\n"); goto done; } -#endif + tracks[datatrack].startingBlock = STARTBLOCK + 13*datatrack; // make it look like it came from a WOZ2 image tracks[datatrack].blockCount = 13; uint32_t sizeInBits = nibblizeTrack(tracks[datatrack].trackData, sectorData, subtype, phystrack); @@ -803,9 +776,6 @@ bool Woz::readDskFile(const char *filename, bool preloadTracks, uint8_t subtype) bool Woz::readNibFile(const char *filename, bool preloadTracks) { -#ifdef STATICALLOC - preloadTracks = false; -#endif autoFlushTrackData = !preloadTracks; imageType = T_NIB; @@ -828,16 +798,12 @@ bool Woz::readNibFile(const char *filename, bool preloadTracks) return false; } uint8_t datatrack = quarterTrackMap[phystrack * 4]; -#ifdef STATICALLOC - tracks[datatrack].trackData = singleCachedTrack; - memset(singleCachedTrack, 0, sizeof(singleCachedTrack)); -#else tracks[datatrack].trackData = (uint8_t *)calloc(NIBTRACKSIZE, 1); if (!tracks[datatrack].trackData) { fprintf(stderr, "Failed to malloc track data\n"); return false; } -#endif + memcpy(tracks[datatrack].trackData, nibData, NIBTRACKSIZE); tracks[datatrack].startingBlock = STARTBLOCK + 13*phystrack; // make it look like it came from a WOZ2 image tracks[datatrack].blockCount = 13; @@ -854,9 +820,6 @@ bool Woz::readNibFile(const char *filename, bool preloadTracks) bool Woz::readWozFile(const char *filename, bool preloadTracks) { -#ifdef STATICALLOC - preloadTracks = false; -#endif imageType = T_WOZ; autoFlushTrackData = !preloadTracks; @@ -1009,9 +972,6 @@ bool Woz::readWozFile(const char *filename, bool preloadTracks) bool Woz::readFile(const char *filename, bool preloadTracks, uint8_t forceType) { -#ifdef STATICALLOC - preloadTracks = false; -#endif if (forceType == T_AUTO) { // Try to determine type from the file extension const char *p = strrchr(filename, '.'); @@ -1214,20 +1174,13 @@ bool Woz::readWozDataTrack(uint8_t datatrack) if (tracks[datatrack].trackData) { return true; // We've already read this track's data; don't re-read it } -#ifdef STATICALLOC - tracks[datatrack].trackData = singleCachedTrack; - memset(singleCachedTrack, 0, sizeof(singleCachedTrack)); - if (count > sizeof(singleCachedTrack)) { - fprintf(stderr, "Want to alloc buffer than size of singleCachedTrack! About to overrun memory"); - } -#else tracks[datatrack].trackData = (uint8_t *)calloc(count, 1); if (!tracks[datatrack].trackData) { perror("Failed to alloc buf to read track magnetic data"); return false; } -#endif + if (di.version == 1) { if (verbose) { printf("Reading datatrack[1] %d starting at byte 0x%X\n", diff --git a/apple/woz.h b/apple/woz.h index 0a7608c..01e291d 100644 --- a/apple/woz.h +++ b/apple/woz.h @@ -123,7 +123,6 @@ class Woz { uint8_t quarterTrackMap[40*4]; diskInfo di; trackInfo tracks[160]; - uint8_t singleCachedTrack[0x1A00]; // cursor for track enumeration protected: From b09df8e5f96d80158341efd3a2dd79670b0a8483 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sun, 10 Jan 2021 15:04:52 -0500 Subject: [PATCH 13/23] VBL interrupts work; roughing in physical mouse --- apple/applevm.cpp | 1 + apple/mouse.cpp | 225 ++++++++++++++++++++++++++++++++++++++++------ apple/mouse.h | 6 ++ physicalmouse.h | 14 +++ teensy/teensy.ino | 4 +- vmram.cpp | 4 +- 6 files changed, 224 insertions(+), 30 deletions(-) create mode 100644 physicalmouse.h diff --git a/apple/applevm.cpp b/apple/applevm.cpp index 3fc0d2c..07e2986 100644 --- a/apple/applevm.cpp +++ b/apple/applevm.cpp @@ -136,6 +136,7 @@ void AppleVM::cpuMaintenance(int64_t cycles) keyboard->maintainKeyboard(cycles); disk6->maintenance(cycles); + mouse->maintainMouse(cycles); } void AppleVM::Reset() diff --git a/apple/mouse.cpp b/apple/mouse.cpp index 9eacc91..e252ef4 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -1,9 +1,31 @@ #include "mouse.h" #include +#include "globals.h" + #include "mouse-rom.h" +enum { + SW_R_HOMEMOUSE = 0x08, + SW_R_POSMOUSE = 0x09, + SW_R_CLEARMOUSE = 0x0A, + SW_R_READMOUSE = 0x0B, + SW_R_INITMOUSE = 0x0C, + SW_W_CLAMPMOUSE = 0x0D, + SW_R_SERVEMOUSE = 0x0E, + SW_W_SETMOUSE = 0x0F +}; + +enum { + ST_MOUSEENABLE = 1, + ST_INTMOUSE = 2, + ST_INTBUTTON = 4, + ST_INTVBL = 8 +}; + Mouse::Mouse() { + status = 0; + interruptsTriggered = 0; } Mouse::~Mouse() @@ -26,17 +48,82 @@ void Mouse::Reset() uint8_t Mouse::readSwitches(uint8_t s) { + switch (s) { + case SW_R_HOMEMOUSE: + printf("unimplemented SW_R_HOMEMOUSE\n"); + /* physical mouse X = $578/$478; + * physical mouse Y = $5f8/$4f8 */ + break; + case SW_R_POSMOUSE: + printf("unimplemented SW_R_POSMOUSE\n"); + /* physical mouse X = $578+4/$478+4; + * physical mouse Y + $5F8+4/$4f8+4 */ + break; + case SW_R_CLEARMOUSE: + g_ram.writeByte(0x578+4, 0); + g_ram.writeByte(0x478+4, 0); + g_ram.writeByte(0x5F8+4, 0); + g_ram.writeByte(0x4F8+4, 0); + /* physical mouse X = Y = 0 */ + break; + case SW_R_READMOUSE: + printf("unimplemented SW_R_READMOUSE\n"); + // FIXME: read from physical mouse and write to: + g_ram.writeByte(0x578+4, 0); // high X + g_ram.writeByte(0x478+4, 0); // low X + g_ram.writeByte(0x5F8+4, 0); // high Y + g_ram.writeByte(0x4F8+4, 0); // low Y + break; + case SW_R_INITMOUSE: + // Set clamp to (0,0) - (1023,1023) + g_ram.writeByte(0x578, 0); // high of lowclamp + g_ram.writeByte(0x478, 0); // low of lowclamp + g_ram.writeByte(0x5F8, 0x03); // high of highclamp + g_ram.writeByte(0x4F8, 0xFF); // low of highclamp + printf("unimplemented SW_R_INITMOUSE\n"); + /* physicalMouse->setClamp(XCLAMP, 0, 1023); + * physicalMouse->setClamp(YCLAMP, 0, 1023); */ + break; + case SW_R_SERVEMOUSE: + g_ram.writeByte(0x778+4, interruptsTriggered); + g_ram.writeByte(0x6B8+4, interruptsTriggered); // hack to appease ROM + interruptsTriggered = 0; + break; + default: + printf("mouse: unknown switch read 0x%X\n", s); + }; return 0xFF; } void Mouse::writeSwitches(uint8_t s, uint8_t v) { - printf("unknown switch 0x%X\n", s); + switch (s) { + case SW_W_CLAMPMOUSE: + { + uint16_t lowval = (g_ram.readByte(0x578) << 8) | (g_ram.readByte(0x478)); + uint16_t highval = (g_ram.readByte(0x5F8) << 8) | (g_ram.readByte(0x4F8)); + if (v) { + // Y is clamping + /* physicalMouse->setClamp(YCLAMP, lowval, highval); */ + } else { + // X is clamping + /* physicalMouse->setClamp(XCLAMP, lowval, highval); */ + } + printf("unimplemented SW_W_CLAMPMOUSE [0x%X]\n", v); + } + break; + case SW_W_SETMOUSE: + status = v; + break; + default: + printf("mouse: unknown switch write 0x%X\n", s); + break; + } } void Mouse::loadROM(uint8_t *toWhere) { - /* ROM Disassembly: + /* Actual mouse ROM Disassembly: C400- 2C 58 FF BIT $FF58 ; test bits in FF58 w/ A C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $20 on boot-up C405- 38 SEC @@ -149,16 +236,16 @@ C46F- B0 3F BCS $C4B0 ; RTS if A >= 0x10 C471- 99 82 C0 STA $C082,Y ; LC RAM bank 2, read ROM, wr-protect RAM C474- 60 RTS ; ServeMouse -C475- 48 PHA +C475- 48 PHA ; save A C476- 18 CLC -C477- 90 39 BCC $C4B2 ; always branches +C477- 90 39 BCC $C4B2 ; always branches ; ServeMouse cleanup and exit C479- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM -C47C- BD B8 06 LDA $06B8,X +C47C- BD B8 06 LDA $06B8,X ; apparently this is where the new status wound up, also $7f8 + C47F- 29 0E AND #$0E -C481- D0 01 BNE $C484 +C481- D0 01 BNE $C484 ; if the interrupt bits don't show it was a mouse interrupt, set error (C) before returning C483- 38 SEC -C484- 68 PLA +C484- 68 PLA ; restore A C485- 60 RTS ; ClampMouse C486- C9 02 CMP #$02 @@ -216,39 +303,102 @@ C4CC- A9 03 LDA #$03 C4CE- 18 CLC C4CF- 90 A8 BCC $C479 ; always branches +... but the version below is patched so it uses soft switches to call +back here. + +SETMOUSE: +C471- 8D CF C0 STA $C0CF ; use soft switch 0xF to handle it + 60 RTS + +Patch: C471 from 99 82 C0 60 => 8D CF C0 60 + +SERVEMOUSE @ $C4B2: + 78 SEI + AD CE C0 LDA $C0CE ; use soft switch 0xE (read) to trigger this - expect ne\ +w value to be placed in $7f8+4 and $6b8+4 + A2 04 LDX #$04 ; our slot number, for cleanup code + 18 CLC + 90 C1 BCC $C47C + +Patch: C4B2 from 08 A5 00 48 A9 60 85 00 78 => + 78 AD CE C0 A2 04 18 90 C1 + +READMOUSE +C48E- AD CB C0 LDA $C04B ; soft switch 0x0B for readmouse + 18 CLC + 60 RTS + +Patch: from A9 04 99 83 C0 => + AD CB C0 18 60 + +CLEARMOUSE +C49F- AD CA C0 LDA $C04A ; soft switch 0x0A for clearmouse + 18 CLC + 60 RTS + +Patch: from EA A9 05 D0 F6 => + AD CA C0 18 60 +POSMOUSE +C4a4- AD C9 C0 LDA $C049 ; soft switch 0x09 for posmouse + 18 CLC + 60 RTS + +Patch: from EA A9 06 D0 F1 => + AD C9 C0 18 60 + +CLAMPMOUSE +C48A- 8D CD C0 STA $C04D ; use write to soft switch 0x0D to trigger clamp + 60 RTS + +Patch: from 99 83 C0 60 => 8D CD C0 60 + +HOMEMOUSE +C4A9- AD C8 C0 LDA $c048 ; soft switch 0x08 for homemouse (read) + 18 CLC + 60 RTS + +Patch: from EA A9 07 D0 EC => AD C8 C0 18 60 + +INITMOUSE +C498- AD CC C0 LDA $C04C ; soft switch 0x0C read for initmouse + 18 CLC + 60 RTS + +Patch: from A9 02 99 83 C0 => AD CC C0 18 60 */ - uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, + + uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, // C400 0xb8, 0x50, 0x15, 0x01, 0x20, 0xae, 0xae, 0xae, - 0xae, 0x00, 0x6d, 0x75, 0x8e, 0x9f, 0xa4, 0x86, + 0xae, 0x00, 0x6d, 0x75, 0x8e, 0x9f, 0xa4, 0x86, // C410 0xa9, 0x97, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0x48, 0x98, 0x48, 0x8a, 0x48, 0x08, 0x78, 0x20, + 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, + 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, + 0xa9, 0x05, 0x85, 0x38, 0xd0, 0x0b, 0xb0, 0x09, // C440 0x68, 0xaa, 0x68, 0xea, 0x68, 0x99, 0x80, 0xc0, - 0x60, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, + 0x60, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, // C450 0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C460 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x10, 0xb0, - 0x3f, 0x99, 0x82, 0xc0, 0x60, 0x48, 0x18, 0x90, + 0x3f, 0x8D, 0xCF, 0xc0, 0x60, 0x48, 0x18, 0x90, // C470 0x39, 0x99, 0x83, 0xc0, 0xbd, 0xb8, 0x06, 0x29, - 0x0E, 0xD0, 0x01, 0x38, 0x68, 0x60, 0xc9, 0x02, - 0xb0, 0x26, 0x99, 0x83, 0xc0, 0x60, 0xa9, 0x04, - 0x99, 0x83, 0xc0, 0x18, 0xea, 0xea, 0x60, 0xea, - 0xa9, 0x02, 0x99, 0x83, 0xc0, 0x18, 0x60, 0xea, - 0xa9, 0x05, 0xd0, 0xf6, 0xea, 0xa9, 0x06, 0xd0, - 0xf1, 0xea, 0xa9, 0x07, 0xd0, 0xec, 0xa2, 0x03, - 0x38, 0x60, 0x08, 0xa5, 0x00, 0x48, 0xa9, 0x60, - 0x85, 0x00, 0x78, 0x20, 0x00, 0x00, 0xba, 0x68, - 0x85, 0x00, 0xbd, 0x00, 0x01, 0x28, 0xaa, 0x0a, + 0x0E, 0xD0, 0x01, 0x38, 0x68, 0x60, 0xc9, 0x02, // C480 + 0xb0, 0x26, 0x8D, 0xCD, 0xc0, 0x60, 0xAD, 0xCB, + 0xC0, 0x18, 0x60, 0x18, 0xea, 0xea, 0x60, 0xea, // C490 + 0xAD, 0xCC, 0xC0, 0x18, 0x60, 0x18, 0x60, 0xAD, + 0xCA, 0xC0, 0x18, 0x60, 0xAD, 0xC9, 0xc0, 0x18, // C4A0 + 0x60, 0xAD, 0xC8, 0xC0, 0x18, 0x60, 0xa2, 0x03, + 0x38, 0x60, 0x78, 0xad, 0xce, 0xc0, 0xa2, 0x04, // C4B0 + 0x18, 0x90, 0xc1, 0x20, 0x00, 0x00, 0xba, 0x68, + 0x85, 0x00, 0xbd, 0x00, 0x01, 0x28, 0xaa, 0x0a, // C4C0 0x0a, 0x0a, 0x0a, 0xa8, 0xa9, 0x03, 0x18, 0x90, - 0xa8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xa8, 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); } @@ -260,8 +410,29 @@ bool Mouse::hasExtendedRom() void Mouse::loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset) { +#if 0 printf("loading extended rom for the mouse\n"); for (int i=0; i<256; i++) { toWhere[i] = romData[i + byteOffset]; } +#endif +} + +void Mouse::maintainMouse(int64_t cycleCount) +{ + // static int64_t startTime = cycleCount; + + // Fake a 60Hz VBL in case we need it for our interrupts + static int64_t nextInterruptTime = cycleCount + 17050; + + if ( (status & ST_MOUSEENABLE) && + (status & ST_INTVBL) ) { + if (cycleCount >= nextInterruptTime) { + g_cpu->irq(); + + interruptsTriggered |= ST_INTVBL; + + nextInterruptTime += 17050; + } + } } diff --git a/apple/mouse.h b/apple/mouse.h index fcc330b..83a045d 100644 --- a/apple/mouse.h +++ b/apple/mouse.h @@ -26,6 +26,12 @@ class Mouse : public Slot { virtual bool hasExtendedRom(); virtual void loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset); + + void maintainMouse(int64_t cycleCount); + +private: + uint8_t status; + uint8_t interruptsTriggered; }; #endif diff --git a/physicalmouse.h b/physicalmouse.h new file mode 100644 index 0000000..6fb82a7 --- /dev/null +++ b/physicalmouse.h @@ -0,0 +1,14 @@ +#ifndef __PHYSICALMOUSE_H +#define __PHYSICALMOUSE_H + +#include + +class PhysicalMouse { + public: + PhysicalMouse() {} + virtual ~PhysicalMouse() {}; + + virtual void maintainMouse() = 0; +}; + +#endif diff --git a/teensy/teensy.ino b/teensy/teensy.ino index 36f39e1..9cb7b10 100644 --- a/teensy/teensy.ino +++ b/teensy/teensy.ino @@ -286,7 +286,8 @@ void runMaintenance(uint32_t now) static uint32_t nextRuntime = 0; if (now >= nextRuntime) { - nextRuntime = now + 100000; // FIXME: what's a good time here? 1/10 sec? + // Run maintenance at 60 Hz because the mouse will need it + nextRuntime = now + 16667; if (!resetButtonDebouncer.read()) { // This is the BIOS interrupt. Wait for it to clear and process it. @@ -297,6 +298,7 @@ void runMaintenance(uint32_t now) } if (!g_biosInterrupt) { + g_mouse->maintainMouse(); g_keyboard->maintainKeyboard(); usb.maintain(); } diff --git a/vmram.cpp b/vmram.cpp index 236de94..8f58f78 100644 --- a/vmram.cpp +++ b/vmram.cpp @@ -48,8 +48,8 @@ void VMRam::writeByte(uint32_t addr, uint8_t value) uint8_t *VMRam::memPtr(uint32_t addr) { - printf("Asked for preallocated RAM pointer at 0x%X\n", addr); - printf("Base is 0x%llX\n", (unsigned long long) preallocatedRam); + // printf("Asked for preallocated RAM pointer at 0x%X\n", addr); + // printf("Base is 0x%llX\n", (unsigned long long) preallocatedRam); return &preallocatedRam[addr]; } From 0b8e0270964433c8ab17de8f5fb8c1f390b3ed3e Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Sun, 10 Jan 2021 23:52:58 -0500 Subject: [PATCH 14/23] patching together more mouse work --- Makefile | 8 +-- apple/mouse.cpp | 142 ++++++++++++++++++++++++++++--------------- apple/mouse.h | 4 ++ globals.cpp | 1 + globals.h | 2 + nix/debugger.cpp | 87 +++++++++++++++++++------- nix/debugger.h | 2 + physicalmouse.h | 16 ++++- sdl/aiie.cpp | 5 +- sdl/sdl-keyboard.cpp | 7 +++ 10 files changed, 196 insertions(+), 78 deletions(-) diff --git a/Makefile b/Makefile index 886e889..eaf2de5 100755 --- a/Makefile +++ b/Makefile @@ -8,17 +8,17 @@ CXXFLAGS=-Wall -I/usr/include/SDL2 -I .. -I . -I apple -I nix -I sdl -I/usr/loca TSRC=cpu.cpp util/testharness.cpp -COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp +COMMONSRCS=cpu.cpp apple/appledisplay.cpp apple/applekeyboard.cpp apple/applemmu.cpp apple/applevm.cpp apple/diskii.cpp apple/nibutil.cpp LRingBuffer.cpp globals.cpp apple/parallelcard.cpp apple/fx80.cpp lcg.cpp apple/hd32.cpp images.cpp apple/appleui.cpp vmram.cpp bios.cpp apple/noslotclock.cpp apple/woz.cpp apple/crc32.c apple/woz-serializer.cpp apple/mouse.c -COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o apple/pia6821.o +COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o vmram.o bios.o apple/noslotclock.o apple/woz.o apple/crc32.o apple/woz-serializer.o apple/mouse.o FBSRCS=linuxfb/linux-speaker.cpp linuxfb/fb-display.cpp linuxfb/linux-keyboard.cpp linuxfb/fb-paddles.cpp nix/nix-filemanager.cpp linuxfb/aiie.cpp linuxfb/linux-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp FBOBJS=linuxfb/linux-speaker.o linuxfb/fb-display.o linuxfb/linux-keyboard.o linuxfb/fb-paddles.o nix/nix-filemanager.o linuxfb/aiie.o linuxfb/linux-printer.o nix/nix-clock.o nix/nix-prefs.o -SDLSRCS=sdl/sdl-speaker.cpp sdl/sdl-display.cpp sdl/sdl-keyboard.cpp sdl/sdl-paddles.cpp nix/nix-filemanager.cpp sdl/aiie.cpp sdl/sdl-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp nix/debugger.cpp nix/disassembler.cpp +SDLSRCS=sdl/sdl-speaker.cpp sdl/sdl-display.cpp sdl/sdl-keyboard.cpp sdl/sdl-paddles.cpp nix/nix-filemanager.cpp sdl/aiie.cpp sdl/sdl-printer.cpp nix/nix-clock.cpp nix/nix-prefs.cpp nix/debugger.cpp nix/disassembler.cpp sdl/sdl-mouse.cpp -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 +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 MouseInterface.rom diff --git a/apple/mouse.cpp b/apple/mouse.cpp index e252ef4..ad0ad25 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -5,6 +5,7 @@ #include "mouse-rom.h" enum { + SW_W_INIT = 0x00, SW_R_HOMEMOUSE = 0x08, SW_R_POSMOUSE = 0x09, SW_R_CLEARMOUSE = 0x0A, @@ -15,6 +16,11 @@ 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 = 1, ST_INTMOUSE = 2, @@ -26,6 +32,8 @@ Mouse::Mouse() { status = 0; interruptsTriggered = 0; + lastX = lastY = 0; + lastButton = false; } Mouse::~Mouse() @@ -50,29 +58,43 @@ uint8_t Mouse::readSwitches(uint8_t s) { switch (s) { case SW_R_HOMEMOUSE: - printf("unimplemented SW_R_HOMEMOUSE\n"); - /* physical mouse X = $578/$478; - * physical mouse Y = $5f8/$4f8 */ + g_mouse->setPosition( (g_ram.readByte(0x578) << 8) | g_ram.readByte(0x478), + (g_ram.readByte(0x5F8) << 8) | g_ram.readByte(0x4F8) + ); break; case SW_R_POSMOUSE: - printf("unimplemented SW_R_POSMOUSE\n"); - /* physical mouse X = $578+4/$478+4; - * physical mouse Y + $5F8+4/$4f8+4 */ + g_mouse->setPosition( (g_ram.readByte(0x578+4) << 8) | g_ram.readByte(0x478+4), + (g_ram.readByte(0x5F8+4) << 8) | g_ram.readByte(0x4F8+4) + ); break; case SW_R_CLEARMOUSE: g_ram.writeByte(0x578+4, 0); g_ram.writeByte(0x478+4, 0); g_ram.writeByte(0x5F8+4, 0); g_ram.writeByte(0x4F8+4, 0); - /* physical mouse X = Y = 0 */ + g_mouse->setPosition(0,0); break; case SW_R_READMOUSE: - printf("unimplemented SW_R_READMOUSE\n"); - // FIXME: read from physical mouse and write to: - g_ram.writeByte(0x578+4, 0); // high X - g_ram.writeByte(0x478+4, 0); // low X - g_ram.writeByte(0x5F8+4, 0); // high Y - g_ram.writeByte(0x4F8+4, 0); // low Y + { + uint16_t xpos, ypos; + g_mouse->getPosition(&xpos, &ypos); + if (lastX != xpos || lastY != ypos) { + interruptsTriggered |= 0x20; // "x or y changed since last reading" + lastX = xpos; lastY = ypos; + } + curButton = g_mouse->getButton(); + uint8_t newStatus = g_ram.readByte(0x778+4) & ~0xC0; + if (curButton) { newStatus |= 0x80; }; + if (lastButton) { newStatus |= 0x40; }; + + uint16_t xv = xpos >> 8; xv &= 0xFF; + printf("XPOS: %d => 0x%X 0x%X\n", xpos, xv, xpos & 0xFF); + + g_ram.writeByte(0x578+4, xv); // high X + g_ram.writeByte(0x478+4, xpos & 0xFF); // low X + g_ram.writeByte(0x5F8+4, (ypos >> 8) & 0xFF); // high Y + g_ram.writeByte(0x4F8+4, ypos); // low Y + } break; case SW_R_INITMOUSE: // Set clamp to (0,0) - (1023,1023) @@ -80,11 +102,15 @@ uint8_t Mouse::readSwitches(uint8_t s) g_ram.writeByte(0x478, 0); // low of lowclamp g_ram.writeByte(0x5F8, 0x03); // high of highclamp g_ram.writeByte(0x4F8, 0xFF); // low of highclamp - printf("unimplemented SW_R_INITMOUSE\n"); - /* physicalMouse->setClamp(XCLAMP, 0, 1023); - * physicalMouse->setClamp(YCLAMP, 0, 1023); */ + g_mouse->setClamp(XCLAMP, 0, 1023); + g_mouse->setClamp(YCLAMP, 0, 1023); break; case SW_R_SERVEMOUSE: + if (lastButton) interruptsTriggered |= 0x40; + if (curButton != lastButton) { + interruptsTriggered |= 0x80; + lastButton = curButton; + } g_ram.writeByte(0x778+4, interruptsTriggered); g_ram.writeByte(0x6B8+4, interruptsTriggered); // hack to appease ROM interruptsTriggered = 0; @@ -98,25 +124,30 @@ uint8_t Mouse::readSwitches(uint8_t s) void Mouse::writeSwitches(uint8_t s, uint8_t v) { switch (s) { + case SW_W_INIT: + v &= 0x03; // just the low 3 bits apparently? + printf("Simple init: value is 0x%X\n", v); + status = v; + g_ram.writeByte(0x7f8 + 4, v); + break; case SW_W_CLAMPMOUSE: { uint16_t lowval = (g_ram.readByte(0x578) << 8) | (g_ram.readByte(0x478)); uint16_t highval = (g_ram.readByte(0x5F8) << 8) | (g_ram.readByte(0x4F8)); if (v) { - // Y is clamping - /* physicalMouse->setClamp(YCLAMP, lowval, highval); */ + g_mouse->setClamp(YCLAMP, lowval, highval); } else { // X is clamping - /* physicalMouse->setClamp(XCLAMP, lowval, highval); */ + g_mouse->setClamp(XCLAMP, lowval, highval); } - printf("unimplemented SW_W_CLAMPMOUSE [0x%X]\n", v); } break; case SW_W_SETMOUSE: status = v; + g_ram.writeByte(0x7f8 + 4, v); break; default: - printf("mouse: unknown switch write 0x%X\n", s); + printf("mouse: unknown switch write 0x%X = 0x%2X\n", s, v); break; } } @@ -125,7 +156,7 @@ void Mouse::loadROM(uint8_t *toWhere) { /* Actual mouse ROM Disassembly: C400- 2C 58 FF BIT $FF58 ; test bits in FF58 w/ A -C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $20 on boot-up +C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $60 on boot-up (RTS), which has $40 set, so should branch here C405- 38 SEC C406- 90 18 BCC $C420 ; no-op; unless called @ $C406 directly? @@ -154,13 +185,12 @@ C41D- AE C41E- AE C41F- AE -; Main +; Main (installs KSW for IN# handling) C420- 48 PHA ; push accumulator to stack C421- 98 TYA C422- 48 PHA ; push Y to stack C423- 8A TXA C424- 48 PHA ; push X to stack -C424- 48 PHA C425- 08 PHP ; push status to stack C426- 78 SEI ; disable interrupts @@ -176,28 +206,30 @@ C426- 78 SEI ; disable interrupts ; TSX ; LDA $100, X ; grab the return address off the stack -C427- 20 58 FF JSR $FF58 -C42A- BA TSX -C42B- BD 00 01 LDA $0100,X -C42E- AA TAX +C427- 20 58 FF JSR $FF58 ; call something that will RTS +C42A- BA TSX ; pull stack pointer to X +C42B- BD 00 01 LDA $0100,X ; grab A from the current stack pointer, which has our return addr +C42E- AA TAX ; X = return addr C42F- 0A ASL C430- 0A ASL C431- 0A ASL C432- 0A ASL -C433- A8 TAY -C434- 28 PLP ; restore status from stack -C435- 50 0F BVC $C446 ; overflow is clear if ... ? -C437- A5 38 LDA $38 ; >> what's in $38? +C433- A8 TAY ; Y = (return addr) << 4 +C434- 28 PLP ; restore status from stack (includes V,C) +C435- 50 0F BVC $C446 ; overflow is clear from when we were called? +C437- A5 38 LDA $38 ; >> $38 is the IN# vector ("KSW") low byte C439- D0 0D BNE $C448 ; restore stack & return C43B- 8A TXA -C43C- 45 39 EOR $39 ; >> what's in $39? +C43C- 45 39 EOR $39 ; >> KSW high byte C43E- D0 08 BNE $C448 ; restore stack & return C440- A9 05 LDA #$05 C442- 85 38 STA $38 ; ($38) = $05 -C442- 85 38 STA $38 C444- D0 0B BNE $C451 +;; we wind up here when the entry vector $c405 is called directly (from $9eba) C446- B0 09 BCS $C451 ; carry set if ... ? + +;; entry point when called as PR# so BASIC/DOS can init the mouse C448- 68 PLA ; pull X from stack C449- AA TAX C44A- 68 PLA ; pull Y from stack, but @@ -277,6 +309,7 @@ C4A7- D0 F1 BNE $C49A C4A9- EA NOP C4AA- A9 07 LDA #$07 C4AC- D0 EC BNE $C49A +; "TimeData" to set freq before init to 50/60 Hz? Doesn't look like it... C4AE- A2 03 LDX #$03 C4B0- 38 SEC C4B1- 60 RTS @@ -314,8 +347,7 @@ Patch: C471 from 99 82 C0 60 => 8D CF C0 60 SERVEMOUSE @ $C4B2: 78 SEI - AD CE C0 LDA $C0CE ; use soft switch 0xE (read) to trigger this - expect ne\ -w value to be placed in $7f8+4 and $6b8+4 + AD CE C0 LDA $C0CE ; use soft switch 0xE (read) to trigger this - expect new value to be placed in $7f8+4 and $6b8+4 A2 04 LDX #$04 ; our slot number, for cleanup code 18 CLC 90 C1 BCC $C47C @@ -324,7 +356,7 @@ Patch: C4B2 from 08 A5 00 48 A9 60 85 00 78 => 78 AD CE C0 A2 04 18 90 C1 READMOUSE -C48E- AD CB C0 LDA $C04B ; soft switch 0x0B for readmouse +C48E- AD CB C0 LDA $C0CB ; soft switch 0x0B for readmouse 18 CLC 60 RTS @@ -332,14 +364,14 @@ Patch: from A9 04 99 83 C0 => AD CB C0 18 60 CLEARMOUSE -C49F- AD CA C0 LDA $C04A ; soft switch 0x0A for clearmouse +C49F- AD CA C0 LDA $C0CA ; soft switch 0x0A for clearmouse 18 CLC 60 RTS Patch: from EA A9 05 D0 F6 => AD CA C0 18 60 POSMOUSE -C4a4- AD C9 C0 LDA $C049 ; soft switch 0x09 for posmouse +C4a4- AD C9 C0 LDA $C0C9 ; soft switch 0x09 for posmouse 18 CLC 60 RTS @@ -347,20 +379,20 @@ Patch: from EA A9 06 D0 F1 => AD C9 C0 18 60 CLAMPMOUSE -C48A- 8D CD C0 STA $C04D ; use write to soft switch 0x0D to trigger clamp +C48A- 8D CD C0 STA $C0CD ; use write to soft switch 0x0D to trigger clamp 60 RTS Patch: from 99 83 C0 60 => 8D CD C0 60 HOMEMOUSE -C4A9- AD C8 C0 LDA $c048 ; soft switch 0x08 for homemouse (read) +C4A9- AD C8 C0 LDA $c0C8 ; soft switch 0x08 for homemouse (read) 18 CLC 60 RTS Patch: from EA A9 07 D0 EC => AD C8 C0 18 60 INITMOUSE -C498- AD CC C0 LDA $C04C ; soft switch 0x0C read for initmouse +C498- AD CC C0 LDA $C0CC ; soft switch 0x0C read for initmouse 18 CLC 60 RTS @@ -376,8 +408,8 @@ Patch: from A9 02 99 83 C0 => AD CC C0 18 60 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, 0x99, 0x80, 0xc0, - 0x60, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, // C450 + 0x68, 0xaa, 0x68, 0xea, 0x68, 0xea, 0xea, 0xea, + 0x60, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, // C450 0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C460 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x10, 0xb0, @@ -426,13 +458,25 @@ void Mouse::maintainMouse(int64_t cycleCount) static int64_t nextInterruptTime = cycleCount + 17050; if ( (status & ST_MOUSEENABLE) && - (status & ST_INTVBL) ) { - if (cycleCount >= nextInterruptTime) { - g_cpu->irq(); + (status & ST_INTVBL) && + (cycleCount >= nextInterruptTime) ) { + g_cpu->irq(); + + interruptsTriggered |= ST_INTVBL; + + nextInterruptTime += 17050; + } else { + uint16_t xpos, ypos; + g_mouse->getPosition(&xpos, &ypos); - interruptsTriggered |= ST_INTVBL; + if ( (status & ST_MOUSEENABLE) && + (status & ST_INTMOUSE) && + (xpos != lastX || ypos != lastY) ) { + g_cpu->irq(); - nextInterruptTime += 17050; + interruptsTriggered |= ST_INTMOUSE; + lastX = xpos; lastY = ypos; } } + /* FIXME: still need button */ } diff --git a/apple/mouse.h b/apple/mouse.h index 83a045d..5a29e7c 100644 --- a/apple/mouse.h +++ b/apple/mouse.h @@ -32,6 +32,10 @@ class Mouse : public Slot { private: uint8_t status; uint8_t interruptsTriggered; + + uint16_t lastX, lastY; + bool lastButton; + bool curButton; }; #endif diff --git a/globals.cpp b/globals.cpp index e614a4c..8f7f2ea 100644 --- a/globals.cpp +++ b/globals.cpp @@ -5,6 +5,7 @@ Cpu *g_cpu = NULL; VM *g_vm = NULL; PhysicalDisplay *g_display = NULL; PhysicalKeyboard *g_keyboard = NULL; +PhysicalMouse *g_mouse = NULL; PhysicalSpeaker *g_speaker = NULL; PhysicalPaddles *g_paddles = NULL; PhysicalPrinter *g_printer = NULL; diff --git a/globals.h b/globals.h index 5edd239..634c8fa 100644 --- a/globals.h +++ b/globals.h @@ -8,6 +8,7 @@ #include "vm.h" #include "physicaldisplay.h" #include "physicalkeyboard.h" +#include "physicalmouse.h" #include "physicalspeaker.h" #include "physicalpaddles.h" #include "physicalprinter.h" @@ -41,6 +42,7 @@ extern Cpu *g_cpu; extern VM *g_vm; extern PhysicalDisplay *g_display; extern PhysicalKeyboard *g_keyboard; +extern PhysicalMouse *g_mouse; extern PhysicalSpeaker *g_speaker; extern PhysicalPaddles *g_paddles; extern PhysicalPrinter *g_printer; diff --git a/nix/debugger.cpp b/nix/debugger.cpp index aea5cc4..b547ce0 100644 --- a/nix/debugger.cpp +++ b/nix/debugger.cpp @@ -51,6 +51,9 @@ Debugger::Debugger() server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(12345); + steppingOut = false; + singleStep = false; + if (bind(sd, (struct sockaddr *) &server, sizeof(server)) < 0) { perror("error binding to debug socket"); exit(1); @@ -71,10 +74,14 @@ Debugger::~Debugger() bool getAddress(const char *buf, unsigned int *addrOut) { unsigned int val; - if (sscanf(buf, " 0x%X", &val) == 1) { + if (sscanf(buf, " 0x%X", &val) == 1 || + sscanf(buf, " 0x%x", &val) == 1 + ) { *addrOut = val; return true; - } else if (sscanf(buf, " $%X", &val) == 1) { + } else if (sscanf(buf, " $%X", &val) == 1 || + sscanf(buf, " $%x", &val) == 1 + ) { *addrOut = val; return true; } else if (sscanf(buf, " %d", &val) == 1) { @@ -91,11 +98,10 @@ bool getAddress(const char *buf, unsigned int *addrOut) #define HEXCHAR(x) ((x>='0'&&x<='9')?x-'0':(x>='a'&&x<='f')?x-'a'+10:(x>='A'&&x<='F')?x-'A'+10:(x=='i' || x=='I')?1:(x=='o' || x=='O')?0:0) #define FROMHEXP(p) ((HEXCHAR(*p) << 4) | HEXCHAR(*(p+1))) -bool steppingOut = false; - void Debugger::step() { static char buf[256]; + uint8_t cmdbuf[50]; // FIXME: add more than just RTS(0x60) here if (steppingOut && @@ -124,38 +130,54 @@ void Debugger::step() return; } - uint8_t cmdbuf[50]; - - uint16_t loc=g_cpu->pc; - for (int i=0; i<50/3; i++) { - for (int idx=0; idxgetMMU()->read(loc+idx); - } - loc += dis.instructionToMnemonic(loc, cmdbuf, buf, sizeof(buf)); - write(cd, buf, strlen(buf)); - buf[0] = 13; - buf[1] = 10; - write(cd, buf, 2); - } - - - if (breakpoint && g_cpu->pc != breakpoint) { + if (!singleStep && breakpoint && g_cpu->pc != breakpoint) { // Running until we reach the breakpoint return; } + singleStep = false; // we have taken a single step, so reset flag uint8_t b; // byte value used in parsing unsigned int val; // common value buffer used in parsing - GETCH; - snprintf(buf, sizeof(buf), "Got char %d\012\015", b); + // debugging what's at FF58 right now + uint8_t tmp = g_vm->getMMU()->read(0xff58); + sprintf(buf, " 0xFF58: 0x%.2X\r\n", tmp); write(cd, buf, strlen(buf)); + doover: + do { + GETCH; + } while (b != 'c' && // continue (with breakpoint set) + b != 'q' && // quit + b != 's' && // single step + b != 'S' && // step out + b != 'b' && // set breakpoint + b != 'd' && // show disassembly + b != 'L' && // load memory (lines) + b != '*' // show memory (byte) + ); + switch (b) { - case 'c': // Continue - close connection and let execution flow + case 'c': // continue (if there is a breakpoint set) + if (breakpoint) { + snprintf(buf, sizeof(buf), "Continuing until breakpoint 0x%X\012\015", breakpoint); + write(cd, buf, strlen(buf)); + } else { + snprintf(buf, sizeof(buf), "No breakpoint to continue until\012\015"); + write(cd, buf, strlen(buf)); + goto doover; + } + break; + + case 'q': // Close debugging socket and quit printf("Closing debugging socket\n"); + breakpoint = 0; close(cd); cd=-1; break; + + case 's': + singleStep = true; // for when breakpoint is set: just step once + break; case 'S': steppingOut = true; @@ -176,6 +198,23 @@ void Debugger::step() write(cd, buf, strlen(buf)); break; + case 'd': // show disassembly @ PC + { + uint16_t loc=g_cpu->pc; + for (int i=0; i<50/3; i++) { + for (int idx=0; idxgetMMU()->read(loc+idx); + } + loc += dis.instructionToMnemonic(loc, cmdbuf, buf, sizeof(buf)); + write(cd, buf, strlen(buf)); + buf[0] = 13; + buf[1] = 10; + write(cd, buf, 2); + } + } + goto doover; + break; + case 'L': // Load data to memory. Use: "L 0x
\n" followed by lines of packed hex; ends with a blank line { printf("Loading data\n"); @@ -198,6 +237,7 @@ void Debugger::step() } } } + goto doover; break; case '*': // read 1 byte of memory. Use '* 0x
' @@ -214,6 +254,7 @@ void Debugger::step() write(cd, buf, strlen(buf)); } } + goto doover; break; case 'G': // Goto (set PC) diff --git a/nix/debugger.h b/nix/debugger.h index 05d7bc7..66936c9 100644 --- a/nix/debugger.h +++ b/nix/debugger.h @@ -19,6 +19,8 @@ class Debugger { pthread_t listenThreadID; uint32_t breakpoint; + bool steppingOut; + bool singleStep; }; diff --git a/physicalmouse.h b/physicalmouse.h index 6fb82a7..9189d11 100644 --- a/physicalmouse.h +++ b/physicalmouse.h @@ -2,13 +2,27 @@ #define __PHYSICALMOUSE_H #include +#include + +enum { + XCLAMP = 0, + YCLAMP = 1 +}; class PhysicalMouse { public: - PhysicalMouse() {} + PhysicalMouse() { lowClamp[XCLAMP] = lowClamp[YCLAMP] = 0; highClamp[XCLAMP] = highClamp[YCLAMP] = 1023; } virtual ~PhysicalMouse() {}; virtual void maintainMouse() = 0; + + virtual void setClamp(uint8_t direction, uint16_t low, uint16_t high) { lowClamp[direction] = low; highClamp[direction] = high; printf("clamp %d %d-%d\n", direction, low, high); } + virtual void setPosition(uint16_t x, uint16_t y) = 0; + virtual void getPosition(uint16_t *x, uint16_t *y) = 0; + virtual bool getButton() = 0; + +protected: + uint16_t lowClamp[2], highClamp[2]; }; #endif diff --git a/sdl/aiie.cpp b/sdl/aiie.cpp index 04ba5c4..97648e7 100644 --- a/sdl/aiie.cpp +++ b/sdl/aiie.cpp @@ -7,6 +7,7 @@ #include "applevm.h" #include "sdl-display.h" #include "sdl-keyboard.h" +#include "sdl-mouse.h" #include "sdl-speaker.h" #include "sdl-paddles.h" #include "nix-filemanager.h" @@ -291,7 +292,7 @@ struct timespec runMaintenance(struct timespec now) initialized = true; } - timespec_add_us(&startTime, 100000*cycleCount, &nextRuntime); // FIXME: what's a good time here? 1/10 sec? + timespec_add_us(&startTime, 16667*cycleCount, &nextRuntime); // FIXME: what's a good time here? 60 Hz? // Check if it's time to run - and if not, return how long it will // be until we need to run @@ -305,6 +306,7 @@ struct timespec runMaintenance(struct timespec now) if (!g_biosInterrupt) { // If the BIOS is running, then let it handle the keyboard directly g_keyboard->maintainKeyboard(); + g_mouse->maintainMouse(); } doDebugging(); @@ -389,6 +391,7 @@ int main(int argc, char *argv[]) g_vm = new AppleVM(); g_keyboard = new SDLKeyboard(g_vm->getKeyboard()); + g_mouse = new SDLMouse(); // Now that the VM exists and it has created an MMU, we tell the CPU how to access memory through the MMU. g_cpu->SetMMU(g_vm->getMMU()); diff --git a/sdl/sdl-keyboard.cpp b/sdl/sdl-keyboard.cpp index 89b0b1a..bb81c34 100644 --- a/sdl/sdl-keyboard.cpp +++ b/sdl/sdl-keyboard.cpp @@ -1,6 +1,7 @@ #include "sdl-keyboard.h" #include "sdl-paddles.h" +#include "sdl-mouse.h" #include "globals.h" SDLKeyboard::SDLKeyboard(VMKeyboard *k) : PhysicalKeyboard(k) @@ -149,12 +150,18 @@ void SDLKeyboard::maintainKeyboard() if (event.key.repeat == 0) handleKeypress(&event.key); break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + ((SDLMouse *)g_mouse)->mouseButtonEvent(event.type == SDL_MOUSEBUTTONDOWN); + break; case SDL_MOUSEMOTION: // We are handling the SDL input loop, so need to pass this off to the paddles. :/ // FIXME: nasty rooting around in other objects and typecasting. // FIXME: event.motion.state & SDL_BUTTON_LMASK, et al? ((SDLPaddles *)g_paddles)->gotMouseMovement(event.motion.x, event.motion.y); + ((SDLMouse *)g_mouse)->gotMouseEvent(event.motion.state, // button + event.motion.xrel, event.motion.yrel); break; case SDL_QUIT: From 6e49c9f6f9eab49909bf1013d7cc2dc2c2b22ba2 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 07:31:51 -0500 Subject: [PATCH 15/23] rebuild ROM image cleanly --- apple/mouse.cpp | 62 ++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/apple/mouse.cpp b/apple/mouse.cpp index ad0ad25..7d56609 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -55,6 +55,15 @@ void Mouse::Reset() } uint8_t Mouse::readSwitches(uint8_t s) +{ + switch (s) { + default: + printf("mouse: unknown switch read 0x%X\n", s); + }; + return 0xFF; +} + +void Mouse::writeSwitches(uint8_t s, uint8_t v) { switch (s) { case SW_R_HOMEMOUSE: @@ -115,15 +124,6 @@ uint8_t Mouse::readSwitches(uint8_t s) g_ram.writeByte(0x6B8+4, interruptsTriggered); // hack to appease ROM interruptsTriggered = 0; break; - default: - printf("mouse: unknown switch read 0x%X\n", s); - }; - return 0xFF; -} - -void Mouse::writeSwitches(uint8_t s, uint8_t v) -{ - switch (s) { case SW_W_INIT: v &= 0x03; // just the low 3 bits apparently? printf("Simple init: value is 0x%X\n", v); @@ -379,20 +379,20 @@ Patch: from EA A9 06 D0 F1 => AD C9 C0 18 60 CLAMPMOUSE -C48A- 8D CD C0 STA $C0CD ; use write to soft switch 0x0D to trigger clamp +C48A- 8D CD C0 STA $C04D ; use write to soft switch 0x0D to trigger clamp 60 RTS Patch: from 99 83 C0 60 => 8D CD C0 60 HOMEMOUSE -C4A9- AD C8 C0 LDA $c0C8 ; soft switch 0x08 for homemouse (read) +C4A9- AD C8 C0 LDA $c048 ; soft switch 0x08 for homemouse (read) 18 CLC 60 RTS Patch: from EA A9 07 D0 EC => AD C8 C0 18 60 INITMOUSE -C498- AD CC C0 LDA $C0CC ; soft switch 0x0C read for initmouse +C498- AD CC C0 LDA $C04C ; soft switch 0x0C read for initmouse 18 CLC 60 RTS @@ -400,33 +400,33 @@ Patch: from A9 02 99 83 C0 => AD CC C0 18 60 */ uint8_t rom[256] = { 0x2c, 0x58, 0xff, 0x70, 0x1B, 0x38, 0x90, 0x18, // C400 - 0xb8, 0x50, 0x15, 0x01, 0x20, 0xae, 0xae, 0xae, - 0xae, 0x00, 0x6d, 0x75, 0x8e, 0x9f, 0xa4, 0x86, // C410 - 0xa9, 0x97, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 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, 0x99, 0x81, 0xc0, 0x68, 0xbd, 0x38, 0x06, // C450 + 0x60, 0xea, 0xea, 0xea, 0x68, 0xbd, 0x38, 0x06, // C450 0xaa, 0x68, 0xa8, 0x68, 0xbd, 0x00, 0x02, 0x60, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C460 - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x10, 0xb0, - 0x3f, 0x8D, 0xCF, 0xc0, 0x60, 0x48, 0x18, 0x90, // C470 - 0x39, 0x99, 0x83, 0xc0, 0xbd, 0xb8, 0x06, 0x29, + 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, - 0x0E, 0xD0, 0x01, 0x38, 0x68, 0x60, 0xc9, 0x02, // C480 - 0xb0, 0x26, 0x8D, 0xCD, 0xc0, 0x60, 0xAD, 0xCB, - 0xC0, 0x18, 0x60, 0x18, 0xea, 0xea, 0x60, 0xea, // C490 - 0xAD, 0xCC, 0xC0, 0x18, 0x60, 0x18, 0x60, 0xAD, - 0xCA, 0xC0, 0x18, 0x60, 0xAD, 0xC9, 0xc0, 0x18, // C4A0 - 0x60, 0xAD, 0xC8, 0xC0, 0x18, 0x60, 0xa2, 0x03, - 0x38, 0x60, 0x78, 0xad, 0xce, 0xc0, 0xa2, 0x04, // C4B0 - 0x18, 0x90, 0xc1, 0x20, 0x00, 0x00, 0xba, 0x68, - 0x85, 0x00, 0xbd, 0x00, 0x01, 0x28, 0xaa, 0x0a, // C4C0 - 0x0a, 0x0a, 0x0a, 0xa8, 0xa9, 0x03, 0x18, 0x90, - 0xa8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // C4D0 + 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, From 1f998aa17cf7a52aafa14796bb7bb0bb95b4be00 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 08:19:23 -0500 Subject: [PATCH 16/23] remove debugging hack --- nix/debugger.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nix/debugger.cpp b/nix/debugger.cpp index b547ce0..85ab710 100644 --- a/nix/debugger.cpp +++ b/nix/debugger.cpp @@ -139,11 +139,6 @@ void Debugger::step() uint8_t b; // byte value used in parsing unsigned int val; // common value buffer used in parsing - // debugging what's at FF58 right now - uint8_t tmp = g_vm->getMMU()->read(0xff58); - sprintf(buf, " 0xFF58: 0x%.2X\r\n", tmp); - write(cd, buf, strlen(buf)); - doover: do { GETCH; From 12d4f7bdf29645b7a1c294a4f9af50cd481cffb2 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 08:19:36 -0500 Subject: [PATCH 17/23] remove debugging printf --- physicalmouse.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/physicalmouse.h b/physicalmouse.h index 9189d11..4a1d489 100644 --- a/physicalmouse.h +++ b/physicalmouse.h @@ -2,7 +2,6 @@ #define __PHYSICALMOUSE_H #include -#include enum { XCLAMP = 0, @@ -16,7 +15,7 @@ class PhysicalMouse { virtual void maintainMouse() = 0; - virtual void setClamp(uint8_t direction, uint16_t low, uint16_t high) { lowClamp[direction] = low; highClamp[direction] = high; printf("clamp %d %d-%d\n", direction, low, high); } + virtual void setClamp(uint8_t direction, uint16_t low, uint16_t high) { lowClamp[direction] = low; highClamp[direction] = high; } virtual void setPosition(uint16_t x, uint16_t y) = 0; virtual void getPosition(uint16_t *x, uint16_t *y) = 0; virtual bool getButton() = 0; From 579e7e9f79574c050caeaed5f2ec6bc670c0ea63 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 08:43:23 -0500 Subject: [PATCH 18/23] show bytes in disassembly --- nix/disassembler.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nix/disassembler.cpp b/nix/disassembler.cpp index edeec08..db29676 100755 --- a/nix/disassembler.cpp +++ b/nix/disassembler.cpp @@ -133,6 +133,7 @@ uint8_t Disassembler::instructionToMnemonic(uint16_t addr, uint8_t *p, char *out addrmode amode = opcodes[*p].mode; uint16_t target = 0; char arg[40] = "\0"; + char bytes[10] = "\0"; switch (amode) { case A_REL: @@ -153,14 +154,19 @@ uint8_t Disassembler::instructionToMnemonic(uint16_t addr, uint8_t *p, char *out switch (instructionBytes(*p)) { case 1: // no arguments + sprintf(bytes, " %.2X ", *(uint8_t *)p); break; case 2: + sprintf(arg, "%s$%X%s", om.prefix, target, om.suffix); + sprintf(bytes, " %.2X %.2X ", *(uint8_t *)p, *(uint8_t *)(p+1)); + break; case 3: sprintf(arg, "%s$%X%s", om.prefix, target, om.suffix); + sprintf(bytes, "%.2X %.2X %.2X ", *(uint8_t *)p, *(uint8_t *)(p+1), *(uint8_t *)(p+2)); break; } - sprintf(outp, "$%.4X %s %s", addr, mn, arg); + sprintf(outp, "$%.4X %s %s %s", addr, bytes, mn, arg); return instructionBytes(*p); } From d6bcac42d72b9ef6ac530b533436c91774dea49a Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 08:43:40 -0500 Subject: [PATCH 19/23] when writing to ram, use the MMU. Also cleaned up comments. --- apple/mouse.cpp | 420 +++++++++++++++++------------------------------- 1 file changed, 144 insertions(+), 276 deletions(-) diff --git a/apple/mouse.cpp b/apple/mouse.cpp index 7d56609..f6e43ba 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -66,21 +66,25 @@ uint8_t Mouse::readSwitches(uint8_t s) void Mouse::writeSwitches(uint8_t s, uint8_t v) { switch (s) { + /* Many of these were designed to be reads, because they don't have to + * 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_R_HOMEMOUSE: - g_mouse->setPosition( (g_ram.readByte(0x578) << 8) | g_ram.readByte(0x478), - (g_ram.readByte(0x5F8) << 8) | g_ram.readByte(0x4F8) + 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) ); break; case SW_R_POSMOUSE: - g_mouse->setPosition( (g_ram.readByte(0x578+4) << 8) | g_ram.readByte(0x478+4), - (g_ram.readByte(0x5F8+4) << 8) | g_ram.readByte(0x4F8+4) + g_mouse->setPosition( (g_vm->getMMU()->read(0x578+4) << 8) | g_vm->getMMU()->read(0x478+4), + (g_vm->getMMU()->read(0x5F8+4) << 8) | g_vm->getMMU()->read(0x4F8+4) ); break; case SW_R_CLEARMOUSE: - g_ram.writeByte(0x578+4, 0); - g_ram.writeByte(0x478+4, 0); - g_ram.writeByte(0x5F8+4, 0); - g_ram.writeByte(0x4F8+4, 0); + g_vm->getMMU()->write(0x578+4, 0); + g_vm->getMMU()->write(0x478+4, 0); + g_vm->getMMU()->write(0x5F8+4, 0); + g_vm->getMMU()->write(0x4F8+4, 0); g_mouse->setPosition(0,0); break; case SW_R_READMOUSE: @@ -92,25 +96,22 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v) lastX = xpos; lastY = ypos; } curButton = g_mouse->getButton(); - uint8_t newStatus = g_ram.readByte(0x778+4) & ~0xC0; + uint8_t newStatus = g_vm->getMMU()->read(0x778+4) & ~0xC0; if (curButton) { newStatus |= 0x80; }; if (lastButton) { newStatus |= 0x40; }; - uint16_t xv = xpos >> 8; xv &= 0xFF; - printf("XPOS: %d => 0x%X 0x%X\n", xpos, xv, xpos & 0xFF); - - g_ram.writeByte(0x578+4, xv); // high X - g_ram.writeByte(0x478+4, xpos & 0xFF); // low X - g_ram.writeByte(0x5F8+4, (ypos >> 8) & 0xFF); // high Y - g_ram.writeByte(0x4F8+4, ypos); // low Y + g_vm->getMMU()->write(0x578+4, (xpos >> 8) & 0xFF); // high X + g_vm->getMMU()->write(0x478+4, xpos & 0xFF); // low X + g_vm->getMMU()->write(0x5F8+4, (ypos >> 8) & 0xFF); // high Y + g_vm->getMMU()->write(0x4F8+4, ypos); // low Y } break; case SW_R_INITMOUSE: // Set clamp to (0,0) - (1023,1023) - g_ram.writeByte(0x578, 0); // high of lowclamp - g_ram.writeByte(0x478, 0); // low of lowclamp - g_ram.writeByte(0x5F8, 0x03); // high of highclamp - g_ram.writeByte(0x4F8, 0xFF); // low of highclamp + g_vm->getMMU()->write(0x578, 0); // high of lowclamp + g_vm->getMMU()->write(0x478, 0); // low of lowclamp + g_vm->getMMU()->write(0x5F8, 0x03); // high of highclamp + g_vm->getMMU()->write(0x4F8, 0xFF); // low of highclamp g_mouse->setClamp(XCLAMP, 0, 1023); g_mouse->setClamp(YCLAMP, 0, 1023); break; @@ -120,20 +121,20 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v) interruptsTriggered |= 0x80; lastButton = curButton; } - g_ram.writeByte(0x778+4, interruptsTriggered); - g_ram.writeByte(0x6B8+4, interruptsTriggered); // hack to appease ROM + g_vm->getMMU()->write(0x778+4, interruptsTriggered); + 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_ram.writeByte(0x7f8 + 4, v); + g_vm->getMMU()->write(0x7f8 + 4, v); break; case SW_W_CLAMPMOUSE: { - uint16_t lowval = (g_ram.readByte(0x578) << 8) | (g_ram.readByte(0x478)); - uint16_t highval = (g_ram.readByte(0x5F8) << 8) | (g_ram.readByte(0x4F8)); + uint16_t lowval = (g_vm->getMMU()->read(0x578) << 8) | (g_vm->getMMU()->read(0x478)); + uint16_t highval = (g_vm->getMMU()->read(0x5F8) << 8) | (g_vm->getMMU()->read(0x4F8)); if (v) { g_mouse->setClamp(YCLAMP, lowval, highval); } else { @@ -144,7 +145,7 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v) break; case SW_W_SETMOUSE: status = v; - g_ram.writeByte(0x7f8 + 4, v); + g_vm->getMMU()->write(0x7f8 + 4, v); break; default: printf("mouse: unknown switch write 0x%X = 0x%2X\n", s, v); @@ -154,250 +155,121 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v) void Mouse::loadROM(uint8_t *toWhere) { - /* Actual mouse ROM Disassembly: -C400- 2C 58 FF BIT $FF58 ; test bits in FF58 w/ A -C403- 70 1B BVS $C420 ; V will contain bit 6 from $FF58, which should be $60 on boot-up (RTS), which has $40 set, so should branch here -C405- 38 SEC -C406- 90 18 BCC $C420 ; no-op; unless called @ $C406 directly? - -C408- B8 CLV ; clear overflow -C409- 50 15 BVC $C420 ; always branches - -; unused... ? more lookup table... ? -C40B- 01 20 ORA ($20,X) -C40D- AE AE AE LDX $AEAE - -; This is the lookup table for entry addresses -C410- AE -C411- 00 -C412- 6D ;(setmouse @ c46d) -C413- 75 ;(servemouse @ C475) -C414- 8E ;(readmouse @ C48E) -C415- 9F ;(clearmouse @ C49F) -C416- A4 ;(posmouse @ C4A4) -C417- 86 ;(clampmouse @ C486) -C418- A9 ;(homemouse @ C4A9) -C419- 97 ;(initmouse @ C497) -C41A- AE -C41B- AE -C41C- AE ;(semi-documented: sets mouse frequency handler to 60 or 50 hz) -C41D- AE -C41E- AE -C41F- AE - -; Main (installs KSW for IN# handling) -C420- 48 PHA ; push accumulator to stack -C421- 98 TYA -C422- 48 PHA ; push Y to stack -C423- 8A TXA -C424- 48 PHA ; push X to stack -C425- 08 PHP ; push status to stack -C426- 78 SEI ; disable interrupts - -; This JSR $FF58 is a trick to get the address we're calling from. By -; default, $FF58 contains a RTS (until patched as the DOS '&' vector, -; or ProDOS does something similar). As long as this executes before -; the DOS takes over, it's safe; but if we're doing this after ProDOS -; loads, a 64k machine might have garbage after the language card RAM -; is loaded here. A safer alternative would be something like -; LDA #$60 ; Write an RTS ($60) to a temporary memory -; STA WORK ; address, and then -; JSR WORK ; jump to it -; TSX -; LDA $100, X ; grab the return address off the stack - -C427- 20 58 FF JSR $FF58 ; call something that will RTS -C42A- BA TSX ; pull stack pointer to X -C42B- BD 00 01 LDA $0100,X ; grab A from the current stack pointer, which has our return addr -C42E- AA TAX ; X = return addr -C42F- 0A ASL -C430- 0A ASL -C431- 0A ASL -C432- 0A ASL -C433- A8 TAY ; Y = (return addr) << 4 -C434- 28 PLP ; restore status from stack (includes V,C) -C435- 50 0F BVC $C446 ; overflow is clear from when we were called? -C437- A5 38 LDA $38 ; >> $38 is the IN# vector ("KSW") low byte -C439- D0 0D BNE $C448 ; restore stack & return -C43B- 8A TXA -C43C- 45 39 EOR $39 ; >> KSW high byte -C43E- D0 08 BNE $C448 ; restore stack & return -C440- A9 05 LDA #$05 -C442- 85 38 STA $38 ; ($38) = $05 -C444- D0 0B BNE $C451 - -;; we wind up here when the entry vector $c405 is called directly (from $9eba) -C446- B0 09 BCS $C451 ; carry set if ... ? - -;; entry point when called as PR# so BASIC/DOS can init the mouse -C448- 68 PLA ; pull X from stack -C449- AA TAX -C44A- 68 PLA ; pull Y from stack, but -C44B- EA NOP ; throw it away -C44C- 68 PLA ; pull A from stack -C44D- 99 80 C0 STA $C080,Y ; LC RAM bank2, read and wr-protect -C450- 60 RTS - -C451- 99 81 C0 STA $C081,Y ; LC RAM bank 2, read ROM -C454- 68 PLA ; -C455- BD 38 06 LDA $0638,X -C458- AA TAX -C459- 68 PLA -C45A- A8 TAY -C45B- 68 PLA -C45C- BD 00 02 LDA $0200,X ; keyboard character buffer? -C45F- 60 RTS - -C460- 00 BRK -C461- 00 BRK -C462- 00 BRK -C463- 00 BRK -C464- 00 BRK -C465- 00 BRK -C466- 00 BRK -C467- 00 BRK -C468- 00 BRK -C469- 00 BRK -C46A- 00 BRK -C46B- 00 BRK -C46C- 00 BRK - -; SetMouse -C46D- C9 10 CMP #$10 ; interrupt on VBL + interrupt on mouse move? -C46F- B0 3F BCS $C4B0 ; RTS if A >= 0x10 -C471- 99 82 C0 STA $C082,Y ; LC RAM bank 2, read ROM, wr-protect RAM -C474- 60 RTS -; ServeMouse -C475- 48 PHA ; save A -C476- 18 CLC -C477- 90 39 BCC $C4B2 ; always branches -; ServeMouse cleanup and exit -C479- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM -C47C- BD B8 06 LDA $06B8,X ; apparently this is where the new status wound up, also $7f8 + -C47F- 29 0E AND #$0E -C481- D0 01 BNE $C484 ; if the interrupt bits don't show it was a mouse interrupt, set error (C) before returning -C483- 38 SEC -C484- 68 PLA ; restore A -C485- 60 RTS -; ClampMouse -C486- C9 02 CMP #$02 -C488- B0 26 BCS $C4B0 ; RTS if 2 <= the A register -C48A- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM -C48D- 60 RTS -; ReadMouse -C48E- A9 04 LDA #$04 -C490- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM -C493- 18 CLC -C494- EA NOP -C495- EA NOP -C496- 60 RTS -; InitMouse -C497- EA NOP -C498- A9 02 LDA #$02 -C49A- 99 83 C0 STA $C083,Y ; LC RAM bank 2, read RAM -C49D- 18 CLC -C49E- 60 RTS -; ClearMouse -C49F- EA NOP -C4A0- A9 05 LDA #$05 -C4A2- D0 F6 BNE $C49A -; PosMouse -C4A4- EA NOP -C4A5- A9 06 LDA #$06 -C4A7- D0 F1 BNE $C49A -; HomeMouse -C4A9- EA NOP -C4AA- A9 07 LDA #$07 -C4AC- D0 EC BNE $C49A -; "TimeData" to set freq before init to 50/60 Hz? Doesn't look like it... -C4AE- A2 03 LDX #$03 -C4B0- 38 SEC -C4B1- 60 RTS -; ServeMouse main worker -C4B2- 08 PHP -C4B3- A5 00 LDA $00 -C4B5- 48 PHA -C4B6- A9 60 LDA #$60 -C4B8- 85 00 STA $00 -C4BA- 78 SEI -C4BB- 20 00 00 JSR $0000 -C4BE- BA TSX -C4BF- 68 PLA -C4C0- 85 00 STA $00 -C4C2- BD 00 01 LDA $0100,X -C4C5- 28 PLP -C4C6- AA TAX -C4C7- 0A ASL -C4C8- 0A ASL -C4C9- 0A ASL -C4CA- 0A ASL -C4CB- A8 TAY -C4CC- A9 03 LDA #$03 -C4CE- 18 CLC -C4CF- 90 A8 BCC $C479 ; always branches - -... but the version below is patched so it uses soft switches to call -back here. - -SETMOUSE: -C471- 8D CF C0 STA $C0CF ; use soft switch 0xF to handle it - 60 RTS - -Patch: C471 from 99 82 C0 60 => 8D CF C0 60 - -SERVEMOUSE @ $C4B2: - 78 SEI - AD CE C0 LDA $C0CE ; use soft switch 0xE (read) to trigger this - expect new value to be placed in $7f8+4 and $6b8+4 - A2 04 LDX #$04 ; our slot number, for cleanup code - 18 CLC - 90 C1 BCC $C47C - -Patch: C4B2 from 08 A5 00 48 A9 60 85 00 78 => - 78 AD CE C0 A2 04 18 90 C1 - -READMOUSE -C48E- AD CB C0 LDA $C0CB ; soft switch 0x0B for readmouse - 18 CLC - 60 RTS - -Patch: from A9 04 99 83 C0 => - AD CB C0 18 60 - -CLEARMOUSE -C49F- AD CA C0 LDA $C0CA ; soft switch 0x0A for clearmouse - 18 CLC - 60 RTS - -Patch: from EA A9 05 D0 F6 => - AD CA C0 18 60 -POSMOUSE -C4a4- AD C9 C0 LDA $C0C9 ; soft switch 0x09 for posmouse - 18 CLC - 60 RTS - -Patch: from EA A9 06 D0 F1 => - AD C9 C0 18 60 - -CLAMPMOUSE -C48A- 8D CD C0 STA $C04D ; use write to soft switch 0x0D to trigger clamp - 60 RTS - -Patch: from 99 83 C0 60 => 8D CD C0 60 - -HOMEMOUSE -C4A9- AD C8 C0 LDA $c048 ; soft switch 0x08 for homemouse (read) - 18 CLC - 60 RTS - -Patch: from EA A9 07 D0 EC => AD C8 C0 18 60 - -INITMOUSE -C498- AD CC C0 LDA $C04C ; soft switch 0x0C read for initmouse - 18 CLC - 60 RTS - -Patch: from A9 02 99 83 C0 => AD CC C0 18 60 - */ + /* 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 $C420 + * ; $c405 is the entry point for IN#4 when we set KSW + * $C405 38 SEC + * $C406 90 18 BCC $C420 + * $C408 B8 CLV + * $C409 50 15 BVC $C420 ; 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) + * ; $c420 is the I/O handler + * $C420 48 PHA + * $C421 98 TYA + * $C422 48 PHA + * $C423 8A TXA + * $C424 48 PHA + * $C425 08 PHP + * $C426 78 SEI + * $C427 20 58 FF JSR $FF58 + * $C42A BA TSX + * $C42B BD 00 01 LDA $100,X + * $C42E AA TAX + * $C42F 0A ASL + * $C430 0A ASL + * $C431 0A ASL + * $C432 0A ASL + * $C433 A8 TAY + * $C434 28 PLP + * $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 $C451 + * $C446 B0 09 BCS $C451 + * $C448 68 PLA + * $C449 AA TAX + * $C44A 68 PLA + * $C44B EA NOP + * $C44C 68 PLA + * $C44D EA NOP + * $C44E EA NOP + * $C44F EA NOP + * $C450 60 RTS + * $C451 EA NOP + * $C452 EA NOP + * $C453 EA NOP + * $C454 68 PLA + * $C455 BD 38 06 LDA $638,X + * $C458 AA TAX + * $C459 68 PLA + * $C45A A8 TAY + * $C45B 68 PLA + * $C45C BD 00 02 LDA $200,X + * $C45F 60 RTS + * ; $c460 is SetMouse + * $C460 C9 10 CMP #$0 + * $C462 B0 29 BCS $C48D + * $C464 8D CF C0 STA $C0CF + * $C467 60 RTS + * ; $c468 is ServeMouse + * $C468 48 PHA + * $C469 18 CLC + * $C46A 90 2D BCC $C499 ; jump to ServeMouseWorker + * ; $c46c is ServeMouseExit + * $C46C BD B8 06 LDA $6B8,X + * $C46F 29 0E AND #$0 + * $C471 D0 01 BNE $C474 + * $C473 38 SEC + * $C474 68 PLA + * $C475 60 RTS + * ; $c476 is ReadMouse + * $C476 8D CB C0 STA $C0CB + * $C479 18 CLC + * $C47A 60 RTS + * ; $c47b is ClearMouse + * $C47B 8D CA C0 STA $C0CA + * $C47E 18 CLC + * $C47F 60 RTS + * ; $c480 is PosMouse + * $C480 8D C9 C0 STA $C0C9 + * $C483 18 CLC + * $C484 60 RTS + * ; $c485 is ClampMouse + * $C485 C9 02 CMP #$0 + * $C487 B0 04 BCS $C48D + * $C489 8D CD C0 STA $C0CD + * $C48C 60 RTS + * ; $c48d is an error exit point + * $C48D 38 SEC + * $C48E 60 RTS + * ; $c48f is HomeMouse + * $C48F 8D C8 C0 STA $C0C8 + * $C492 18 CLC + * $C493 60 RTS + * ; $c494 is InitMouse + * $C494 8D CC C0 STA $C0CC + * $C497 18 CLC + * $C498 60 RTS + * ; $c499 is ServeMouse + * $C499 78 SEI + * $C49A 8D CE C0 STA $C0CE + * $C49D A2 04 LDX #$0 + * $C49F 18 CLC + * $C4A0 90 CA BCC $C46C + * ; $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, @@ -442,12 +314,8 @@ bool Mouse::hasExtendedRom() void Mouse::loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset) { -#if 0 - printf("loading extended rom for the mouse\n"); - for (int i=0; i<256; i++) { - toWhere[i] = romData[i + byteOffset]; - } -#endif + // There's no extended ROM needed, b/c we do the extended ROM work + // directly in C++ } void Mouse::maintainMouse(int64_t cycleCount) From 93746ed8d3b9ce18a65853166911c83f42f04b30 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 10:47:51 -0500 Subject: [PATCH 20/23] adding missing serialization include --- serialize.h | 142 +++++++++++++++++++++++++++++++++++++++++++++ teensy/serialize.h | 1 + 2 files changed, 143 insertions(+) create mode 100644 serialize.h create mode 120000 teensy/serialize.h diff --git a/serialize.h b/serialize.h new file mode 100644 index 0000000..f40812a --- /dev/null +++ b/serialize.h @@ -0,0 +1,142 @@ +#ifndef __SERIALIZE_H +#define __SERIALIZE_H + +#define serialize8(var) { uint8_t buf = (uint8_t)var; \ + if (g_filemanager->write(fd, &buf, 1) != 1) { \ + printf("Failed to write 1 byte\n"); \ + goto err; \ + } \ +} + +#define serializeMagic(var) { \ + printf("Serializing magic '%d'\n", var); \ + uint8_t buf = var; \ + if (g_filemanager->write(fd, &buf, 1) != 1) { \ + printf("Failed to write 1 byte of magic\n"); \ + goto err; \ + } \ +} + +#define serialize16(var) { \ + uint8_t buf[2]; \ + uint8_t ptr = 0; \ + buf[ptr++] = ((var >> 8) & 0xFF); \ + buf[ptr++] = ((var ) & 0xFF); \ + if (g_filemanager->write(fd, buf, 2) != 2) { \ + printf("Failed to write 2 bytes\n"); \ + goto err; \ + } \ +} + +#define serialize32(var) { \ + uint8_t buf[4]; \ + uint8_t ptr = 0; \ + buf[ptr++] = ((var >> 24) & 0xFF); \ + buf[ptr++] = ((var >> 16) & 0xFF); \ + buf[ptr++] = ((var >> 8) & 0xFF); \ + buf[ptr++] = ((var ) & 0xFF); \ + if (g_filemanager->write(fd, buf, 4) != 4) { \ + printf("Failed to write 4 bytes\n"); \ + goto err; \ + } \ +} + +#define serialize64(var) { \ + uint8_t buf[8]; \ + uint8_t ptr = 0; \ + buf[ptr++] = ((var >> 56) & 0xFF); \ + buf[ptr++] = ((var >> 48) & 0xFF); \ + buf[ptr++] = ((var >> 40) & 0xFF); \ + buf[ptr++] = ((var >> 32) & 0xFF); \ + buf[ptr++] = ((var >> 24) & 0xFF); \ + buf[ptr++] = ((var >> 16) & 0xFF); \ + buf[ptr++] = ((var >> 8) & 0xFF); \ + buf[ptr++] = ((var ) & 0xFF); \ + if (g_filemanager->write(fd, buf, 8) != 8) { \ + printf("Failed to write 8 bytes\n"); \ + goto err; \ + } \ +} + +#define serializeString(s) { \ + if (g_filemanager->write(fd, s, strlen(s)+1) != strlen(s)+1) { \ + printf("Failed to write string '%s'\n", s); \ + goto err; \ + } \ +} + +#define deserialize8(var) { \ + uint8_t buf; \ + if (g_filemanager->read(fd, &buf, 1) != 1) { \ + printf("Failed to deserialize 1 byte\n"); \ + goto err; \ + } \ + var = buf; \ +} + +#define deserializeMagic(expect) { \ + uint8_t buf; \ + printf("Deserializing magic, expecting 0x%X\n", expect); \ + if (g_filemanager->read(fd, &buf, 1) != 1) { \ + printf("Failed to deserialize 1 byte of magic\n"); \ + goto err; \ + } \ + if (buf != expect) { \ + printf("magic error: 0x%X does not match expected 0x%X\n", buf, expect); \ + goto err; \ + } \ +} + +#define deserialize16(var) { \ + uint8_t buf[2]; \ + uint8_t ptr = 0; \ + if (g_filemanager->read(fd, buf, 2) != 2) { \ + printf("Failed to deserialize 2 bytes\n"); \ + goto err; \ + } \ + var = buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; } + +#define deserialize32(var) { \ + uint8_t buf[4]; \ + uint8_t ptr = 0; \ + if (g_filemanager->read(fd, buf, 4) != 4) { \ + printf("Failed to deserialize 4 bytes\n"); \ + goto err; \ + } \ + var = buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; } + +#define deserialize64(var) { \ + uint8_t buf[8]; \ + uint8_t ptr = 0; \ + if (g_filemanager->read(fd, buf, 8) != 8) { \ + printf("Failed to deserialize 8 bytes\n"); \ + goto err; \ + } \ + var = buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; \ + var <<= 8; var |= buf[ptr++]; } + +#define deserializeString(var) { \ + uint8_t c; \ + char *ptr = var; \ + while (1) { \ + if (g_filemanager->read(fd, &c, 1) != 1) { \ + printf("Failed to read string byte\n"); \ + goto err; \ + } \ + printf(". "); \ + *(ptr++) = c; \ + if (c == 0) { break; } \ + } \ +} + +#endif diff --git a/teensy/serialize.h b/teensy/serialize.h new file mode 120000 index 0000000..c72647a --- /dev/null +++ b/teensy/serialize.h @@ -0,0 +1 @@ +../serialize.h \ No newline at end of file From bab3560273fffadf7354e42f23900e62dab75ea8 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 10:53:03 -0500 Subject: [PATCH 21/23] wired in mouse support; left-apple is the mouse button on the teensy for now --- .gitignore | 3 +- Makefile | 4 +- apple/mouse.cpp | 2 - sdl/sdl-mouse.cpp | 62 +++++++++++++++++++++++++++++ sdl/sdl-mouse.h | 26 ++++++++++++ teensy/mouse.cpp | 1 + teensy/mouse.h | 1 + teensy/physicalmouse.h | 1 + teensy/teensy-keyboard.cpp | 15 ++++++- teensy/teensy-mouse.cpp | 81 ++++++++++++++++++++++++++++++++++++++ teensy/teensy-mouse.h | 24 +++++++++++ teensy/teensy.ino | 2 + util/genrom.pl | 3 -- 13 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 sdl/sdl-mouse.cpp create mode 100644 sdl/sdl-mouse.h create mode 120000 teensy/mouse.cpp create mode 120000 teensy/mouse.h create mode 120000 teensy/physicalmouse.h create mode 100644 teensy/teensy-mouse.cpp create mode 100644 teensy/teensy-mouse.h diff --git a/.gitignore b/.gitignore index 97bf4a3..6372f9a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ apple/hd32-rom.h aiie-sdl mockingboard-d.rom *.d - +*.dSYM +suspend.vm diff --git a/Makefile b/Makefile index eaf2de5..1997de9 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 MouseInterface.rom +ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h apple/hd32-rom.h .PHONY: roms clean @@ -40,7 +40,7 @@ test: $(TSRC) ./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 MouseInterface.rom + ./util/genrom.pl apple2e.rom disk.rom parallel.rom HDDRVR.BIN apple/applemmu-rom.h: roms diff --git a/apple/mouse.cpp b/apple/mouse.cpp index f6e43ba..4ac82e2 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -2,8 +2,6 @@ #include #include "globals.h" -#include "mouse-rom.h" - enum { SW_W_INIT = 0x00, SW_R_HOMEMOUSE = 0x08, diff --git a/sdl/sdl-mouse.cpp b/sdl/sdl-mouse.cpp new file mode 100644 index 0000000..c7e386e --- /dev/null +++ b/sdl/sdl-mouse.cpp @@ -0,0 +1,62 @@ +#include "sdl-mouse.h" + +#include "globals.h" + +SDLMouse::SDLMouse() : PhysicalMouse() +{ + xpos = ypos = 0; + button = false; +} + +SDLMouse::~SDLMouse() +{ +} + +void SDLMouse::gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y) +{ + xpos += x; ypos += y; + + if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP]; + if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP]; + if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP]; + if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP]; +} + +void SDLMouse::mouseButtonEvent(bool state) +{ + button = state; +} + +void SDLMouse::maintainMouse() +{ +} + +void SDLMouse::setPosition(uint16_t x, uint16_t y) +{ + xpos = x; + ypos = y; + + if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP]; + if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP]; + if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP]; + if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP]; +} + +void SDLMouse::getPosition(uint16_t *x, uint16_t *y) +{ + if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP]; + if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP]; + if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP]; + if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP]; + + uint16_t outx = xpos; + uint16_t outy = ypos; + + *x = outx; + *y = outy; +} + +bool SDLMouse::getButton() +{ + return button; +} diff --git a/sdl/sdl-mouse.h b/sdl/sdl-mouse.h new file mode 100644 index 0000000..9da03db --- /dev/null +++ b/sdl/sdl-mouse.h @@ -0,0 +1,26 @@ +#ifndef __SDL_MOUSE_H +#define __SDL_MOUSE_H + +#include "physicalmouse.h" + +#include + +class SDLMouse : public PhysicalMouse { + public: + SDLMouse(); + virtual ~SDLMouse(); + + virtual void maintainMouse(); + + virtual void setPosition(uint16_t x, uint16_t y); + virtual void getPosition(uint16_t *x, uint16_t *y); + virtual bool getButton(); + + void gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y); + void mouseButtonEvent(bool state); +private: + int32_t xpos, ypos; + bool button; +}; + +#endif diff --git a/teensy/mouse.cpp b/teensy/mouse.cpp new file mode 120000 index 0000000..b2d16ed --- /dev/null +++ b/teensy/mouse.cpp @@ -0,0 +1 @@ +../apple/mouse.cpp \ No newline at end of file diff --git a/teensy/mouse.h b/teensy/mouse.h new file mode 120000 index 0000000..67eec56 --- /dev/null +++ b/teensy/mouse.h @@ -0,0 +1 @@ +../apple/mouse.h \ No newline at end of file diff --git a/teensy/physicalmouse.h b/teensy/physicalmouse.h new file mode 120000 index 0000000..80c4786 --- /dev/null +++ b/teensy/physicalmouse.h @@ -0,0 +1 @@ +../physicalmouse.h \ No newline at end of file diff --git a/teensy/teensy-keyboard.cpp b/teensy/teensy-keyboard.cpp index 7912fbc..7df9b1b 100644 --- a/teensy/teensy-keyboard.cpp +++ b/teensy/teensy-keyboard.cpp @@ -4,6 +4,9 @@ #include "LRingBuffer.h" #include "teensy-println.h" +#include "globals.h" +#include "teensy-mouse.h" + const byte ROWS = 5; const byte COLS = 13; @@ -71,12 +74,13 @@ void TeensyKeyboard::pressedKey(uint8_t key) break; case PK_RSHFT: rightShiftPressed = 1; - break; + break; case PK_LOCK: capsLock = !capsLock; break; case PK_LA: - leftApplePressed = 1; + ((TeensyMouse *)g_mouse)->mouseButtonEvent(true); + leftApplePressed = 1; break; case PK_RA: rightApplePressed = 1; @@ -162,6 +166,7 @@ void TeensyKeyboard::releasedKey(uint8_t key) rightShiftPressed = 0; break; case PK_LA: + ((TeensyMouse *)g_mouse)->mouseButtonEvent(false); leftApplePressed = 0; break; case PK_RA: @@ -218,9 +223,15 @@ void TeensyKeyboard::maintainKeyboard() switch (keypad.key[i].kstate) { case PRESSED: vmkeyboard->keyDepressed(keypad.key[i].kchar); + if (keypad.key[i].kchar == PK_LSHFT) { + ((TeensyMouse *)g_mouse)->mouseButtonEvent(true); + } break; case RELEASED: vmkeyboard->keyReleased(keypad.key[i].kchar); + if (keypad.key[i].kchar == PK_LSHFT) { + ((TeensyMouse *)g_mouse)->mouseButtonEvent(false); + } break; case HOLD: case IDLE: diff --git a/teensy/teensy-mouse.cpp b/teensy/teensy-mouse.cpp new file mode 100644 index 0000000..e6faaf4 --- /dev/null +++ b/teensy/teensy-mouse.cpp @@ -0,0 +1,81 @@ +#include +#include "teensy-mouse.h" + +#include "globals.h" + +TeensyMouse::TeensyMouse() : PhysicalMouse() +{ + xpos = ypos = 0; + button = false; +} + +TeensyMouse::~TeensyMouse() +{ +} + +void TeensyMouse::gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y) +{ + xpos += x; ypos += y; + + if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP]; + if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP]; + if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP]; + if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP]; +} + +void TeensyMouse::mouseButtonEvent(bool state) +{ + button = state; +} + +void TeensyMouse::maintainMouse() +{ + // FIXME: only do this if the mouse card is enabled, so we're not incurring + // analogRead delays constantly + uint8_t paddle0 = g_paddles->paddle0(); + uint8_t paddle1 = g_paddles->paddle1(); + int16_t dx=0, dy=0; + if (paddle0 <= 25) { + dx = -1; + } else if (paddle0 >= 245) { + dx = 1; + } + if (paddle1 <= 25) { + dy = -1; + } else if (paddle1 >= 245) { + dy = 1; + } + if (dx || dy) { + gotMouseEvent(button, dx, dy); + } +} + +void TeensyMouse::setPosition(uint16_t x, uint16_t y) +{ + xpos = x; + ypos = y; + + if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP]; + if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP]; + if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP]; + if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP]; +} + +void TeensyMouse::getPosition(uint16_t *x, uint16_t *y) +{ + if (xpos < lowClamp[XCLAMP]) xpos=lowClamp[XCLAMP]; + if (xpos > highClamp[XCLAMP]) xpos=highClamp[XCLAMP]; + if (ypos < lowClamp[YCLAMP]) ypos = lowClamp[YCLAMP]; + if (ypos > highClamp[YCLAMP]) ypos = highClamp[YCLAMP]; + + uint16_t outx = xpos; + uint16_t outy = ypos; + + *x = outx; + *y = outy; +} + +bool TeensyMouse::getButton() +{ + return button; +} diff --git a/teensy/teensy-mouse.h b/teensy/teensy-mouse.h new file mode 100644 index 0000000..8365d70 --- /dev/null +++ b/teensy/teensy-mouse.h @@ -0,0 +1,24 @@ +#ifndef __TEENSY_MOUSE_H +#define __TEENSY_MOUSE_H + +#include "physicalmouse.h" + +class TeensyMouse : public PhysicalMouse { + public: + TeensyMouse(); + virtual ~TeensyMouse(); + + virtual void maintainMouse(); + + virtual void setPosition(uint16_t x, uint16_t y); + virtual void getPosition(uint16_t *x, uint16_t *y); + virtual bool getButton(); + + void gotMouseEvent(uint32_t buttonState, int32_t x, int32_t y); + void mouseButtonEvent(bool state); +private: + int32_t xpos, ypos; + bool button; +}; + +#endif diff --git a/teensy/teensy.ino b/teensy/teensy.ino index 9cb7b10..0b22b97 100644 --- a/teensy/teensy.ino +++ b/teensy/teensy.ino @@ -6,6 +6,7 @@ #include "applevm.h" #include "teensy-display.h" #include "teensy-keyboard.h" +#include "teensy-mouse.h" #include "teensy-speaker.h" #include "teensy-paddles.h" #include "teensy-filemanager.h" @@ -211,6 +212,7 @@ void setup() // And the physical keyboard needs hooks in to the virtual keyboard... println(" keyboard"); g_keyboard = new TeensyKeyboard(g_vm->getKeyboard()); + g_mouse = new TeensyMouse(); println(" paddles"); g_paddles = new TeensyPaddles(A3, A2, g_invertPaddleX, g_invertPaddleY); diff --git a/util/genrom.pl b/util/genrom.pl index b5ecaf2..867f2b0 100755 --- a/util/genrom.pl +++ b/util/genrom.pl @@ -7,19 +7,16 @@ 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 the 2k Mouse rom"; 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, 2048, "2k Mouse extended ROM image"); 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($hdrom, "apple/mouse-rom.h", "romData", 2048); exit 0; sub validate { From b6cd790fa9518d3c86bd7d63847bbbb520925f65 Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 11:32:40 -0500 Subject: [PATCH 22/23] only re-read joystick for mouse posn while mouse is enabled; added comments in mouse rom --- apple/applevm.cpp | 5 ++ apple/applevm.h | 2 + apple/mouse.cpp | 119 ++++++++++++++++++++++------------------ apple/mouse.h | 9 +++ teensy/teensy-mouse.cpp | 38 +++++++------ 5 files changed, 103 insertions(+), 70 deletions(-) diff --git a/apple/applevm.cpp b/apple/applevm.cpp index 07e2986..f182b9f 100644 --- a/apple/applevm.cpp +++ b/apple/applevm.cpp @@ -193,3 +193,8 @@ VMKeyboard * AppleVM::getKeyboard() { return keyboard; } + +bool AppleVM::isMouseEnabled() +{ + return mouse->isEnabled(); +} diff --git a/apple/applevm.h b/apple/applevm.h index 57759b1..f3a490b 100644 --- a/apple/applevm.h +++ b/apple/applevm.h @@ -35,6 +35,8 @@ class AppleVM : public VM { virtual VMKeyboard *getKeyboard(); + bool isMouseEnabled(); + DiskII *disk6; HD32 *hd32; protected: diff --git a/apple/mouse.cpp b/apple/mouse.cpp index 4ac82e2..f7e4be6 100644 --- a/apple/mouse.cpp +++ b/apple/mouse.cpp @@ -31,7 +31,9 @@ Mouse::Mouse() status = 0; interruptsTriggered = 0; lastX = lastY = 0; + lastXForInt = lastYForInt = 0; lastButton = false; + lastButtonForInt = false; } Mouse::~Mouse() @@ -125,7 +127,7 @@ void Mouse::writeSwitches(uint8_t s, uint8_t v) break; case SW_W_INIT: v &= 0x03; // just the low 3 bits apparently? - printf("Simple init: value is 0x%X\n", v); + // printf("Simple init: value is 0x%X\n", v); status = v; g_vm->getMMU()->write(0x7f8 + 4, v); break; @@ -158,33 +160,33 @@ void Mouse::loadROM(uint8_t *toWhere) * * ; $c400 is the entry point for PR#4 * $C400 2C 58 FF BIT $FF58 - * $C403 70 1B BVS $C420 + * $C403 70 1B BVS IOHandler * ; $c405 is the entry point for IN#4 when we set KSW * $C405 38 SEC - * $C406 90 18 BCC $C420 + * $C406 90 18 BCC IOHandler * $C408 B8 CLV - * $C409 50 15 BVC $C420 ; always branch + * $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) - * ; $c420 is the I/O handler - * $C420 48 PHA + * ; 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 - * $C427 20 58 FF JSR $FF58 - * $C42A BA TSX - * $C42B BD 00 01 LDA $100,X - * $C42E AA TAX - * $C42F 0A ASL + * $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 - * $C434 28 PLP + * $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 @@ -193,9 +195,9 @@ void Mouse::loadROM(uint8_t *toWhere) * $C43E D0 08 BNE $C448 * $C440 A9 05 LDA #$0 * $C442 85 38 STA $0 - * $C444 D0 0B BNE $C451 - * $C446 B0 09 BCS $C451 - * $C448 68 PLA + * $C444 D0 0B BNE SendInputToDOS + * $C446 B0 09 BCS SendInputToDOS + * $C448 68 PLA ; restore registers * $C449 AA TAX * $C44A 68 PLA * $C44B EA NOP @@ -204,67 +206,68 @@ void Mouse::loadROM(uint8_t *toWhere) * $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 - * $C458 AA TAX + * $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 + * $C45C BD 00 02 LDA $200,X ; keyboard buffer output * $C45F 60 RTS - * ; $c460 is SetMouse + * ; SetMouse ORG $c460 * $C460 C9 10 CMP #$0 - * $C462 B0 29 BCS $C48D - * $C464 8D CF C0 STA $C0CF + * $C462 B0 29 BCS ExitWithError + * $C464 8D CF C0 STA $C0CF ; soft switch 0x0F invokes SetMouse * $C467 60 RTS - * ; $c468 is ServeMouse + * ; ServeMouse ORG $c468 * $C468 48 PHA - * $C469 18 CLC - * $C46A 90 2D BCC $C499 ; jump to ServeMouseWorker - * ; $c46c is ServeMouseExit - * $C46C BD B8 06 LDA $6B8,X + * $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 - * $C473 38 SEC + * $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 - * ; $c476 is ReadMouse - * $C476 8D CB C0 STA $C0CB + * ; ReadMouse ORG $c476 + * $C476 8D CB C0 STA $C0CB ; soft switch 0x0B * $C479 18 CLC * $C47A 60 RTS - * ; $c47b is ClearMouse - * $C47B 8D CA C0 STA $C0CA + * ; ClearMouse ORG $c47b + * $C47B 8D CA C0 STA $C0CA ; soft switch 0x0A * $C47E 18 CLC * $C47F 60 RTS - * ; $c480 is PosMouse - * $C480 8D C9 C0 STA $C0C9 + * ; PosMouse ORG $c480 + * $C480 8D C9 C0 STA $C0C9 ; soft switch 0x09 * $C483 18 CLC * $C484 60 RTS - * ; $c485 is ClampMouse + * ; ClampMouse ORG $c485 * $C485 C9 02 CMP #$0 * $C487 B0 04 BCS $C48D - * $C489 8D CD C0 STA $C0CD + * $C489 8D CD C0 STA $C0CD ; soft switch 0x0D * $C48C 60 RTS - * ; $c48d is an error exit point - * $C48D 38 SEC + * ; ExitWithError ORG $c48d + * $C48D 38 SEC ; the spec says carry is set on errors * $C48E 60 RTS - * ; $c48f is HomeMouse - * $C48F 8D C8 C0 STA $C0C8 + * ; HomeMouse ORG $c48f + * $C48F 8D C8 C0 STA $C0C8 ; soft switch 0x08 * $C492 18 CLC * $C493 60 RTS - * ; $c494 is InitMouse - * $C494 8D CC C0 STA $C0CC + * ; InitMouse ORG $c494 + * $C494 8D CC C0 STA $C0CC ; soft switch 0x0C * $C497 18 CLC * $C498 60 RTS - * ; $c499 is ServeMouse - * $C499 78 SEI - * $C49A 8D CE C0 STA $C0CE + * ; 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 $C46C + * $C4A0 90 CA BCC ServeMouseExit ; force relative jump * ; $C4A2..C4FA is dead space (all $FF) * $C4FB D6 FF FF FF 01 ; data (ID bytes) */ @@ -318,11 +321,9 @@ void Mouse::loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset) void Mouse::maintainMouse(int64_t cycleCount) { - // static int64_t startTime = cycleCount; - // Fake a 60Hz VBL in case we need it for our interrupts static int64_t nextInterruptTime = cycleCount + 17050; - + if ( (status & ST_MOUSEENABLE) && (status & ST_INTVBL) && (cycleCount >= nextInterruptTime) ) { @@ -337,12 +338,24 @@ void Mouse::maintainMouse(int64_t cycleCount) if ( (status & ST_MOUSEENABLE) && (status & ST_INTMOUSE) && - (xpos != lastX || ypos != lastY) ) { + (xpos != lastXForInt || ypos != lastYForInt) ) { g_cpu->irq(); interruptsTriggered |= ST_INTMOUSE; - lastX = xpos; lastY = ypos; + lastXForInt = xpos; lastYForInt = ypos; + } else if ( (status & ST_MOUSEENABLE) && + (status & ST_INTBUTTON) && + lastButtonForInt != g_mouse->getButton()) { + g_cpu->irq(); + + interruptsTriggered |= ST_INTBUTTON; + lastButtonForInt = g_mouse->getButton(); } } /* FIXME: still need button */ } + +bool Mouse::isEnabled() +{ + return status & ST_MOUSEENABLE; +} diff --git a/apple/mouse.h b/apple/mouse.h index 5a29e7c..bafa602 100644 --- a/apple/mouse.h +++ b/apple/mouse.h @@ -28,14 +28,23 @@ class Mouse : public Slot { virtual void loadExtendedRom(uint8_t *toWhere, uint16_t byteOffset); void maintainMouse(int64_t cycleCount); + + bool isEnabled(); private: uint8_t status; uint8_t interruptsTriggered; + // Previous state vars used when we're asked "did this change since last time" uint16_t lastX, lastY; bool lastButton; + bool curButton; + + // second set of previous state vars for use when checking if an interrupt + // needs to fire based on a change + uint16_t lastXForInt, lastYForInt; + bool lastButtonForInt; }; #endif diff --git a/teensy/teensy-mouse.cpp b/teensy/teensy-mouse.cpp index e6faaf4..b04974d 100644 --- a/teensy/teensy-mouse.cpp +++ b/teensy/teensy-mouse.cpp @@ -3,6 +3,8 @@ #include "globals.h" +#include "applevm.h" + TeensyMouse::TeensyMouse() : PhysicalMouse() { xpos = ypos = 0; @@ -30,23 +32,25 @@ void TeensyMouse::mouseButtonEvent(bool state) void TeensyMouse::maintainMouse() { - // FIXME: only do this if the mouse card is enabled, so we're not incurring - // analogRead delays constantly - uint8_t paddle0 = g_paddles->paddle0(); - uint8_t paddle1 = g_paddles->paddle1(); - int16_t dx=0, dy=0; - if (paddle0 <= 25) { - dx = -1; - } else if (paddle0 >= 245) { - dx = 1; - } - if (paddle1 <= 25) { - dy = -1; - } else if (paddle1 >= 245) { - dy = 1; - } - if (dx || dy) { - gotMouseEvent(button, dx, dy); + if (((AppleVM *)g_vm)->isMouseEnabled()) { + // only do this if the mouse card is enabled, so we're not incurring + // analogRead delays constantly + uint8_t paddle0 = g_paddles->paddle0(); + uint8_t paddle1 = g_paddles->paddle1(); + int16_t dx=0, dy=0; + if (paddle0 <= 25) { + dx = -1; + } else if (paddle0 >= 245) { + dx = 1; + } + if (paddle1 <= 25) { + dy = -1; + } else if (paddle1 >= 245) { + dy = 1; + } + if (dx || dy) { + gotMouseEvent(button, dx, dy); + } } } From 766e04a8200569e8b8d7604cce34b7399f25563e Mon Sep 17 00:00:00 2001 From: Jorj Bauer Date: Mon, 11 Jan 2021 12:32:42 -0500 Subject: [PATCH 23/23] tweak handling of B&W for GEOS. Not perfect on a scaled display. --- apple/appledisplay.cpp | 7 +++++-- teensy/teensy-display.cpp | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apple/appledisplay.cpp b/apple/appledisplay.cpp index 1494684..ea2c4d5 100644 --- a/apple/appledisplay.cpp +++ b/apple/appledisplay.cpp @@ -216,10 +216,13 @@ inline void AppleDisplay::Draw14DoubleHiresPixelsAt(uint16_t addr) drawApplePixel(bitTrain & 0x0F, col+xoff+1,row); } else { // Perfect color, B&W, monochrome. Draw an exact version of the pixels, and let - // the physical display figure out if they need to be reduced to B&W or not. + // the physical display figure out if they need to be reduced to B&W or not + // (for the most part - the m_blackAndWhite piece here allows full-res displays + // to give the crispest resolution.) uint8_t color = bitTrain & 0x0F; - + if (g_displayType == m_blackAndWhite) { color = c_white; } + g_display->cachePixel((col*2)+(xoff*2), row, ((bitTrain & 0x01) ? color : c_black)); diff --git a/teensy/teensy-display.cpp b/teensy/teensy-display.cpp index 3d38079..e3b916a 100644 --- a/teensy/teensy-display.cpp +++ b/teensy/teensy-display.cpp @@ -345,10 +345,14 @@ void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color) // with a color between the two. #if 1 - // This is straight blending, R/G/B average + // This is straight blending, R/G/B average, except in B&W mode uint16_t origColor = dmaBuffer[y+VOFFSET][(x>>1)+HOFFSET]; uint16_t newColor = loresPixelColors[color]; - cacheDoubleWidePixel(x>>1, y, blendColors(origColor, newColor)); + if (g_displayType == m_blackAndWhite) { + cacheDoubleWidePixel(x>>1, y, (origColor && newColor) ? 0xFFFF : 0x0000); + } else { + cacheDoubleWidePixel(x>>1, y, blendColors(origColor, newColor)); + } #endif #if 0