mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-11-25 19:31:36 +00:00
fix suspend/resume
This commit is contained in:
parent
c6f39f9b39
commit
4cded72e12
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
177
apple/diskii.cpp
177
apple/diskii.cpp
@ -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()
|
||||
|
109
apple/hd32.cpp
109
apple/hd32.cpp
@ -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()
|
||||
|
@ -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
87
cpu.cpp
@ -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()
|
||||
|
@ -19,3 +19,7 @@ bool g_invertPaddleX = false;
|
||||
bool g_invertPaddleY = false;
|
||||
|
||||
char debugBuf[255];
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
char fsbuf[200];
|
||||
#endif
|
||||
|
@ -56,4 +56,8 @@ extern bool g_invertPaddleY;
|
||||
|
||||
extern char debugBuf[255];
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
extern char fsbuf[200];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -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)
|
||||
|
@ -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
12
teensy/iocompat.h
Normal 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
|
@ -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
4
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; }
|
||||
|
46
vmram.cpp
46
vmram.cpp
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user