Minor Debugger improvements, notes, etc, while debugging the PDP-11 BASIC
This commit is contained in:
parent
8f4537c2bc
commit
aa2a25c5ec
7 changed files with 163 additions and 94 deletions
|
|
@ -827,7 +827,7 @@ PDP11.opBPL = function(opCode)
|
|||
*/
|
||||
PDP11.opBPT = function(opCode)
|
||||
{
|
||||
this.trap(PDP11.TRAP.BREAKPOINT, PDP11.REASON.BPT);
|
||||
this.trap(PDP11.TRAP.BPT, PDP11.REASON.BPT);
|
||||
this.nStepCycles -= (4 + 1);
|
||||
};
|
||||
|
||||
|
|
@ -1101,7 +1101,7 @@ PDP11.opDIV = function(opCode)
|
|||
*/
|
||||
PDP11.opEMT = function(opCode)
|
||||
{
|
||||
this.trap(PDP11.TRAP.EMULATOR, PDP11.REASON.EMT);
|
||||
this.trap(PDP11.TRAP.EMT, PDP11.REASON.EMT);
|
||||
this.nStepCycles -= (22 + 3);
|
||||
};
|
||||
|
||||
|
|
@ -1496,8 +1496,15 @@ PDP11.opRTS = function(opCode)
|
|||
}
|
||||
var src = this.popWord();
|
||||
var reg = opCode & PDP11.OPREG.MASK;
|
||||
this.setPC(this.regsGen[reg]);
|
||||
this.regsGen[reg] = src;
|
||||
/*
|
||||
* When the popular "RTS PC" form is used, we might as well eliminate the useless setting of PC to itself.
|
||||
*/
|
||||
if (reg == PDP11.REG.PC) {
|
||||
this.setPC(src);
|
||||
} else {
|
||||
this.setPC(this.regsGen[reg]);
|
||||
this.regsGen[reg] = src;
|
||||
}
|
||||
this.nStepCycles -= (7 + 2);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -547,31 +547,6 @@ CPUStatePDP11.prototype.setNF = function()
|
|||
this.flagN = 0x8000;
|
||||
};
|
||||
|
||||
/**
|
||||
* getPC()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getPC = function()
|
||||
{
|
||||
return this.regsGen[PDP11.REG.PC];
|
||||
};
|
||||
|
||||
/**
|
||||
* getLastPC()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getLastPC = function()
|
||||
{
|
||||
/*
|
||||
* As long as we're always snapping the PC before every opcode, we might as well use it.
|
||||
*/
|
||||
return this.regMMR2;
|
||||
};
|
||||
|
||||
/**
|
||||
* getOpcode()
|
||||
*
|
||||
|
|
@ -595,6 +570,8 @@ CPUStatePDP11.prototype.getOpcode = function()
|
|||
/**
|
||||
* advancePC(off)
|
||||
*
|
||||
* NOTE: This function is nothing more than a convenience, and we fully expect it to be inlined at runtime.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} off
|
||||
* @return {number} (original PC)
|
||||
|
|
@ -606,9 +583,40 @@ CPUStatePDP11.prototype.advancePC = function(off)
|
|||
return pc;
|
||||
};
|
||||
|
||||
/**
|
||||
* getPC()
|
||||
*
|
||||
* NOTE: This function is nothing more than a convenience, and we fully expect it to be inlined at runtime.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getPC = function()
|
||||
{
|
||||
return this.regsGen[PDP11.REG.PC];
|
||||
};
|
||||
|
||||
/**
|
||||
* getLastPC()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getLastPC = function()
|
||||
{
|
||||
/*
|
||||
* As long as we're always snapping the PC into regMMR2 before every opcode, we might as well use it.
|
||||
*/
|
||||
return this.regMMR2;
|
||||
};
|
||||
|
||||
/**
|
||||
* setPC()
|
||||
*
|
||||
* NOTE: Unlike other PCjs emulators, such as PCx86, where all PC updates MUST go through the setPC()
|
||||
* function, this function is nothing more than a convenience, because in the PDP-11, the PC can be loaded
|
||||
* like any other general register. We fully expect this function to be inlined at runtime.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} addr
|
||||
*/
|
||||
|
|
@ -620,6 +628,8 @@ CPUStatePDP11.prototype.setPC = function(addr)
|
|||
/**
|
||||
* getSP()
|
||||
*
|
||||
* NOTE: This function is nothing more than a convenience, and we fully expect it to be inlined at runtime.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
|
|
@ -631,6 +641,10 @@ CPUStatePDP11.prototype.getSP = function()
|
|||
/**
|
||||
* setSP()
|
||||
*
|
||||
* NOTE: Unlike other PCjs emulators, such as PCx86, where all SP updates MUST go through the setSP()
|
||||
* function, this function is nothing more than a convenience, because in the PDP-11, the PC can be loaded
|
||||
* like any other general register. We fully expect this function to be inlined at runtime.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} addr
|
||||
*/
|
||||
|
|
@ -1326,7 +1340,7 @@ CPUStatePDP11.prototype.mapVirtualToPhysical = function(virtualAddress, accessFl
|
|||
if (!(this.regMMR0 & 0xe000)) {
|
||||
this.regMMR0 |= errorMask | (this.mmuLastMode << 5) | (this.mmuLastPage << 1);
|
||||
}
|
||||
this.trap(PDP11.TRAP.MMU_FAULT, PDP11.REASON.MAPERROR);
|
||||
this.trap(PDP11.TRAP.MMU, PDP11.REASON.MAPERROR);
|
||||
}
|
||||
if (!(this.regMMR0 & 0xf000)) {
|
||||
//if (physicalAddress < 017772200 || physicalAddress > 017777677) {
|
||||
|
|
@ -2083,13 +2097,13 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
*/
|
||||
if (this.opFlags & PDP11.OPFLAG.TRAP_MASK) {
|
||||
if (this.opFlags & PDP11.OPFLAG.TRAP_MMU) {
|
||||
this.trap(PDP11.TRAP.MMU_FAULT, PDP11.REASON.TRAPMMU); // MMU trap has priority
|
||||
this.trap(PDP11.TRAP.MMU, PDP11.REASON.TRAPMMU); // MMU trap has priority
|
||||
} else {
|
||||
if (this.opFlags & PDP11.OPFLAG.TRAP_SP) {
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, PDP11.REASON.TRAPSP); // then SP trap
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, PDP11.REASON.TRAPSP); // then SP trap
|
||||
} else {
|
||||
if (this.opFlags & PDP11.OPFLAG.TRAP_TF) {
|
||||
this.trap(PDP11.TRAP.BREAKPOINT, PDP11.REASON.TRAPTF); // and finally a TF trap
|
||||
this.trap(PDP11.TRAP.BPT, PDP11.REASON.TRAPTF); // and finally a TF trap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ function DebuggerPDP11(parmsDbg)
|
|||
* The new "bn" command allows you to specify a number of instructions to execute and then stop;
|
||||
* "bn 0" disables any outstanding count.
|
||||
*/
|
||||
this.nBreakIns = 0;
|
||||
this.nBreakInstructions = 0;
|
||||
|
||||
/*
|
||||
* Execution history is allocated by historyInit() whenever checksEnabled() conditions change.
|
||||
|
|
@ -280,6 +280,7 @@ if (DEBUGGER) {
|
|||
DebuggerPDP11.OP_DSTOFF = 0x2000;
|
||||
DebuggerPDP11.OP_DSTNUM3 = 0x3000; // DST 3-bit number (ie, just the DSTREG field)
|
||||
DebuggerPDP11.OP_DSTNUM6 = 0x6000; // DST 6-bit number (ie, both the DSTREG and DSTMODE fields)
|
||||
DebuggerPDP11.OP_DSTNUM8 = 0x8000; // DST 8-bit number
|
||||
DebuggerPDP11.OP_OTHER = 0xF000;
|
||||
|
||||
/*
|
||||
|
|
@ -339,8 +340,8 @@ if (DEBUGGER) {
|
|||
0x8500: [DebuggerPDP11.OPS.BVS, DebuggerPDP11.OP_BRANCH],
|
||||
0x8600: [DebuggerPDP11.OPS.BCC, DebuggerPDP11.OP_BRANCH],
|
||||
0x8700: [DebuggerPDP11.OPS.BCS, DebuggerPDP11.OP_BRANCH],
|
||||
0x8800: [DebuggerPDP11.OPS.EMT], // 104000..104377
|
||||
0x8900: [DebuggerPDP11.OPS.TRAP] // 104400..104777
|
||||
0x8800: [DebuggerPDP11.OPS.EMT, DebuggerPDP11.OP_DSTNUM8], // 104000..104377
|
||||
0x8900: [DebuggerPDP11.OPS.TRAP, DebuggerPDP11.OP_DSTNUM8] // 104400..104777
|
||||
},
|
||||
0xFFC0: {
|
||||
0x0040: [DebuggerPDP11.OPS.JMP, DebuggerPDP11.OP_DST], // 0001DD
|
||||
|
|
@ -932,8 +933,8 @@ if (DEBUGGER) {
|
|||
{
|
||||
var sMore = "";
|
||||
var cHistory = 0;
|
||||
var iHistory = this.iOpcodeHistory;
|
||||
var aHistory = this.aOpcodeHistory;
|
||||
var iHistory = this.iInstructionHistory;
|
||||
var aHistory = this.aInstructionHistory;
|
||||
|
||||
if (aHistory.length) {
|
||||
var nPrev = +sPrev || this.nextHistory;
|
||||
|
|
@ -985,7 +986,7 @@ if (DEBUGGER) {
|
|||
*
|
||||
* If you re-enable this protection, be sure to re-enable the decrement below, too.
|
||||
*/
|
||||
while (nLines > 0 && iHistory != this.iOpcodeHistory) {
|
||||
while (nLines > 0 && iHistory != this.iInstructionHistory) {
|
||||
|
||||
var dbgAddr = aHistory[iHistory++];
|
||||
if (dbgAddr.addr == null) break;
|
||||
|
|
@ -1245,34 +1246,27 @@ if (DEBUGGER) {
|
|||
{
|
||||
var i;
|
||||
if (!this.checksEnabled()) {
|
||||
if (this.aOpcodeHistory && this.aOpcodeHistory.length && !fQuiet) {
|
||||
if (this.aInstructionHistory && this.aInstructionHistory.length && !fQuiet) {
|
||||
this.println("instruction history buffer freed");
|
||||
}
|
||||
this.iOpcodeHistory = 0;
|
||||
this.aOpcodeHistory = [];
|
||||
this.aaOpcodeCounts = [];
|
||||
this.iInstructionHistory = 0;
|
||||
this.aInstructionHistory = [];
|
||||
return;
|
||||
}
|
||||
if (!this.aOpcodeHistory || !this.aOpcodeHistory.length) {
|
||||
this.aOpcodeHistory = new Array(DebuggerPDP11.HISTORY_LIMIT);
|
||||
for (i = 0; i < this.aOpcodeHistory.length; i++) {
|
||||
if (!this.aInstructionHistory || !this.aInstructionHistory.length) {
|
||||
this.aInstructionHistory = new Array(DebuggerPDP11.HISTORY_LIMIT);
|
||||
for (i = 0; i < this.aInstructionHistory.length; i++) {
|
||||
/*
|
||||
* Preallocate dummy Addr (Array) objects in every history slot, so that
|
||||
* checkInstruction() doesn't need to call newAddr() on every slot update.
|
||||
*/
|
||||
this.aOpcodeHistory[i] = this.newAddr();
|
||||
this.aInstructionHistory[i] = this.newAddr();
|
||||
}
|
||||
this.iOpcodeHistory = 0;
|
||||
this.iInstructionHistory = 0;
|
||||
if (!fQuiet) {
|
||||
this.println("instruction history buffer allocated");
|
||||
}
|
||||
}
|
||||
if (!this.aaOpcodeCounts || !this.aaOpcodeCounts.length) {
|
||||
this.aaOpcodeCounts = new Array(256);
|
||||
for (i = 0; i < this.aaOpcodeCounts.length; i++) {
|
||||
this.aaOpcodeCounts[i] = [i, 0];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1324,7 +1318,7 @@ if (DEBUGGER) {
|
|||
this.nCycles += nCyclesStep;
|
||||
this.cpu.addCycles(nCyclesStep, true);
|
||||
this.cpu.updateChecksum(nCyclesStep);
|
||||
this.cOpcodes++;
|
||||
this.cInstructions++;
|
||||
}
|
||||
}
|
||||
catch(exception) {
|
||||
|
|
@ -1456,7 +1450,7 @@ if (DEBUGGER) {
|
|||
DebuggerPDP11.prototype.reset = function(fQuiet)
|
||||
{
|
||||
this.historyInit();
|
||||
this.cOpcodes = this.cOpcodesStart = 0;
|
||||
this.cInstructions = this.cInstructionsStart = 0;
|
||||
this.sMessagePrev = null;
|
||||
this.nCycles = 0;
|
||||
this.dbgAddrNextCode = this.newAddr(this.cpu.getPC());
|
||||
|
|
@ -1550,14 +1544,14 @@ if (DEBUGGER) {
|
|||
var nCyclesPerSecond = (msTotal > 0? Math.round(this.nCycles * 1000 / msTotal) : 0);
|
||||
sStopped += " (";
|
||||
if (this.checksEnabled()) {
|
||||
sStopped += this.cOpcodes + " opcodes, ";
|
||||
sStopped += this.cInstructions + " instructions, ";
|
||||
/*
|
||||
* $ops displays progress by calculating cOpcodes - cOpcodesStart, so before
|
||||
* zeroing cOpcodes, we should subtract cOpcodes from cOpcodesStart (since we're
|
||||
* effectively subtracting cOpcodes from cOpcodes as well).
|
||||
*/
|
||||
this.cOpcodesStart -= this.cOpcodes;
|
||||
this.cOpcodes = 0;
|
||||
this.cInstructionsStart -= this.cInstructions;
|
||||
this.cInstructions = 0;
|
||||
}
|
||||
sStopped += this.nCycles + " cycles, " + msTotal + " ms, " + nCyclesPerSecond + " hz)";
|
||||
} else {
|
||||
|
|
@ -1594,7 +1588,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
DebuggerPDP11.prototype.checksEnabled = function(fRelease)
|
||||
{
|
||||
return ((DEBUG && !fRelease)? true : (this.aBreakExec.length > 1 || !!this.nBreakIns));
|
||||
return ((DEBUG && !fRelease)? true : (this.aBreakExec.length > 1 || !!this.nBreakInstructions));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1610,7 +1604,7 @@ if (DEBUGGER) {
|
|||
*/
|
||||
DebuggerPDP11.prototype.checkInstruction = function(addr, nState)
|
||||
{
|
||||
var opCode = -1
|
||||
var opCode = -1;
|
||||
var cpu = this.cpu;
|
||||
|
||||
/*
|
||||
|
|
@ -1620,13 +1614,13 @@ if (DEBUGGER) {
|
|||
if (nState == 0) {
|
||||
opCode = this.cpu.getWordDirect(addr);
|
||||
if (opCode == PDP11.OPCODE.HALT) {
|
||||
this.cpu.advancePC(2);
|
||||
addr = this.cpu.advancePC(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (nState > 0) {
|
||||
if (this.nBreakIns && !--this.nBreakIns) {
|
||||
return true;
|
||||
if (this.nBreakInstructions) {
|
||||
if (!--this.nBreakInstructions) return true;
|
||||
}
|
||||
if (this.checkBreakpoint(addr, 1, this.aBreakExec)) {
|
||||
return true;
|
||||
|
|
@ -1639,14 +1633,16 @@ if (DEBUGGER) {
|
|||
* adding/removing breakpoints, simply because it's breakpoints that trigger the call to checkInstruction();
|
||||
* well, OK, and a few other things now, like enabling MessagesPDP11.INT messages.
|
||||
*/
|
||||
if (nState >= 0 && this.aaOpcodeCounts.length) {
|
||||
this.cOpcodes++;
|
||||
if (opCode < 0) opCode = this.cpu.getWordDirect(addr);
|
||||
if (opCode != null) {
|
||||
var dbgAddr = this.aOpcodeHistory[this.iOpcodeHistory];
|
||||
this.setAddr(dbgAddr, cpu.getPC());
|
||||
if (nState >= 0 && this.aInstructionHistory.length) {
|
||||
this.cInstructions++;
|
||||
if (opCode < 0) {
|
||||
opCode = this.cpu.getWordDirect(addr);
|
||||
}
|
||||
if ((opCode & 0xffff) != PDP11.OPCODE.INVALID) {
|
||||
var dbgAddr = this.aInstructionHistory[this.iInstructionHistory];
|
||||
this.setAddr(dbgAddr, addr);
|
||||
// if (DEBUG) dbgAddr.cycleCount = cpu.getCycles();
|
||||
if (++this.iOpcodeHistory == this.aOpcodeHistory.length) this.iOpcodeHistory = 0;
|
||||
if (++this.iInstructionHistory == this.aInstructionHistory.length) this.iInstructionHistory = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -2161,13 +2157,17 @@ if (DEBUGGER) {
|
|||
sOperand = this.toStrBase(addr);
|
||||
}
|
||||
else if (opTypeOther == DebuggerPDP11.OP_DSTNUM3) {
|
||||
disp = (opCode & 0x7);
|
||||
disp = (opCode & 0x07);
|
||||
sOperand = this.toStrBase(disp, 1);
|
||||
}
|
||||
else if (opTypeOther == DebuggerPDP11.OP_DSTNUM6) {
|
||||
disp = (opCode & 0x3f);
|
||||
sOperand = this.toStrBase(disp, 1);
|
||||
}
|
||||
else if (opTypeOther == DebuggerPDP11.OP_DSTNUM8) {
|
||||
disp = (opCode & 0xff);
|
||||
sOperand = this.toStrBase(disp, 1);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Isolate all OP_SRC or OP_DST bits from opcode in the opMode variable.
|
||||
|
|
@ -2724,8 +2724,8 @@ if (DEBUGGER) {
|
|||
}
|
||||
|
||||
if (sParm == 'n') {
|
||||
this.nBreakIns = this.parseValue(sAddr);
|
||||
this.println("break after " + this.nBreakIns + " instruction(s)");
|
||||
this.nBreakInstructions = this.parseValue(sAddr);
|
||||
this.println("break after " + this.nBreakInstructions + " instruction(s)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2914,7 +2914,7 @@ if (DEBUGGER) {
|
|||
data = shift = 0;
|
||||
}
|
||||
sChars += (v >= 32 && v < 128? String.fromCharCode(v) : '.');
|
||||
nBytes--;
|
||||
nBytes -= n;
|
||||
}
|
||||
if (sDump) sDump += '\n';
|
||||
sDump += sAddr + " " + sData + ((i == 0)? (' ' + sChars) : "");
|
||||
|
|
@ -3680,16 +3680,16 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* shiftArgs(asArgs)
|
||||
*
|
||||
* Used with any command (eg, "r") that allows but doesn't require whitespace between command and first argument.
|
||||
* splitArgs(sCmd)
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
* @param {Array.<string>} asArgs
|
||||
* @param {string} sCmd
|
||||
* @return {Array.<string>}
|
||||
*/
|
||||
DebuggerPDP11.prototype.shiftArgs = function(asArgs)
|
||||
DebuggerPDP11.prototype.splitArgs = function(sCmd)
|
||||
{
|
||||
var asArgs = sCmd.replace(/ +/g, ' ').split(' ');
|
||||
asArgs[0] = asArgs[0].toLowerCase();
|
||||
if (asArgs && asArgs.length) {
|
||||
var s0 = asArgs[0];
|
||||
var ch0 = s0.charAt(0);
|
||||
|
|
@ -3749,8 +3749,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
|
||||
var fError = false;
|
||||
var asArgs = this.shiftArgs(sCmd.replace(/ +/g, ' ').split(' '));
|
||||
asArgs[0] = asArgs[0].toLowerCase();
|
||||
var asArgs = this.splitArgs(sCmd);
|
||||
|
||||
switch (asArgs[0].charAt(0)) {
|
||||
case 'a':
|
||||
|
|
|
|||
|
|
@ -189,7 +189,8 @@ var PDP11 = {
|
|||
* Assorted common opcodes
|
||||
*/
|
||||
OPCODE: {
|
||||
HALT: 0x0000
|
||||
HALT: 0x0000,
|
||||
INVALID: 0xFFFF // far from the only invalid opcode, just a KNOWN invalid opcode
|
||||
},
|
||||
/*
|
||||
* Internal operation state flags
|
||||
|
|
@ -249,13 +250,13 @@ var PDP11 = {
|
|||
UNDEFINED: 0x00, // 000 (reserved)
|
||||
BUS_ERROR: 0x04, // 004 illegal instructions, bus errors, stack limit, illegal internal address, microbreak
|
||||
RESERVED: 0x08, // 010 reserved instructions
|
||||
BREAKPOINT: 0x0C, // 014 BPT, breakpoint trap (trace)
|
||||
IOT: 0x10, // 020 IOT, input/output trap
|
||||
POWER_FAIL: 0x14, // 024 power fail
|
||||
EMULATOR: 0x18, // 030 EMT, emulator trap
|
||||
BPT: 0x0C, // 014 BPT: breakpoint trap (trace)
|
||||
IOT: 0x10, // 020 IOT: input/output trap
|
||||
PF: 0x14, // 024 power fail
|
||||
EMT: 0x18, // 030 EMT: emulator trap
|
||||
TRAP: 0x1C, // 034 TRAP instruction
|
||||
PIRQ: 0xA0, // 240 PIRQ, program interrupt request
|
||||
MMU_FAULT: 0xA8 // 250 MMU aborts and traps
|
||||
PIRQ: 0xA0, // 240 PIRQ: program interrupt request
|
||||
MMU: 0xA8 // 250 MMU: aborts and traps
|
||||
},
|
||||
/*
|
||||
* PDP-11 trap reasons (for diagnostic purposes only)
|
||||
|
|
|
|||
|
|
@ -258,8 +258,8 @@ RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit)
|
|||
* unless the address is odd (usually 1). DEC's "Absolute Loader" jumps to the exec address
|
||||
* in former case, halts in the latter.
|
||||
*
|
||||
* All values are stored "little endian" (low byte first, followed by high byte), just like
|
||||
* the PDP-11 does.
|
||||
* All values are stored "little endian" (low byte followed by high byte), just like the
|
||||
* PDP-11's memory architecture.
|
||||
*
|
||||
* After the data bytes, there is a single checksum byte. The 8-bit sum of all the bytes in
|
||||
* the block (including the header bytes and checksum byte) should be zero.
|
||||
|
|
@ -267,7 +267,9 @@ RAMPDP11.prototype.loadImage = function(aBytes, addrLoad, addrExec, addrInit)
|
|||
* ANOMALIES: Tape files don't always begin with a signature word, so I allow any number of
|
||||
* leading zeros before the first signature. Tape files don't always end cleanly either, so as
|
||||
* soon as I see an invalid signature, I break out of the loop without signalling an error, as
|
||||
* long as at least ONE block was successfully processed.
|
||||
* long as at least ONE block was successfully processed. In fact, it's possible that as
|
||||
* soon as a block with ZERO data bytes is encountered, processing is supposed to stop, but
|
||||
* I haven't examined enough tapes (or the Absolute Loader code) to know for sure.
|
||||
*/
|
||||
if (addrLoad == null) {
|
||||
var off = 0, fError = false;
|
||||
|
|
|
|||
Loading…
Reference in a new issue