Assorted PDP-11 debugger changes
This commit is contained in:
parent
6984a97512
commit
1df54a338f
21 changed files with 499 additions and 276 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(' '));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = "";
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue