Started working on save/restore support for the PDP-11; still a lot of state left to capture, but the basics seem to be working

This commit is contained in:
Jeff Parsons 2016-12-31 16:07:33 -08:00 committed by Jeff Parsons
commit ee45dbd8cf
7 changed files with 679 additions and 612 deletions

View file

@ -316,15 +316,6 @@ class BusPDP11 extends Component {
/**
* powerUp(data, fRepower)
*
* We don't need a powerDown() handler, because for largely historical reasons, our state is saved by saveMemory(),
* which called by the CPU.
*
* However, we do need a powerUp() handler, because on resumable machines, the Computer's onReset() function calls
* everyone's powerUp() handler rather than their reset() handler.
*
* TODO: Perhaps Computer should be smarter: if there's no powerUp() handler, then fallback to the reset() handler.
* In that case, however, we'd either need to remove the powerUp() stub in Component, or detect the existence of the stub.
*
* @this {BusPDP11}
* @param {Object|null} data (always null because we supply no powerDown() handler)
* @param {boolean} [fRepower]
@ -332,10 +323,54 @@ class BusPDP11 extends Component {
*/
powerUp(data, fRepower)
{
if (!fRepower) this.reset();
if (!fRepower) {
if (!data) {
this.reset();
} else {
if (!this.restore(data)) return false;
}
}
return true;
}
/**
* powerDown(fSave, fShutdown)
*
* @this {BusPDP11}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
powerDown(fSave, fShutdown)
{
return fSave? this.save() : true;
}
/**
* save()
*
* @this {BusPDP11}
* @return {Object|null}
*/
save()
{
var state = new State(this);
state.set(0, this.saveMemory());
return state.data();
}
/**
* restore(data)
*
* @this {BusPDP11}
* @param {Object} data
* @return {boolean} true if restore successful, false if not
*/
restore(data)
{
return this.restoreMemory(data[0]);
}
/**
* addMemory(addr, size, type, controller)
*

View file

@ -613,11 +613,15 @@ class ComputerPDP11 extends Component {
{
if (!component.flags.powered) {
/*
* TODO: If all components called super.powerUp(), the powered flag would be set automatically.
*/
this.assert(component.powerUp);
component.flags.powered = true;
if (component.powerUp) {
var data = null;
var data = null;
try {
if (fRestore) {
data = stateComputer.get(component.id);
if (!data) {
@ -690,14 +694,17 @@ class ComputerPDP11 extends Component {
*/
fRestore = false;
}
}
if (!fRepower && component.comment) {
var asComments = component.comment.split("|");
for (var i = 0; i < asComments.length; i++) {
component.status(asComments[i]);
if (!fRepower && component.comment) {
var asComments = component.comment.split("|");
for (var i = 0; i < asComments.length; i++) {
component.status(asComments[i]);
}
}
}
catch (err) {
Component.error("Error restoring state for " + component.type + " (" + err.message + ")");
}
}
return fRestore;
}

View file

@ -244,7 +244,7 @@ class CPUPDP11 extends Component {
}
if (!fRepower) {
if (!data || !this.restore) {
if (!data) {
this.reset();
} else {
this.resetCycles();
@ -291,12 +291,6 @@ class CPUPDP11 extends Component {
*/
powerDown(fSave, fShutdown)
{
/*
* The Computer component (which is responsible for all powerDown and powerUp notifications)
* is now responsible for managing a component's fPowered flag, not us.
*
* this.flags.powered = false;
*/
return fSave? this.save() : true;
}

View file

@ -104,7 +104,7 @@ class CPUStatePDP11 extends CPUPDP11 {
}
/*
* WARNING: With ES6 classes, you cannot access "this" until all superclasses have been initialized as well.
* ES6 ALERT: Classes cannot access "this" until all superclasses have been initialized as well.
*/
super(parmsCPU, nCyclesDefault);
@ -211,6 +211,9 @@ class CPUStatePDP11 extends CPUPDP11 {
/**
* powerUp(data, fRepower)
*
* We hook the powerUp() notification only because it's our best opportunity to take care of any
* floating vector assignments.
*
* @this {CPUStatePDP11}
* @param {Object|null} data
* @param {boolean} [fRepower]
@ -267,8 +270,7 @@ class CPUStatePDP11 extends CPUPDP11 {
this.flagN = 0x8000; // PSW N bit
this.regPSW = 0x000f; // PSW other bits (TODO: What's the point of setting the flag bits here, too?)
this.regsGen = [ // General R0-R7
0, 0, 0, 0, 0, 0, 0, this.addrReset,
-1, -2, -3, -4, -5, -6, -7, -8
0, 0, 0, 0, 0, 0, 0, this.addrReset, -1, -2, -3, -4, -5, -6, -7, -8
];
this.regsAlt = [ // Alternate R0-R5
@ -612,19 +614,19 @@ class CPUStatePDP11 extends CPUPDP11 {
/**
* getChecksum()
*
* TODO: Implement
*
* @this {CPUStatePDP11}
* @return {number} a 32-bit summation of key elements of the current CPU state (used by the CPU checksum code)
*/
getChecksum()
{
return 0; // TODO: Implement
return 0;
}
/**
* save()
*
* This implements save support for the CPUStatePDP11 component.
*
* @this {CPUStatePDP11}
* @return {Object|null}
*/
@ -641,7 +643,6 @@ class CPUStatePDP11 extends CPUPDP11 {
this.regMBR,
this.regPIR,
this.regSLR,
this.getPSW(),
this.pswTrap,
this.pswMode,
this.opFlags,
@ -658,26 +659,60 @@ class CPUStatePDP11 extends CPUPDP11 {
this.addrLast,
this.opLast
]);
state.set(1, [this.nTotalCycles, this.getSpeed()]);
state.set(2, this.bus.saveMemory());
state.set(1, [this.getPSW()]);
state.set(2, [this.nTotalCycles, this.getSpeed()]);
return state.data();
}
/**
* restore(data)
*
* This implements restore support for the CPUStatePDP11 component.
*
* @this {CPUStatePDP11}
* @param {Object} data
* @return {boolean} true if restore successful, false if not
*/
restore(data)
{
var a = data[1];
this.nTotalCycles = a[1];
this.setSpeed(a[3]);
return this.bus.restoreMemory(data[2]);
var a;
/*
* ES6 ALERT: Gotta love these destructuring assignments, which make it easy to perform the inverse
* of what save() does when it collects a bunch of object properties into an array.
*/
[
this.regsGen,
this.regsAlt,
this.regsAltStack,
this.regsUniMap,
this.regsControl,
this.regErr,
this.regMBR,
this.regPIR,
this.regSLR,
this.pswTrap,
this.pswMode,
this.opFlags,
this.regMMR0,
this.regMMR1,
this.regMMR2,
this.regMMR3,
this.mmuLastMode,
this.mmuLastPage,
this.mmuPDR,
this.mmuPAR,
this.mmuEnable,
this.mmuMask,
this.addrLast,
this.opLast
] = data[0];
a = data[1];
this.setPSW(a[0]);
a = data[2];
this.nTotalCycles = a[0];
this.setSpeed(a[1]);
return true;
}
/**
@ -1215,13 +1250,6 @@ class CPUStatePDP11 extends CPUPDP11 {
*/
getPSW()
{
/*
* TODO: I'm not sure why this function can't simply be written as:
*
* return (this.regPSW & ~PDP11.PSW.FLAGS) | (this.getNF() | this.getZF() | this.getVF() | this.getCF());
*
* but for now, I'm keeping the same masking logic as the original pdp11.js.
*/
var mask = PDP11.PSW.CMODE | PDP11.PSW.PMODE | PDP11.PSW.REGSET | PDP11.PSW.PRI | PDP11.PSW.TF;
return this.regPSW = (this.regPSW & mask) | this.getNF() | this.getZF() | this.getVF() | this.getCF();
}