Assorted PDP-11 debugger changes

This commit is contained in:
Jeff Parsons 2016-09-19 16:30:08 -07:00 committed by Jeff Parsons
commit 1df54a338f
21 changed files with 499 additions and 276 deletions

View file

@ -2777,7 +2777,7 @@ if (DEBUGGER) {
sType += " -> " + Memory.TYPE.NAMES[block.type];
}
if (block) {
this.println(str.toHex(block.id) + " %" + str.toHex(i << this.cpu.nBlockShift) + " %%" + str.toHex(block.addr) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + sType);
this.println(str.toHex(block.id, 8) + " %" + str.toHex(i << this.cpu.nBlockShift, 8) + " %%" + str.toHex(block.addr, 8) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + sType);
}
if (typePrev != Memory.TYPE.NONE && typePrev != Memory.TYPE.UNPAGED) typePrev = -1;
cPrev = 0;

View file

@ -1951,7 +1951,7 @@ X86CPU.prototype.restore = function(data)
* getSeg(sName)
*
* @param {string} sName
* @return {Array}
* @return {X86Seg|Array}
*/
X86CPU.prototype.getSeg = function(sName)
{
@ -2374,8 +2374,11 @@ X86CPU.prototype.setSP = function(off)
* specifies any flags not contained in the new type parameter, then those flags must be immediately
* calculated and written to the appropriate bit(s) in regPS.
*
* The fSubtract parameter is used to indicate a "subtracted" result (eg, CMP, DEC, SUB, SBB); the
* default assumes an "added" result (eg, ADD, ADC, INC).
* The default assumes an "addition" (eg, ADD, ADC, INC), where value = dst + src. The fSubtract
* parameter is used to indicate a "subtraction" (eg, CMP, DEC, SUB, SBB), where value = dst - src;
* We can transform a subtraction into an addition, since it's also true that dst = value + src,
* by swapping swap dst and value -- which is exactly what we do below. This allows all downstream
* flag calculations (eg, getCF(), getOF()) to remain the same.
*
* @this {X86CPU}
* @param {number} dst
@ -2469,12 +2472,11 @@ X86CPU.prototype.getCarry = function()
/**
* getCF()
*
* Notes regarding carry following an I386 addition:
* The following table summarizes bit 31 of the dst (D) and src (S) operands, bit 31 of the
* addition (A), along with the expected carry bit (C):
*
* The following table summarizes bit 31 of dst, src, and result, along with the expected carry:
*
* dst src res carry
* --- --- --- -----
* D S A C
* - - - -
* 0 0 0 0 no
* 0 0 1 0 no (there must have been a carry out of bit 30, but it was "absorbed")
* 0 1 0 1 yes (there must have been a carry out of bit 30, but it was NOT "absorbed")
@ -2488,6 +2490,10 @@ X86CPU.prototype.getCarry = function()
*
* (resultDst ^ ((resultDst ^ resultSrc) & (resultSrc ^ resultArith))) & resultType
*
* NOTE: The above table assumes that the resultDst (D) and resultSrc (S) operands were ADDED to
* produce resultArith (A); if they were SUBTRACTED instead (D - S), then D and A must be swapped
* after the subtraction, so that the above truth table still applies; see setArithResult().
*
* @this {X86CPU}
* @return {number} 0 or X86.PS.CF
*/
@ -2522,8 +2528,8 @@ X86CPU.prototype.getCF = function()
* lowest nibble of v. This number is like a miniature 16-bit parity-table indexed by the low four bits in v.
* The result has the parity of v in bit 1, which is masked and returned.
*
* The x86 parity flag (PF) is based exclusively on the low 8 bits of resultParitySign, and PF must be SET if that byte
* has EVEN parity; the above calculation yields ODD parity, so we use the conditional operator to invert the result.
* The x86 parity flag (PF) is based exclusively on the low 8 bits of resultParitySign, so our calculation is bit
* simpler. Note that PF must be SET if that byte has EVEN parity, and CLEAR if it has ODD parity.
*
* @this {X86CPU}
* @return {number} 0 or X86.PS.PF
@ -2625,8 +2631,8 @@ X86CPU.prototype.getSF = function()
*
* ((resultDst ^ resultArith) & (resultSrc ^ resultArith)) & resultType
*
* which you can verify from the following table of sign bits (where x1 is resultDst ^ resultArith,
* and x2 is resultSrc ^ resultArith):
* which you can verify from the following table of sign bits, where x1 is resultDst ^ resultArith,
* and x2 is resultSrc ^ resultArith:
*
* D S A x1 x2 OF
* - - - -- -- --
@ -2639,6 +2645,10 @@ X86CPU.prototype.getSF = function()
* 1 1 0 1 1 1 (adding two negative values yielded a positive value)
* 1 1 1 0 0 0
*
* NOTE: The above table assumes that the resultDst (D) and resultSrc (S) operands were ADDED to
* produce resultArith (A); if they were SUBTRACTED instead (D - S), then D and A must be swapped
* after the subtraction, so that the above truth table still applies; see setArithResult().
*
* @this {X86CPU}
* @return {number} 0 or X86.PS.OF
*/

View file

@ -38,7 +38,7 @@ try {
var asLines = sText.split('\n');
for (var iLine = 0; iLine < asLines.length; iLine++) {
var sLine = asLines[iLine];
var match, re = /([^0-9a-z_-])(0[0-7]+)([^0-9a-z_])/gi;
var match, re = /(^|[^0-9a-z_-]*)(0[0-7]+)([^0-9a-z_,]*|$)/gi;
var iComment = sLine.indexOf("//");
while (match = re.exec(sLine)) {
if (iComment >= 0 && match.index > iComment) break;
@ -47,7 +47,7 @@ try {
console.log("found negative octal value (" + match[2] + "), skipping");
continue;
}
var sReplace = match[1] + "0x" + n.toString(16).toUpperCase() + match[3] + " /*" + match[2] + "*/";
var sReplace = match[1] + "0x" + ("0000" + n.toString(16).toUpperCase()).substr(-4) + match[3] + " /*" + match[2] + "*/";
sLine = sLine.substr(0, match.index) + sReplace + sLine.substr(match.index + match[0].length);
re.lastIndex = match.index + sReplace.length;
asLines[iLine] = sLine;

View file

@ -333,7 +333,7 @@ BusPDP11.prototype.addMemory = function(addr, size, type)
}
if (sizeLeft <= 0) {
this.status(Math.floor(size / 1024) + "Kb " + MemoryPDP11.TYPE.NAMES[type] + " at " + str.toHexWord(addr));
this.status(Math.floor(size / 1024) + "Kb " + MemoryPDP11.TYPE.NAMES[type] + " at " + str.toHexLong(addr));
return true;
}

View file

@ -50,6 +50,7 @@ if (NODE) {
* The CPUStatePDP11 class uses the following (parmsCPU) properties:
*
* model: a number (eg, 1170) that should match one of the PDP11.MODEL_* values
* resetAddr: reset address (default is 0)
*
* This extends the CPU class and passes any remaining parmsCPU properties to the CPU class
* constructor, along with a default speed (cycles per second) based on the specified (or default)
@ -62,6 +63,7 @@ if (NODE) {
function CPUStatePDP11(parmsCPU)
{
this.model = +parmsCPU['model'] || PDP11.MODEL_1170;
this.resetAddr = parmsCPU['resetAddr'] || 0;
var nCyclesDefault = 0;
switch(this.model) {
@ -125,11 +127,45 @@ CPUStatePDP11.prototype.reset = function()
*/
CPUStatePDP11.prototype.initRegs = function()
{
// BEGIN pdp11.js:40:82
/*
* Instead of having separate flagC, flagZ and flagN variables, I would prefer to have only one: flagsCZN.
* The C and N flags don't conflict; they are always bits 16 and 15 of the last 16-bit arithmetic result (or
* bits 8 and 7 of the last 8-bit arithmetic result). The Z flag is a "bit" more complicated, because it's a
* representation of bits 15-0 (or 7-0), which overlap the N flag bit. That overlap is fine after any given
* arithmetic operation, because of the four possible N and Z combinations:
*
* N Z
* - -
* 0 0 Positive non-zero number
* 0 1 Zero
* 1 0 Negative non-zero number
* 1 1 INVALID
*
* the fourth combination is an impossibility (the world of floating point numbers, with their NaNs, positive
* and negative zeros, infinities, etc, is another story, which doesn't concern us here).
*
* The problem is that some intervening NON-arithmetic instruction (eg, SEN or SEZ) could be executed that sets
* either N or Z independently, resulting in BOTH flags being set.
*
* One way to support that combination would be to define Z as the result of all non-sign bits. However,
* that means that, after any arithmetic operation, we would have to propagate the sign bit of the result to
* one or more other bits in flagsCZN; eg:
*
* flagsCZN = result | ((result & 0x8000) >> 1)
* or:
* flagsCZN = result | ((result & 0xffff)? 1 : 0)
*
* It's worth noting that all that extra work is actually required for only ONE 16-bit value: -32768 or 0x8000
* (and ONE 8-bit value: -128 or 0x80), because all other negative numbers already have 1 or more lower bits set.
*
* A simpler approach would be to leave flagN independent, and only combine flagC and flagZ (into flagCZ).
* Alternatively, we could combine flagC and flagN and leave flagZ independent; the choice is arbitrary. -JP
*/
this.flagC = 0x10000; // PSW C bit
this.flagN = 0x8000; // PSW N bit
this.flagV = 0x8000; // PSW V bit
this.flagZ = 0xffff; // ~ PSW Z bit
this.flagN = 0x8000; // PSW N bit
this.PSW = 0xf; // PSW other bits
this.regsGen = [ // General R0 - R7
0, 0, 0, 0, 0, 0, 0, 0
@ -137,7 +173,7 @@ CPUStatePDP11.prototype.initRegs = function()
this.regsAlt = [ // Alternate R0 - R5
0, 0, 0, 0, 0, 0
];
this.regsAltStack = [ // Alternate R6 (kernel, super, illegal, user)
this.regsAltStack = [ // Alternate R6 stack pointers (kernel, super, illegal, user)
0, 0, 0, 0
];
this.memory = []; // Main memory (words)
@ -177,7 +213,6 @@ CPUStatePDP11.prototype.initRegs = function()
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
this.debugPC = -1;
// END pdp11.js:40:82
};
/**
@ -187,6 +222,7 @@ CPUStatePDP11.prototype.initRegs = function()
*/
CPUStatePDP11.prototype.resetRegs = function()
{
this.setPC(this.resetAddr);
this.stackLimit = 0xff;
this.CPU_Error = 0;
this.interruptQueue = [];
@ -660,14 +696,15 @@ CPUStatePDP11.prototype.panic = function(reason)
/**
* trap(vector, reason)
*
* trap() handles all the trap/abort functions. It reads the trap vector from kernel
* trap() handles all the trap/abort functions. It reads the trap vector from kernel
* D space, changes mode to reflect the new PSW and PC, and then pushes the old PSW and
* PC onto the new mode stack. trap() returns a -1 which is passed up through function
* PC onto the new mode stack. trap() returns a -1 which is passed up through function
* calls to indicate that a trap/abort has occurred (suspend instruction processing).
*
* @this {CPUStatePDP11}
* @param {number} vector
* @param {number} reason
* @return {number}
*/
CPUStatePDP11.prototype.trap = function(vector, reason)
{
@ -1320,7 +1357,6 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
nDebugState = 1;
}
// BEGIN pdp11.js:886:1936
var instruction,
src,
dst,
@ -2401,7 +2437,6 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
}
this.trapMask = 0;
}
// END pdp11.js:886:1936
} while (this.nStepCycles > 0);
}

View file

@ -260,28 +260,19 @@ if (DEBUGGER) {
DebuggerPDP11.REG_PC = 7; // aka R7
DebuggerPDP11.REG_PSW = 20;
DebuggerPDP11.MODE_REG = 0x0; // REGISTER (register is operand)
DebuggerPDP11.MODE_REGD = 0x1; // REGISTER DEFERRED (register is address of operand)
DebuggerPDP11.MODE_POSTINC = 0x2; // POST-INCREMENT (register is address of operand, register incremented)
DebuggerPDP11.MODE_POSTINCD = 0x3; // POST-INCREMENT DEFERRED (register is address of address of operand, register incremented)
DebuggerPDP11.MODE_PREDEC = 0x4; // PRE-DECREMENT (register decremented, register is address of operand)
DebuggerPDP11.MODE_PREDECD = 0x5; // PRE-DECREMENT DEFERRED (register decremented, register is address of address of operand)
DebuggerPDP11.MODE_INDEX = 0x6; // INDEX (register + next word is address of operand)
DebuggerPDP11.MODE_INDEXD = 0x7; // INDEX DEFERRED (register + next word is address of address of operand)
/*
* Operand descriptor masks; anything that's not covered by TYPE_SRC or TYPE_DST must be a TYPE_OTHER value.
*/
DebuggerPDP11.TYPE_DSTREG = 0x0007;
DebuggerPDP11.TYPE_DSTMOD = 0x0038;
DebuggerPDP11.TYPE_DST = (DebuggerPDP11.TYPE_DSTMOD | DebuggerPDP11.TYPE_DSTREG);
DebuggerPDP11.TYPE_DSTMODE = 0x0038;
DebuggerPDP11.TYPE_DST = (DebuggerPDP11.TYPE_DSTMODE | DebuggerPDP11.TYPE_DSTREG);
DebuggerPDP11.TYPE_SRCREG = 0x01C0;
DebuggerPDP11.TYPE_SRCMOD = 0x0E00;
DebuggerPDP11.TYPE_SRC = (DebuggerPDP11.TYPE_SRCMOD | DebuggerPDP11.TYPE_SRCREG);
DebuggerPDP11.TYPE_SRCMODE = 0x0E00;
DebuggerPDP11.TYPE_SRC = (DebuggerPDP11.TYPE_SRCMODE | DebuggerPDP11.TYPE_SRCREG);
DebuggerPDP11.TYPE_BRANCH = 0x1000;
DebuggerPDP11.TYPE_DSTOFF = 0x2000;
DebuggerPDP11.TYPE_DSTNUM3 = 0x3000; // DST 3-bit number (ie, just the DSTREG field)
DebuggerPDP11.TYPE_DSTNUM6 = 0x6000; // DST 6-bit number (ie, both the DSTREG and DSTMOD fields)
DebuggerPDP11.TYPE_DSTNUM6 = 0x6000; // DST 6-bit number (ie, both the DSTREG and DSTMODE fields)
DebuggerPDP11.TYPE_OTHER = 0xF000;
/*
@ -791,27 +782,27 @@ if (DEBUGGER) {
};
/**
* toHexOffset(off)
* toStrOffset(off)
*
* @this {DebuggerPDP11}
* @param {number|null|undefined} [off]
* @return {string} the hex representation of off
*/
DebuggerPDP11.prototype.toHexOffset = function(off)
DebuggerPDP11.prototype.toStrOffset = function(off)
{
return str.toHex(off, 4);
return this.toStrBase(off);
};
/**
* toHexAddr(dbgAddr)
* toStrAddr(dbgAddr)
*
* @this {DebuggerPDP11}
* @param {DbgAddrPDP11} dbgAddr
* @return {string} the hex representation of the address
*/
DebuggerPDP11.prototype.toHexAddr = function(dbgAddr)
DebuggerPDP11.prototype.toStrAddr = function(dbgAddr)
{
return this.toHexOffset(dbgAddr.addr);
return this.toStrOffset(dbgAddr.addr);
};
/**
@ -871,7 +862,7 @@ if (DEBUGGER) {
typePrev = block.type;
var sType = MemoryPDP11.TYPE.NAMES[typePrev];
if (block) {
this.println(str.toHex(block.id) + " %" + str.toHex(i << this.bus.nBlockShift) + " %%" + str.toHex(block.addr) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + sType);
this.println(str.toHex(block.id, 8) + " %" + str.toHex(i << this.bus.nBlockShift, 8) + " %%" + str.toHex(block.addr, 8) + " " + str.toHexWord(block.used) + " " + str.toHexWord(block.size) + " " + sType);
}
if (typePrev != MemoryPDP11.TYPE.NONE) typePrev = -1;
cPrev = 0;
@ -1080,7 +1071,7 @@ if (DEBUGGER) {
DebuggerPDP11.prototype.message = function(sMessage, fAddress)
{
if (fAddress) {
sMessage += " at " + this.toHexAddr(this.newAddr(this.cpu.getPC()));
sMessage += " at " + this.toStrAddr(this.newAddr(this.cpu.getPC()));
}
if (this.bitsMessage & MessagesPDP11.BUFFER) {
@ -1657,7 +1648,7 @@ if (DEBUGGER) {
if (aBreak != this.aBreakExec) {
var addr = this.getAddr(dbgAddr);
if (addr === PDP11.ADDR_INVALID) {
this.println("invalid address: " + this.toHexAddr(dbgAddr));
this.println("invalid address: " + this.toStrAddr(dbgAddr));
fSuccess = false;
} else {
this.bus.addMemBreak(addr, aBreak == this.aBreakWrite);
@ -1751,7 +1742,7 @@ if (DEBUGGER) {
DebuggerPDP11.prototype.printBreakpoint = function(aBreak, i, sAction)
{
var dbgAddr = aBreak[i];
this.println(aBreak[0] + ' ' + this.toHexAddr(dbgAddr) + (sAction? (' ' + sAction) : (dbgAddr.sCmd? (' "' + dbgAddr.sCmd + '"') : '')));
this.println(aBreak[0] + ' ' + this.toStrAddr(dbgAddr) + (sAction? (' ' + sAction) : (dbgAddr.sCmd? (' "' + dbgAddr.sCmd + '"') : '')));
};
/**
@ -1929,16 +1920,16 @@ if (DEBUGGER) {
sOperands += (sOperand || "???");
}
var sBytes = "";
var sLine = this.toHexAddr(dbgAddrOp) + ": ";
var sOpcodes = "";
var sLine = this.toStrAddr(dbgAddrOp) + ": ";
if (dbgAddrOp.addr !== PDP11.ADDR_INVALID && dbgAddr.addr !== PDP11.ADDR_INVALID) {
do {
sBytes += str.toHex(this.getByte(dbgAddrOp, 1), 2);
sOpcodes += this.toStrBase(this.getWord(dbgAddrOp, true));
if (dbgAddrOp.addr == null) break;
} while (dbgAddrOp.addr != dbgAddr.addr);
}
sLine += str.pad(sBytes, 10);
sLine += str.pad(sOpcodes, 10);
sLine += str.pad(sOpName, 7);
if (sOperands) sLine += ' ' + sOperands;
@ -2008,14 +1999,14 @@ if (DEBUGGER) {
* Note that opcodes that specify only REG bits in the type mask (ie, no MOD bits)
* will automatically default to MODE_REG below.
*/
switch(mode & DebuggerPDP11.TYPE_DSTMOD) {
case DebuggerPDP11.MODE_REG: // 0x0: REGISTER
switch(mode & DebuggerPDP11.TYPE_DSTMODE) {
case PDP11.OPMODE.REG: // 0x0: REGISTER
sOperand = "R" + reg;
break;
case DebuggerPDP11.MODE_REGD: // 0x1: REGISTER DEFERRED
case PDP11.OPMODE.REGD: // 0x1: REGISTER DEFERRED
sOperand = "@R" + reg;
break;
case DebuggerPDP11.MODE_POSTINC: // 0x2: POST-INCREMENT
case PDP11.OPMODE.POSTINC: // 0x2: POST-INCREMENT
if (reg < 7) {
sOperand = "(R" + reg + ")+";
} else {
@ -2026,7 +2017,7 @@ if (DEBUGGER) {
sOperand = "#" + str.toHexWord(wIndex);
}
break;
case DebuggerPDP11.MODE_POSTINCD: // 0x3: POST-INCREMENT DEFERRED
case PDP11.OPMODE.POSTINCD: // 0x3: POST-INCREMENT DEFERRED
if (reg < 7) {
sOperand = "@(R" + reg + ")+";
} else {
@ -2037,20 +2028,20 @@ if (DEBUGGER) {
sOperand = "@#" + str.toHexWord(wIndex);
}
break;
case DebuggerPDP11.MODE_PREDEC: // 0x4: PRE-DECREMENT
case PDP11.OPMODE.PREDEC: // 0x4: PRE-DECREMENT
sOperand = "-(R" + reg + ")";
break;
case DebuggerPDP11.MODE_PREDECD: // 0x5: PRE-DECREMENT DEFERRED
case PDP11.OPMODE.PREDECD: // 0x5: PRE-DECREMENT DEFERRED
sOperand = "@-R(" + reg + ")";
break;
case DebuggerPDP11.MODE_INDEX: // 0x6: INDEX
case PDP11.OPMODE.INDEX: // 0x6: INDEX
wIndex = this.getWord(dbgAddr, true);
/*
* When using R7 (aka PC), INDEX is known as RELATIVE
*/
sOperand = str.toHexWord(wIndex) + (reg < 7? "(R" + reg + ")" : "(PC)");
break;
case DebuggerPDP11.MODE_INDEXD: // 0x7: INDEX DEFERRED
case PDP11.OPMODE.INDEXD: // 0x7: INDEX DEFERRED
wIndex = this.getWord(dbgAddr, true);
/*
* When using R7 (aka PC), INDEX DEFERRED is known as RELATIVE DEFERRED
@ -2125,16 +2116,16 @@ if (DEBUGGER) {
if (iReg < 8) {
sReg = (iReg < 6? ("R" + iReg) : (iReg == 6? "SP" : "PC"));
sReg += '=' + str.toHex(cpu.regsGen[iReg], 4);
sReg += '=' + this.toStrBase(cpu.regsGen[iReg]);
}
else if (iReg < 13) {
sReg = "A" + (iReg - 8) + '=' + str.toHex(cpu.regsAlt[iReg - 8], 4);
sReg = "A" + (iReg - 8) + '=' + this.toStrBase(cpu.regsAlt[iReg - 8]);
}
else if (iReg >= 16 && iReg < 20) {
sReg = "S" + (iReg - 16) + '=' + str.toHex(cpu.regsAltStack[iReg - 16], 4);
sReg = "S" + (iReg - 16) + '=' + this.toStrBase(cpu.regsAltStack[iReg - 16]);
}
else if (iReg == DebuggerPDP11.REG_PSW) {
sReg = "PS=" + str.toHex(cpu.getPSW(), 4);
sReg = "PS=" + this.toStrBase(cpu.getPSW());
}
if (sReg) sReg += ' ';
return sReg;
@ -2299,7 +2290,7 @@ if (DEBUGGER) {
if (offSymbol === undefined) continue;
var sSymbolOrig = symbolTable.aSymbols[sSymbol]['l'];
if (sSymbolOrig) sSymbol = sSymbolOrig;
this.println(this.toHexOffset(offSymbol) + ' ' + sSymbol);
this.println(this.toStrOffset(offSymbol) + ' ' + sSymbol);
}
}
};
@ -2461,7 +2452,7 @@ if (DEBUGGER) {
this.dbgAddrAssemble = dbgAddr;
if (asArgs[2] === undefined) {
this.println("begin assemble at " + this.toHexAddr(dbgAddr));
this.println("begin assemble at " + this.toStrAddr(dbgAddr));
this.fAssemble = true;
this.cpu.updateCPU();
return;
@ -2561,7 +2552,7 @@ if (DEBUGGER) {
return;
if (this.findBreakpoint(this.aBreakWrite, dbgAddr, true))
return;
this.println("breakpoint missing: " + this.toHexAddr(dbgAddr));
this.println("breakpoint missing: " + this.toStrAddr(dbgAddr));
return;
}
@ -2706,7 +2697,7 @@ if (DEBUGGER) {
while (cLines-- && cb > 0) {
var data = 0, iByte = 0, i;
var sData = "", sChars = "";
sAddr = this.toHexAddr(dbgAddr);
sAddr = this.toStrAddr(dbgAddr);
for (i = 16; i > 0 && cb > 0; i--) {
var b = this.getByte(dbgAddr, 1);
data |= (b << (iByte++ << 3));
@ -2767,7 +2758,7 @@ if (DEBUGGER) {
this.println("warning: " + str.toHex(vNew) + " exceeds " + size + "-byte value");
}
var vOld = fnGet.call(this, dbgAddr);
this.println("changing " + this.toHexAddr(dbgAddr) + " from " + str.toHex(vOld, cch, true) + " to " + str.toHex(vNew, cch, true));
this.println("changing " + this.toStrAddr(dbgAddr) + " from " + str.toHex(vOld, cch, true) + " to " + str.toHex(vNew, cch, true));
fnSet.call(this, dbgAddr, vNew, size);
}
};
@ -2896,7 +2887,7 @@ if (DEBUGGER) {
sDelta = "";
nDelta = dbgAddr.addr - aSymbol[1];
if (nDelta) sDelta = " + " + str.toHexWord(nDelta);
s = aSymbol[0] + " (" + this.toHexOffset(aSymbol[1]) + ')' + sDelta;
s = aSymbol[0] + " (" + this.toStrOffset(aSymbol[1]) + ')' + sDelta;
if (fPrint) this.println(s);
sSymbol = s;
}
@ -2904,7 +2895,7 @@ if (DEBUGGER) {
sDelta = "";
nDelta = aSymbol[5] - dbgAddr.addr;
if (nDelta) sDelta = " - " + str.toHexWord(nDelta);
s = aSymbol[4] + " (" + this.toHexOffset(aSymbol[5]) + ')' + sDelta;
s = aSymbol[4] + " (" + this.toStrOffset(aSymbol[5]) + ')' + sDelta;
if (fPrint) this.println(s);
if (!sSymbol) sSymbol = s;
}
@ -3015,6 +3006,18 @@ if (DEBUGGER) {
DebuggerPDP11.prototype.doOptions = function(asArgs)
{
switch (asArgs[1]) {
case "base":
if (asArgs[2]) {
var nBase = +asArgs[2];
if (nBase == 8 || nBase == 10 || nBase == 16) {
this.nBase = nBase;
} else {
this.println("invalid base: " + nBase);
break;
}
}
this.println("default base: " + this.nBase);
break;
case "cs":
var nCycles;
if (asArgs[3] !== undefined) nCycles = +asArgs[3]; // warning: decimal instead of hex conversion
@ -3049,6 +3052,7 @@ if (DEBUGGER) {
case "?":
this.println("debugger options:");
this.println("\tbase #\t\tset default base to #");
this.println("\tcs int #\tset checksum cycle interval to #");
this.println("\tcs start #\tset checksum cycle start count to #");
this.println("\tcs stop #\tset checksum cycle stop count to #");
@ -3139,7 +3143,7 @@ if (DEBUGGER) {
if (fInstruction) {
this.dbgAddrNextCode = this.newAddr(cpu.getPC());
this.doUnassemble(this.toHexAddr(this.dbgAddrNextCode));
this.doUnassemble(this.toStrAddr(this.dbgAddrNextCode));
}
};
@ -3300,7 +3304,7 @@ if (DEBUGGER) {
var nFrames = 10, cFrames = 0;
var dbgAddrCall = this.newAddr();
var dbgAddrStack = this.newAddr(this.cpu.getSP());
this.println("stack trace for " + this.toHexAddr(dbgAddrStack));
this.println("stack trace for " + this.toStrAddr(dbgAddrStack));
while (cFrames < nFrames) {
var sCall = null, sCallPrev = null, cTests = 256;
@ -3326,7 +3330,7 @@ if (DEBUGGER) {
var a = sCall.match(/[0-9A-F]+$/);
if (a) sSymbol = this.doList(a[0]);
}
sCall = str.pad(sCall, 50) + " ;" + (sSymbol || "stack=" + this.toHexAddr(dbgAddrStack)); // + " return=" + this.toHexAddr(dbgAddrCall));
sCall = str.pad(sCall, 50) + " ;" + (sSymbol || "stack=" + this.toStrAddr(dbgAddrStack)); // + " return=" + this.toStrAddr(dbgAddrCall));
this.println(sCall);
sCallPrev = sCall;
cFrames++;
@ -3489,7 +3493,7 @@ if (DEBUGGER) {
try {
if (!sCmd.length || sCmd == "end") {
if (this.fAssemble) {
this.println("ended assemble at " + this.toHexAddr(this.dbgAddrAssemble));
this.println("ended assemble at " + this.toStrAddr(this.dbgAddrAssemble));
this.dbgAddrNextCode = this.dbgAddrAssemble;
this.fAssemble = false;
}
@ -3514,7 +3518,7 @@ if (DEBUGGER) {
if (this.isReady() /* && !this.isBusy(true) */ && sCmd.length > 0) {
if (this.fAssemble) {
sCmd = "a " + this.toHexAddr(this.dbgAddrAssemble) + ' ' + sCmd;
sCmd = "a " + this.toStrAddr(this.dbgAddrAssemble) + ' ' + sCmd;
}
var asArgs = this.shiftArgs(sCmd.replace(/ +/g, ' ').split(' '));

View file

@ -123,7 +123,7 @@ var PDP11 = {
*/
ADDR_INVALID: -1,
/*
* Processor Modes
* Processor modes
*/
MODE: {
KERNEL: 0x0,
@ -163,6 +163,19 @@ var PDP11 = {
INTR: 0x00ff, // mask for 8 bits, representing interrupt levels 0-7
HALT: 0x0100 // halt requested; see opHLT()
},
/*
* Opcode modes
*/
OPMODE: {
REG: 0x0, // REGISTER (register is operand)
REGD: 0x1, // REGISTER DEFERRED (register is address of operand)
POSTINC: 0x2, // POST-INCREMENT (register is address of operand, register incremented)
POSTINCD: 0x3, // POST-INCREMENT DEFERRED (register is address of address of operand, register incremented)
PREDEC: 0x4, // PRE-DECREMENT (register decremented, register is address of operand)
PREDECD: 0x5, // PRE-DECREMENT DEFERRED (register decremented, register is address of address of operand)
INDEX: 0x6, // INDEX (register + next word is address of operand)
INDEXD: 0x7 // INDEX DEFERRED (register + next word is address of address of operand)
},
/*
* Opcode definitions
*/

View file

@ -204,28 +204,39 @@ ROMPDP11.prototype.doneLoad = function(sURL, sROMData, nErrorCode)
Component.addMachineResource(this.idMachine, sURL, sROMData);
var i;
if (sROMData.charAt(0) == "[" || sROMData.charAt(0) == "{") {
try {
/*
* The most likely source of any exception will be here: parsing the JSON-encoded ROM data.
* The most likely source of any exception will be here: parsing the JSON-encoded ROM.
*/
var a, ib;
var rom = eval("(" + sROMData + ")");
var ab = rom['bytes'];
var adw = rom['data'];
if (ab) {
this.abROM = ab;
if (a = rom['bytes']) {
this.abROM = a;
}
else if (adw) {
else if (a = rom['words']) {
/*
* Convert all the DWORDs into BYTEs, so that subsequent code only has to deal with abROM.
* Convert all WORDs into BYTEs, so that subsequent code only has to deal with abROM.
*/
this.abROM = new Array(adw.length * 4);
for (var idw = 0, ib = 0; idw < adw.length; idw++) {
this.abROM[ib++] = adw[idw] & 0xff;
this.abROM[ib++] = (adw[idw] >> 8) & 0xff;
this.abROM[ib++] = (adw[idw] >> 16) & 0xff;
this.abROM[ib++] = (adw[idw] >> 24) & 0xff;
this.abROM = new Array(a.length * 2);
for (i = 0, ib = 0; i < a.length; i++) {
this.abROM[ib++] = a[i] & 0xff;
this.abROM[ib++] = (a[i] >> 8) & 0xff;
this.assert(!(a[i] & ~0xffff));
}
}
else if (a = rom['data']) {
/*
* Convert all DWORDs into BYTEs, so that subsequent code only has to deal with abROM.
*/
this.abROM = new Array(a.length * 4);
for (i = 0, ib = 0; i < a.length; i++) {
this.abROM[ib++] = a[i] & 0xff;
this.abROM[ib++] = (a[i] >> 8) & 0xff;
this.abROM[ib++] = (a[i] >> 16) & 0xff;
this.abROM[ib++] = (a[i] >> 24) & 0xff;
}
}
else {
@ -255,7 +266,7 @@ ROMPDP11.prototype.doneLoad = function(sURL, sROMData, nErrorCode)
var sHexData = sROMData.replace(/\n/gm, " ").replace(/ +$/, "");
var asHexData = sHexData.split(" ");
this.abROM = new Array(asHexData.length);
for (var i = 0; i < asHexData.length; i++) {
for (i = 0; i < asHexData.length; i++) {
this.abROM[i] = str.parseInt(asHexData[i], 16);
}
}

View file

@ -74,6 +74,11 @@ function Debugger(parmsDbg)
Component.call(this, "Debugger", parmsDbg, Debugger);
/*
* Default base used to display all values; modified with the "s base" command.
*/
this.nBase = 16;
/*
* These keep track of instruction activity, but only when tracing or when Debugger checks
* have been enabled (eg, one or more breakpoints have been set).
@ -564,7 +569,7 @@ if (DEBUGGER) {
value = this.getRegValue(iReg);
} else {
value = this.getVariable(sValue);
if (value == null) value = str.parseInt(sValue, 16);
if (value == null) value = str.parseInt(sValue, this.nBase);
}
if (value == null && !fQuiet) this.println("invalid " + (sName? sName : "value") + ": " + sValue);
} else {
@ -587,7 +592,7 @@ if (DEBUGGER) {
var fDefined = false;
if (value !== undefined) {
fDefined = true;
sValue = str.toHex(value, 0, true) + " " + value + ". " + str.toOctal(value, 0, true) + " " + str.toBinBytes(value, 0, true);
sValue = str.toHex(value, 0, true) + " " + value + ". " + str.toOct(value, 0, true) + " " + str.toBinBytes(value, 0, true);
}
sVar = (sVar != null? (sVar + ": ") : "");
this.println(sVar + sValue);
@ -649,6 +654,29 @@ if (DEBUGGER) {
this.aVariables[sVar] = value;
};
/**
* toStrBase(n, cch)
*
* Use this instead of str.toHex() or str.toOct() to convert words to the default base.
*
* @this {Debugger}
* @param {number|null|undefined} n
* @param {number} [cch] is the desired number of hex digits (0 or undefined for default)
* @return {string}
*/
Debugger.prototype.toStrBase = function(n, cch)
{
switch(this.nBase) {
case 8:
return str.toOct(n, cch);
case 10:
return n.toString(); // TODO: Do we want to support any formatting based on cch?
case 16:
default:
return str.toHex(n, cch);
}
};
} // endif DEBUGGER
if (NODE) module.exports = Debugger;

View file

@ -201,7 +201,7 @@ str.toBinBytes = function(n, cb, fPrefix)
};
/**
* toOctal(n, cch, fPrefix)
* toOct(n, cch, fPrefix)
*
* Converts an integer to octal, with the specified number of digits (default of 6; max of 11)
*
@ -214,7 +214,7 @@ str.toBinBytes = function(n, cb, fPrefix)
* @param {boolean} [fPrefix]
* @return {string} the octal representation of n
*/
str.toOctal = function(n, cch, fPrefix)
str.toOct = function(n, cch, fPrefix)
{
var s = "";

View file

@ -580,6 +580,12 @@
<xsl:otherwise>null</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="resetAddr">
<xsl:choose>
<xsl:when test="@resetAddr"><xsl:value-of select="@resetAddr"/></xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="csStart">
<xsl:choose>
<xsl:when test="@csstart"><xsl:value-of select="@csstart"/></xsl:when>
@ -604,7 +610,7 @@
<xsl:call-template name="component">
<xsl:with-param name="machine" select="$machine"/>
<xsl:with-param name="class" select="'cpu'"/>
<xsl:with-param name="parms">,model:'<xsl:value-of select="$model"/>',stepping:'<xsl:value-of select="$stepping"/>',fpu:<xsl:value-of select="$fpu"/>,cycles:<xsl:value-of select="$cycles"/>,multiplier:<xsl:value-of select="$multiplier"/>,autoStart:<xsl:value-of select="$autoStart"/>,csStart:<xsl:value-of select="$csStart"/>,csInterval:<xsl:value-of select="$csInterval"/>,csStop:<xsl:value-of select="$csStop"/></xsl:with-param>
<xsl:with-param name="parms">,model:'<xsl:value-of select="$model"/>',stepping:'<xsl:value-of select="$stepping"/>',fpu:<xsl:value-of select="$fpu"/>,cycles:<xsl:value-of select="$cycles"/>,multiplier:<xsl:value-of select="$multiplier"/>,autoStart:<xsl:value-of select="$autoStart"/>,resetAddr:<xsl:value-of select="$resetAddr"/>,csStart:<xsl:value-of select="$csStart"/>,csInterval:<xsl:value-of select="$csInterval"/>,csStop:<xsl:value-of select="$csStop"/></xsl:with-param>
</xsl:call-template>
</xsl:template>