fix suspend/resume

This commit is contained in:
Jorj Bauer 2021-01-09 21:32:40 -05:00
parent c6f39f9b39
commit 4cded72e12
15 changed files with 312 additions and 430 deletions

View File

@ -12,10 +12,13 @@
#include "physicalspeaker.h" #include "physicalspeaker.h"
#include "cpu.h" #include "cpu.h"
#include "serialize.h"
#include "globals.h" #include "globals.h"
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include "teensy-clock.h" #include "teensy-clock.h"
#include "iocompat.h"
#else #else
#include "nix-clock.h" #include "nix-clock.h"
#endif #endif
@ -155,24 +158,23 @@ AppleMMU::~AppleMMU()
bool AppleMMU::Serialize(int8_t fd) bool AppleMMU::Serialize(int8_t fd)
{ {
uint8_t buf[13] = { MMUMAGIC, serializeMagic(MMUMAGIC);
(uint8_t)((switches >> 8) & 0xFF), serialize16(switches);
(uint8_t)((switches ) & 0xFF), serialize8(auxRamRead ? 1 : 0);
auxRamRead ? 1 : 0, serialize8(auxRamWrite ? 1 : 0);
auxRamWrite ? 1 : 0, serialize8(bank2 ? 1 : 0);
bank2 ? 1 : 0, serialize8(readbsr ? 1 : 0);
readbsr ? 1 : 0, serialize8(writebsr ? 1 : 0);
writebsr ? 1 : 0, serialize8(altzp ? 1 : 0);
altzp ? 1 : 0, serialize8(intcxrom ? 1 : 0);
intcxrom ? 1 : 0, serialize8(slot3rom ? 1 : 0);
slot3rom ? 1 : 0, serialize8(slotLatch);
slotLatch, serialize8(preWriteFlag ? 1 : 0);
preWriteFlag ? 1 : 0 };
if (g_filemanager->write(fd, buf, 13) != 13)
return false;
if (!g_ram.Serialize(fd)) if (!g_ram.Serialize(fd)) {
return false; printf("Failed to serialize RAM\n");
goto err;
}
// readPages & writePages don't need suspending, but we will need to // readPages & writePages don't need suspending, but we will need to
// recalculate after resume // recalculate after resume
@ -180,47 +182,42 @@ bool AppleMMU::Serialize(int8_t fd)
// Not suspending/resuming slots b/c they're a fixed configuration // Not suspending/resuming slots b/c they're a fixed configuration
// in this project. Should probably checksum them though. FIXME. // in this project. Should probably checksum them though. FIXME.
if (g_filemanager->write(fd, buf, 1) != 1) serializeMagic(MMUMAGIC);
return false;
return true; return true;
err:
return false;
} }
bool AppleMMU::Deserialize(int8_t fd) bool AppleMMU::Deserialize(int8_t fd)
{ {
uint8_t buf[13]; deserializeMagic(MMUMAGIC);
if (g_filemanager->read(fd, buf, 13) != 13) deserialize16(switches);
return false; serialize8(auxRamRead);
serialize8(auxRamWrite);
if (buf[0] != MMUMAGIC) serialize8(bank2);
return false; serialize8(readbsr);
serialize8(writebsr);
switches = (buf[1] << 8) | buf[2]; serialize8(altzp);
auxRamRead = buf[3]; serialize8(intcxrom);
auxRamWrite = buf[4]; serialize8(slot3rom);
bank2 = buf[5]; serialize8(slotLatch);
readbsr = buf[6]; serialize8(preWriteFlag);
writebsr = buf[7];
altzp = buf[8];
intcxrom = buf[9];
slot3rom = buf[10];
slotLatch = buf[11];
preWriteFlag = buf[12];
if (!g_ram.Deserialize(fd)) { if (!g_ram.Deserialize(fd)) {
return false; goto err;
} }
if (g_filemanager->read(fd, buf, 1) != 1) deserializeMagic(MMUMAGIC);
return false;
if (buf[0] != MMUMAGIC)
return false;
// Reset readPages[] and writePages[] and the display // Reset readPages[] and writePages[] and the display
resetDisplay(); resetDisplay();
return true; return true;
err:
return false;
} }
void AppleMMU::Reset() void AppleMMU::Reset()

View File

@ -6,10 +6,13 @@
#include "applekeyboard.h" #include "applekeyboard.h"
#include "physicalkeyboard.h" #include "physicalkeyboard.h"
#include "serialize.h"
#include "globals.h" #include "globals.h"
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include "teensy-println.h" #include "teensy-println.h"
#include "iocompat.h"
#endif #endif
#include <errno.h> #include <errno.h>
@ -40,83 +43,75 @@ AppleVM::~AppleVM()
delete parallel; 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 /* Open a new suspend file via the file manager; tell all our
objects to serialize in to it; close the file */ objects to serialize in to it; close the file */
int8_t fh = g_filemanager->openFile(fn); int8_t fd = g_filemanager->openFile(fn);
if (fh == -1) { if (fd == -1) {
// Unable to open; skip suspend // Unable to open; skip suspend
return; printf("failed to open suspend file\n");
return false;
} }
/* Header */ /* Header */
if (g_filemanager->write(fh, suspendHdr, strlen(suspendHdr)) != strlen(suspendHdr)) serializeString(suspendHdr);
return;
/* Tell all of the peripherals to suspend */ /* Tell all of the peripherals to suspend */
if (g_cpu->Serialize(fh) && if (g_cpu->Serialize(fd) &&
disk6->Serialize(fh) && disk6->Serialize(fd) &&
hd32->Serialize(fh) hd32->Serialize(fd)
) { ) {
#ifdef TEENSYDUINO
println("All serialized successfully");
#else
printf("All serialized successfully\n"); 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 /* Open the given suspend file via the file manager; tell all our
objects to deserialize from it; close the file */ objects to deserialize from it; close the file */
int8_t fh = g_filemanager->openFile(fn); int8_t fd = g_filemanager->openFile(fn);
if (fh == -1) { if (fd == -1) {
// Unable to open; skip resume // Unable to open; skip resume
#ifdef TEENSYDUINO printf("Unable to open resume file '%s'\n", fn);
print("Unable to open resume file "); goto err;
println(fn);
#else
printf("Unable to open resume file\n");
#endif
g_filemanager->closeFile(fh);
return;
} }
/* Header */ /* Header */
uint8_t c; deserializeString(debugBuf);
for (int i=0; i<strlen(suspendHdr); i++) { if (strcmp(debugBuf, suspendHdr)) {
if (g_filemanager->read(fh, &c, 1) != 1 || printf("Bad file header while resuming\n");
c != suspendHdr[i]) { goto err;
/* Failed to read correct header; abort */
g_filemanager->closeFile(fh);
return;
}
} }
/* Tell all of the peripherals to resume */ /* Tell all of the peripherals to resume */
if (g_cpu->Deserialize(fh) && if (g_cpu->Deserialize(fd) &&
disk6->Deserialize(fh) && disk6->Deserialize(fd) &&
hd32->Deserialize(fh) hd32->Deserialize(fd)
) { ) {
#ifdef TEENSYDUINO
println("Deserialization successful");
#else
printf("All deserialized successfully\n"); printf("All deserialized successfully\n");
#endif
} else { } else {
#ifndef TEENSYDUINO
printf("Deserialization failed\n"); printf("Deserialization failed\n");
#ifndef TEENSYDUINO
exit(1); exit(1);
#endif #endif
goto err;
} }
g_filemanager->closeFile(fh); g_filemanager->closeFile(fd);
return true;
err:
g_filemanager->closeFile(fd);
return false;
} }
// fixme: make member vars // fixme: make member vars

View File

@ -14,8 +14,8 @@ class AppleVM : public VM {
AppleVM(); AppleVM();
virtual ~AppleVM(); virtual ~AppleVM();
void Suspend(const char *fn); bool Suspend(const char *fn);
void Resume(const char *fn); bool Resume(const char *fn);
void cpuMaintenance(int64_t cycles); void cpuMaintenance(int64_t cycles);

View File

@ -3,6 +3,7 @@
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include <Arduino.h> #include <Arduino.h>
#include "teensy-println.h" #include "teensy-println.h"
#include "iocompat.h"
#else #else
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@ -16,6 +17,8 @@
#include "globals.h" #include "globals.h"
#include "appleui.h" #include "appleui.h"
#include "serialize.h"
#include "diskii-rom.h" #include "diskii-rom.h"
#define DISKIIMAGIC 0xAA #define DISKIIMAGIC 0xAA
@ -57,171 +60,101 @@ DiskII::~DiskII()
bool DiskII::Serialize(int8_t fd) bool DiskII::Serialize(int8_t fd)
{ {
uint8_t buf[27] = { DISKIIMAGIC, serializeMagic(DISKIIMAGIC);
readWriteLatch, serialize8(readWriteLatch);
sequencer, serialize8(sequencer);
dataRegister, serialize8(dataRegister);
writeMode, serialize8(writeMode);
writeProt, serialize8(writeProt);
selectedDisk }; serialize8(selectedDisk);
if (g_filemanager->write(fd, buf, 7) != 7) {
return false;
}
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
uint8_t ptr = 0; serialize8(curHalfTrack[i]);
buf[ptr++] = curHalfTrack[i]; serialize8(curWozTrack[i]);
buf[ptr++] = curWozTrack[i]; serialize8(curPhase[i]);
buf[ptr++] = curPhase[i]; serialize64(driveSpinupCycles[i]);
buf[ptr++] = ((driveSpinupCycles[i] >> 56) & 0xFF); serialize64(deliveredDiskBits[i]);
buf[ptr++] = ((driveSpinupCycles[i] >> 48) & 0xFF); serialize64(diskIsSpinningUntil[i]);
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;
}
if (disk[i]) { if (disk[i]) {
// Make sure we have flushed the disk images // Make sure we have flushed the disk images
disk[i]->flush(); disk[i]->flush();
flushAt[i] = 0; // and there's no need to re-flush them now flushAt[i] = 0; // and there's no need to re-flush them now
buf[0] = 1; serialize8(1);
if (g_filemanager->write(fd, buf, 1) != 1)
return false;
// FIXME: this ONLY works for builds using the filemanager to read // 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! // the disk image, so it's broken until we port Woz to do that!
const char *fn = disk[i]->diskName(); const char *fn = disk[i]->diskName();
if (g_filemanager->write(fd, fn, strlen(fn)+1) != strlen(fn)+1) // include null terminator serializeString(fn);
return false;
if (!disk[i]->Serialize(fd)) if (!disk[i]->Serialize(fd))
return false; goto err;
} else { } else {
buf[0] = 0; serialize8(0);
if (g_filemanager->write(fd, buf, 0) != 1)
return false;
} }
} }
buf[0] = DISKIIMAGIC; serializeMagic(DISKIIMAGIC);
if (g_filemanager->write(fd, buf, 1) != 1)
return false;
return true; return true;
err:
return false;
} }
bool DiskII::Deserialize(int8_t fd) bool DiskII::Deserialize(int8_t fd)
{ {
uint8_t buf[MAXPATH]; deserializeMagic(DISKIIMAGIC);
if (g_filemanager->read(fd, buf, 7) != 7)
return false;
if (buf[0] != DISKIIMAGIC)
return false;
readWriteLatch = buf[1]; deserialize8(readWriteLatch);
sequencer = buf[2]; deserialize8(sequencer);
dataRegister = buf[3]; deserialize8(dataRegister);
writeMode = buf[4]; deserialize8(writeMode);
writeProt = buf[5]; deserialize8(writeProt);
selectedDisk = buf[6]; deserialize8(selectedDisk);
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
uint8_t ptr = 0; deserialize8(curHalfTrack[i]);
if (g_filemanager->read(fd, buf, 27) != 27) deserialize8(curWozTrack[i]);
return false; deserialize8(curPhase[i]);
curHalfTrack[i] = buf[ptr++]; deserialize64(driveSpinupCycles[i]);
curWozTrack[i] = buf[ptr++]; deserialize64(deliveredDiskBits[i]);
curPhase[i] = buf[ptr++]; deserialize64(diskIsSpinningUntil[i]);
driveSpinupCycles[i] = buf[ptr++]; uint8_t hasDisk;
driveSpinupCycles[i] <<= 8; driveSpinupCycles[i] |= buf[ptr++]; deserialize8(hasDisk);
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++]; if (disk[i]) delete disk[i];
deliveredDiskBits[i] <<= 8; deliveredDiskBits[i] |= buf[ptr++]; if (hasDisk) {
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++];
if (disk[i])
delete disk[i];
if (g_filemanager->read(fd, buf, 1) != 1)
return false;
if (buf[0]) {
disk[i] = new WozSerializer(); disk[i] = new WozSerializer();
ptr = 0;
// FIXME: MAXPATH check! // FIXME: MAXPATH check!
while (1) { char fn[MAXPATH];
if (g_filemanager->read(fd, &buf[ptr++], 1) != 1) deserializeString(fn);
return false; if (fn[0]) {
if (buf[ptr-1] == 0) printf("Restoring disk image named '%s'\n", fn);
break; disk[i]->readFile((char *)fn, false, T_AUTO); // FIXME error checking
}
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
} else { } else {
// ERROR: there's a disk but we don't have the path to its image? // 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)) if (!disk[i]->Deserialize(fd)) {
return false; printf("Failed to deserialize disk %d\n", i);
goto err;
}
} else { } else {
disk[i] = NULL; disk[i] = NULL;
} }
} }
if (g_filemanager->read(fd, buf, 1) != 1) deserializeMagic(DISKIIMAGIC);
return false;
if (buf[0] != DISKIIMAGIC)
return false;
return true; return true;
err:
return false;
} }
void DiskII::Reset() void DiskII::Reset()

View File

@ -12,6 +12,7 @@
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include <Arduino.h> #include <Arduino.h>
#include "teensy-println.h" #include "teensy-println.h"
#include "iocompat.h"
#else #else
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@ -23,6 +24,8 @@
#include "applemmu.h" // for FLOATING #include "applemmu.h" // for FLOATING
#include "serialize.h"
#include "globals.h" #include "globals.h"
#include "hd32-rom.h" #include "hd32-rom.h"
@ -66,92 +69,58 @@ HD32::~HD32()
bool HD32::Serialize(int8_t fd) bool HD32::Serialize(int8_t fd)
{ {
uint8_t buf[19] = { HD32MAGIC, serializeMagic(HD32MAGIC);
driveSelected, serialize8(driveSelected);
unitSelected, serialize8(unitSelected);
command, serialize8(command);
enabled, serialize8(enabled);
errorState[0], serialize8(errorState[0]);
errorState[1], serialize8(errorState[1]);
(uint8_t)((memBlock[0] >> 8) & 0xFF), serialize16(memBlock[0]);
(uint8_t)((memBlock[0] ) & 0xFF), serialize16(memBlock[1]);
(uint8_t)((memBlock[1] >> 8) & 0xFF), serialize32(cursor[0]);
(uint8_t)((memBlock[1] ) & 0xFF), serialize32(cursor[1]);
(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;
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
const char *fn = diskName(i); const char *fn = diskName(i);
if (g_filemanager->write(fd, fn, strlen(fn)+1) != strlen(fn)+1) { serializeString(fn);
return false;
}
} }
serializeMagic(HD32MAGIC);
return true;
buf[0] = HD32MAGIC; err:
return (g_filemanager->write(fd, buf, 1) == 1); return false;
} }
bool HD32::Deserialize(int8_t fd) bool HD32::Deserialize(int8_t fd)
{ {
uint8_t buf[255]; deserializeMagic(HD32MAGIC);
if (g_filemanager->read(fd, buf, 19) != 19) {
return false;
}
if (buf[0] != HD32MAGIC)
return false;
driveSelected = buf[1]; deserialize8(driveSelected);
unitSelected = buf[2]; deserialize8(unitSelected);
command = buf[3]; deserialize8(command);
enabled = buf[4]; deserialize8(enabled);
errorState[0] = buf[5]; deserialize8(errorState[0]);
errorState[1] = buf[6]; deserialize8(errorState[1]);
memBlock[0] = buf[7]; deserialize16(memBlock[0]);
memBlock[0] <<= 8; memBlock[0] |= buf[8]; deserialize16(memBlock[1]);
memBlock[1] = buf[9]; deserialize32(cursor[0]);
memBlock[1] <<= 8; memBlock[1] |= buf[10]; deserialize32(cursor[1]);
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];
cachedBlockNum = -1; // just invalidate the cache; it will reload... cachedBlockNum = -1; // just invalidate the cache; it will reload...
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
uint32_t ptr = 0; char buf[MAXPATH];
// FIXME: MAXPATH check! deserializeString(buf);
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 // FIXME: this tromps on error and some other vars ... that we just restored
insertDisk(i, (char *)buf); insertDisk(i, (char *)buf);
} }
}
if (g_filemanager->read(fd, buf, 1) != 1) deserializeMagic(HD32MAGIC);
return false;
if (buf[0] != HD32MAGIC)
return false;
return true; return true;
err:
return false;
} }
void HD32::Reset() void HD32::Reset()

View File

@ -1,6 +1,12 @@
#include "woz-serializer.h" #include "woz-serializer.h"
#include "globals.h" #include "globals.h"
#include "serialize.h"
#ifdef TEENSYDUINO
#include "iocompat.h"
#endif
#define WOZMAGIC 0xD5 #define WOZMAGIC 0xD5
WozSerializer::WozSerializer() : Woz(0,0) 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 // If we're being asked to serialize, make sure we've flushed any data first
flush(); flush();
uint8_t buf[17] = { WOZMAGIC, serializeMagic(WOZMAGIC);
(trackPointer >> 24) & 0xFF, serialize32(trackPointer);
(trackPointer >> 16) & 0xFF, serialize32(trackBitCounter);
(trackPointer >> 8) & 0xFF, serialize32(lastReadPointer);
(trackPointer ) & 0xFF, serialize8(trackByte);
(trackBitCounter >> 24) & 0xFF, serialize8(trackBitIdx);
(trackBitCounter >> 16) & 0xFF, serialize8(trackLoopCounter);
(trackBitCounter >> 8) & 0xFF, serializeMagic(WOZMAGIC);
(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;
return true; return true;
err:
return false;
} }
bool WozSerializer::Deserialize(int8_t fd) bool WozSerializer::Deserialize(int8_t fd)
{ {
// Before deserializing, the caller has to re-load the right disk image! // Before deserializing, the caller has to re-load the right disk image!
uint8_t buf[17]; deserializeMagic(WOZMAGIC);
if (g_filemanager->read(fd, buf, 17) != 17) deserialize32(trackPointer);
return false; deserialize32(trackBitCounter);
deserialize32(lastReadPointer);
if (buf[0] != WOZMAGIC) deserialize8(trackByte);
return false; deserialize8(trackBitIdx);
deserialize8(trackLoopCounter);
trackPointer = buf[1]; deserializeMagic(WOZMAGIC);
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;
return true; return true;
err:
return false;
} }

85
cpu.cpp
View File

@ -7,10 +7,13 @@
#include <unistd.h> #include <unistd.h>
#include "mmu.h" #include "mmu.h"
#include "serialize.h"
#include "globals.h" #include "globals.h"
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include "teensy-println.h" #include "teensy-println.h"
#include "iocompat.h"
#endif #endif
// define DEBUGSTEPS to show disassembly of each instruction as it's processed // define DEBUGSTEPS to show disassembly of each instruction as it's processed
@ -320,74 +323,54 @@ Cpu::~Cpu()
mmu = NULL; mmu = NULL;
} }
bool Cpu::Serialize(int8_t fh) bool Cpu::Serialize(int8_t fd)
{ {
uint8_t buf[13] = { CPUMAGIC, serializeMagic(CPUMAGIC);
(uint8_t)((pc >> 8) & 0xFF), serialize16(pc);
(uint8_t)((pc ) & 0xFF), serialize8(sp);
sp, serialize8(a);
a, serialize8(x);
x, serialize8(y);
y, serialize8(flags);
flags, serialize32(cycles);
(uint8_t)((cycles >> 24) & 0xFF), serialize8(irqPending ? 1 : 0);
(uint8_t)((cycles >> 16) & 0xFF),
(uint8_t)((cycles >> 8) & 0xFF),
(uint8_t)((cycles ) & 0xFF),
irqPending ? (uint8_t)1 : (uint8_t)0 };
if (g_filemanager->write(fh, buf, 13) != 13) if (!mmu->Serialize(fd)) {
return false;
if (!mmu->Serialize(fh)) {
#ifndef TEENSYDUINO
printf("MMU serialization failed\n"); printf("MMU serialization failed\n");
#else goto err;
println("MMU serialization failed");
#endif
return false;
} }
serializeMagic(CPUMAGIC);
if (g_filemanager->write(fh, buf, 1) != 1)
return false;
return true; return true;
err:
return false;
} }
bool Cpu::Deserialize(int8_t fh) bool Cpu::Deserialize(int8_t fd)
{ {
uint8_t buf[13]; deserializeMagic(CPUMAGIC);
if (g_filemanager->read(fh, buf, 13) != 13) deserialize16(pc);
return false; deserialize8(sp);
if (buf[0] != CPUMAGIC) deserialize8(a);
return false; deserialize8(x);
pc = (buf[1] << 8) | buf[2]; deserialize8(y);
sp = buf[3]; deserialize8(flags);
a = buf[4]; deserialize32(cycles);
x = buf[5]; deserialize8(irqPending);
y = buf[6];
flags = buf[7];
cycles = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; if (!mmu->Deserialize(fd)) {
irqPending = buf[12];
if (!mmu->Deserialize(fh)) {
#ifndef TEENSYDUINO
printf("MMU deserialization failed\n"); printf("MMU deserialization failed\n");
#endif
return false; return false;
} }
if (g_filemanager->read(fh, buf, 1) != 1) deserializeMagic(CPUMAGIC);
return false;
if (buf[0] != CPUMAGIC)
return false;
#ifndef TEENSYDUINO
printf("CPU deserialization complete\n"); printf("CPU deserialization complete\n");
#endif
return true; return true;
err:
return false;
} }
void Cpu::Reset() void Cpu::Reset()

View File

@ -19,3 +19,7 @@ bool g_invertPaddleX = false;
bool g_invertPaddleY = false; bool g_invertPaddleY = false;
char debugBuf[255]; char debugBuf[255];
#ifdef TEENSYDUINO
char fsbuf[200];
#endif

View File

@ -56,4 +56,8 @@ extern bool g_invertPaddleY;
extern char debugBuf[255]; extern char debugBuf[255];
#ifdef TEENSYDUINO
extern char fsbuf[200];
#endif
#endif #endif

View File

@ -194,33 +194,43 @@ void NixFileManager::seekToEnd(int8_t fd)
int NixFileManager::write(int8_t fd, const void *buf, int nbyte) 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; return -1;
}
if (cachedNames[fd][0] == 0) if (cachedNames[fd][0] == 0) {
printf("invalid fd (not opened)\n");
return -1; return -1;
}
uint32_t pos = fileSeekPositions[fd]; uint32_t pos = fileSeekPositions[fd];
// open, seek, write, close. // open, seek, write, close.
bool ret = false; ssize_t rv = 0;
int ffd = ::open(cachedNames[fd], O_WRONLY|O_CREAT, 0644); int ffd = ::open(cachedNames[fd], O_WRONLY|O_CREAT, 0644);
if (ffd != -1) { if (ffd == -1) {
if (::lseek(ffd, pos, SEEK_SET) == -1) { printf("Failed to open '%s' for writing: %d\n",
cachedNames[fd], errno);
close(ffd); close(ffd);
return -1; return -1;
} }
ssize_t rv = ::write(ffd, buf, nbyte);
if (rv != nbyte) { if (::lseek(ffd, pos, SEEK_SET) == -1) {
printf("error writing: %d; wanted to write %d got %d\n", errno, nbyte, ret); printf("failed to open and seek\n");
}
close(ffd); close(ffd);
} else { return -1;
printf("Failed to open '%s' for writing: %d\n",
cachedNames[fd], errno);
} }
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; fileSeekPositions[fd]+=nbyte;
return ret; return (int)rv;
}; };
int NixFileManager::read(int8_t fd, void *buf, int nbyte) int NixFileManager::read(int8_t fd, void *buf, int nbyte)

View File

@ -16,8 +16,4 @@
#define read(filedes,buf,nbyte) g_filemanager->read(filedes,buf,nbyte) #define read(filedes,buf,nbyte) g_filemanager->read(filedes,buf,nbyte)
#define lseek(filedes,offset,whence) g_filemanager->lseek(filedes,offset,whence) #define lseek(filedes,offset,whence) g_filemanager->lseek(filedes,offset,whence)
static char fsbuf[200]; #include "iocompat.h"
#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();}

12
teensy/iocompat.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __IOCOMPAT_H
#define __IOCOMPAT_H
#include "globals.h"
#include <Arduino.h>
#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

View File

@ -9,7 +9,7 @@ static SdFat sd;
static FsFile cacheFile; static FsFile cacheFile;
static FsFile outerDir; static FsFile outerDir;
#include "iocompat.h"
TeensyFileManager::TeensyFileManager() TeensyFileManager::TeensyFileManager()
{ {
@ -179,14 +179,15 @@ bool TeensyFileManager::_prepCache(int8_t fd)
} }
// Open the new one // Open the new one
cacheFile.open(cachedNames[fd], O_RDWR); cacheFile.open(cachedNames[fd], O_CREAT|O_RDWR);
if (!cacheFile) { if (!cacheFile) {
printf("failed to open cacheFile\n");
return false; return false;
} }
cacheFd = fd; // cache is live cacheFd = fd; // cache is live
} }
return true; // FIXME error handling return true;
} }
void TeensyFileManager::getRootPath(char *toWhere, int8_t maxLen) 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. // open, seek, write, close.
if (fd < 0 || fd >= numCached) { if (fd < 0 || fd >= numCached) {
printf("no fd\n");
return -1; return -1;
} }
if (cachedNames[fd][0] == 0) { if (cachedNames[fd][0] == 0) {
printf("no name\n");
return -1; return -1;
} }
@ -237,15 +240,16 @@ int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte)
uint32_t pos = fileSeekPositions[fd]; uint32_t pos = fileSeekPositions[fd];
if (!cacheFile.seek(pos)) { if (!cacheFile.seek(pos)) {
printf("can't seek to %d\n", pos);
return -1; return -1;
} }
if (cacheFile.write((const uint8_t *)buf, (size_t)nbyte) != (size_t)nbyte) { if (cacheFile.write((const uint8_t *)buf, (size_t)nbyte) != (size_t)nbyte) {
printf("can't write\n");
return -1; return -1;
} }
fileSeekPositions[fd] += nbyte; fileSeekPositions[fd] += nbyte;
cacheFile.close();
return nbyte; return nbyte;
}; };
@ -266,6 +270,7 @@ int TeensyFileManager::read(int8_t fd, void *buf, int nbyte)
if (!cacheFile.seek(pos)) { if (!cacheFile.seek(pos)) {
return -1; return -1;
} }
fileSeekPositions[fd] += nbyte; fileSeekPositions[fd] += nbyte;
if (cacheFile.read(buf, nbyte) != nbyte) { if (cacheFile.read(buf, nbyte) != nbyte) {

4
vm.h
View File

@ -16,8 +16,8 @@ class VM {
VM() { mmu=NULL; vmdisplay = NULL; hasIRQ = false;} VM() { mmu=NULL; vmdisplay = NULL; hasIRQ = false;}
virtual ~VM() { if (mmu) delete mmu; if (vmdisplay) delete vmdisplay; } virtual ~VM() { if (mmu) delete mmu; if (vmdisplay) delete vmdisplay; }
virtual void Suspend(const char *fn) = 0; virtual bool Suspend(const char *fn) = 0;
virtual void Resume(const char *fn) = 0; virtual bool Resume(const char *fn) = 0;
virtual void SetMMU(MMU *mmu) { this->mmu = mmu; } virtual void SetMMU(MMU *mmu) { this->mmu = mmu; }
virtual MMU *getMMU() { return mmu; } virtual MMU *getMMU() { return mmu; }

View File

@ -5,11 +5,14 @@
#include "vmram.h" #include "vmram.h"
#include <string.h> #include <string.h>
#include "serialize.h"
#include "globals.h" #include "globals.h"
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include "iocompat.h"
EXTMEM uint8_t preallocatedRam[591*256]; EXTMEM uint8_t preallocatedRam[591*256];
#else #else
#include <stdio.h>
uint8_t preallocatedRam[591*256]; uint8_t preallocatedRam[591*256];
#endif #endif
@ -47,46 +50,35 @@ void VMRam::writeByte(uint32_t addr, uint8_t value)
bool VMRam::Serialize(int8_t fd) bool VMRam::Serialize(int8_t fd)
{ {
uint32_t size = sizeof(preallocatedRam); uint32_t size = sizeof(preallocatedRam);
uint8_t buf[5] = { RAMMAGIC, serializeMagic(RAMMAGIC);
(uint8_t)((size >> 24) & 0xFF), serialize32(size);
(uint8_t)((size >> 16) & 0xFF),
(uint8_t)((size >> 8) & 0xFF),
(uint8_t)((size ) & 0xFF) };
if (g_filemanager->write(fd, buf, 5) != 5)
return false;
if (g_filemanager->write(fd, preallocatedRam, sizeof(preallocatedRam)) != sizeof(preallocatedRam)) if (g_filemanager->write(fd, preallocatedRam, sizeof(preallocatedRam)) != sizeof(preallocatedRam))
return false; goto err;
if (g_filemanager->write(fd, buf, 1) != 1) serializeMagic(RAMMAGIC);
return false;
return true; return true;
err:
return false;
} }
bool VMRam::Deserialize(int8_t fd) bool VMRam::Deserialize(int8_t fd)
{ {
uint8_t buf[5]; deserializeMagic(RAMMAGIC);
if (g_filemanager->read(fd, buf, 5) != 5) uint32_t size;
return false; deserialize32(size);
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;
if (g_filemanager->read(fd, preallocatedRam, size) != size) if (g_filemanager->read(fd, preallocatedRam, size) != size)
return false; goto err;
if (g_filemanager->read(fd, buf, 1) != 1) deserializeMagic(RAMMAGIC);
return false;
if (buf[0] != RAMMAGIC)
return false;
return true; return true;
err:
return false;
} }
bool VMRam::Test() bool VMRam::Test()