Fixed read/write breakpoints for instructions that snapshot the cycle count, and improved the disassembly of PC-relative operands

This commit is contained in:
Jeff Parsons 2016-10-21 13:45:01 -07:00 committed by Jeff Parsons
commit 22e24697fe
5 changed files with 286 additions and 263 deletions

View file

@ -530,7 +530,7 @@ CPUPDP11.prototype.addCycles = function(nCycles, fEndStep)
{
this.nTotalCycles += nCycles;
if (fEndStep) {
this.nBurstCycles = this.nStepCycles = 0;
this.nBurstCycles = this.nStepCycles = this.nSnapCycles = 0;
}
};
@ -643,7 +643,7 @@ CPUPDP11.prototype.resetCycles = function()
{
this.mhz = 0;
this.nYieldsSinceStatusUpdate = 0;
this.nTotalCycles = this.nRunCycles = this.nBurstCycles = this.nStepCycles = 0;
this.nTotalCycles = this.nRunCycles = this.nBurstCycles = this.nStepCycles = this.nSnapCycles = 0;
this.resetChecksum();
this.setSpeed(1);
};
@ -1019,7 +1019,13 @@ CPUPDP11.prototype.updateTimers = function(nCycles)
CPUPDP11.prototype.endBurst = function(fReset)
{
var nCycles = this.nBurstCycles -= this.nStepCycles;
this.nStepCycles = 0;
/*
* In addition to zeroing nStepCycles, it's important that we also zero nSnapCycles, because if a CPU
* burst is being ended after nStepCycles has been "snapped" (because a certain opcode has an unusual timing
* calculation that must be based on a "snapped" cycle count rather the opcode's starting cycle count), we
* could inadvertently undo the endBurst() if the original "snapped" value was used to update nStepCycles.
*/
this.nStepCycles = this.nSnapCycles = 0;
if (fReset) this.nBurstCycles = 0;
return nCycles;
};
@ -1190,7 +1196,6 @@ CPUPDP11.prototype.yieldCPU = function()
{
this.endBurst(); // this will break us out of stepCPU()
this.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
// if (DEBUG) this.nSnapCycles = this.nBurstCycles;
/*
* The Debugger calls yieldCPU() after every message() to ensure browser responsiveness, but it looks
* odd for those messages to show CPU state changes if the Control Panel, Video display, etc, does not,

View file

@ -1191,9 +1191,9 @@ PDP11.opJMP = function(opCode)
* Since JMP and JSR opcodes have their own unique timings for the various dst modes, we must snapshot
* nStepCycles before decoding the mode, and then use that to update nStepCycles.
*/
var nSnapCycles = this.nStepCycles;
this.nSnapCycles = this.nStepCycles;
this.setPC(this.readDstAddr(opCode));
this.nStepCycles = nSnapCycles - PDP11.JMP_CYCLES[this.dstMode];
this.nStepCycles = this.nSnapCycles - PDP11.JMP_CYCLES[this.dstMode];
};
PDP11.JSR_CYCLES = [
@ -1212,7 +1212,7 @@ PDP11.opJSR = function(opCode)
* Since JMP and JSR opcodes have their own unique timings for the various dst modes, we must snapshot
* nStepCycles before decoding the mode, and then use that to update nStepCycles.
*/
var nSnapCycles = this.nStepCycles;
this.nSnapCycles = this.nStepCycles;
/*
* TODO: Determine whether or not the SRCMODE operand (regsGen[reg]) should be snapped BEFORE or AFTER we
* decode the DSTMODE operand. Doing it AFTER seems a bit risky.
@ -1222,7 +1222,7 @@ PDP11.opJSR = function(opCode)
this.pushWord(this.regsGen[reg]);
this.regsGen[reg] = this.getPC();
this.setPC(addr);
this.nStepCycles = nSnapCycles - PDP11.JSR_CYCLES[this.dstMode];
this.nStepCycles = this.nSnapCycles - PDP11.JSR_CYCLES[this.dstMode];
};
/**
@ -1287,9 +1287,9 @@ PDP11.opMOV = function(opCode)
* nStepCycles after decoding the src mode, and then use that to update nStepCycles.
*/
var data = this.readSrcWord(opCode);
var nSnapCycles = this.nStepCycles;
this.nSnapCycles = this.nStepCycles;
this.updateNZVFlags(this.writeDstWord(opCode, data));
this.nStepCycles = nSnapCycles - PDP11.MOV_CYCLES[(this.srcMode? 8 : 0) + this.dstMode] + (this.dstReg == 7 && !this.dstMode? 2 : 0);
this.nStepCycles = this.nSnapCycles - PDP11.MOV_CYCLES[(this.srcMode? 8 : 0) + this.dstMode] + (this.dstReg == 7 && !this.dstMode? 2 : 0);
};
/**
@ -1322,10 +1322,10 @@ PDP11.opMTPD = function(opCode)
* nStepCycles before decoding the mode, and then use that to update nStepCycles.
*/
var data = this.popWord();
var nSnapCycles = this.nStepCycles;
this.nSnapCycles = this.nStepCycles;
this.writeWordToPrevSpace(opCode, PDP11.ACCESS.DSPACE, data);
this.updateNZVFlags(data);
this.nStepCycles = nSnapCycles - PDP11.MTP_CYCLES[this.dstMode];
this.nStepCycles = this.nSnapCycles - PDP11.MTP_CYCLES[this.dstMode];
};
/**
@ -1341,10 +1341,10 @@ PDP11.opMTPI = function(opCode)
* nStepCycles before decoding the mode, and then use that to update nStepCycles.
*/
var data = this.popWord();
var nSnapCycles = this.nStepCycles;
this.nSnapCycles = this.nStepCycles;
this.writeWordToPrevSpace(opCode, PDP11.ACCESS.ISPACE, data);
this.updateNZVFlags(data);
this.nStepCycles = nSnapCycles - PDP11.MTP_CYCLES[this.dstMode];
this.nStepCycles = this.nSnapCycles - PDP11.MTP_CYCLES[this.dstMode];
};
/**
@ -1497,7 +1497,7 @@ PDP11.opRTS = function(opCode)
var src = this.popWord();
var reg = opCode & PDP11.OPREG.MASK;
/*
* When the popular "RTS PC" form is used, we might as well eliminate the useless setting of PC to itself.
* When the popular "RTS PC" form is used, we might as well eliminate the useless setting of PC to
*/
if (reg == PDP11.REG.PC) {
this.setPC(src);

View file

@ -2091,7 +2091,8 @@ if (DEBUGGER) {
/*
* If getOperand() returns an Array rather than a string, then the first element is the original
* operand, and the second element contains an alternate representation of the operand (eg, target address).
* operand, and the second element contains an alternate representation of the operand (eg, target address,
* memory contents, etc).
*/
if (typeof sOperand != "string") {
sTarget = sOperand[1];
@ -2134,6 +2135,10 @@ if (DEBUGGER) {
* If getOperand() returns an Array rather than a string, then the first element is the original
* operand, and the second element is a comment containing an alternate representation of the operand.
*
* TODO: For PC-relative addresses, we now return the effective address directly, rather than as the
* second element of an Array; however, I still envision using Array return values to include current
* memory operands, so support for such values is being left in place.
*
* @this {DebuggerPDP11}
* @param {number} opCode
* @param {number} opType
@ -2229,9 +2234,20 @@ if (DEBUGGER) {
sOperand = this.toStrBase(wIndex, 0, true) + '(' + this.getRegName(reg) + ')';
if (reg == 7) {
/*
* When using R7 (aka PC), INDEX is known as RELATIVE
* When using R7 (aka PC), INDEX is known as RELATIVE. However, instead of displaying
* such an instruction like this:
*
* 016156: 010167 001300 MOV R1,1300(PC) ; @017462
*
* with the effective address display to the far right, let's display it like this instead:
*
* 016156: 010167 001300 MOV R1,017462
*
* because you can still clearly see PC-relative offset (eg, 001300) as part of the disassembly.
*
* sOperand = [sOperand, this.toStrBase((wIndex + dbgAddr.addr) & 0xffff)];
*/
sOperand = [sOperand, this.toStrBase((wIndex + dbgAddr.addr) & 0xffff)];
sOperand = this.toStrBase((wIndex + dbgAddr.addr) & 0xffff);
}
break;
case PDP11.OPMODE.INDEXD: // 0x7: INDEX DEFERRED
@ -2239,9 +2255,12 @@ if (DEBUGGER) {
sOperand = '@' + this.toStrBase(wIndex) + '(' + this.getRegName(reg) + ')';
if (reg == 7) {
/*
* When using R7 (aka PC), INDEX DEFERRED is known as RELATIVE DEFERRED
* When using R7 (aka PC), INDEX DEFERRED is known as RELATIVE DEFERRED. And for the same
* reasons articulated above, we now display the effective address inline.
*
* sOperand = [sOperand, this.toStrBase((wIndex + dbgAddr.addr) & 0xffff)];
*/
sOperand = [sOperand, this.toStrBase((wIndex + dbgAddr.addr) & 0xffff)];
sOperand = '@' + this.toStrBase((wIndex + dbgAddr.addr) & 0xffff);
}
break;
default: