OS/2 1.0 debugging begins
This commit is contained in:
parent
23eeb37938
commit
6660b9479f
8 changed files with 365 additions and 177 deletions
|
|
@ -204,6 +204,7 @@ about a few:
|
|||
- Unfiltered for…in loop
|
||||
- Bitwise operator usage
|
||||
- Comma expressions
|
||||
- loop statement that doesn't loop
|
||||
- “throw” of exception caught locally
|
||||
|
||||
I acknowledge those those features can introduce bugs if you're not careful, so I make sure I'm careful. I don't
|
||||
|
|
|
|||
|
|
@ -160,12 +160,21 @@ function Debugger(parmsDbg)
|
|||
* things down, but by that point, you've presumably already captured the info you need
|
||||
* and are willing to wait.
|
||||
*/
|
||||
if (DEBUG) {
|
||||
this.traceInit();
|
||||
}
|
||||
if (DEBUG) this.traceInit();
|
||||
|
||||
this.sInitCommands = parmsDbg['commands'];
|
||||
|
||||
/*
|
||||
* Make it easier to access Debugger commands from an external REPL (eg, the WebStorm
|
||||
* "live" console window); eg:
|
||||
*
|
||||
* $('r')
|
||||
*/
|
||||
var dbg = this;
|
||||
if (window && window['$'] === undefined) {
|
||||
window['$'] = function(s) { return dbg.doCommand(s); };
|
||||
}
|
||||
|
||||
} // endif DEBUGGER
|
||||
}
|
||||
|
||||
|
|
@ -2145,7 +2154,7 @@ if (DEBUGGER) {
|
|||
if (sel == this.cpu.segDS.sel) return this.cpu.segDS;
|
||||
if (sel == this.cpu.segES.sel) return this.cpu.segES;
|
||||
if (sel == this.cpu.segSS.sel) return this.cpu.segSS;
|
||||
var seg = new X86Seg(this.cpu);
|
||||
var seg = new X86Seg(this.cpu, X86Seg.ID.OTHER, "DBG");
|
||||
/*
|
||||
* TODO: Confirm that it's OK for this function to drop any error from seg.load() on the floor....
|
||||
*/
|
||||
|
|
@ -2902,7 +2911,8 @@ if (DEBUGGER) {
|
|||
s += (fProt? '\n' : ' ');
|
||||
s += this.getSegStr(this.cpu.segCS, fProt) + " IP=" + str.toHexWord(this.cpu.regIP) +
|
||||
this.getFlagStr("V") + this.getFlagStr("D") + this.getFlagStr("I") + this.getFlagStr("T") +
|
||||
this.getFlagStr("S") + this.getFlagStr("Z") + this.getFlagStr("A") + this.getFlagStr("P") + this.getFlagStr("C");
|
||||
this.getFlagStr("S") + this.getFlagStr("Z") + this.getFlagStr("A") + this.getFlagStr("P") + this.getFlagStr("C") +
|
||||
" PS=" + str.toHexWord(this.cpu.getPS());
|
||||
if (fProt) {
|
||||
s += " MS=" + str.toHexWord(this.cpu.regMSW) + '\n' +
|
||||
this.getDTRStr("LD", this.cpu.segLDT.sel, this.cpu.segLDT.base, this.cpu.segLDT.base + this.cpu.segLDT.limit) + ' ' +
|
||||
|
|
@ -3517,14 +3527,6 @@ if (DEBUGGER) {
|
|||
if (aAddr[0] == null)
|
||||
return;
|
||||
if (sCmd == "ds") {
|
||||
/*
|
||||
* We used to call:
|
||||
*
|
||||
* var seg = new X86Seg(this.cpu);
|
||||
* if (seg.load(aAddr[0], true) >= 0) { ... }
|
||||
*
|
||||
* but using getSegment() allows us to dump active segment registers, too.
|
||||
*/
|
||||
var seg = this.getSegment(aAddr[0]);
|
||||
if (seg.sel != null) {
|
||||
var s = "selector=" + str.toHexWord(aAddr[0]) + " limit=" + str.toHexWord(seg.limit) + " base=" + str.toHex(seg.base);
|
||||
|
|
@ -4455,8 +4457,8 @@ if (DEBUGGER) {
|
|||
function onCountStepComplete() {
|
||||
/*
|
||||
* We explicitly called stepCPU() with fUpdateCPU === false, because repeatedly
|
||||
* calling updateCPU() is very slow, so once the repeat count has been exhausted,
|
||||
* we need to perform a final updateCPU().
|
||||
* calling updateCPU() can be very slow, especially when fDisplayLiveRegs is true,
|
||||
* so once the repeat count has been exhausted, we must perform a final updateCPU().
|
||||
*/
|
||||
dbg.cpu.updateCPU();
|
||||
dbg.setBusy(false);
|
||||
|
|
@ -4580,10 +4582,19 @@ if (DEBUGGER) {
|
|||
this.println("ended assemble @" + this.hexAddr(this.aAddrAssemble));
|
||||
this.aAddrNextCode = this.aAddrAssemble;
|
||||
this.fAssemble = false;
|
||||
} else {
|
||||
sCmd = '?';
|
||||
}
|
||||
}
|
||||
|
||||
sCmd = sCmd.toLowerCase();
|
||||
if (this.isReady() && !this.isBusy(true) && sCmd.length > 0) {
|
||||
|
||||
/*
|
||||
* I'm going to try relaxing the !isBusy() requirement for doCommand(), to maximize our
|
||||
* ability to issue Debugger commands externally.
|
||||
*/
|
||||
if (this.isReady() /* && !this.isBusy(true) */ && sCmd.length > 0) {
|
||||
|
||||
if (this.fAssemble) {
|
||||
sCmd = "a " + this.hexAddr(this.aAddrAssemble) + " " + sCmd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ var X86 = {
|
|||
DF: 0x0400, // bit 10: Direction flag
|
||||
OF: 0x0800, // bit 11: Overflow flag
|
||||
IOPL: {
|
||||
MASK: 0x3000, // 12-13: I/O Privilege Level (always set on 8086/80186, clear on 80286)
|
||||
MASK: 0x3000, // bits 12-13: I/O Privilege Level (always set on 8086/80186, clear on 80286 reset)
|
||||
SHIFT: 12
|
||||
},
|
||||
NT: 0x4000, // bit 14: Nested Task flag, always set on 8086/80186, clear on 80286
|
||||
BIT15: 0x8000 // bit 15: reserved, always set on 8086/80186, clear otherwise
|
||||
NT: 0x4000, // bit 14: Nested Task flag (always set on 8086/80186, clear on 80286 reset)
|
||||
BIT15: 0x8000 // bit 15: reserved (always set on 8086/80186, clear otherwise)
|
||||
},
|
||||
/*
|
||||
* Machine Status Word definitions (stored in regMSW)
|
||||
|
|
@ -109,7 +109,6 @@ var X86 = {
|
|||
*/
|
||||
TSS: 0x0100,
|
||||
LDT: 0x0200,
|
||||
TSS_LDT: 0x0300,
|
||||
TSS_BUSY: 0x0300,
|
||||
GATE_CALL: 0x0400,
|
||||
GATE_TASK: 0x0500,
|
||||
|
|
@ -139,6 +138,30 @@ var X86 = {
|
|||
BASE2431: 0xff00
|
||||
}
|
||||
},
|
||||
TSS: {
|
||||
PREV_TSS: 0x00,
|
||||
CPL0_SP: 0x02, // start of values altered by task switches
|
||||
CPL0_SS: 0x04,
|
||||
CPL1_SP: 0x06,
|
||||
CPL1_SS: 0x08,
|
||||
CPL2_SP: 0x0a,
|
||||
CPL2_SS: 0x0c,
|
||||
CURR_IP: 0x0e,
|
||||
CURR_PS: 0x10,
|
||||
CURR_AX: 0x12,
|
||||
CURR_CX: 0x14,
|
||||
CURR_DX: 0x16,
|
||||
CURR_BX: 0x18,
|
||||
CURR_SP: 0x1a,
|
||||
CURR_BP: 0x1c,
|
||||
CURR_SI: 0x1e,
|
||||
CURR_DI: 0x20,
|
||||
CURR_ES: 0x22,
|
||||
CURR_CS: 0x24,
|
||||
CURR_SS: 0x26,
|
||||
CURR_DS: 0x28, // end of values altered by task switches
|
||||
CURR_LDT: 0x2a
|
||||
},
|
||||
/*
|
||||
* Processor Exception Interrupts
|
||||
*
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ X86CPU.prototype.resetRegs = function()
|
|||
*/
|
||||
this.regMSW = X86.MSW.SET;
|
||||
this.addrIDT = 0; this.addrIDTLimit = 0x03FF;
|
||||
this.descIDT = {off: 0, sel: 0, acc: 0, maskPS: -1};
|
||||
this.descIDT = {off: 0, sel: 0, acc: 0, maskPS: 0};
|
||||
this.nIOPL = 0; // this should be set before the first setPS() call
|
||||
|
||||
/*
|
||||
|
|
@ -799,11 +799,11 @@ X86CPU.prototype.resetRegs = function()
|
|||
* segment number and base physical address, respectively), but all segment registers are now defined
|
||||
* as X86Seg objects.
|
||||
*/
|
||||
this.segCS = new X86Seg(this, "CS");
|
||||
this.segDS = new X86Seg(this, "DS");
|
||||
this.segSS = new X86Seg(this, "SS");
|
||||
this.segES = new X86Seg(this, "ES");
|
||||
this.segZERO = new X86Seg(this, "ZERO");
|
||||
this.segCS = new X86Seg(this, X86Seg.ID.CODE, "CS");
|
||||
this.segDS = new X86Seg(this, X86Seg.ID.DATA, "DS");
|
||||
this.segES = new X86Seg(this, X86Seg.ID.DATA, "ES");
|
||||
this.segSS = new X86Seg(this, X86Seg.ID.STACK, "SS");
|
||||
this.segNULL = new X86Seg(this, X86Seg.ID.NULL, "NULL");
|
||||
this.setCSIP(0, 0xFFFF); // this should be called before the first setPS() call
|
||||
|
||||
/*
|
||||
|
|
@ -826,10 +826,10 @@ X86CPU.prototype.resetRegs = function()
|
|||
/*
|
||||
* TODO: Verify what the 80286 actually sets addrGDT and addrGDTLimit to on reset (or if it leaves them alone).
|
||||
*/
|
||||
this.addrGDT = 0; this.addrGDTLimit = 0xFFFF; // GDTR
|
||||
this.segLDT = new X86Seg(this, "LDT", true); // LDTR
|
||||
this.segTSS = new X86Seg(this, "TSS", true); // TR
|
||||
this.segVER = new X86Seg(this, "VER", true); // a scratch segment register for VERR and VERW instructions
|
||||
this.addrGDT = 0; this.addrGDTLimit = 0xFFFF; // GDTR
|
||||
this.segLDT = new X86Seg(this, X86Seg.ID.LDT, "LDT", true); // LDTR
|
||||
this.segTSS = new X86Seg(this, X86Seg.ID.TSS, "TSS", true); // TR
|
||||
this.segVER = new X86Seg(this, X86Seg.ID.OTHER, "VER", true); // a scratch segment register for VERR and VERW instructions
|
||||
this.setCSIP(0xFFF0, 0xF000); // in real-mode, 0xF000 defaults the CS base address to 0x0F0000
|
||||
this.segCS.setBase(0xFF0000); // which is why we must manually adjust the CS base address to 0xFF0000
|
||||
}
|
||||
|
|
@ -1180,8 +1180,8 @@ X86CPU.prototype.getSeg = function(sName)
|
|||
return this.segSS;
|
||||
case "ES":
|
||||
return this.segES;
|
||||
case "ZERO":
|
||||
return this.segZERO;
|
||||
case "NULL":
|
||||
return this.segNULL;
|
||||
default:
|
||||
/*
|
||||
* HACK: We return a fake segment register object in which only the base physical address is valid,
|
||||
|
|
@ -1192,62 +1192,6 @@ X86CPU.prototype.getSeg = function(sName)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* loadIDTEntry(nIDT)
|
||||
*
|
||||
* Updates descIDT as follows:
|
||||
*
|
||||
* descIDT.off 0x0-0x1 offset of interrupt handler
|
||||
* descIDT.sel 0x2-0x3 selector of interrupt handler
|
||||
* descIDT.acc 0x4-0x5 access word (protected-mode only)
|
||||
* descIDT.maskPS mask to apply PS after saving current PS
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} nIDT
|
||||
* @return {boolean} true if successful, false if not (all failure cases currently limited to protected mode)
|
||||
*/
|
||||
X86CPU.prototype.loadIDTEntry = function(nIDT)
|
||||
{
|
||||
var offIDT;
|
||||
|
||||
if (DEBUG) this.assert(nIDT >= 0 && nIDT < 256);
|
||||
|
||||
if (this.regMSW & X86.MSW.PE) {
|
||||
offIDT = this.addrIDT + (nIDT << 3);
|
||||
if (offIDT + 7 <= this.addrIDTLimit) {
|
||||
this.descIDT.off = this.getWord(offIDT);
|
||||
this.descIDT.sel = this.getWord(offIDT + 2);
|
||||
this.descIDT.acc = this.getWord(offIDT + 4);
|
||||
switch (this.descIDT.acc & X86.DESC.ACC.TYPE.MASK) {
|
||||
case X86.DESC.ACC.TYPE.GATE_INT:
|
||||
this.descIDT.maskPS = ~(X86.PS.NT | X86.PS.TF | X86.PS.IF);
|
||||
break;
|
||||
case X86.DESC.ACC.TYPE.GATE_TRAP:
|
||||
this.descIDT.maskPS = ~(X86.PS.NT | X86.PS.TF);
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) this.assert(false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (DEBUG) this.assert(!this.addrIDT && this.addrIDTLimit == 0x03FF);
|
||||
/*
|
||||
* Intel documentation for INT/INTO under "REAL ADDRESS MODE EXCEPTIONS" says:
|
||||
*
|
||||
* "[T]he 80286 will shut down if the SP = 1, 3, or 5 before executing the INT or INTO instruction--due to lack of stack space"
|
||||
*
|
||||
* Huh? Why would real-mode care? See http://localhost:8088/pubs/pc/reference/intel/80286/progref/#page-260
|
||||
*/
|
||||
offIDT = this.addrIDT + (nIDT << 2);
|
||||
this.descIDT.off = this.getWord(offIDT);
|
||||
this.descIDT.sel = this.getWord(offIDT + 2);
|
||||
this.descIDT.maskPS = ~(X86.PS.TF | X86.PS.IF);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* setCS(sel)
|
||||
*
|
||||
|
|
@ -1973,7 +1917,7 @@ X86CPU.prototype.modEAWordEnabled = function modEAWordEnabled(seg, off)
|
|||
X86CPU.prototype.setEAByteEnabled = function setEAByteEnabled(b)
|
||||
{
|
||||
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
|
||||
this.setByte(this.segEA.checkWrite(this.offEA, 1), b);
|
||||
this.setByte(this.segEA.checkWrite(this.offEA, 0), b);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1985,7 +1929,7 @@ X86CPU.prototype.setEAByteEnabled = function setEAByteEnabled(b)
|
|||
X86CPU.prototype.setEAWordEnabled = function setEAWordEnabled(w)
|
||||
{
|
||||
if (!EAFUNCS && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
|
||||
this.setWord(this.segEA.checkWrite(this.offEA, 2), w);
|
||||
this.setWord(this.segEA.checkWrite(this.offEA, 1), w);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2593,7 +2537,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
|
|||
/*
|
||||
* Make sure that every instruction is assessing a cycle cost, and that the cost is a net positive.
|
||||
*/
|
||||
if (this.nStepCycles >= this.nSnapCycles && !(this.opFlags & X86.OPFLAG.PREFIXES)) {
|
||||
if (this.aFlags.fComplete && this.nStepCycles >= this.nSnapCycles && !(this.opFlags & X86.OPFLAG.PREFIXES)) {
|
||||
this.println("cycle miscount: " + (this.nSnapCycles - this.nStepCycles));
|
||||
this.setIP(this.opEA - this.segCS.base);
|
||||
this.stopCPU();
|
||||
|
|
|
|||
|
|
@ -410,29 +410,6 @@ var X86Help = {
|
|||
}
|
||||
return src;
|
||||
},
|
||||
/**
|
||||
* @this {X86CPU}
|
||||
* @param {number} nIDT
|
||||
* @param {number|null|undefined} nError
|
||||
* @param {number} nCycles (in addition to the default of nOpCyclesInt)
|
||||
*/
|
||||
opHelpINT: function(nIDT, nError, nCycles) {
|
||||
/*
|
||||
* TODO: We assess the cycle cost up front, because if loadIDTEntry() fails and we end up in opHelpFault(),
|
||||
* no cost may get assessed. opHelpFault() needs to determine an appropriate cycle cost.
|
||||
*/
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesInt + nCycles;
|
||||
if (this.loadIDTEntry(nIDT)) {
|
||||
this.pushWord(this.getPS());
|
||||
this.regPS &= this.descIDT.maskPS;
|
||||
this.pushWord(this.segCS.sel);
|
||||
this.pushWord(this.regIP);
|
||||
if (nError != null) this.pushWord(nError);
|
||||
this.setCSIP(this.descIDT.off, this.descIDT.sel);
|
||||
return;
|
||||
}
|
||||
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, (nIDT << 3) | X86.ERRCODE.IDT | X86.ERRCODE.EXT, true);
|
||||
},
|
||||
/**
|
||||
* opHelpLMSW(w)
|
||||
*
|
||||
|
|
@ -459,6 +436,8 @@ var X86Help = {
|
|||
|
||||
},
|
||||
/**
|
||||
* opHelpDIVOverflow()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
opHelpDIVOverflow: function() {
|
||||
|
|
@ -468,6 +447,202 @@ var X86Help = {
|
|||
*/
|
||||
X86Help.opHelpINT.call(this, X86.EXCEPTION.DIV_ERR, null, 2);
|
||||
},
|
||||
/**
|
||||
* opHelpINT(nIDT, nError, nCycles)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} nIDT
|
||||
* @param {number|null|undefined} nError
|
||||
* @param {number} nCycles (in addition to the default of nOpCyclesInt)
|
||||
*/
|
||||
opHelpINT: function(nIDT, nError, nCycles) {
|
||||
/*
|
||||
* TODO: We assess the cycle cost up front, because otherwise, if opHelpLoadIDT() fails and we end up in
|
||||
* opHelpFault(), no cost may be assessed. Ultimately, opHelpFault() needs to determine an appropriate cost.
|
||||
*/
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesInt + nCycles;
|
||||
if (X86Help.opHelpLoadIDT.call(this, nIDT)) {
|
||||
if (this.descIDT.maskPS) {
|
||||
X86Help.opHelpPushPS.call(this, nError);
|
||||
} else {
|
||||
X86Help.opHelpSwitchTSS.call(this, this.descIDT.sel, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, (nIDT << 3) | X86.ERRCODE.IDT | X86.ERRCODE.EXT, true);
|
||||
},
|
||||
/**
|
||||
* opHelpIRET()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
opHelpIRET: function() {
|
||||
/*
|
||||
* TODO: We assess a fixed cycle cost up front, because at the moment, opHelpSwitchTSS() doesn't assess anything.
|
||||
*/
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesIRet;
|
||||
if (this.regMSW & X86.MSW.PE) {
|
||||
if (this.regPS & X86.PS.NT) {
|
||||
var addrNew = this.segTSS.base;
|
||||
var sel = this.getWord(addrNew + X86.TSS.PREV_TSS);
|
||||
X86Help.opHelpSwitchTSS.call(this, sel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.setCSIP(this.popWord(), this.popWord());
|
||||
this.setPS(this.popWord());
|
||||
if (this.cIntReturn) this.checkIntReturn(this.regEIP);
|
||||
},
|
||||
/**
|
||||
* opHelpLoadIDT(nIDT)
|
||||
*
|
||||
* Updates descIDT as follows:
|
||||
*
|
||||
* descIDT.off 0x0-0x1 offset of interrupt handler
|
||||
* descIDT.sel 0x2-0x3 selector of interrupt handler
|
||||
* descIDT.acc 0x4-0x5 access word (protected-mode only)
|
||||
* descIDT.maskPS mask to apply PS after saving current PS (0 if none; ie, task switch)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} nIDT
|
||||
* @return {boolean} true if successful, false if not (all failure cases currently limited to protected mode)
|
||||
*/
|
||||
opHelpLoadIDT: function(nIDT) {
|
||||
var offIDT;
|
||||
|
||||
if (DEBUG) this.assert(nIDT >= 0 && nIDT < 256);
|
||||
|
||||
if (this.regMSW & X86.MSW.PE) {
|
||||
offIDT = this.addrIDT + (nIDT << 3);
|
||||
if (offIDT + 7 > this.addrIDTLimit) {
|
||||
return false;
|
||||
}
|
||||
this.descIDT.off = this.getWord(offIDT);
|
||||
this.descIDT.sel = this.getWord(offIDT + 2);
|
||||
this.descIDT.acc = this.getWord(offIDT + 4);
|
||||
this.descIDT.maskPS = 0;
|
||||
|
||||
switch (this.descIDT.acc & X86.DESC.ACC.TYPE.MASK) {
|
||||
case X86.DESC.ACC.TYPE.GATE_INT:
|
||||
this.descIDT.maskPS = ~(X86.PS.NT | X86.PS.TF | X86.PS.IF);
|
||||
break;
|
||||
case X86.DESC.ACC.TYPE.GATE_TRAP:
|
||||
this.descIDT.maskPS = ~(X86.PS.NT | X86.PS.TF);
|
||||
break;
|
||||
case X86.DESC.ACC.TYPE.GATE_TASK:
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) this.assert(false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (DEBUG) this.assert(!this.addrIDT && this.addrIDTLimit == 0x03FF);
|
||||
/*
|
||||
* Intel documentation for INT/INTO under "REAL ADDRESS MODE EXCEPTIONS" says:
|
||||
*
|
||||
* "[T]he 80286 will shut down if the SP = 1, 3, or 5 before executing the INT or INTO instruction--due to lack of stack space"
|
||||
*
|
||||
* Huh? Why would real-mode care? See http://localhost:8088/pubs/pc/reference/intel/80286/progref/#page-260
|
||||
*/
|
||||
offIDT = this.addrIDT + (nIDT << 2);
|
||||
this.descIDT.off = this.getWord(offIDT);
|
||||
this.descIDT.sel = this.getWord(offIDT + 2);
|
||||
this.descIDT.maskPS = ~(X86.PS.TF | X86.PS.IF);
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* @this {X86CPU}
|
||||
* @param {number|null|undefined} nError
|
||||
*/
|
||||
opHelpPushPS: function(nError) {
|
||||
this.pushWord(this.getPS());
|
||||
this.regPS &= this.descIDT.maskPS;
|
||||
this.pushWord(this.segCS.sel);
|
||||
this.pushWord(this.regIP);
|
||||
if (nError != null) this.pushWord(nError);
|
||||
this.setCSIP(this.descIDT.off, this.descIDT.sel);
|
||||
this.nFault = -1;
|
||||
},
|
||||
/**
|
||||
* opHelpSwitchTSS(selNew, fNest)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} selNew
|
||||
* @param {boolean} [fNest]
|
||||
* @return {boolean} true if successful, false if error
|
||||
*/
|
||||
opHelpSwitchTSS: function(selNew, fNest) {
|
||||
var addrOld = this.segTSS.base;
|
||||
var cplOld = this.segCS.cpl;
|
||||
var selOld = this.segTSS.sel;
|
||||
if (!fNest) {
|
||||
if (this.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
X86Help.opHelpFault.call(this, X86.EXCEPTION.TS_FAULT, selNew, true);
|
||||
return false;
|
||||
}
|
||||
this.setWord(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc &= ~X86.DESC.ACC.TYPE.LDT);
|
||||
this.segTSS.type = X86.DESC.ACC.TYPE.TSS;
|
||||
}
|
||||
if (this.segTSS.load(selNew) == null) return false;
|
||||
var addrNew = this.segTSS.base;
|
||||
if (DEBUG) {
|
||||
this.messageDebugger((fNest? "switchTSS" : "returnTSS") + ": old TR=" + str.toHexWord(selOld) + " TSS=" + str.toHex(addrOld, 6) + ", new TR=" + str.toHexWord(selNew) + " TSS=" + str.toHex(addrNew, 6));
|
||||
}
|
||||
if (fNest) {
|
||||
if (this.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, selNew, true);
|
||||
return false;
|
||||
}
|
||||
this.setWord(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.LDT);
|
||||
this.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY;
|
||||
}
|
||||
this.setWord(addrOld + X86.TSS.CURR_IP, this.regIP);
|
||||
this.setWord(addrOld + X86.TSS.CURR_PS, this.getPS());
|
||||
this.setWord(addrOld + X86.TSS.CURR_AX, this.regAX);
|
||||
this.setWord(addrOld + X86.TSS.CURR_CX, this.regCX);
|
||||
this.setWord(addrOld + X86.TSS.CURR_DX, this.regDX);
|
||||
this.setWord(addrOld + X86.TSS.CURR_BX, this.regBX);
|
||||
this.setWord(addrOld + X86.TSS.CURR_SP, this.regSP);
|
||||
this.setWord(addrOld + X86.TSS.CURR_BP, this.regBP);
|
||||
this.setWord(addrOld + X86.TSS.CURR_SI, this.regSI);
|
||||
this.setWord(addrOld + X86.TSS.CURR_DI, this.regDI);
|
||||
this.setWord(addrOld + X86.TSS.CURR_ES, this.segES.sel);
|
||||
this.setWord(addrOld + X86.TSS.CURR_CS, this.segCS.sel);
|
||||
this.setWord(addrOld + X86.TSS.CURR_SS, this.segSS.sel);
|
||||
this.setWord(addrOld + X86.TSS.CURR_DS, this.segDS.sel);
|
||||
var offSS = X86.TSS.CURR_SS;
|
||||
var offSP = X86.TSS.CURR_SP;
|
||||
var regPS = this.getWord(addrNew + X86.TSS.CURR_PS);
|
||||
this.setPS(regPS);
|
||||
/*
|
||||
* We have to set the NT (Nested Task) flag manually, because setPS() doesn't allow it.
|
||||
*/
|
||||
this.regPS = (this.regPS & ~X86.PS.NT) | (regPS | X86.PS.NT);
|
||||
this.regAX = this.getWord(addrNew + X86.TSS.CURR_AX);
|
||||
this.regCX = this.getWord(addrNew + X86.TSS.CURR_CX);
|
||||
this.regDX = this.getWord(addrNew + X86.TSS.CURR_DX);
|
||||
this.regBX = this.getWord(addrNew + X86.TSS.CURR_BX);
|
||||
this.regBP = this.getWord(addrNew + X86.TSS.CURR_BP);
|
||||
this.regSI = this.getWord(addrNew + X86.TSS.CURR_SI);
|
||||
this.regDI = this.getWord(addrNew + X86.TSS.CURR_DI);
|
||||
this.segES.load(this.getWord(addrNew + X86.TSS.CURR_ES));
|
||||
this.segDS.load(this.getWord(addrNew + X86.TSS.CURR_DS));
|
||||
this.setCSIP(this.getWord(addrNew + X86.TSS.CURR_IP), this.getWord(addrNew + X86.TSS.CURR_CS));
|
||||
if (this.segCS.cpl < cplOld) {
|
||||
offSP = (this.segCS.cpl << 2) + X86.TSS.CPL0_SP;
|
||||
offSS = offSP + 2;
|
||||
}
|
||||
this.regSP = this.getWord(addrNew + offSP);
|
||||
this.segSS.load(this.getWord(addrNew + offSS));
|
||||
this.segLDT.load(this.getWord(addrNew + X86.TSS.CURR_LDT));
|
||||
if (fNest) {
|
||||
this.setWord(addrNew + X86.TSS.PREV_TSS, selOld);
|
||||
this.regPS |= X86.PS.NT;
|
||||
}
|
||||
this.regMSW |= X86.MSW.TS;
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* @this {X86CPU}
|
||||
* @param {number} nFault
|
||||
|
|
@ -479,7 +654,7 @@ var X86Help = {
|
|||
if (this.model >= X86.MODEL_80186) {
|
||||
if (this.nFault < 0) {
|
||||
/*
|
||||
* Single-fault (error code is passed through, and the original instruction is restartable)
|
||||
* Single-fault (error code is passed through, and the responsible instruction is restartable)
|
||||
*/
|
||||
this.setIP(this.opEA - this.segCS.base);
|
||||
fFault = true;
|
||||
|
|
@ -516,18 +691,19 @@ var X86Help = {
|
|||
/*
|
||||
* OS/2 1.0 uses an INT3 (0xCC) opcode in conjunction with an invalid IDT to trigger a triple-fault
|
||||
* reset and return to real-mode, and these resets happen quite frequently during boot; for example, OS/2
|
||||
* startup messages are displayed using INT 0x10 BIOS calls for each character, and each call requires a
|
||||
* round-trip mode switch.
|
||||
* startup messages are displayed using a series of INT 0x10 BIOS calls for each character, and each
|
||||
* series of BIOS calls requires a round-trip mode switch.
|
||||
*
|
||||
* Since we really only want to halt on "bad" faults, not "good" (ie, intentional) faults, we take
|
||||
* advantage of the fact that all 3 faults comprising the triple-fault point to the INT3 (0xCC) opcode,
|
||||
* and so whenever we see that opcode, we ignore the caller's fHalt flag.
|
||||
* and so whenever we see that opcode, we ignore the caller's fHalt flag, and suppress FAULT messages
|
||||
* unless CPU messages are also enabled.
|
||||
*/
|
||||
if (bOpcode == X86.OPCODE.INT3) {
|
||||
fHalt = false;
|
||||
bitsMessage |= Debugger.MESSAGE.CPU;
|
||||
}
|
||||
this.messageDebugger("Fault 0x" + str.toHexByte(nFault) + (nError != null? " (0x" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP) + ")", bitsMessage);
|
||||
this.messageDebugger("Fault 0x" + str.toHexByte(nFault) + (nError != null? " (0x" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (" + str.toHex(this.regEIP, 6) + ")", bitsMessage);
|
||||
if (fHalt) this.dbg.stopCPU();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,7 +199,10 @@ var X86Op0F = {
|
|||
*/
|
||||
opLTR: function(dst, src) {
|
||||
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
this.segTSS.load(dst);
|
||||
if (this.segTSS.load(dst) != null) {
|
||||
this.setWord(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.LDT);
|
||||
this.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY;
|
||||
}
|
||||
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2));
|
||||
return dst;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1758,7 +1758,7 @@ var X86OpXX = {
|
|||
*/
|
||||
opLEA: function() {
|
||||
if (EAFUNCS) this.getEAWord = this.getEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.segData = this.segStack = this.segZERO; // we can't have the EA calculation, if any, "polluted" by segment arithmetic
|
||||
this.segData = this.segStack = this.segNULL; // we can't have the EA calculation, if any, "polluted" by segment arithmetic
|
||||
X86Mods.aOpModsRegWord[this.getIPByte()].call(this, X86Help.opHelpLEA);
|
||||
if (EAFUNCS) this.getEAWord = this.getEAWordEnabled;
|
||||
},
|
||||
|
|
@ -2844,11 +2844,7 @@ var X86OpXX = {
|
|||
* op=0xCF (iret)
|
||||
*/
|
||||
opIRET: function() {
|
||||
this.setCSIP(this.popWord(), this.popWord());
|
||||
this.setPS(this.popWord());
|
||||
this.nFault = -1;
|
||||
if (this.cIntReturn) this.checkIntReturn(this.regEIP);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesIRet;
|
||||
X86Help.opHelpIRET.call(this);
|
||||
},
|
||||
/**
|
||||
* @this {X86CPU}
|
||||
|
|
|
|||
|
|
@ -43,23 +43,35 @@ if (typeof module !== 'undefined') {
|
|||
*
|
||||
* @constructor
|
||||
* @param {X86CPU} cpu
|
||||
* @param {number} id
|
||||
* @param {string} [sName] segment name
|
||||
* @param {boolean} [fProt] true if segment register used exclusively in protected-mode
|
||||
*/
|
||||
function X86Seg(cpu, sName, fProt)
|
||||
function X86Seg(cpu, id, sName, fProt)
|
||||
{
|
||||
this.cpu = cpu;
|
||||
this.id = id;
|
||||
this.sName = sName || "";
|
||||
this.sel = 0;
|
||||
this.base = 0;
|
||||
this.limit = 0xffff;
|
||||
this.acc = 0;
|
||||
this.fCode = (sName == "CS");
|
||||
this.sName = sName;
|
||||
this.addrDesc = null;
|
||||
this.cpl = 0;
|
||||
this.dpl = 0;
|
||||
this.updateAccess(fProt);
|
||||
}
|
||||
|
||||
X86Seg.ID = {
|
||||
NULL: 0, // "NULL"
|
||||
CODE: 1, // "CS"
|
||||
DATA: 2, // "DS", "ES"
|
||||
STACK: 3, // "SS"
|
||||
TSS: 4, // "TSS"
|
||||
LDT: 5, // "LDT"
|
||||
OTHER: 6 // "VER", "DBG", etc
|
||||
};
|
||||
|
||||
/*
|
||||
* Class methods
|
||||
*/
|
||||
|
|
@ -72,7 +84,7 @@ function X86Seg(cpu, sName, fProt)
|
|||
* @this {X86Seg}
|
||||
* @param {number} sel
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
* @return {number|null} base address of selected segment, or null if error
|
||||
*/
|
||||
X86Seg.loadReal = function loadReal(sel, fSuppress)
|
||||
{
|
||||
|
|
@ -101,7 +113,7 @@ X86Seg.loadReal = function loadReal(sel, fSuppress)
|
|||
* @this {X86Seg}
|
||||
* @param {number} sel
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
* @return {number|null} base address of selected segment, or null if error
|
||||
*/
|
||||
X86Seg.loadProt = function loadProt(sel, fSuppress)
|
||||
{
|
||||
|
|
@ -124,7 +136,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
|
|||
this.cpu.nStepCycles -= 15;
|
||||
return this.loadDesc8(sel, addrDesc);
|
||||
}
|
||||
return -1;
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -137,7 +149,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
|
|||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of extra bytes to check (0 or 1)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding physical address if valid, -1 if not
|
||||
* @return {number|null} corresponding physical address if valid, null if not
|
||||
*/
|
||||
X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
|
||||
{
|
||||
|
|
@ -154,7 +166,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
|
|||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of extra bytes to check (0 or 1)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding physical address if valid, -1 if not
|
||||
* @return {number|null} corresponding physical address if valid, null if not
|
||||
*/
|
||||
X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
|
||||
{
|
||||
|
|
@ -168,7 +180,7 @@ X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
|
|||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of extra bytes to check (0 or 1)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding physical address if valid, -1 if not
|
||||
* @return {number|null} corresponding physical address if valid, null if not
|
||||
*/
|
||||
X86Seg.checkReadProtEnabled = function checkReadProtEnabled(off, cb, fSuppress)
|
||||
{
|
||||
|
|
@ -185,14 +197,14 @@ X86Seg.checkReadProtEnabled = function checkReadProtEnabled(off, cb, fSuppress)
|
|||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of extra bytes to check (0 or 1)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding physical address if valid, -1 if not
|
||||
* @return {number|null} corresponding physical address if valid, null if not
|
||||
*/
|
||||
X86Seg.checkReadProtDisabled = function checkReadProtDisabled(off, cb, fSuppress)
|
||||
{
|
||||
if (!fSuppress) {
|
||||
X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
|
||||
}
|
||||
return -1;
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -202,7 +214,7 @@ X86Seg.checkReadProtDisabled = function checkReadProtDisabled(off, cb, fSuppress
|
|||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of extra bytes to check (0 or 1)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding physical address if valid, -1 if not
|
||||
* @return {number|null} corresponding physical address if valid, null if not
|
||||
*/
|
||||
X86Seg.checkWriteProtEnabled = function checkWriteProtEnabled(off, cb, fSuppress)
|
||||
{
|
||||
|
|
@ -219,14 +231,14 @@ X86Seg.checkWriteProtEnabled = function checkWriteProtEnabled(off, cb, fSuppress
|
|||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of extra bytes to check (0 or 1)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding physical address if valid, -1 if not
|
||||
* @return {number|null} corresponding physical address if valid, null if not
|
||||
*/
|
||||
X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppress)
|
||||
{
|
||||
if (!fSuppress) {
|
||||
X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
|
||||
}
|
||||
return -1;
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -245,7 +257,7 @@ X86Seg.checkWriteProtDisabled = function checkWriteProtDisabled(off, cb, fSuppre
|
|||
* @this {X86Seg}
|
||||
* @param {number} sel is the selector
|
||||
* @param {number} addrDesc is the offset
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
* @return {number} base address of selected segment
|
||||
*/
|
||||
X86Seg.prototype.loadDesc6 = function(sel, addrDesc)
|
||||
{
|
||||
|
|
@ -253,16 +265,15 @@ X86Seg.prototype.loadDesc6 = function(sel, addrDesc)
|
|||
var base = this.cpu.getWord(addrDesc + 0) | ((acc & 0xff) << 16);
|
||||
var limit = this.cpu.getWord(addrDesc + 4);
|
||||
|
||||
if (DEBUG) {
|
||||
this.cpu.messageDebugger("loadDesc6(" + this.sName + "): base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc), Debugger.MESSAGE.SEG);
|
||||
}
|
||||
|
||||
this.sel = sel;
|
||||
this.base = base;
|
||||
this.limit = limit;
|
||||
this.acc = acc & X86.DESC.ACC.MASK;
|
||||
this.addrDesc = addrDesc;
|
||||
this.updateAccess();
|
||||
|
||||
this.messageDebugger(base, limit, acc);
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
|
|
@ -281,40 +292,40 @@ X86Seg.prototype.loadDesc6 = function(sel, addrDesc)
|
|||
* @this {X86Seg}
|
||||
* @param {number} sel is the selector
|
||||
* @param {number} addrDesc is the offset
|
||||
* @return {number} base address of selected segment, or -1 if error
|
||||
* @return {number|null} base address of selected segment, or null if error
|
||||
*/
|
||||
X86Seg.prototype.loadDesc8 = function(sel, addrDesc)
|
||||
{
|
||||
var limit = this.cpu.getWord(addrDesc + X86.DESC.LIMIT.OFFSET);
|
||||
var acc = this.cpu.getWord(addrDesc + X86.DESC.ACC.OFFSET);
|
||||
var type = (acc & X86.DESC.ACC.TYPE.MASK);
|
||||
var base = this.cpu.getWord(addrDesc + X86.DESC.BASE.OFFSET) | ((acc & X86.DESC.ACC.BASE1623) << 16);
|
||||
var ext = (DEBUG? this.cpu.getWord(addrDesc + X86.DESC.EXT.OFFSET) : 0);
|
||||
|
||||
if (DEBUG) {
|
||||
var ch = (this.sName.length < 3? " " : "");
|
||||
this.cpu.messageDebugger("loadDesc8(" + this.sName + "):" + ch + " base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc) + (ext? " ext=" + str.toHexWord(ext) : ""), Debugger.MESSAGE.SEG);
|
||||
this.cpu.assert(!ext || ext == X86.DESC.EXT.AVAIL);
|
||||
}
|
||||
|
||||
/*
|
||||
* For LSL (which uses fSuppress), we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
|
||||
*/
|
||||
var accType;
|
||||
if ((acc & X86.DESC.ACC.TYPE.SEG) || (accType = (acc & X86.DESC.ACC.TYPE.MASK)) && accType <= X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
while (true) {
|
||||
/*
|
||||
* For LSL, we must support X86.DESC.ACC.TYPE.SEG as well as TSS and LDT.
|
||||
*/
|
||||
if (!(acc & X86.DESC.ACC.TYPE.SEG) && type > X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
base = null;
|
||||
break;
|
||||
}
|
||||
if (this.id == X86Seg.ID.TSS) {
|
||||
if (type != X86.DESC.ACC.TYPE.TSS && type != X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||
X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.TS_FAULT, sel, true);
|
||||
base = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.sel = sel;
|
||||
this.base = base;
|
||||
this.limit = limit;
|
||||
/*
|
||||
* Note that bits 0-7 of acc will usually contain the BASE1623 bits from the descriptor entry,
|
||||
* but it doesn't matter, because the only acc bits we pay attention to are bits 8-15; however,
|
||||
* to keep things tidy, we zero bits 0-7. Perhaps we'll find other (internal) uses for those bits.
|
||||
*/
|
||||
this.acc = acc & X86.DESC.ACC.MASK;
|
||||
this.type = acc & X86.DESC.ACC.TYPE.MASK;
|
||||
this.acc = acc;
|
||||
this.type = type;
|
||||
this.addrDesc = addrDesc;
|
||||
this.updateAccess();
|
||||
}
|
||||
else {
|
||||
base = -1;
|
||||
this.messageDebugger(base, limit, acc, ext);
|
||||
break;
|
||||
}
|
||||
return base;
|
||||
};
|
||||
|
|
@ -325,7 +336,7 @@ X86Seg.prototype.loadDesc8 = function(sel, addrDesc)
|
|||
* This is used in unusual situations where the base must be set independently; normally, the base
|
||||
* is set according to the selector provided to load(), but there are a few cases where setBase() is
|
||||
* required (eg, in resetRegs() where the 80286 wants the real-mode CS selector to be 0xF000 but the
|
||||
* CS base must be 0xFF0000, and LOADALL).
|
||||
* CS base must be 0xFF0000, and possibly LOADALL).
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} addr
|
||||
|
|
@ -346,7 +357,7 @@ X86Seg.prototype.setBase = function(addr)
|
|||
*/
|
||||
X86Seg.prototype.save = function()
|
||||
{
|
||||
return [this.sel, this.base, this.limit, this.acc, this.fCode, this.sName, this.cpl, this.dpl];
|
||||
return [this.sel, this.base, this.limit, this.acc, this.id, this.sName, this.cpl, this.dpl, this.addrDesc];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -363,14 +374,15 @@ X86Seg.prototype.restore = function(a)
|
|||
if (typeof a == "number") {
|
||||
this.load(a);
|
||||
} else {
|
||||
this.sel = a[0];
|
||||
this.base = a[1];
|
||||
this.limit = a[2];
|
||||
this.acc = a[3];
|
||||
this.fCode = a[4];
|
||||
this.sName = a[5];
|
||||
this.cpl = a[6];
|
||||
this.dpl = a[7];
|
||||
this.sel = a[0];
|
||||
this.base = a[1];
|
||||
this.limit = a[2];
|
||||
this.acc = a[3];
|
||||
this.id = a[4];
|
||||
this.sName = a[5];
|
||||
this.cpl = a[6];
|
||||
this.dpl = a[7];
|
||||
this.addrDesc = a[8];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -414,8 +426,30 @@ X86Seg.prototype.updateAccess = function(fProt)
|
|||
this.checkRead = X86Seg.checkReadReal;
|
||||
this.checkWrite = X86Seg.checkWriteReal;
|
||||
this.cpl = this.dpl = 0;
|
||||
this.addrDesc = null;
|
||||
}
|
||||
return fProt;
|
||||
};
|
||||
|
||||
/**
|
||||
* messageDebugger(base, limit, acc, ext)
|
||||
*
|
||||
* @param {number} base
|
||||
* @param {number} limit
|
||||
* @param {number} acc
|
||||
* @param {number} [ext]
|
||||
*/
|
||||
X86Seg.prototype.messageDebugger = function(base, limit, acc, ext)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (DEBUGGER) {
|
||||
var ch = (this.sName.length < 3? " " : "");
|
||||
var sDPL = " dpl=" + this.dpl;
|
||||
if (this.id == X86Seg.ID.CODE) sDPL += " cpl=" + this.cpl;
|
||||
this.cpu.messageDebugger("loadDesc(" + this.sName + "):" + ch + " base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc) + sDPL, Debugger.MESSAGE.SEG);
|
||||
}
|
||||
this.cpu.assert(!ext || ext == X86.DESC.EXT.AVAIL);
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof module !== 'undefined') module.exports = X86Seg;
|
||||
|
|
|
|||
Loading…
Reference in a new issue