It is now possible to re-attach or re-load the current paper tape; re-attaching means repositioning it at the beginning, and re-loading means loading it into RAM again. Note that whenever you reload a tape, it's HIGHLY recommended that you reset the machine first, too.

This commit is contained in:
Jeff Parsons 2016-10-23 13:44:31 -07:00 committed by Jeff Parsons
commit de916981f3
8 changed files with 339 additions and 283 deletions

View file

@ -1168,9 +1168,11 @@ CPUPDP11.prototype.stepCPU = function(nMinCycles)
*
* @this {CPUPDP11}
* @param {boolean} [fComplete]
* @return {boolean} true if the CPU was stopped, false if it was already stopped
*/
CPUPDP11.prototype.stopCPU = function(fComplete)
{
var fStopped = false;
if (this.flags.running) {
this.endBurst();
this.addCycles(this.nRunCycles);
@ -1181,8 +1183,10 @@ CPUPDP11.prototype.stopCPU = function(fComplete)
if (this.cmp) {
this.cmp.stop(usr.getTime(), this.getCycles());
}
fStopped = true;
}
this.flags.complete = fComplete;
return fStopped;
};
/**

View file

@ -246,7 +246,7 @@ CPUStatePDP11.prototype.resetRegs = function()
this.mmuMask = 0x3ffff;
this.mmuMemorySize = BusPDP11.IOPAGE_18BIT;
this.opFlags |= PDP11.OPFLAG.INTQ;
this.resetTriggers();
if (this.bus) this.setMemoryAccess();
};
@ -383,10 +383,15 @@ CPUStatePDP11.prototype.setReset = function(addr, fReset)
this.setPC(addr);
if (!fReset && this.dbg) {
/*
* TODO: Review the decision to always stop the CPU if the Debugger is loaded.
* TODO: Review the decision to always stop the CPU if the Debugger is loaded. Note that
* when stopCPU() stops a running CPU, the Debugger gets notified, so again, no need to notify it here.
*
* TODO: There are more serious problems to deal with if another component is slamming a new PC down
* the CPU's throat (presumably while also dropping some new code into RAM) while the CPU was still running;
* we should probably force a complete reset if the CPU is running, but for now, it's up to the user
* to hit the reset button themselves.
*/
this.stopCPU();
this.dbg.updateStatus();
if (!this.stopCPU()) this.dbg.updateStatus();
}
};
@ -765,12 +770,25 @@ CPUStatePDP11.prototype.checkTriggers = function(priority)
};
/**
* checkInterrupts()
* resetTriggers(priority)
*
* @this {CPUStatePDP11}
*/
CPUStatePDP11.prototype.resetTriggers = function()
{
this.triggerNext = null;
};
/**
* checkInterrupts()
*
* @this {CPUStatePDP11}
* @return {boolean} true if an interrupt was dispatched, false if not
*/
CPUStatePDP11.prototype.checkInterrupts = function()
{
var fInterrupt = false;
if (this.opFlags & PDP11.OPFLAG.INTQ) {
this.opFlags &= ~PDP11.OPFLAG.INTQ;
@ -785,6 +803,7 @@ CPUStatePDP11.prototype.checkInterrupts = function()
if (this.dispatchInterrupt(vector, priority)) {
if (trigger) this.removeTrigger(trigger);
fInterrupt = true;
}
}
else if (this.opFlags & PDP11.OPFLAG.INTQ_SPL) {
@ -794,6 +813,7 @@ CPUStatePDP11.prototype.checkInterrupts = function()
*/
this.opFlags++;
}
return fInterrupt;
};
/**
@ -879,7 +899,7 @@ CPUStatePDP11.prototype.setPSW = function(newPSW)
this.regPSW = newPSW;
/*
* Trigger a call to checkInterrupts(), just in case.
* Trigger (no pun intended) a call to checkInterrupts(), just in case.
*
* TODO: I think this is overdone; if you set a breakpoint on checkInterrupts(), you'll see that a significant
* percentage of calls do nothing. For example, you'll usually see a spurious checkInterrupts() immediately after
@ -2050,7 +2070,11 @@ CPUStatePDP11.prototype.writeDstWord = function(opCode, data)
CPUStatePDP11.prototype.branch = function(opCode, condition)
{
if (condition) {
this.setPC(this.getPC() + ((opCode << 24) >> 23));
var off = ((opCode << 24) >> 23);
if (DEBUG && DEBUGGER && this.dbg && off == -2) {
this.dbg.stopInstruction("branch to self");
}
this.setPC(this.getPC() + off);
this.nStepCycles -= 2;
}
this.nStepCycles -= (2 + 1);
@ -2117,7 +2141,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
this.stopCPU();
break;
}
nDebugState = 1;
if (!nDebugState) nDebugState++;
nDebugCheck++;
}
@ -2150,7 +2174,14 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
* interrupting the natural flow of instructions whenever the Debugger is stepping through code.
*/
if ((this.opFlags & (PDP11.OPFLAG.INTQ_SPL | PDP11.OPFLAG.INTQ | PDP11.OPFLAG.WAIT)) /*&& nMinCycles*/) {
this.checkInterrupts();
if (this.checkInterrupts()) {
/*
* Since an interrupt was just dispatched, altering the normal flow of time and changing
* the future as we knew it, let's break out immediately if we're single-stepping, so that
* the Debugger gets to see the first instruction of the interrupt handler.
*/
if (nDebugState < 0) break;
}
}
}

View file

@ -1596,6 +1596,7 @@ if (DEBUGGER) {
this.updateStatus(true);
this.setFocus();
this.clearTempBreakpoint(this.cpu.getPC());
this.sMessagePrev = null;
}
};
@ -1679,18 +1680,20 @@ if (DEBUGGER) {
};
/**
* stopInstruction()
* stopInstruction(sMessage)
*
* TODO: Currently, the only way to prevent this call from stopping the CPU is when you're single-stepping.
*
* @this {DebuggerPDP11}
* @param {string} [sMessage]
* @return {boolean} true if stopping is enabled, false if not
*/
DebuggerPDP11.prototype.stopInstruction = function()
DebuggerPDP11.prototype.stopInstruction = function(sMessage)
{
var cpu = this.cpu;
if (cpu.isRunning()) {
cpu.setPC(this.cpu.getLastPC());
if (sMessage) this.println(sMessage);
this.stopCPU();
/*
* TODO: Review the appropriate-ness of throwing a bogus vector number in order to immediately stop

View file

@ -82,6 +82,13 @@ function PC11(parms)
this.sTapeSource = PC11.SOURCE.NONE;
this.nTapeTarget = PC11.TARGET.NONE;
this.sTapeName = this.sTapePath = "";
/*
* These next few variables simply keep track of the previous parameters to parseTape(),
* so that we can easily reparse the previous tape as needed.
*/
this.aBytes = this.addrLoad = this.addrExec = null;
this.nLastPercent = -1; // ensure the first displayProgress() displays something
/*
@ -447,7 +454,15 @@ PC11.prototype.loadTape = function(sTapeName, sTapePath, nTapeTarget, fAutoMount
}
}
}
if (nResult) this.status(this.nTapeTarget == PC11.TARGET.READER? "tape attached" : "tape loaded");
if (nResult) {
/*
* Now that we're calling parseTape() again (so that the current tape can either be restarted on
* the reader or reloaded into RAM), we can also rely on it to display an appropriate status message, too.
*
* this.status(this.nTapeTarget == PC11.TARGET.READER? "tape attached" : "tape loaded");
*/
this.parseTape(this.sTapeName, this.sTapePath, this.nTapeTarget, this.aBytes, this.addrLoad, this.addrExec);
}
return nResult;
};
@ -674,6 +689,9 @@ PC11.prototype.parseTape = function(sTapeName, sTapePath, nTapeTarget, aBytes, a
this.sTapeName = sTapeName;
this.sTapePath = sTapePath;
this.nTapeTarget = nTapeTarget;
this.aBytes = aBytes;
this.addrLoad = addrLoad;
this.addrExec = addrExec;
if (nTapeTarget == PC11.TARGET.MEMORY) {
/*