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 "cpu.h"
#include "serialize.h"
#include "globals.h"
#ifdef TEENSYDUINO
#include "teensy-clock.h"
#include "iocompat.h"
#else
#include "nix-clock.h"
#endif
@ -155,24 +158,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
@ -180,47 +182,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;
}
void AppleMMU::Reset()

View File

@ -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 <errno.h>
@ -40,83 +43,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; i<strlen(suspendHdr); i++) {
if (g_filemanager->read(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

View File

@ -14,8 +14,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);

View File

@ -3,6 +3,7 @@
#ifdef TEENSYDUINO
#include <Arduino.h>
#include "teensy-println.h"
#include "iocompat.h"
#else
#include <unistd.h>
#include <fcntl.h>
@ -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()

View File

@ -12,6 +12,7 @@
#ifdef TEENSYDUINO
#include <Arduino.h>
#include "teensy-println.h"
#include "iocompat.h"
#else
#include <unistd.h>
#include <fcntl.h>
@ -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()

View File

@ -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;
}

87
cpu.cpp
View File

@ -7,10 +7,13 @@
#include <unistd.h>
#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()

View File

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

View File

@ -56,4 +56,8 @@ extern bool g_invertPaddleY;
extern char debugBuf[255];
#ifdef TEENSYDUINO
extern char fsbuf[200];
#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)
{
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)

View File

@ -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"

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 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) {

4
vm.h
View File

@ -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; }

View File

@ -5,11 +5,14 @@
#include "vmram.h"
#include <string.h>
#include "serialize.h"
#include "globals.h"
#ifdef TEENSYDUINO
#include "iocompat.h"
EXTMEM uint8_t preallocatedRam[591*256];
#else
#include <stdio.h>
uint8_t preallocatedRam[591*256];
#endif
@ -47,46 +50,35 @@ void VMRam::writeByte(uint32_t addr, uint8_t value)
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()