Cleaned up interrupt handling, register initialization, MMU initialization, etc
This commit is contained in:
parent
1e1388b9ca
commit
3497466113
8 changed files with 1642 additions and 1620 deletions
|
|
@ -1087,8 +1087,12 @@ CPUPDP11.prototype.runCPU = function(fUpdateFocus)
|
|||
this.stepCPU(nCyclesPerBurst);
|
||||
}
|
||||
catch(exception) {
|
||||
/*
|
||||
* We assume that any numeric exception was explicitly thrown by the CPU to interrupt the
|
||||
* current instruction (and by extension, the current burst, but not the current run). All
|
||||
* other exceptions are re-thrown to the catch below, which will attempt a stack dump.
|
||||
*/
|
||||
if (typeof exception != "number") throw exception;
|
||||
if (DEBUG) this.println("CPU exception: " + str.toHexWord(exception));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -89,6 +89,16 @@ function CPUStatePDP11(parmsCPU)
|
|||
|
||||
Component.subclass(CPUStatePDP11, CPUPDP11);
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* delay: number,
|
||||
* priority: number,
|
||||
* vector: number,
|
||||
* callback: (function()|null|undefined)
|
||||
* }} InterruptEvent
|
||||
*/
|
||||
var InterruptEvent;
|
||||
|
||||
/**
|
||||
* initProcessor()
|
||||
*
|
||||
|
|
@ -139,21 +149,9 @@ CPUStatePDP11.prototype.initRegs = function()
|
|||
this.regsAltStack = [ // Alternate R6 stack pointers (kernel, super, illegal, user)
|
||||
0, 0, 0, 0
|
||||
];
|
||||
this.regSL = 0xff; // 177774
|
||||
this.regPIR = 0; // 177772
|
||||
this.regCPUErr = 0; // 177766
|
||||
this.MMR0 = 0; // 177572
|
||||
this.MMR1 = 0; // 177574
|
||||
this.MMR2 = 0; // 177576
|
||||
this.MMR3 = 0; // 172516
|
||||
this.mmuMode = 0; // current memory management mode (see PDP11.MODE.KERNEL | SUPER | UNUSED | USER)
|
||||
this.mmuEnable = 0; // MMU enabled for PDP11.ACCESS.READ or PDP11.ACCESS.WRITE
|
||||
this.mmuLastMode = 0;
|
||||
this.mmuLastPage = 0;
|
||||
this.mmuLastVirtual = 0;
|
||||
this.mmuMask = [ // mask to control I&D access for each mode
|
||||
0x7, 0x7, 0x7, 0x7
|
||||
];
|
||||
this.mmuMap = [ // memory management register by mode - 16 PDR (8 I then 8 D descriptors) followed by 16 PAR (I/D addresses)
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // kernel
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], // super
|
||||
|
|
@ -167,18 +165,13 @@ CPUStatePDP11.prototype.initRegs = function()
|
|||
this.controlReg = [ // various control registers we don't really care about
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
];
|
||||
|
||||
this.regOp = -1; // current opcode
|
||||
this.opFlags = 0;
|
||||
|
||||
this.cpuType = 70;
|
||||
this.trapPSW = -1;
|
||||
this.interruptQueue = []; // List of interrupts pending
|
||||
this.runState = 0; // 0=run, 1=step, 2=wait, 3=run
|
||||
this.loopRate = 9999; // instructions we can execute in 12ms
|
||||
this.priorityReview = 2; // flag to mark if we need to check priority change
|
||||
|
||||
this.initMemoryAccess();
|
||||
this.resetRegs();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -188,32 +181,31 @@ CPUStatePDP11.prototype.initRegs = function()
|
|||
*/
|
||||
CPUStatePDP11.prototype.resetRegs = function()
|
||||
{
|
||||
this.regSL = 0xff;
|
||||
this.regCPUErr = 0;
|
||||
this.interruptQueue = [];
|
||||
this.regPIR = 0;
|
||||
this.MMR0 = this.MMR1 = this.MMR2 = this.MMR3 = this.mmuFrozen = this.mmuEnable = 0;
|
||||
this.mmuMask[0] = this.mmuMask[1] = this.mmuMask[3] = 0x7;
|
||||
this.regSL = 0xff; // 177774
|
||||
this.regErr = 0; // 177766
|
||||
this.regPIR = 0; // 177772
|
||||
this.MMR0 = 0; // 177572
|
||||
this.MMR1 = 0; // 177574
|
||||
this.MMR2 = 0; // 177576
|
||||
this.MMR3 = 0; // 172516
|
||||
this.mmuEnable = 0; // MMU enabled for PDP11.ACCESS.READ or PDP11.ACCESS.WRITE
|
||||
this.mmuLastMode = 0;
|
||||
|
||||
this.mmuMask = [ // mask to control I&D access for each mode
|
||||
0x7, 0x7, 0x7, 0x7
|
||||
];
|
||||
/**
|
||||
* @type {Array.<InterruptEvent>}
|
||||
*/
|
||||
this.interruptQueue = []; // List of interrupts pending
|
||||
this.priorityReview = 2; // flag to mark if we need to check priority change
|
||||
this.initMemoryAccess();
|
||||
};
|
||||
|
||||
/**
|
||||
* initMemoryAccess()
|
||||
*
|
||||
* Define getAddr(), readWord(), etc, handlers appropriate for the current MMU mode.
|
||||
*
|
||||
* The initial goal is to eliminate unnecessary calls to mapVirtualToPhysical(); for example,
|
||||
* readWordFromVirtual() always does this:
|
||||
*
|
||||
* return this.readWordFromPhysical(this.mapVirtualToPhysical(virtualAddress, PDP11.ACCESS.READ));
|
||||
*
|
||||
* and getAddrVirtual() -- formerly getAddrByMode() -- always does this:
|
||||
*
|
||||
* return this.mapVirtualToPhysical(this.getVirtualByMode(addressMode, accessFlags), accessFlags);
|
||||
*
|
||||
* So now we define readWord() and getAddr() functions that are more appropriate for the current MMU mode.
|
||||
* Define getAddr(), readWord(), etc, handlers appropriate for the current MMU mode, in order to
|
||||
* eliminate unnecessary calls to mapVirtualToPhysical().
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
*/
|
||||
|
|
@ -230,6 +222,42 @@ CPUStatePDP11.prototype.initMemoryAccess = function()
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* getMMR0()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.getMMR0 = function()
|
||||
{
|
||||
return (this.MMR0 & 0xf381) | (this.mmuLastMode << 5) | (this.mmuLastPage << 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* setMMR0()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} newMMR0
|
||||
* @return {number}
|
||||
*/
|
||||
CPUStatePDP11.prototype.setMMR0 = function(newMMR0)
|
||||
{
|
||||
this.MMR0 = newMMR0 &= 0xf381;
|
||||
this.mmuLastMode = (newMMR0 >> 5) & 3;
|
||||
this.mmuLastPage = (newMMR0 >> 1) & 0xf;
|
||||
if (newMMR0 & 0x101) {
|
||||
if (newMMR0 & 0x1) {
|
||||
this.mmuEnable = PDP11.ACCESS.READ | PDP11.ACCESS.WRITE;
|
||||
} else {
|
||||
this.mmuEnable = PDP11.ACCESS.WRITE;
|
||||
}
|
||||
} else {
|
||||
this.mmuEnable = 0;
|
||||
}
|
||||
this.initMemoryAccess();
|
||||
return this.MMR0;
|
||||
};
|
||||
|
||||
/**
|
||||
* getChecksum()
|
||||
*
|
||||
|
|
@ -253,7 +281,7 @@ CPUStatePDP11.prototype.save = function()
|
|||
{
|
||||
var state = new State(this);
|
||||
state.set(0, []);
|
||||
state.set(1, [this.intFlags, this.nTotalCycles, this.getSpeed()]);
|
||||
state.set(1, [this.nTotalCycles, this.getSpeed()]);
|
||||
state.set(2, this.bus.saveMemory());
|
||||
return state.data();
|
||||
};
|
||||
|
|
@ -270,7 +298,6 @@ CPUStatePDP11.prototype.save = function()
|
|||
CPUStatePDP11.prototype.restore = function(data)
|
||||
{
|
||||
var a = data[1];
|
||||
this.intFlags = a[0];
|
||||
this.nTotalCycles = a[1];
|
||||
this.setSpeed(a[3]);
|
||||
return this.bus.restoreMemory(data[2]);
|
||||
|
|
@ -499,45 +526,6 @@ CPUStatePDP11.prototype.getSP = function()
|
|||
return this.regsGen[6];
|
||||
};
|
||||
|
||||
/**
|
||||
* checkINTR()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {boolean} true if execution may proceed, false if not
|
||||
*/
|
||||
CPUStatePDP11.prototype.checkINTR = function()
|
||||
{
|
||||
if (this.intFlags & PDP11.INTFLAG.HALT) {
|
||||
/*
|
||||
* As discussed in opHLT(), the CPU is never REALLY halted by a HLT instruction; instead, opHLT()
|
||||
* calls requestHALT(), which sets INTFLAG.HALT and signals to stepCPU() that it's free to end the
|
||||
* current burst AND that it should not execute any more instructions until checkINTR() indicates
|
||||
* that a hardware interrupt has been requested.
|
||||
*/
|
||||
this.endBurst();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* clearINTR(nLevel)
|
||||
*
|
||||
* Clear the corresponding interrupt level.
|
||||
*
|
||||
* nLevel can either be a valid interrupt level (0-7), or -1 to clear all pending interrupts
|
||||
* (eg, in the event of a system-wide reset).
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} nLevel (0-7, or -1 for all)
|
||||
*/
|
||||
CPUStatePDP11.prototype.clearINTR = function(nLevel)
|
||||
{
|
||||
var bitsClear = nLevel < 0? 0xff : (1 << nLevel);
|
||||
this.intFlags &= ~bitsClear;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* requestHALT()
|
||||
*
|
||||
|
|
@ -545,7 +533,7 @@ CPUStatePDP11.prototype.clearINTR = function(nLevel)
|
|||
*/
|
||||
CPUStatePDP11.prototype.requestHALT = function()
|
||||
{
|
||||
this.intFlags |= PDP11.INTFLAG.HALT;
|
||||
// TODO: There will be more work to do than this....
|
||||
this.endBurst();
|
||||
};
|
||||
|
||||
|
|
@ -602,6 +590,50 @@ CPUStatePDP11.prototype.interrupt = function(delay, priority, vector, callback)
|
|||
this.priorityReview = 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkInterruptQueue()
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
*/
|
||||
CPUStatePDP11.prototype.checkInterruptQueue = function()
|
||||
{
|
||||
if (this.priorityReview == 1) {
|
||||
this.priorityReview = 2; // SPL delay
|
||||
} else {
|
||||
this.priorityReview = 0;
|
||||
var interruptEvent = null;
|
||||
var savePSW = this.regPIR & 0xe0;
|
||||
for (var i = this.interruptQueue.length; --i >= 0;) {
|
||||
if (this.interruptQueue[i].delay > 0) {
|
||||
this.interruptQueue[i].delay--;
|
||||
this.priorityReview = 2;
|
||||
break; // Decrement only one delay 'difference' per cycle
|
||||
}
|
||||
//if (typeof this.interruptQueue[i].callback !== "undefined") {
|
||||
if (this.interruptQueue[i].callback) {
|
||||
if (!this.interruptQueue[i].callback()) {
|
||||
this.interruptQueue.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
//delete
|
||||
this.interruptQueue[i].callback = null;
|
||||
}
|
||||
if (this.interruptQueue[i].priority > savePSW) {
|
||||
savePSW = this.interruptQueue[i].priority;
|
||||
interruptEvent = this.interruptQueue[i];
|
||||
this.interruptQueue.splice(i, 1);
|
||||
}
|
||||
}
|
||||
if (savePSW > (this.PSW & 0xe0)) {
|
||||
if (!interruptEvent) {
|
||||
this.trap(PDP11.TRAP.PIRQ, 42);
|
||||
} else {
|
||||
this.trap(interruptEvent.vector, 44);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* getPSW()
|
||||
*
|
||||
|
|
@ -752,7 +784,7 @@ CPUStatePDP11.prototype.panic = function(reason)
|
|||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} vector
|
||||
* @param {number} reason
|
||||
* @param {number} [reason]
|
||||
*/
|
||||
CPUStatePDP11.prototype.trap = function(vector, reason)
|
||||
{
|
||||
|
|
@ -783,7 +815,7 @@ CPUStatePDP11.prototype.trap = function(vector, reason)
|
|||
this.setPSW((newPSW & 0xcfff) | ((this.trapPSW >> 2) & 0x3000));
|
||||
|
||||
if (doubleTrap) {
|
||||
this.regCPUErr |= PDP11.CPUERR.RED;
|
||||
this.regErr |= PDP11.CPUERR.RED;
|
||||
this.regsGen[6] = 4;
|
||||
}
|
||||
|
||||
|
|
@ -793,7 +825,10 @@ CPUStatePDP11.prototype.trap = function(vector, reason)
|
|||
|
||||
this.opFlags &= ~PDP11.OPFLAG.TRAP_MASK; // lose interest in traps after an abort
|
||||
this.trapPSW = -1; // reset flag that we have a trap within a trap
|
||||
throw vector | (reason << 8);
|
||||
|
||||
if (DEBUG) this.println("trap to vector " + str.toOct(vector, 3) + (reason? " (reason " + reason + ")" : ""));
|
||||
|
||||
throw vector;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -878,7 +913,7 @@ CPUStatePDP11.prototype.mapVirtualToPhysical = function(virtualAddress, accessFl
|
|||
physicalAddress |= BusPDP11.IOPAGE_22BIT;
|
||||
} else { // no max_memory check in 16 bit mode
|
||||
if ((physicalAddress & 1) && !(accessFlags & PDP11.ACCESS.BYTE)) {
|
||||
this.regCPUErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.regErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, 22);
|
||||
}
|
||||
}
|
||||
|
|
@ -897,11 +932,11 @@ CPUStatePDP11.prototype.mapVirtualToPhysical = function(virtualAddress, accessFl
|
|||
}
|
||||
if (physicalAddress < BusPDP11.IOPAGE_UNIBUS) {
|
||||
if (physicalAddress >= BusPDP11.MAX_MEMORY) {
|
||||
this.regCPUErr |= PDP11.CPUERR.NOMEMORY;
|
||||
this.regErr |= PDP11.CPUERR.NOMEMORY;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, 24); // KB11-EM does this after ABORT handling - KB11-CM before
|
||||
}
|
||||
if ((physicalAddress & 1) && !(accessFlags & PDP11.ACCESS.BYTE)) {
|
||||
this.regCPUErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.regErr |= PDP11.CPUERR.ODDADDR;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, 26);
|
||||
}
|
||||
}
|
||||
|
|
@ -1115,11 +1150,11 @@ CPUStatePDP11.prototype.pushWord = function(data)
|
|||
|
||||
if ((!this.mmuMode) && virtualAddress <= this.regSL && virtualAddress > 4) {
|
||||
if (virtualAddress <= this.regSL - 32) {
|
||||
this.regCPUErr |= PDP11.CPUERR.RED;
|
||||
this.regErr |= PDP11.CPUERR.RED;
|
||||
this.regsGen[6] = 4;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, 32);
|
||||
} else {
|
||||
this.regCPUErr |= PDP11.CPUERR.YELLOW;
|
||||
this.regErr |= PDP11.CPUERR.YELLOW;
|
||||
this.opFlags |= 4;
|
||||
}
|
||||
}
|
||||
|
|
@ -1179,11 +1214,11 @@ CPUStatePDP11.prototype.getVirtualByMode = function(addressMode, accessFlags)
|
|||
if (reg === 6 && (!this.mmuMode) && (accessFlags & PDP11.ACCESS.WRITE) &&
|
||||
(this.regsGen[6] <= this.regSL || this.regsGen[6] >= 0xfffe)) {
|
||||
if (this.regsGen[6] <= this.regSL - 32 || this.regsGen[6] >= 0xfffe) {
|
||||
this.regCPUErr |= PDP11.CPUERR.RED;
|
||||
this.regErr |= PDP11.CPUERR.RED;
|
||||
this.regsGen[6] = 4;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, 36);
|
||||
} else {
|
||||
this.regCPUErr |= PDP11.CPUERR.YELLOW;
|
||||
this.regErr |= PDP11.CPUERR.YELLOW;
|
||||
this.opFlags |= PDP11.OPFLAG.TRAP_SP;
|
||||
}
|
||||
}
|
||||
|
|
@ -1284,11 +1319,11 @@ CPUStatePDP11.prototype.getVirtualByMode = function(addressMode, accessFlags)
|
|||
|
||||
if (reg === 6 && (!this.mmuMode) && (accessFlags & PDP11.ACCESS.WRITE) && stepSize <= 0 && (this.regsGen[6] <= this.regSL || this.regsGen[6] >= 0xfffe)) {
|
||||
if (this.regsGen[6] <= this.regSL - 32) {
|
||||
this.regCPUErr |= PDP11.CPUERR.RED;
|
||||
this.regErr |= PDP11.CPUERR.RED;
|
||||
this.regsGen[6] = 4;
|
||||
this.trap(PDP11.TRAP.BUS_ERROR, 38);
|
||||
} else {
|
||||
this.regCPUErr |= PDP11.CPUERR.YELLOW;
|
||||
this.regErr |= PDP11.CPUERR.YELLOW;
|
||||
this.opFlags |= PDP11.OPFLAG.TRAP_SP;
|
||||
}
|
||||
}
|
||||
|
|
@ -1532,10 +1567,6 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
*/
|
||||
this.nBurstCycles = this.nStepCycles = nMinCycles;
|
||||
|
||||
/*
|
||||
* NOTE: If checkINTR() returns false, INTFLAG.HALT must be set, so no instructions should be executed.
|
||||
*/
|
||||
if (this.checkINTR()) {
|
||||
do {
|
||||
if (DEBUGGER && fDebugCheck) {
|
||||
if (this.dbg.checkInstruction(this.getPC(), nDebugState)) {
|
||||
|
|
@ -1545,13 +1576,6 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
nDebugState = 1;
|
||||
}
|
||||
|
||||
var opCode,
|
||||
src,
|
||||
dst,
|
||||
dstAddr,
|
||||
result,
|
||||
virtualAddress, savePSW, reg, i, j;
|
||||
|
||||
/*
|
||||
* Check for any pending traps.
|
||||
*
|
||||
|
|
@ -1574,45 +1598,8 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
this.opFlags &= ~PDP11.OPFLAG.TRAP_MASK;
|
||||
}
|
||||
|
||||
if (this.priorityReview) { // if nothing has changed don't check priority
|
||||
if (this.priorityReview === 1) {
|
||||
this.priorityReview = 2; // SPL delay
|
||||
} else {
|
||||
this.priorityReview = 0;
|
||||
j = -1;
|
||||
savePSW = this.regPIR & 0xe0;
|
||||
if ((i = this.interruptQueue.length) > 0) {
|
||||
while (i-- > 0) {
|
||||
if (this.interruptQueue[i].delay > 0) {
|
||||
this.interruptQueue[i].delay--;
|
||||
this.priorityReview = 2;
|
||||
break; // Decrement only one delay 'difference' per cycle
|
||||
}
|
||||
//if (typeof this.interruptQueue[i].callback !== "undefined") {
|
||||
if (this.interruptQueue[i].callback) {
|
||||
if (!this.interruptQueue[i].callback()) {
|
||||
this.interruptQueue.splice(i, 1);
|
||||
j--;
|
||||
continue;
|
||||
}
|
||||
//delete
|
||||
this.interruptQueue[i].callback = null;
|
||||
}
|
||||
if (this.interruptQueue[i].priority > savePSW) {
|
||||
savePSW = this.interruptQueue[i].priority;
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (savePSW > (this.PSW & 0xe0)) {
|
||||
if (j < 0) {
|
||||
this.trap(PDP11.TRAP.PIRQ, 42);
|
||||
} else {
|
||||
this.trap(this.interruptQueue[j].vector, 44);
|
||||
this.interruptQueue.splice(j, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.priorityReview) {
|
||||
this.checkInterruptQueue();
|
||||
}
|
||||
|
||||
if (!(this.MMR0 & 0xe000)) {
|
||||
|
|
@ -1632,7 +1619,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
* it to detect if our new decode() function has processed (ie, "consumed") the opcode,
|
||||
* by setting it to -1. If it has, then we can skip the older opcode decode logic below.
|
||||
*/
|
||||
this.regOp = opCode = this.readWordFromVirtual(this.regsGen[7]);
|
||||
var opCode = this.regOp = this.readWordFromVirtual(this.regsGen[7]);
|
||||
if (opCode >= 0) this.regsGen[7] = (this.regsGen[7] + 2) & 0xffff;
|
||||
|
||||
this.decode(opCode);
|
||||
|
|
@ -1643,6 +1630,13 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
break;
|
||||
}
|
||||
|
||||
// var opCode,
|
||||
// src,
|
||||
// dst,
|
||||
// dstAddr,
|
||||
// result,
|
||||
// virtualAddress, savePSW, reg, i, j;
|
||||
|
||||
switch (opCode & 0xF000) /*0170000*/ { // Double operand instructions xxSSDD
|
||||
case 0x1000: /*0010000*/ // MOV 01SSDD
|
||||
//LOG_INSTRUCTION(opCode, 2, "MOV");
|
||||
|
|
@ -2619,7 +2613,7 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
// case 0x0: /*0000000*/ // HALT 000000
|
||||
// //LOG_INSTRUCTION(opCode, 0, "HALT");
|
||||
// if (0xc000 & this.PSW) {
|
||||
// this.regCPUErr |= PDP11.CPUERR.BADHALT;
|
||||
// this.regErr |= PDP11.CPUERR.BADHALT;
|
||||
// this.trap(PDP11.TRAP.BUS_ERROR, 46);
|
||||
// } else {
|
||||
// this.runState = 3; // halt
|
||||
|
|
@ -2695,7 +2689,6 @@ CPUStatePDP11.prototype.stepCPU = function(nMinCycles)
|
|||
// }
|
||||
}
|
||||
} while (this.nStepCycles > 0);
|
||||
}
|
||||
|
||||
return (this.flags.complete? this.nBurstCycles - this.nStepCycles : (this.flags.complete === undefined? 0 : -1));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1200,12 +1200,14 @@ if (DEBUGGER) {
|
|||
}
|
||||
}
|
||||
catch(exception) {
|
||||
/*
|
||||
* We assume that any numeric exception was explicitly thrown by the CPU to interrupt the
|
||||
* current instruction. For all other exceptions, we attempt a stack dump.
|
||||
*/
|
||||
if (typeof exception != "number") {
|
||||
var e = exception;
|
||||
this.nCycles = 0;
|
||||
this.cpu.setError(e.stack || e.message);
|
||||
} else {
|
||||
if (DEBUG) this.println("CPU exception: " + str.toHexWord(exception));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1980,11 +1982,11 @@ if (DEBUGGER) {
|
|||
}
|
||||
else if (opTypeOther == DebuggerPDP11.OP_DSTNUM3) {
|
||||
disp = (opCode & 0x7);
|
||||
sOperand = this.toStrBase(disp, 2);
|
||||
sOperand = this.toStrBase(disp, 1);
|
||||
}
|
||||
else if (opTypeOther == DebuggerPDP11.OP_DSTNUM6) {
|
||||
disp = (opCode & 0x3f);
|
||||
sOperand = this.toStrBase(disp);
|
||||
sOperand = this.toStrBase(disp, 1);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -157,14 +157,6 @@ var PDP11 = {
|
|||
CMODE: 14
|
||||
}
|
||||
},
|
||||
/*
|
||||
* Interrupt-related flags (stored in intFlags)
|
||||
*/
|
||||
INTFLAG: {
|
||||
NONE: 0x0000,
|
||||
INTR: 0x00ff, // mask for 8 bits, representing interrupt levels 0-7
|
||||
HALT: 0x0100 // halt requested; see opHLT()
|
||||
},
|
||||
/*
|
||||
* Internal operation state flags
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -233,6 +233,38 @@ DevicePDP11.prototype.writeLKS = function(data, addr)
|
|||
this.kw11.lks = data & ~PDP11.KW11.LKS.MONITOR;
|
||||
};
|
||||
|
||||
/**
|
||||
* readMMR0(addr)
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.MMR0 or 177572)
|
||||
* @return {number}
|
||||
*/
|
||||
DevicePDP11.prototype.readMMR0 = function(addr)
|
||||
{
|
||||
return this.cpu.getMMR0();
|
||||
};
|
||||
|
||||
/**
|
||||
* writeMMR0(data, addr)
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
* @param {number} data
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.MMR0 or 177572)
|
||||
*/
|
||||
DevicePDP11.prototype.writeMMR0 = function(data, addr)
|
||||
{
|
||||
/*
|
||||
* Set idx to 1 (22-bit), 2 (18-bit), or 4 (16-bit)
|
||||
*/
|
||||
var idx = 4;
|
||||
data = this.cpu.setMMR0(data);
|
||||
if (data & PDP11.MMR0.ENABLED | PDP11.MMR0.DSTMODE) {
|
||||
idx = (this.cpu.MMR3 & PDP11.MMR3.MMU_22BIT)? 1 : 2;
|
||||
}
|
||||
this.display.misc = (this.display.misc & ~7) | idx;
|
||||
};
|
||||
|
||||
/**
|
||||
* readXCSR(addr)
|
||||
*
|
||||
|
|
@ -890,24 +922,23 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
switch (physicalAddress & ~0x3F) /*077*/ {
|
||||
case 0x3FFFC0: /*017777700*/ // 017777700 - 017777777
|
||||
switch (physicalAddress & ~1) {
|
||||
/*
|
||||
* Superseded by UNIBUS_TABLE (more of this code will be commented out
|
||||
* as it is replaced by read/write handlers in the UNIBUS_TABLE; stay tuned).
|
||||
*
|
||||
case 0x3FFFFE: // 017777776 // PSW
|
||||
result = cpu.getPSW();
|
||||
if (data >= 0) {
|
||||
if (physicalAddress & 1) {
|
||||
data = (data << 8) | (result & 0xff);
|
||||
} else {
|
||||
if (byteFlag) data = (result & 0xff00) | (data & 0xff);
|
||||
}
|
||||
data = (data & 0xf8ef) | (result & 0x0710);
|
||||
cpu.setPSW(data);
|
||||
return -1; // KLUDGE - no trap but abort any CC updates
|
||||
}
|
||||
break;
|
||||
*/
|
||||
//
|
||||
// Superseded by UNIBUS_TABLE (more of this code will be commented out
|
||||
// as it is replaced by read/write handlers in UNIBUS_TABLE; stay tuned).
|
||||
//
|
||||
// case 0x3FFFFE: // 017777776 // PSW
|
||||
// result = cpu.getPSW();
|
||||
// if (data >= 0) {
|
||||
// if (physicalAddress & 1) {
|
||||
// data = (data << 8) | (result & 0xff);
|
||||
// } else {
|
||||
// if (byteFlag) data = (result & 0xff00) | (data & 0xff);
|
||||
// }
|
||||
// data = (data & 0xf8ef) | (result & 0x0710);
|
||||
// cpu.setPSW(data);
|
||||
// return -1; // KLUDGE - no trap but abort any CC updates
|
||||
// }
|
||||
// break;
|
||||
case 0x3FFFFC: /*017777774*/ // stack limit
|
||||
if (data < 0) {
|
||||
result = cpu.regSL & 0xff00;
|
||||
|
|
@ -941,9 +972,9 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
case 0x3FFFF6: /*017777766*/ // CPU error
|
||||
if (cpu.cpuType !== 70) return cpu.trap(PDP11.TRAP.BUS_ERROR, 222);
|
||||
if (data < 0) {
|
||||
result = cpu.regCPUErr;
|
||||
result = cpu.regErr;
|
||||
} else {
|
||||
result = cpu.regCPUErr = 0; // TODO: Always writes as zero?
|
||||
result = cpu.regErr = 0; // TODO: Always writes as zero?
|
||||
}
|
||||
break;
|
||||
case 0x3FFFF4: /*017777764*/ // System I/D
|
||||
|
|
@ -1038,7 +1069,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
}
|
||||
return result;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 124);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1062,32 +1093,32 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
result = cpu.MMR1;
|
||||
if (result & 0xff00) result = ((result << 8) | (result >> 8)) & 0xffff;
|
||||
break;
|
||||
case 0x3FFF7A: /*017777572*/ // MMR0
|
||||
cpu.MMR0 = (cpu.MMR0 & 0xf381) | (cpu.mmuLastMode << 5) | (cpu.mmuLastPage << 1);
|
||||
if (data < 0) {
|
||||
result = cpu.MMR0;
|
||||
} else {
|
||||
result = this.insertData(cpu.MMR0, physicalAddress, data, byteFlag);
|
||||
if (result >= 0) {
|
||||
cpu.MMR0 = result &= 0xf381;
|
||||
cpu.mmuLastMode = (result >> 5) & 3;
|
||||
cpu.mmuLastPage = (result >> 1) & 0xf;
|
||||
if (result & 0x101) {
|
||||
idx = 2; // 18 bit
|
||||
if (cpu.MMR3 & 0x10) idx = 1; // 22 bit
|
||||
if (result & 0x1) {
|
||||
cpu.mmuEnable = PDP11.ACCESS.READ | PDP11.ACCESS.WRITE;
|
||||
} else {
|
||||
cpu.mmuEnable = PDP11.ACCESS.WRITE;
|
||||
}
|
||||
} else {
|
||||
cpu.mmuEnable = 0;
|
||||
idx = 4; // 16 bit
|
||||
}
|
||||
this.display.misc = (this.display.misc & ~7) | idx;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// case 0x3FFF7A: /*017777572*/ // MMR0
|
||||
// cpu.MMR0 = (cpu.MMR0 & 0xf381) | (cpu.mmuLastMode << 5) | (cpu.mmuLastPage << 1);
|
||||
// if (data < 0) {
|
||||
// result = cpu.MMR0;
|
||||
// } else {
|
||||
// result = this.insertData(cpu.MMR0, physicalAddress, data, byteFlag);
|
||||
// if (result >= 0) {
|
||||
// cpu.MMR0 = result &= 0xf381;
|
||||
// cpu.mmuLastMode = (result >> 5) & 3;
|
||||
// cpu.mmuLastPage = (result >> 1) & 0xf;
|
||||
// if (result & 0x101) {
|
||||
// idx = 2; // 18 bit
|
||||
// if (cpu.MMR3 & 0x10) idx = 1; // 22 bit
|
||||
// if (result & 0x1) {
|
||||
// cpu.mmuEnable = PDP11.ACCESS.READ | PDP11.ACCESS.WRITE;
|
||||
// } else {
|
||||
// cpu.mmuEnable = PDP11.ACCESS.WRITE;
|
||||
// }
|
||||
// } else {
|
||||
// cpu.mmuEnable = 0;
|
||||
// idx = 4; // 16 bit
|
||||
// }
|
||||
// this.display.misc = (this.display.misc & ~7) | idx;
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
case 0x3FFF78: /*017777570*/ // console display/switch;
|
||||
if (data < 0) {
|
||||
result = this.display.switches & 0xffff;
|
||||
|
|
@ -1191,7 +1222,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
// }
|
||||
// break;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 126);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1234,7 +1265,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
if (result >= 0) rk11.rkdb = result;
|
||||
break;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 128);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1339,7 +1370,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
if (result >= 0) rp11.rpcs3 = result;
|
||||
break;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 132);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1378,7 +1409,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 134);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1404,7 +1435,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 136);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1454,12 +1485,12 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
idx = (physicalAddress >> 1) & 0xff;
|
||||
result = DevicePDP11.M9312[idx];
|
||||
} else {
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 138);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cpu.regCPUErr |= PDP11.CPUERR.TIMEOUT;
|
||||
cpu.regErr |= PDP11.CPUERR.TIMEOUT;
|
||||
return cpu.trap(PDP11.TRAP.BUS_ERROR, 142);
|
||||
}
|
||||
if (byteFlag && result >= 0) { // make any required byte adjustment
|
||||
|
|
@ -1480,6 +1511,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
|
|||
*/
|
||||
DevicePDP11.UNIBUS_TABLE = {
|
||||
[PDP11.UNIBUS.LKS]: [null, null, DevicePDP11.prototype.readLKS, DevicePDP11.prototype.writeLKS],
|
||||
[PDP11.UNIBUS.MMR0]: [null, null, DevicePDP11.prototype.readMMR0, DevicePDP11.prototype.writeMMR0],
|
||||
[PDP11.UNIBUS.XCSR]: [null, null, DevicePDP11.prototype.readXCSR, DevicePDP11.prototype.writeXCSR],
|
||||
[PDP11.UNIBUS.PSW]: [null, null, DevicePDP11.prototype.readPSW, DevicePDP11.prototype.writePSW]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -659,25 +659,25 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* toStrBase(n, cch)
|
||||
* toStrBase(n, nBytes)
|
||||
*
|
||||
* Use this instead of str.toHex() or str.toOct() to convert words to the default base.
|
||||
* Use this instead of str.toHex() or str.toOct() to convert bytes/words to the Debugger's default base.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number|null|undefined} n
|
||||
* @param {number} [cch] is the desired number of hex digits (0 or undefined for default)
|
||||
* @param {number} [nBytes] is the number of bytes to display, which we translate into a number of characters
|
||||
* @return {string}
|
||||
*/
|
||||
Debugger.prototype.toStrBase = function(n, cch)
|
||||
Debugger.prototype.toStrBase = function(n, nBytes)
|
||||
{
|
||||
switch(this.nBase) {
|
||||
case 8:
|
||||
return str.toOct(n, cch);
|
||||
return str.toOct(n, nBytes * 3);
|
||||
case 10:
|
||||
return n.toString(); // TODO: Do we want to support any formatting based on cch?
|
||||
return n.toString();
|
||||
case 16:
|
||||
default:
|
||||
return str.toHex(n, cch);
|
||||
return str.toHex(n, nBytes * 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue