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:
parent
1cbcb5b0e2
commit
ee45dbd8cf
7 changed files with 679 additions and 612 deletions
|
|
@ -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)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue