From b6f06c7cba33e34d695cbdaa1b212f1d88c86dd2 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Wed, 2 Apr 2014 13:00:00 -0500 Subject: [PATCH] Added state save/load support. --- Makefile | 2 +- src/apple2.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++++- src/charset.cpp | 6 ++- src/charset.h | 6 ++- src/floppy.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/floppy.h | 8 ++++ 6 files changed, 225 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 340790a..60547df 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # # by James Hammons # (C) 2005 Underground Software -# This software is licensed under the GPL v2 +# This software is licensed under the GPL v3 # FIND = find diff --git a/src/apple2.cpp b/src/apple2.cpp index 0b3ab42..26cab22 100644 --- a/src/apple2.cpp +++ b/src/apple2.cpp @@ -245,14 +245,118 @@ bool LoadImg(char * filename, uint8_t * ram, int size) } +const uint8_t stateHeader[19] = "APPLE2SAVESTATE1.0"; static void SaveApple2State(const char * filename) { + WriteLog("Main: Saving Apple2 state...\n"); + FILE * file = fopen(filename, "wb"); + + if (!file) + { + WriteLog("Could not open file \"%s\" for writing!\n", filename); + return; + } + + // Write out header + fwrite(stateHeader, 1, 18, file); + + // Write out CPU state + fwrite(&mainCPU, 1, sizeof(mainCPU), file); + + // Write out main memory + fwrite(ram, 1, 0x10000, file); + fwrite(ram2, 1, 0x10000, file); + + // Write out state variables + fputc((uint8_t)keyDown, file); + fputc((uint8_t)openAppleDown, file); + fputc((uint8_t)closedAppleDown, file); + fputc((uint8_t)store80Mode, file); + fputc((uint8_t)vbl, file); + fputc((uint8_t)slotCXROM, file); + fputc((uint8_t)slotC3ROM, file); + fputc((uint8_t)ramrd, file); + fputc((uint8_t)ramwrt, file); + fputc((uint8_t)altzp, file); + fputc((uint8_t)ioudis, file); + fputc((uint8_t)dhires, file); + fputc((uint8_t)flash, file); + fputc((uint8_t)textMode, file); + fputc((uint8_t)mixedMode, file); + fputc((uint8_t)displayPage2, file); + fputc((uint8_t)hiRes, file); + fputc((uint8_t)alternateCharset, file); + fputc((uint8_t)col80Mode, file); + fputc(lcState, file); + + // Write out floppy state + floppyDrive.SaveState(file); + fclose(file); } static bool LoadApple2State(const char * filename) { - return false; + WriteLog("Main: Loading Apple2 state...\n"); + FILE * file = fopen(filename, "rb"); + + if (!file) + { + WriteLog("Could not open file \"%s\" for reading!\n", filename); + return false; + } + + uint8_t buffer[18]; + fread(buffer, 1, 18, file); + + // Sanity check... + if (memcmp(buffer, stateHeader, 18) != 0) + { + fclose(file); + WriteLog("File \"%s\" is not a valid Apple2 save state file!\n", filename); + return false; + } + + // Read CPU state + fread(&mainCPU, 1, sizeof(mainCPU), file); + + // Read main memory + fread(ram, 1, 0x10000, file); + fread(ram2, 1, 0x10000, file); + + // Read in state variables + keyDown = (bool)fgetc(file); + openAppleDown = (bool)fgetc(file); + closedAppleDown = (bool)fgetc(file); + store80Mode = (bool)fgetc(file); + vbl = (bool)fgetc(file); + slotCXROM = (bool)fgetc(file); + slotC3ROM = (bool)fgetc(file); + ramrd = (bool)fgetc(file); + ramwrt = (bool)fgetc(file); + altzp = (bool)fgetc(file); + ioudis = (bool)fgetc(file); + dhires = (bool)fgetc(file); + flash = (bool)fgetc(file); + textMode = (bool)fgetc(file); + mixedMode = (bool)fgetc(file); + displayPage2 = (bool)fgetc(file); + hiRes = (bool)fgetc(file); + alternateCharset = (bool)fgetc(file); + col80Mode = (bool)fgetc(file); + lcState = fgetc(file); + + // Read in floppy state + floppyDrive.LoadState(file); + + fclose(file); + + // Make sure things are in a sane state before execution :-P + mainCPU.RdMem = AppleReadMem; + mainCPU.WrMem = AppleWriteMem; + ResetMMUPointers(); + + return true; } @@ -322,7 +426,6 @@ int main(int /*argc*/, char * /*argv*/[]) //Load up disk image from config file (for now)... floppyDrive.LoadImage(settings.diskImagePath1, 0); floppyDrive.LoadImage(settings.diskImagePath2, 1); -// floppyDrive.LoadImage("./disks/temp.nib", 1); // Load temp .nib file into second drive... WriteLog("About to initialize video...\n"); diff --git a/src/charset.cpp b/src/charset.cpp index 0b32c69..3e43623 100644 --- a/src/charset.cpp +++ b/src/charset.cpp @@ -10,7 +10,9 @@ // Apple II character set has 64 chars (56 bytes for each character) -char textChar[0x0E00] = { +#include + +uint8_t textChar[0x0E00] = { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -79,7 +81,7 @@ char textChar[0x0E00] = { // Apple IIe/IIc character set has 256 chars (56 bytes for each character) -char textChar2e[0x3800] = { +uint8_t textChar2e[0x3800] = { 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, diff --git a/src/charset.h b/src/charset.h index f0b3291..126a649 100644 --- a/src/charset.h +++ b/src/charset.h @@ -1,8 +1,10 @@ #ifndef __CHARSET_H__ #define __CHARSET_H__ -extern char textChar[]; -extern char textChar2e[]; +#include + +extern uint8_t textChar[]; +extern uint8_t textChar2e[]; #endif // __CHARSET_H__ diff --git a/src/floppy.cpp b/src/floppy.cpp index ca78135..3a33e8d 100644 --- a/src/floppy.cpp +++ b/src/floppy.cpp @@ -611,6 +611,109 @@ int FloppyDrive::DriveLightStatus(uint8_t driveNum/*= 0*/) } +void FloppyDrive::SaveState(FILE * file) +{ + // Internal state vars + fputc(motorOn, file); + fputc(activeDrive, file); + fputc(ioMode, file); + fputc(latchValue, file); + fputc(phase, file); + fputc(track, file); + fputc((ioHappened ? 1 : 0), file); + WriteLong(file, currentPos); + + // Disk #1 + if (disk[0] != NULL) + { + WriteLong(file, diskSize[0]); + WriteLong(file, diskType[0]); + fputc((imageDirty[0] ? 1 : 0), file); + fputc((writeProtected[0] ? 1 : 0), file); + fwrite(nybblizedImage[0], 1, 232960, file); + fwrite(imageName[0], 1, MAX_PATH, file); + } + else + WriteLong(file, 0); + + // Disk #2 + if (disk[1] != NULL) + { + WriteLong(file, diskSize[1]); + WriteLong(file, diskType[1]); + fputc((imageDirty[1] ? 1 : 0), file); + fputc((writeProtected[1] ? 1 : 0), file); + fwrite(nybblizedImage[1], 1, 232960, file); + fwrite(imageName[1], 1, MAX_PATH, file); + } + else + WriteLong(file, 0); +} + + +void FloppyDrive::LoadState(FILE * file) +{ + // Eject images if they're loaded + EjectImage(0); + EjectImage(1); + + // Read internal state variables + motorOn = fgetc(file); + activeDrive = fgetc(file); + ioMode = fgetc(file); + latchValue = fgetc(file); + phase = fgetc(file); + track = fgetc(file); + ioHappened = (fgetc(file) == 1 ? true : false); + currentPos = ReadLong(file); + + diskSize[0] = ReadLong(file); + + if (diskSize[0]) + { + disk[0] = new uint8_t[diskSize[0]]; + diskType[0] = (uint8_t)ReadLong(file); + imageDirty[0] = (fgetc(file) == 1 ? true : false); + writeProtected[0] = (fgetc(file) == 1 ? true : false); + fread(nybblizedImage[0], 1, 232960, file); + fread(imageName[0], 1, MAX_PATH, file); + } + + diskSize[1] = ReadLong(file); + + if (diskSize[1]) + { + disk[1] = new uint8_t[diskSize[1]]; + diskType[1] = (uint8_t)ReadLong(file); + imageDirty[1] = (fgetc(file) == 1 ? true : false); + writeProtected[1] = (fgetc(file) == 1 ? true : false); + fread(nybblizedImage[1], 1, 232960, file); + fread(imageName[1], 1, MAX_PATH, file); + } +} + + +uint32_t FloppyDrive::ReadLong(FILE * file) +{ + uint32_t r = 0; + + for(int i=0; i<4; i++) + r = (r << 8) | fgetc(file); + + return r; +} + + +void FloppyDrive::WriteLong(FILE * file, uint32_t l) +{ + for(int i=0; i<4; i++) + { + fputc((l >> 24) & 0xFF, file); + l = l << 8; + } +} + + // Memory mapped I/O functions /* diff --git a/src/floppy.h b/src/floppy.h index 6adb039..d439bfe 100644 --- a/src/floppy.h +++ b/src/floppy.h @@ -13,6 +13,7 @@ #include // for MAX_PATH on MinGW/Darwin #endif #include +#include enum { DFT_UNKNOWN, DT_DOS33, DT_DOS33_HDR, DT_PRODOS, DT_NYBBLE }; enum { DLS_OFF, DLS_READ, DLS_WRITE }; @@ -34,9 +35,16 @@ class FloppyDrive bool IsWriteProtected(uint8_t driveNum = 0); void SetWriteProtect(bool, uint8_t driveNum = 0); int DriveLightStatus(uint8_t driveNum = 0); + void SaveState(FILE *); + void LoadState(FILE *); + + private: + uint32_t ReadLong(FILE *); + void WriteLong(FILE *, uint32_t); // I/O functions ($C0Ex accesses) + public: void ControlStepper(uint8_t addr); void ControlMotor(uint8_t addr); void DriveEnable(uint8_t addr);