Restructured ModRM decoding

This commit is contained in:
Jeff Parsons 2015-01-20 20:10:48 -08:00 committed by jeffpar
commit 418f3bd603
13 changed files with 6175 additions and 6516 deletions

File diff suppressed because it is too large Load diff

View file

@ -3323,7 +3323,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
var nIRQ = pic.nIRQBase + nIRL;
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) {
this.printMessage("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regESP, this.cpu.segSS.sel), true);
this.printMessage("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regEIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regESP, this.cpu.segSS.sel), true);
}
if (MAXDEBUG && DEBUGGER) {
this.acInterrupts[nIRQ]++;

View file

@ -1580,7 +1580,7 @@ if (DEBUGGER) {
this.aMessageRegs[asRegs[17]] = str.toHexWord(cpu.segCS.sel);
this.aMessageRegs[asRegs[18]] = str.toHexWord(cpu.segSS.sel);
this.aMessageRegs[asRegs[19]] = str.toHexWord(cpu.segDS.sel);
this.aMessageRegs[asRegs[20]] = str.toHexWord(cpu.regIP);
this.aMessageRegs[asRegs[20]] = str.toHexWord(cpu.regEIP);
};
/**
@ -1593,7 +1593,7 @@ if (DEBUGGER) {
Debugger.prototype.message = function(sMessage, fAddress)
{
if (fAddress) {
sMessage += " @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel);
sMessage += " @" + str.toHexAddr(this.cpu.regEIP, this.cpu.segCS.sel);
}
if (this.sMessagePrev && sMessage == this.sMessagePrev) return;
@ -1737,7 +1737,7 @@ if (DEBUGGER) {
if (this.traceEnabled !== undefined && this.traceEnabled[prop]) {
var trace = Debugger.TRACE[prop];
var len = (trace.size >> 2);
var s = str.toHexAddr(this.cpu.opEA - this.cpu.segCS.base, this.cpu.segCS.sel) + " " + Debugger.asIns[trace.ins] + "(" + str.toHex(dst, len) + "," + str.toHex(src, len) + "," + (flagsIn === null? "-" : str.toHexWord(flagsIn)) + ") " + str.toHex(result, len) + "," + (flagsOut === null? "-" : str.toHexWord(flagsOut));
var s = str.toHexAddr(this.cpu.opLIP - this.cpu.segCS.base, this.cpu.segCS.sel) + " " + Debugger.asIns[trace.ins] + "(" + str.toHex(dst, len) + "," + str.toHex(src, len) + "," + (flagsIn === null? "-" : str.toHexWord(flagsIn)) + ") " + str.toHex(result, len) + "," + (flagsOut === null? "-" : str.toHexWord(flagsOut));
if (!this.aTraceBuffer.length) this.aTraceBuffer = new Array(Debugger.TRACE_LIMIT);
this.aTraceBuffer[this.iTraceBuffer++] = s;
if (this.iTraceBuffer >= this.aTraceBuffer.length) {
@ -1840,7 +1840,7 @@ if (DEBUGGER) {
* is good for avoiding breakpoints, but bad for our instruction data collection if
* checks are enabled.
*/
if (this.checksEnabled()) this.checkInstruction(this.cpu.regEIP, true);
if (this.checksEnabled()) this.checkInstruction(this.cpu.regLIP, true);
}
try {
var nCyclesStep = this.cpu.stepCPU(nCycles);
@ -1893,7 +1893,7 @@ if (DEBUGGER) {
if (fRegs === undefined) fRegs = true;
if (fCompact === undefined) fCompact = true;
this.aAddrNextCode = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel);
this.aAddrNextCode = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel);
/*
* this.fProcStep used to be a simple boolean, but now it's 0 (or undefined)
* if inactive, 1 if stepping over an instruction without a register dump, or 2
@ -1979,7 +1979,7 @@ if (DEBUGGER) {
this.historyInit();
this.cInstructions = 0;
this.nCycles = 0;
this.aAddrNextCode = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel);
this.aAddrNextCode = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel);
/*
* fRunning is set by start() and cleared by stop(). In addition, we clear
* it here, so that if the CPU is reset while running, we can prevent stop()
@ -2109,7 +2109,7 @@ if (DEBUGGER) {
}
this.updateStatus(true, this.fProcStep != 2);
this.setFocus();
this.clearTempBreakpoint(this.cpu.regEIP);
this.clearTempBreakpoint(this.cpu.regLIP);
}
};
@ -2168,12 +2168,12 @@ if (DEBUGGER) {
* This is a good example of what NOT to do in a high-frequency function, and defeats
* the purpose of preallocating and preinitializing the history array in historyInit():
*
* this.aOpcodeHistory[this.iOpcodeHistory] = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel, addr);
* this.aOpcodeHistory[this.iOpcodeHistory] = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel, addr);
*
* As the name implies, newAddr() returns a new "Addr" (Array) object every time it's called.
*/
var a = this.aOpcodeHistory[this.iOpcodeHistory];
a[0] = this.cpu.regIP;
a[0] = this.cpu.regEIP;
a[1] = this.cpu.segCS.sel;
a[2] = addr;
if (++this.iOpcodeHistory == this.aOpcodeHistory.length) this.iOpcodeHistory = 0;
@ -3044,7 +3044,7 @@ if (DEBUGGER) {
" DI=" + str.toHexWord(this.cpu.regEDI) + '\n';
s += this.getSegStr(this.cpu.segDS, fProt) + ' ' + this.getSegStr(this.cpu.segES, fProt) + ' ' + this.getSegStr(this.cpu.segSS, fProt);
s += (fProt? '\n' : ' ');
s += this.getSegStr(this.cpu.segCS, fProt) + " IP=" + str.toHexWord(this.cpu.regIP) +
s += this.getSegStr(this.cpu.segCS, fProt) + " IP=" + str.toHexWord(this.cpu.regEIP) +
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") +
" PS=" + str.toHexWord(this.cpu.getPS());
@ -3174,7 +3174,7 @@ if (DEBUGGER) {
* treat "PC" as an alias for the 16-bit flags register. So for purposes of parseValue(), "PC" has been removed.
*/
case "IP":
value = this.cpu.regIP;
value = this.cpu.regEIP;
break;
default:
value = str.parseInt(sValue);
@ -4342,12 +4342,12 @@ if (DEBUGGER) {
case "CS":
// fIns = true;
this.cpu.setCS(w);
this.aAddrNextCode = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel);
this.aAddrNextCode = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel);
break;
case "IP":
// fIns = true;
this.cpu.setIP(w);
this.aAddrNextCode = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel);
this.aAddrNextCode = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel);
break;
/*
* I used to alias "PC" to "IP", until I discovered that early (perhaps ALL) versions of
@ -4420,7 +4420,7 @@ if (DEBUGGER) {
this.println((fCompact? '' : '\n') + this.getRegStr(fProt));
if (fIns) {
this.aAddrNextCode = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel);
this.aAddrNextCode = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel);
this.doUnassemble(this.hexAddr(this.aAddrNextCode));
}
};
@ -4461,7 +4461,7 @@ if (DEBUGGER) {
if (!this.fProcStep) {
var fPrefix;
var fRepeat = false;
var aAddr = this.newAddr(this.cpu.regIP, this.cpu.segCS.sel);
var aAddr = this.newAddr(this.cpu.regEIP, this.cpu.segCS.sel);
do {
fPrefix = false;
var bOpcode = this.getByte(aAddr);

View file

@ -189,7 +189,7 @@ function Memory(addr, size, fReadOnly, controller)
Memory.readNone = function readNone(off)
{
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel));
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + str.toHexAddr(this.cpu.regEIP, this.cpu.segCS.sel));
}
return 0;
};
@ -201,11 +201,12 @@ Memory.readNone = function readNone(off)
* @param {number} off
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
*/
Memory.writeNone = function writeNone(off, v) {
Memory.writeNone = function writeNone(off, v)
{
if (DEBUGGER && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to write 0x" + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
}
},
};
/**
* readByteMemory(off)

View file

@ -469,7 +469,7 @@ X86CPU.PREFETCH = {
*
* Corresponding to iPrefetchHead is addrPrefetchHead; both are incremented in lock-step.
* Whenever the prefetch queue is flushed, it's typically because a new, non-incremental
* regEIP has been set, so flushPrefetch() expects to receive that address.
* regLIP has been set, so flushPrefetch() expects to receive that address.
*
* If the prefetch queue does not contain any (or enough) bytes to satisfy a getBytePrefetch()
* or getWordPrefetch() request, we force the queue to be filled with the necessary number
@ -786,14 +786,14 @@ X86CPU.prototype.reset = function()
* CS Base = 0xFF0000 DS/ES/SS Base = 0x000000 IDT Base = 0x000000
* CS Limit = 0xFFFF DS/ES/SS Limit = 0xFFFF IDT Limit = 0x03FF
*
* We define some additional "registers", such as regEIP. which mirrors the physical address corresponding
* to CS:IP (ie, the address of the next opcode). This means that whenever segCS or regIP are explicitly
* modified, regEIP must be updated as well. So, when setting segCS or regIP, you should always use setCSIP(),
* We define some additional "registers", such as regLIP. which mirrors the linear address corresponding
* to CS:IP (ie, the address of the next opcode). This means that whenever segCS or regEIP are explicitly
* modified, regLIP must be updated as well. So, when setting segCS or regEIP, you should always use setCSIP(),
* which takes both an offset and a segment, or setIP(), whichever is appropriate; in unusual cases where only
* segCS is changing (eg, undocumented 8086 opcodes), use setCS().
*
* The other segment registers (DS, SS and ES) have similar setters (for segDS, segSS and segES), but those
* functions do not mirror any segment:offset values in the same way that regEIP mirrors CS:IP.
* functions do not mirror any segment:offset values in the same way that regLIP mirrors CS:IP.
*
* @this {X86CPU}
*/
@ -946,12 +946,38 @@ X86CPU.prototype.resetRegs = function()
this.segData = this.segDS;
this.segStack = this.segSS;
this.opFlags = this.opPrefixes = 0;
this.opSize = 2;
this.opMask = 0xffff;
this.opMaskClear = ~this.opMask;
this.addrSize = 2;
this.addrMask = 0xffff;
this.addrMaskClear = ~this.addrMask;
/*
* The following contain the (default) OPERAND size (in terms of number of bytes), and the corresponding masks
* for isolating the (src) bits of an OPERAND and clearing the (dst) bits of an OPERAND. These are reset to
* their segCS counterparts at the start of every new instruction, but are also set here for documentation purposes.
*/
this.opSize = this.segCS.opSize;
this.opMask = this.segCS.opMask;
/*
* Similarly, the following contain the (default) ADDRESS size (in terms of number of bytes), and the corresponding
* masks for isolating the (src) bits of an address and clearing the (dst) bits of an address. Like the OPERAND size
* properties, these are reset to their segCS counterparts at the start of every new instruction.
*/
this.addrSize = this.segCS.addrSize;
this.addrMask = this.segCS.addrMask;
/*
* It's also worth noting that instructions that implicitly use the stack also rely on something called STACK size,
* which is based on the BIG bit of the last descriptor loaded into SS; use the following segSS properties:
*
* segSS.addrSize (2 or 4)
* segSS.addrMask (0xffff or 0xffffffff)
*
* As there is no STACK size instruction prefix override, there's no need to propagate these segSS properties
* to separate X86CPU properties, as we do for the OPERAND size and ADDRESS size properties.
*/
/*
* The default ModRM dispatch tables; the *Word tables will be updated based on the current ADDRESS size,
* which is based foremost on segCS.addrSize, but can also be overridden by an ADDRESS size instruction prefix.
*/
this.aOpModMemByte = X86ModB.aOpModMem;
this.aOpModRegByte = X86ModB.aOpModReg;
this.aOpModGrpByte = X86ModB.aOpModGrp;
@ -969,7 +995,7 @@ X86CPU.prototype.resetRegs = function()
X86CPU.prototype.getChecksum = function()
{
var sum = (this.regEAX + this.regEBX + this.regECX + this.regEDX + this.regESP + this.regEBP + this.regESI + this.regEDI) | 0;
sum = (sum + this.regIP + this.segCS.sel + this.segDS.sel + this.segSS.sel + this.segES.sel + this.getPS()) | 0;
sum = (sum + this.regEIP + this.segCS.sel + this.segDS.sel + this.segSS.sel + this.segES.sel + this.getPS()) | 0;
return sum;
};
@ -1009,7 +1035,7 @@ X86CPU.prototype.checkIntNotify = function(nInt)
var aNotify = this.aIntNotify[nInt];
if (aNotify !== undefined) {
for (var i = 0; i < aNotify.length; i++) {
if (!aNotify[i][1].call(aNotify[i][0], this.regEIP)) {
if (!aNotify[i][1].call(aNotify[i][0], this.regLIP)) {
return false;
}
}
@ -1019,8 +1045,8 @@ X86CPU.prototype.checkIntNotify = function(nInt)
* checksEnabled() function, and therefore in fDebugCheck, so for maximum speed, we check fDebugCheck first.
*/
if (DEBUGGER && this.aFlags.fDebugCheck) {
if (this.messageEnabled(Messages.INT) && this.dbg.messageInt(nInt, this.regEIP)) {
this.addIntReturn(this.regEIP, function(cpu, nCycles) {
if (this.messageEnabled(Messages.INT) && this.dbg.messageInt(nInt, this.regLIP)) {
this.addIntReturn(this.regLIP, function(cpu, nCycles) {
return function onIntReturn(nLevel) {
cpu.dbg.messageIntReturn(nInt, nLevel, cpu.getCycles() - nCycles);
};
@ -1160,7 +1186,7 @@ X86CPU.prototype.save = function()
{
var state = new State(this);
state.set(0, [this.regEAX, this.regEBX, this.regECX, this.regEDX, this.regESP, this.regEBP, this.regESI, this.regEDI, this.nIOPL]);
state.set(1, [this.regIP, this.segCS.save(), this.segDS.save(), this.segSS.save(), this.segES.save(), this.saveProtMode(), this.getPS()]);
state.set(1, [this.regEIP, this.segCS.save(), this.segDS.save(), this.segSS.save(), this.segES.save(), this.saveProtMode(), this.getPS()]);
state.set(2, [this.segData.sName, this.segStack.sName, this.opFlags, this.opPrefixes, this.intFlags, this.regEA, this.regEAWrite]);
state.set(3, [0, this.nTotalCycles, this.getSpeed()]);
state.set(4, this.bus.saveMemory());
@ -1295,9 +1321,9 @@ X86CPU.prototype.getSeg = function(sName)
*/
X86CPU.prototype.setCS = function(sel)
{
this.regEIP = this.segCS.load(sel & 0xffff) + this.regIP;
this.regLIP = this.segCS.load(sel & 0xffff) + this.regEIP;
this.opFlags |= this.OPFLAG_NOINTR8086;
if (PREFETCH) this.flushPrefetch(this.regEIP);
if (PREFETCH) this.flushPrefetch(this.regLIP);
};
/**
@ -1321,8 +1347,6 @@ X86CPU.prototype.setDS = function(sel)
X86CPU.prototype.setSS = function(sel)
{
this.segSS.load(sel & 0xffff);
this.segSS.addrMask = (this.model >= X86.MODEL_80386 && (this.segSS.ext & X86.DESC.EXT.BIG))? 0xffffffff : 0xffff;
this.segSS.addrMaskClear = ~this.segSS.addrMask;
this.opFlags |= X86.OPFLAG.NOINTR;
};
@ -1342,9 +1366,9 @@ X86CPU.prototype.setES = function(sel)
* setIP(off)
*
* With the addition of flushPrefetch(), this function should only be called
* for non-incremental IP updates; setIP(this.regIP+1) is no longer appropriate.
* for non-incremental IP updates; setIP(this.regEIP+1) is no longer appropriate.
*
* In fact, for performance reasons, it's preferable to increment regIP yourself,
* In fact, for performance reasons, it's preferable to increment regEIP yourself,
* but you can also call advanceIP() if speed is not important.
*
* @this {X86CPU}
@ -1352,8 +1376,8 @@ X86CPU.prototype.setES = function(sel)
*/
X86CPU.prototype.setIP = function(off)
{
this.regEIP = this.segCS.base + (this.regIP = off & 0xffff);
if (PREFETCH) this.flushPrefetch(this.regEIP);
this.regLIP = this.segCS.base + (this.regEIP = off & 0xffff);
if (PREFETCH) this.flushPrefetch(this.regLIP);
};
/**
@ -1385,11 +1409,11 @@ X86CPU.prototype.setCSIP = function(off, sel, fCall)
* We break this operation into the following discrete steps (eg, set IP, load CS, and then update EIP)
* so that segCS.load(sel) has the option of modifying IP when sel refers to a gate (call, interrupt, trap, etc).
*/
this.regIP = off;
this.regEIP = off;
var base = this.segCS.load(sel);
if (base != X86.ADDR_INVALID) {
this.regEIP = base + this.regIP;
if (PREFETCH) this.flushPrefetch(this.regEIP);
this.regLIP = base + this.regEIP;
if (PREFETCH) this.flushPrefetch(this.regLIP);
return this.segCS.fStackSwitch;
}
return null;
@ -1403,7 +1427,7 @@ X86CPU.prototype.setCSIP = function(off, sel, fCall)
*/
X86CPU.prototype.advanceIP = function(inc)
{
this.regEIP = this.segCS.base + (this.regIP = (this.regIP + inc) & 0xffff);
this.regLIP = this.segCS.base + (this.regEIP = (this.regEIP + inc) & 0xffff);
if (PREFETCH) this.advancePrefetch(inc);
};
@ -2251,7 +2275,7 @@ X86CPU.prototype.fillPrefetch = function(n)
* Empty the prefetch queue.
*
* @this {X86CPU}
* @param {number} addr is a physical (non-segmented) address of the current program counter (regEIP)
* @param {number} addr is a physical (non-segmented) address of the current program counter (regLIP)
*/
X86CPU.prototype.flushPrefetch = function(addr)
{
@ -2279,7 +2303,7 @@ X86CPU.prototype.advancePrefetch = function(inc)
this.iPrefetchTail = (this.iPrefetchTail + inc) & X86CPU.PREFETCH.MASK;
this.cbPrefetchQueued -= inc;
} else {
this.flushPrefetch(this.regEIP);
this.flushPrefetch(this.regLIP);
if (MAXDEBUG) this.printMessage("advancePrefetch(" + inc + "): flushed");
}
};
@ -2292,9 +2316,9 @@ X86CPU.prototype.advancePrefetch = function(inc)
*/
X86CPU.prototype.getIPByte = function()
{
var b = (PREFETCH? this.getBytePrefetch(this.regEIP) : this.getByte(this.regEIP));
if (BACKTRACK) this.bus.updateBackTrackCode(this.regEIP, this.backTrack.btiMemLo);
this.regEIP = this.segCS.base + (this.regIP = (this.regIP + 1) & 0xffff); // this.advanceIP(1)
var b = (PREFETCH? this.getBytePrefetch(this.regLIP) : this.getByte(this.regLIP));
if (BACKTRACK) this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
this.regLIP = this.segCS.base + (this.regEIP = (this.regEIP + 1) & 0xffff); // this.advanceIP(1)
return b;
};
@ -2306,9 +2330,9 @@ X86CPU.prototype.getIPByte = function()
*/
X86CPU.prototype.getIPDisp = function()
{
var b = ((PREFETCH? this.getBytePrefetch(this.regEIP) : this.getByte(this.regEIP)) << 24) >> 24;
if (BACKTRACK) this.bus.updateBackTrackCode(this.regEIP, this.backTrack.btiMemLo);
this.regEIP = this.segCS.base + (this.regIP = (this.regIP + 1) & 0xffff); // this.advanceIP(1)
var b = ((PREFETCH? this.getBytePrefetch(this.regLIP) : this.getByte(this.regLIP)) << 24) >> 24;
if (BACKTRACK) this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
this.regLIP = this.segCS.base + (this.regEIP = (this.regEIP + 1) & 0xffff); // this.advanceIP(1)
return b & 0xffff;
};
@ -2320,12 +2344,12 @@ X86CPU.prototype.getIPDisp = function()
*/
X86CPU.prototype.getIPWord = function()
{
var w = (PREFETCH? this.getWordPrefetch(this.regEIP) : this.getWord(this.regEIP));
var w = (PREFETCH? this.getWordPrefetch(this.regLIP) : this.getWord(this.regLIP));
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regEIP, this.backTrack.btiMemLo);
this.bus.updateBackTrackCode(this.regEIP + 1, this.backTrack.btiMemHi);
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMemHi);
}
this.regEIP = this.segCS.base + (this.regIP = (this.regIP + 2) & 0xffff); // this.advanceIP(2)
this.regLIP = this.segCS.base + (this.regEIP = (this.regEIP + 2) & 0xffff); // this.advanceIP(2)
return w;
};
@ -2517,7 +2541,7 @@ X86CPU.prototype.displayStatus = function(fForce)
this.displayReg("DS", this.segDS.sel);
this.displayReg("SS", this.segSS.sel);
this.displayReg("ES", this.segES.sel);
this.displayReg("IP", this.regIP);
this.displayReg("IP", this.regEIP);
var regPS = this.getPS();
this.displayReg("PS", regPS);
this.displayReg("C", (regPS & X86.PS.CF)? 1 : 0, 1);
@ -2544,7 +2568,7 @@ X86CPU.prototype.displayStatus = function(fForce)
* stepping vs. running should never change the behavior of the simulation.
*
* Similarly, the Debugger's execution breakpoints have no involvement with the x86 breakpoint instruction
* (0xCC); the Debugger monitors changes to the regEIP register to implement its own execution breakpoints.
* (0xCC); the Debugger monitors changes to the regLIP register to implement its own execution breakpoints.
*
* As a result, the Debugger's complete independence means you can run other 8086/8088 debuggers
* (eg, DEBUG) inside the simulation without interference; you can even "debug" them with the Debugger.
@ -2618,10 +2642,16 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
if (opPrefixes) {
this.opPrefixes |= opPrefixes;
} else {
this.opEA = this.regEIP;
this.opLIP = this.regLIP;
this.regEA = this.regEAWrite = X86.ADDR_INVALID;
this.segData = this.segDS;
this.segStack = this.segSS;
this.opSize = this.segCS.opSize;
this.opMask = this.segCS.opMask;
this.addrSize = this.segCS.addrSize;
this.addrMask = this.segCS.addrMask;
this.opPrefixes = this.opFlags & X86.OPFLAG.REPEAT;
if (this.intFlags) {
if (this.checkINTR()) {
@ -2658,7 +2688,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
}
if (DEBUGGER && fDebugCheck) {
if (this.dbg.checkInstruction(this.regEIP, fDebugSkip)) {
if (this.dbg.checkInstruction(this.regLIP, fDebugSkip)) {
this.stopCPU();
break;
}
@ -2676,11 +2706,11 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
this.stopCPU();
break;
}
var t = this.regEIP + this.getCycles();
var t = this.regLIP + this.getCycles();
var n = this.aSamples[this.iSampleNext];
if (n !== -1) {
if (n !== t) {
this.println("sample deviation at index " + this.iSampleNext + ": current EIP=" + str.toHex(this.regEIP));
this.println("sample deviation at index " + this.iSampleNext + ": current EIP=" + str.toHex(this.regLIP));
this.stopCPU();
break;
}
@ -2726,7 +2756,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
*/
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.setIP(this.opLIP - this.segCS.base);
this.stopCPU();
break;
}

View file

@ -142,6 +142,40 @@ var X86Grps = {
return dst;
},
/**
* opGrpADDw(dst, src)
*
* Notes regarding carry following a 32-bit addition:
*
* The following table summarizes bit 31 of dst, src, and result, along with the expected carry bit:
*
* dst src res carry
* --- --- --- -----
* 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")
* 0 1 1 0 no
* 1 0 0 1 yes (same as the preceding "yes" case)
* 1 0 1 0 no
* 1 1 0 1 yes (since the addition of two ones must always produce a carry)
* 1 1 1 1 yes (since the addition of two ones must always produce a carry)
*
* So, we can use (dst ^ ((dst ^ src) & (src ^ res))) >> 15 to shift the proper carry bit into the conventional
* SIZE_WORD position; eg:
*
* resultValue = ((resultValue >>> 16) | (resultValue & 0xffff)) | (((dst ^ ((dst ^ src) & (src ^ resultValue))) >> 15) & SIZE_WORD);
*
* Essentially, were cramming all 32 result bits into the low 16 bits (which will effectively represent the
* zero flag), and then setting bit 16 to the effective carry flag. This transforms the zero and carry conditions
* for a DWORD computation into the corresponding conditions for a WORD computation. This will slow down 32-bit
* addition, but it allows 8-bit and 16-bit addition to remain fast. Languages that support 64-bit values in
* conjunction with bit-wise operators can omit that one-line transformation, and we can set SIZE_DWORD to a 33-bit
* value, but sadly, we cannot do that in JavaScript.
*
* Alternatively, we could store src and dst into their own result variables (eg, resultSrc and resultDst) and
* compute carry lazily, but that would affect MUCH more existing code (eg, all code that currently inspects carry
* with a single bit test). I think the DWORD-to-WORD flag conversion for 32-bit instructions that modify zero
* and/or carry) is a more reasonable first step.
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
@ -269,54 +303,22 @@ var X86Grps = {
* of updating CARRY and OVERFLOW (and possibly changing resultSize from SIZE_BYTE to SIZE_WORD, or vice versa),
* we must take care to preserve SIGN, ZERO, and the other arithmetic flags.
*
* This code originally left resultParitySign alone, but if resultSize changes, then resultParitySign needs to
* change along with it. PARITY is always based on the low 8 bits of resultParitySign, so let's focus on SIGN:
* if resultSize is changing from SIZE_BYTE to SIZE_WORD, propagating bit 7 to bit 15 of resultParitySign preserves
* SIGN; similarly, if resultSize is changing from SIZE_WORD to SIZE_BYTE, propagating bit 15 to bit 7 preserves
* SIGN--but could also alter PARITY. So we must compensate: if bit 15 differs from bit 7, then XOR resultParitySign
* with 0xC0, which will flip not only bit 7 but also bit 6, thereby preserving PARITY.
*
* resultValue merits similar consideration because of the ZERO flag: if resultSize increases, nothing needs to be
* done, because the larger size will still pick up any non-zero bits in the lower 8 bits of resultValue, but if it
* decreases, we need to OR the upper 8 bits from resultValue into the lower 8 bits.
*
* Finally, this function must set the CARRY and OVERFLOW flags according to the given result. OVERFLOW is a particular
* pain, because it has a dependency on resultParitySign; the simplest solution is to call setOF() or clearOF().
* However, in the interest of efficiency, rather than changing resultSize to match the operand size, it's easier
* to leave resultSize as-is and simply set CARRY and OVERFLOW based on the previous resultSize, since there isn't
* actually any requirement or dependency (that I can think of) that resultSize always reflect the operand size of
* the last operation. Since only 2 of the 6 arithmetic flags need to change, that tips the scales in favor of leaving
* resultSize alone.
*
* NOTE: Although I've yet to find confirmation of this for the 8086/8088, OVERFLOW is "undefined" on modern x86
* CPUs for shift counts > 1 (in fact, on modern CPUs, OVERFLOW tends to be clear in those situations). Since I set
* OVERFLOW the same way for all shift counts, my "well-defined" behavior may or may not match the 8086/8088, but
* until I see a defined behavior (or more importantly, some dependency on a different behavior), this seems good enough.
*
* UPDATE: While the desire to set resultSize to match the operand size is strong, it occurred to me later that
* it would be easier to leave resultSize as-is and simply set CARRY and OVERFLOW based on the previous resultSize,
* since there isn't actually any requirement or dependency (that I can think of) that resultSize always reflect the
* operand size of the last operation. And since only 2 of the 6 arithmetic flags need to change, that tips the scales
* in favor of leaving resultSize alone. However, the previous code that worked so hard to update resultSize is still
* here, commented out; it works, but it's less efficient.
*
* @this {X86CPU}
* @param {number} result (untruncated, so that we can inspect it for CARRY and OVERFLOW)
* @param {number} size
*/
opGrpRotateFlags: function(result, size) {
/*
var deltaSize = size - this.resultSize;
if (deltaSize) {
var bitsXOR = 0;
var bitsSign = this.resultParitySign & 0x8080;
if (deltaSize > 0) {
if (bitsSign == 0x0080 || bitsSign == 0x8000) bitsXOR = 0x8000;
} else {
if (bitsSign == 0x0080 || bitsSign == 0x8000) bitsXOR = 0x00C0;
this.resultValue |= (this.resultValue >> 8);
}
this.resultParitySign ^= bitsXOR;
this.resultSize = size;
}
this.resultValue = (this.resultValue & (size - 1)) | (result & size);
if ((result ^ (result >> 1)) & (size >> 1)) this.setOF(); else this.clearOF();
*/
this.resultValue = (this.resultValue & (this.resultSize - 1)) | ((result & size)? this.resultSize : 0);
if ((result ^ (result >> 1)) & (size >> 1)) this.setOF(); else this.clearOF();
},
@ -1110,7 +1112,7 @@ var X86Grps = {
* @return {number}
*/
opGrpCALLw: function(dst, src) {
this.pushWord(this.regIP);
this.pushWord(this.regEIP);
this.setIP(dst);
this.nStepCycles -= (this.regEA < 0? this.CYCLES.nOpCyclesCallWR : this.CYCLES.nOpCyclesCallWM);
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
@ -1154,7 +1156,7 @@ var X86Grps = {
return X86Grps.opGrpUndefined.call(this, dst, src);
}
this.setCSIP(dst, this.getWord(this.regEA + 2));
if (this.cIntReturn) this.checkIntReturn(this.regEIP);
if (this.cIntReturn) this.checkIntReturn(this.regLIP);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpDM;
if (EAFUNCS) this.setEAWord = this.setEAWordDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;

View file

@ -248,7 +248,7 @@ var X86Help = {
*
* TODO: Determine the cycle cost when a BOUND exception is triggered, over and above nOpCyclesBound.
*/
this.setIP(this.opEA - this.segCS.base);
this.setIP(this.opLIP - this.segCS.base);
X86Help.opHelpINT.call(this, X86.EXCEPTION.BOUND_ERR, null, 0);
}
if (EAFUNCS) this.setEAByte = this.setEAByteDisabled; else this.opFlags |= X86.OPFLAG.NOWRITE;
@ -490,10 +490,10 @@ var X86Help = {
*/
opHelpCALLF: function(off, sel) {
var regCS = this.segCS.sel;
var regIP = this.regIP;
var regEIP = this.regEIP;
if (this.setCSIP(off, sel, true) != null) {
this.pushWord(regCS);
this.pushWord(regIP);
this.pushWord(regEIP);
}
},
/**
@ -506,10 +506,10 @@ var X86Help = {
* @param {number} n
*/
opHelpRETF: function(n) {
var regIP = this.popWord();
var regEIP = this.popWord();
var regCS = this.popWord();
if (n) this.regESP = (this.regESP + n) & 0xffff;
if (this.setCSIP(regIP, regCS, false)) {
if (this.setCSIP(regEIP, regCS, false)) {
if (n) this.regESP = (this.regESP + n) & 0xffff;
/*
* As per Intel documentation: "If any of [the DS or ES] registers refer to segments whose DPL is
@ -529,7 +529,7 @@ var X86Help = {
this.segES.load(0);
}
}
if (n == 2 && this.cIntReturn) this.checkIntReturn(this.regEIP);
if (n == 2 && this.cIntReturn) this.checkIntReturn(this.regLIP);
},
/**
* opHelpINT(nIDT, nError, nCycles)
@ -554,14 +554,14 @@ var X86Help = {
this.segCS.fCall = true;
var regPS = this.getPS();
var regCS = this.segCS.sel;
var regIP = this.regIP;
var regEIP = this.regEIP;
var base = this.segCS.loadIDT(nIDT);
if (base != X86.ADDR_INVALID) {
this.regEIP = base + this.regIP;
if (PREFETCH) this.flushPrefetch(this.regEIP);
this.regLIP = base + this.regEIP;
if (PREFETCH) this.flushPrefetch(this.regLIP);
this.pushWord(regPS);
this.pushWord(regCS);
this.pushWord(regIP);
this.pushWord(regEIP);
if (nError != null) this.pushWord(nError);
this.nFault = -1;
}
@ -585,12 +585,12 @@ var X86Help = {
}
}
var cpl = this.segCS.cpl;
var regIP = this.popWord();
var regEIP = this.popWord();
var regCS = this.popWord();
var regPS = this.popWord();
if (this.setCSIP(regIP, regCS, false) != null) {
if (this.setCSIP(regEIP, regCS, false) != null) {
this.setPS(regPS, cpl);
if (this.cIntReturn) this.checkIntReturn(this.regEIP);
if (this.cIntReturn) this.checkIntReturn(this.regLIP);
}
},
/**
@ -599,7 +599,7 @@ var X86Help = {
* @this {X86CPU}
*/
opHelpDIVOverflow: function() {
this.setIP(this.opEA - this.segCS.base);
this.setIP(this.opLIP - this.segCS.base);
/*
* TODO: Determine the proper cycle cost.
*/
@ -619,7 +619,7 @@ var X86Help = {
{
if (!this.aFlags.fComplete) {
this.printMessage("Fault " + str.toHexByte(nFault) + " blocked by Debugger", Messages.WARN);
this.setIP(this.opEA - this.segCS.base);
this.setIP(this.opLIP - this.segCS.base);
return;
}
@ -629,7 +629,7 @@ var X86Help = {
/*
* Single-fault (error code is passed through, and the responsible instruction is restartable)
*/
this.setIP(this.opEA - this.segCS.base);
this.setIP(this.opLIP - this.segCS.base);
fDispatch = true;
} else if (this.nFault != X86.EXCEPTION.DF_FAULT) {
/*
@ -691,7 +691,7 @@ var X86Help = {
opHelpFaultMessage: function(nFault, nError, fHalt)
{
var bitsMessage = Messages.FAULT;
var bOpcode = this.bus.getByteDirect(this.regEIP);
var bOpcode = this.bus.getByteDirect(this.regLIP);
/*
* OS/2 1.0 uses an INT3 (0xCC) opcode in conjunction with an invalid IDT to trigger a triple-fault
@ -716,7 +716,7 @@ var X86Help = {
* (Power-On Self Test); we don't want to ignore those, but we don't want to halt on them either. We
* detect those faults by virtue of EIP being in the range %0F0000 to %0FFFFF.
*/
if (this.regEIP >= 0x0F0000 && this.regEIP <= 0x0FFFFF) {
if (this.regLIP >= 0x0F0000 && this.regLIP <= 0x0FFFFF) {
fHalt = false;
}
@ -729,7 +729,7 @@ var X86Help = {
}
if (this.messageEnabled(bitsMessage) || fHalt) {
var sMessage = (fHalt? '\n' : '') + "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")";
var sMessage = (fHalt? '\n' : '') + "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regEIP, this.segCS.sel) + " (%" + str.toHex(this.regLIP, 6) + ")";
var fRunning = this.aFlags.fRunning;
if (this.printMessage(sMessage, bitsMessage)) {
if (fHalt) {
@ -767,8 +767,8 @@ var X86Help = {
* @this {X86CPU}
*/
opHelpUndefined: function() {
this.setIP(this.opEA - this.segCS.base);
this.setError("Undefined opcode 0x" + str.toHexByte(this.bus.getByteDirect(this.regEIP)) + " at " + str.toHexAddr(this.regIP, this.segCS.sel));
this.setIP(this.opLIP - this.segCS.base);
this.setError("Undefined opcode 0x" + str.toHexByte(this.bus.getByteDirect(this.regLIP)) + " at " + str.toHexAddr(this.regEIP, this.segCS.sel));
this.stopCPU();
}
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -98,7 +98,7 @@ var X86OpXX = {
* op=0x05 (add AX,imm16)
*/
opADDAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpADDw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpADDw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpADDw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -174,7 +174,7 @@ var X86OpXX = {
* op=0x0D (or AX,imm16)
*/
opORAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpORw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpORw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpORw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -258,7 +258,7 @@ var X86OpXX = {
* op=0x15 (adc AX,imm16)
*/
opADCAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpADCw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpADCw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpADCw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -334,7 +334,7 @@ var X86OpXX = {
* op=0x1D (sbb AX,imm16)
*/
opSBBAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpSBBw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpSBBw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpSBBw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -410,7 +410,7 @@ var X86OpXX = {
* op=0x25 (and AX,imm16)
*/
opANDAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpANDw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpANDw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpANDw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -505,7 +505,7 @@ var X86OpXX = {
* op=0x2D (sub AX,imm16)
*/
opSUBAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpSUBw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpSUBw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpSUBw() will deduct nOpCyclesArithRR, and for all CPUs
* through the 80286, we need deduct only one more cycle.
@ -600,7 +600,7 @@ var X86OpXX = {
* op=0x35 (xor AX,imm16)
*/
opXORAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | X86Grps.opGrpXORw.call(this, this.regEAX & this.opMask, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | X86Grps.opGrpXORw.call(this, this.regEAX & this.opMask, this.getIPWord());
/*
* In the absence of any EA calculations, opGrpXORw() will deduct nOpCyclesArithRR, and for all CPUs through
* the 80286, we need deduct only one more cycle.
@ -759,7 +759,7 @@ var X86OpXX = {
*/
opINCAX: function() {
this.resultAuxOverflow = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.resultParitySign = this.regEAX + 1) & this.opMask;
this.regEAX = (this.regEAX & ~this.opMask) | (this.resultParitySign = this.regEAX + 1) & this.opMask;
this.resultValue = this.regEAX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -771,7 +771,7 @@ var X86OpXX = {
*/
opINCCX: function() {
this.resultAuxOverflow = this.regECX;
this.regECX = (this.regECX & this.opMaskClear) | (this.resultParitySign = this.regECX + 1) & this.opMask;
this.regECX = (this.regECX & ~this.opMask) | (this.resultParitySign = this.regECX + 1) & this.opMask;
this.resultValue = this.regECX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -783,7 +783,7 @@ var X86OpXX = {
*/
opINCDX: function() {
this.resultAuxOverflow = this.regEDX;
this.regEDX = (this.regEDX & this.opMaskClear) | (this.resultParitySign = this.regEDX + 1) & this.opMask;
this.regEDX = (this.regEDX & ~this.opMask) | (this.resultParitySign = this.regEDX + 1) & this.opMask;
this.resultValue = this.regEDX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -795,7 +795,7 @@ var X86OpXX = {
*/
opINCBX: function() {
this.resultAuxOverflow = this.regEBX;
this.regEBX = (this.regEBX & this.opMaskClear) | (this.resultParitySign = this.regEBX + 1) & this.opMask;
this.regEBX = (this.regEBX & ~this.opMask) | (this.resultParitySign = this.regEBX + 1) & this.opMask;
this.resultValue = this.regEBX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -807,7 +807,7 @@ var X86OpXX = {
*/
opINCSP: function() {
this.resultAuxOverflow = this.regESP;
this.regESP = (this.regESP & this.opMaskClear) | (this.resultParitySign = this.regESP + 1) & this.opMask;
this.regESP = (this.regESP & ~this.opMask) | (this.resultParitySign = this.regESP + 1) & this.opMask;
this.resultValue = this.regESP | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -819,7 +819,7 @@ var X86OpXX = {
*/
opINCBP: function() {
this.resultAuxOverflow = this.regEBP;
this.regEBP = (this.regEBP & this.opMaskClear) | (this.resultParitySign = this.regEBP + 1) & this.opMask;
this.regEBP = (this.regEBP & ~this.opMask) | (this.resultParitySign = this.regEBP + 1) & this.opMask;
this.resultValue = this.regEBP | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -831,7 +831,7 @@ var X86OpXX = {
*/
opINCSI: function() {
this.resultAuxOverflow = this.regESI;
this.regESI = (this.regESI & this.opMaskClear) | (this.resultParitySign = this.regESI + 1) & this.opMask;
this.regESI = (this.regESI & ~this.opMask) | (this.resultParitySign = this.regESI + 1) & this.opMask;
this.resultValue = this.regESI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -843,7 +843,7 @@ var X86OpXX = {
*/
opINCDI: function() {
this.resultAuxOverflow = this.regEDI;
this.regEDI = (this.regEDI & this.opMaskClear) | (this.resultParitySign = this.regEDI + 1) & this.opMask;
this.regEDI = (this.regEDI & ~this.opMask) | (this.resultParitySign = this.regEDI + 1) & this.opMask;
this.resultValue = this.regEDI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
@ -855,7 +855,7 @@ var X86OpXX = {
*/
opDECAX: function() {
this.resultAuxOverflow = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.resultParitySign = this.regEAX - 1) & this.opMask;
this.regEAX = (this.regEAX & ~this.opMask) | (this.resultParitySign = this.regEAX - 1) & this.opMask;
this.resultValue = this.regEAX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -867,7 +867,7 @@ var X86OpXX = {
*/
opDECCX: function() {
this.resultAuxOverflow = this.regECX;
this.regECX = (this.regECX & this.opMaskClear) | (this.resultParitySign = this.regECX - 1) & this.opMask;
this.regECX = (this.regECX & ~this.opMask) | (this.resultParitySign = this.regECX - 1) & this.opMask;
this.resultValue = this.regECX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -879,7 +879,7 @@ var X86OpXX = {
*/
opDECDX: function() {
this.resultAuxOverflow = this.regEDX;
this.regEDX = (this.regEDX & this.opMaskClear) | (this.resultParitySign = this.regEDX - 1) & this.opMask;
this.regEDX = (this.regEDX & ~this.opMask) | (this.resultParitySign = this.regEDX - 1) & this.opMask;
this.resultValue = this.regEDX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -891,7 +891,7 @@ var X86OpXX = {
*/
opDECBX: function() {
this.resultAuxOverflow = this.regEBX;
this.regEBX = (this.regEBX & this.opMaskClear) | (this.resultParitySign = this.regEBX - 1) & this.opMask;
this.regEBX = (this.regEBX & ~this.opMask) | (this.resultParitySign = this.regEBX - 1) & this.opMask;
this.resultValue = this.regEBX | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -903,7 +903,7 @@ var X86OpXX = {
*/
opDECSP: function() {
this.resultAuxOverflow = this.regESP;
this.regESP = (this.regESP & this.opMaskClear) | (this.resultParitySign = this.regESP - 1) & this.opMask;
this.regESP = (this.regESP & ~this.opMask) | (this.resultParitySign = this.regESP - 1) & this.opMask;
this.resultValue = this.regESP | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -915,7 +915,7 @@ var X86OpXX = {
*/
opDECBP: function() {
this.resultAuxOverflow = this.regEBP;
this.regEBP = (this.regEBP & this.opMaskClear) | (this.resultParitySign = this.regEBP - 1) & this.opMask;
this.regEBP = (this.regEBP & ~this.opMask) | (this.resultParitySign = this.regEBP - 1) & this.opMask;
this.resultValue = this.regEBP | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -927,7 +927,7 @@ var X86OpXX = {
*/
opDECSI: function() {
this.resultAuxOverflow = this.regESI;
this.regESI = (this.regESI & this.opMaskClear) | (this.resultParitySign = this.regESI - 1) & this.opMask;
this.regESI = (this.regESI & ~this.opMask) | (this.resultParitySign = this.regESI - 1) & this.opMask;
this.resultValue = this.regESI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -939,7 +939,7 @@ var X86OpXX = {
*/
opDECDI: function() {
this.resultAuxOverflow = this.regEDI;
this.regEDI = (this.regEDI & this.opMaskClear) | (this.resultParitySign = this.regEDI - 1) & this.opMask;
this.regEDI = (this.regEDI & ~this.opMask) | (this.resultParitySign = this.regEDI - 1) & this.opMask;
this.resultValue = this.regEDI | (((this.resultValue & this.resultSize)? 1 : 0) << 16);
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
@ -1032,7 +1032,7 @@ var X86OpXX = {
* op=0x58 (pop AX)
*/
opPOPAX: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | this.popWord();
this.regEAX = (this.regEAX & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1041,7 +1041,7 @@ var X86OpXX = {
* op=0x59 (pop CX)
*/
opPOPCX: function() {
this.regECX = (this.regECX & this.opMaskClear) | this.popWord();
this.regECX = (this.regECX & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1050,7 +1050,7 @@ var X86OpXX = {
* op=0x5A (pop DX)
*/
opPOPDX: function() {
this.regEDX = (this.regEDX & this.opMaskClear) | this.popWord();
this.regEDX = (this.regEDX & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1059,7 +1059,7 @@ var X86OpXX = {
* op=0x5B (pop BX)
*/
opPOPBX: function() {
this.regEBX = (this.regEBX & this.opMaskClear) | this.popWord();
this.regEBX = (this.regEBX & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1068,7 +1068,7 @@ var X86OpXX = {
* op=0x5C (pop SP)
*/
opPOPSP: function() {
this.regESP = (this.regESP & this.opMaskClear) | this.popWord();
this.regESP = (this.regESP & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1077,7 +1077,7 @@ var X86OpXX = {
* op=0x5D (pop BP)
*/
opPOPBP: function() {
this.regEBP = (this.regEBP & this.opMaskClear) | this.popWord();
this.regEBP = (this.regEBP & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1086,7 +1086,7 @@ var X86OpXX = {
* op=0x5E (pop SI)
*/
opPOPSI: function() {
this.regESI = (this.regESI & this.opMaskClear) | this.popWord();
this.regESI = (this.regESI & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1095,7 +1095,7 @@ var X86OpXX = {
* op=0x5F (pop DI)
*/
opPOPDI: function() {
this.regEDI = (this.regEDI & this.opMaskClear) | this.popWord();
this.regEDI = (this.regEDI & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
},
/**
@ -1121,14 +1121,14 @@ var X86OpXX = {
* op=0x61 (popa) (80186/80188 and up)
*/
opPOPA: function() {
this.regEDI = (this.regEDI & this.opMaskClear) | this.popWord();
this.regESI = (this.regESI & this.opMaskClear) | this.popWord();
this.regEBP = (this.regEBP & this.opMaskClear) | this.popWord();
this.regEDI = (this.regEDI & ~this.opMask) | this.popWord();
this.regESI = (this.regESI & ~this.opMask) | this.popWord();
this.regEBP = (this.regEBP & ~this.opMask) | this.popWord();
this.regESP += this.opSize;
this.regEBX = (this.regEBX & this.opMaskClear) | this.popWord();
this.regEDX = (this.regEDX & this.opMaskClear) | this.popWord();
this.regECX = (this.regECX & this.opMaskClear) | this.popWord();
this.regEAX = (this.regEAX & this.opMaskClear) | this.popWord();
this.regEBX = (this.regEBX & ~this.opMask) | this.popWord();
this.regEDX = (this.regEDX & ~this.opMask) | this.popWord();
this.regECX = (this.regECX & ~this.opMask) | this.popWord();
this.regEAX = (this.regEAX & ~this.opMask) | this.popWord();
this.nStepCycles -= this.CYCLES.nOpCyclesPopAll;
},
/**
@ -1211,10 +1211,10 @@ var X86OpXX = {
}
if (nReps--) {
var b = this.bus.checkPortInputNotify(this.regEDX, this.regEIP - nDelta - 1);
var b = this.bus.checkPortInputNotify(this.regEDX, this.regLIP - nDelta - 1);
if (BACKTRACK) this.backTrack.btiMemLo = this.backTrack.btiIO;
this.setSOByte(this.segES, this.regEDI & this.addrMask, b);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -1224,6 +1224,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -1257,13 +1258,13 @@ var X86OpXX = {
if (this.opPrefixes & X86.OPFLAG.REPEAT) nCycles = 4;
}
if (nReps--) {
var addrFrom = this.regEIP - nDelta - 1;
var addrFrom = this.regLIP - nDelta - 1;
var w = this.bus.checkPortInputNotify(this.regEDX, addrFrom);
if (BACKTRACK) this.backTrack.btiMemLo = this.backTrack.btiIO;
w |= (this.bus.checkPortInputNotify(this.regEDX, addrFrom) << 8);
if (BACKTRACK) this.backTrack.btiMemHi = this.backTrack.btiIO;
this.setSOWord(this.segES, this.regEDI & this.addrMask, w);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -1273,6 +1274,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -1305,10 +1307,10 @@ var X86OpXX = {
}
if (nReps--) {
var b = this.getSOByte(this.segDS, this.regESI & this.addrMask);
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
this.bus.checkPortOutputNotify(this.regEDX, b, this.regEIP - nDelta - 1);
this.bus.checkPortOutputNotify(this.regEDX, b, this.regLIP - nDelta - 1);
if (nReps) {
/*
* We have to back up to the prefix byte(s), not just to the string instruction,
@ -1316,6 +1318,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -1348,10 +1351,10 @@ var X86OpXX = {
}
if (nReps--) {
var w = this.getSOWord(this.segDS, this.regESI & this.addrMask);
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
var addrFrom = this.regEIP - nDelta - 1;
var addrFrom = this.regLIP - nDelta - 1;
this.bus.checkPortOutputNotify(this.regEDX, w & 0xff, addrFrom);
this.bus.checkPortOutputNotify(this.regEDX, w >> 8, addrFrom);
if (nReps) {
@ -1361,6 +1364,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -1373,7 +1377,7 @@ var X86OpXX = {
opJO: function() {
var disp = this.getIPDisp();
if (this.getOF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1387,7 +1391,7 @@ var X86OpXX = {
opJNO: function() {
var disp = this.getIPDisp();
if (!this.getOF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1401,7 +1405,7 @@ var X86OpXX = {
opJC: function() {
var disp = this.getIPDisp();
if (this.getCF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1415,7 +1419,7 @@ var X86OpXX = {
opJNC: function() {
var disp = this.getIPDisp();
if (!this.getCF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1429,7 +1433,7 @@ var X86OpXX = {
opJZ: function() {
var disp = this.getIPDisp();
if (this.getZF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1443,7 +1447,7 @@ var X86OpXX = {
opJNZ: function() {
var disp = this.getIPDisp();
if (!this.getZF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1457,7 +1461,7 @@ var X86OpXX = {
opJBE: function() {
var disp = this.getIPDisp();
if (this.getCF() || this.getZF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1471,7 +1475,7 @@ var X86OpXX = {
opJNBE: function() {
var disp = this.getIPDisp();
if (!this.getCF() && !this.getZF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1485,7 +1489,7 @@ var X86OpXX = {
opJS: function() {
var disp = this.getIPDisp();
if (this.getSF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1499,7 +1503,7 @@ var X86OpXX = {
opJNS: function() {
var disp = this.getIPDisp();
if (!this.getSF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1513,7 +1517,7 @@ var X86OpXX = {
opJP: function() {
var disp = this.getIPDisp();
if (this.getPF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1527,7 +1531,7 @@ var X86OpXX = {
opJNP: function() {
var disp = this.getIPDisp();
if (!this.getPF()) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1541,7 +1545,7 @@ var X86OpXX = {
opJL: function() {
var disp = this.getIPDisp();
if (!this.getSF() != !this.getOF()) { // jshint ignore:line
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1555,7 +1559,7 @@ var X86OpXX = {
opJNL: function() {
var disp = this.getIPDisp();
if (!this.getSF() == !this.getOF()) { // jshint ignore:line
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1569,7 +1573,7 @@ var X86OpXX = {
opJLE: function() {
var disp = this.getIPDisp();
if (this.getZF() || !this.getSF() != !this.getOF()) { // jshint ignore:line
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1583,7 +1587,7 @@ var X86OpXX = {
opJNLE: function() {
var disp = this.getIPDisp();
if (!this.getZF() && !this.getSF() == !this.getOF()) { // jshint ignore:line
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
return;
}
@ -1881,8 +1885,8 @@ var X86OpXX = {
*/
opXCHGCX: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regECX & this.opMask);
this.regECX = (this.regECX & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regECX & this.opMask);
this.regECX = (this.regECX & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1892,8 +1896,8 @@ var X86OpXX = {
*/
opXCHGDX: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regEDX & this.opMask);
this.regEDX = (this.regEDX & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regEDX & this.opMask);
this.regEDX = (this.regEDX & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1903,8 +1907,8 @@ var X86OpXX = {
*/
opXCHGBX: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regEBX & this.opMask);
this.regEBX = (this.regEBX & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regEBX & this.opMask);
this.regEBX = (this.regEBX & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1914,8 +1918,8 @@ var X86OpXX = {
*/
opXCHGSP: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regESP & this.opMask);
this.regESP = (this.regESP & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regESP & this.opMask);
this.regESP = (this.regESP & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1925,8 +1929,8 @@ var X86OpXX = {
*/
opXCHGBP: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regEBP & this.opMask);
this.regEBP = (this.regEBP & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regEBP & this.opMask);
this.regEBP = (this.regEBP & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1936,8 +1940,8 @@ var X86OpXX = {
*/
opXCHGSI: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regESI & this.opMask);
this.regESI = (this.regESI & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regESI & this.opMask);
this.regESI = (this.regESI & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1947,8 +1951,8 @@ var X86OpXX = {
*/
opXCHGDI: function() {
var temp = this.regEAX;
this.regEAX = (this.regEAX & this.opMaskClear) | (this.regEDI & this.opMask);
this.regEDI = (this.regEDI & this.opMaskClear) | (temp & this.opMask);
this.regEAX = (this.regEAX & ~this.opMask) | (this.regEDI & this.opMask);
this.regEDI = (this.regEDI & ~this.opMask) | (temp & this.opMask);
this.nStepCycles -= 3; // this form of XCHG takes 3 cycles on all CPUs
},
/**
@ -1958,7 +1962,7 @@ var X86OpXX = {
*/
opCBW: function() {
if (this.opSize == 2) {
this.regEAX = (this.regEAX & this.opMaskClear) | (((this.regEAX << 24) >> 24) & 0xffff);
this.regEAX = (this.regEAX & ~this.opMask) | (((this.regEAX << 24) >> 24) & 0xffff);
} else {
this.regEAX = ((this.regEAX << 16) >> 16);
}
@ -1971,7 +1975,7 @@ var X86OpXX = {
*/
opCWD: function() {
if (this.opSize == 2) {
this.regEDX = (this.regEDX & this.opMaskClear) | ((this.regEAX & 0x8000)? 0xffff : 0);
this.regEDX = (this.regEDX & ~this.opMask) | ((this.regEAX & 0x8000)? 0xffff : 0);
} else {
this.regEDX = (this.regEAX & 0x80000000)? 0xffffffff : 0;
}
@ -2064,7 +2068,7 @@ var X86OpXX = {
* op=0xA1 (mov AX,mem)
*/
opMOVAXDst: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | this.getEAWord(this.segData, this.getIPWord());
this.regEAX = (this.regEAX & ~this.opMask) | this.getEAWord(this.segData, this.getIPWord());
this.nStepCycles -= this.CYCLES.nOpCyclesMovAM;
},
/**
@ -2109,8 +2113,8 @@ var X86OpXX = {
if (nReps--) {
var nInc = ((this.regPS & X86.PS.DF)? -1 : 1);
this.setSOByte(this.segES, this.regEDI & this.addrMask, this.getEAByte(this.segData, this.regESI));
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + nInc) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + nInc) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2124,6 +2128,7 @@ var X86OpXX = {
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -2146,8 +2151,8 @@ var X86OpXX = {
if (nReps--) {
var nInc = ((this.regPS & X86.PS.DF)? -2 : 2);
this.setSOWord(this.segES, this.regEDI & this.addrMask, this.getEAWord(this.segData, this.regESI));
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + nInc) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + nInc) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2161,6 +2166,7 @@ var X86OpXX = {
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -2185,8 +2191,8 @@ var X86OpXX = {
var bDst = this.getEAByte(this.segData, this.regESI & this.addrMask);
var bSrc = this.modEAByte(this.segES, this.regEDI & this.addrMask);
X86Grps.opGrpCMPb.call(this, bDst, bSrc);
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + nInc) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + nInc) & this.addrMask);
/*
* NOTE: As long as we're calling opGrpCMPb(), all our cycle times must be reduced by nOpCyclesArithRM
*/
@ -2208,6 +2214,7 @@ var X86OpXX = {
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
@ -2233,8 +2240,8 @@ var X86OpXX = {
var wDst = this.getEAWord(this.segData, this.regESI & this.addrMask);
var wSrc = this.modEAWord(this.segES, this.regEDI & this.addrMask);
X86Grps.opGrpCMPw.call(this, wDst, wSrc);
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + nInc) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + nInc) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + nInc) & this.addrMask);
/*
* NOTE: As long as we're calling opGrpCMPw(), all our cycle times must be reduced by nOpCyclesArithRM
*/
@ -2256,6 +2263,7 @@ var X86OpXX = {
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
@ -2305,7 +2313,7 @@ var X86OpXX = {
* NOTE: We rely on setSOByte() to truncate regEAX to 8 bits; if setSOByte() changes, mask AX below.
*/
this.setSOByte(this.segES, this.regEDI & this.addrMask, this.regEAX);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2315,7 +2323,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regEIP == this.opEA);
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -2345,7 +2353,7 @@ var X86OpXX = {
* if you think the cycle times here are too high.
*/
this.setSOWord(this.segES, this.regEDI & this.addrMask, this.regEAX);
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2355,6 +2363,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -2376,7 +2385,7 @@ var X86OpXX = {
}
if (nReps--) {
this.regEAX = (this.regEAX & ~0xff) | this.getEAByte(this.segData, this.regESI & this.addrMask);
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2390,6 +2399,7 @@ var X86OpXX = {
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -2411,7 +2421,7 @@ var X86OpXX = {
}
if (nReps--) {
this.regEAX = this.getEAWord(this.segData, this.regESI & this.addrMask);
this.regESI = (this.regESI & this.addrMaskClear) | ((this.regESI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regESI = (this.regESI & ~this.addrMask) | ((this.regESI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.nStepCycles -= nCycles;
this.regECX -= nDelta;
if (nReps) {
@ -2425,6 +2435,7 @@ var X86OpXX = {
* string instructions with multiple prefixes.
*/
this.advanceIP(((this.opPrefixes & X86.OPFLAG.SEG)? -3 : -2));
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
}
@ -2446,7 +2457,7 @@ var X86OpXX = {
}
if (nReps--) {
X86Grps.opGrpCMPb.call(this, this.regEAX & 0xff, this.modEAByte(this.segES, this.regEDI & this.addrMask));
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -1 : 1)) & this.addrMask);
/*
* NOTE: As long as we're calling opGrpCMPb(), all our cycle times must be reduced by nOpCyclesArithRM
*/
@ -2464,6 +2475,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (EAFUNCS) this.setEAByte = this.setEAByteEnabled;
@ -2486,7 +2498,7 @@ var X86OpXX = {
}
if (nReps--) {
X86Grps.opGrpCMPw.call(this, this.regEAX, this.modEAWord(this.segES, this.regEDI & this.addrMask));
this.regEDI = (this.regEDI & this.addrMaskClear) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
this.regEDI = (this.regEDI & ~this.addrMask) | ((this.regEDI + ((this.regPS & X86.PS.DF)? -2 : 2)) & this.addrMask);
/*
* NOTE: As long as we're calling opGrpCMPb(), all our cycle times must be reduced by nOpCyclesArithRM
*/
@ -2504,6 +2516,7 @@ var X86OpXX = {
* the interrupt handler will return us to an invalid state.
*/
this.advanceIP(-2); // this instruction does not support segment overrides
this.assert(this.regLIP == this.opLIP);
this.opFlags |= X86.OPFLAG.REPEAT;
}
if (EAFUNCS) this.setEAWord = this.setEAWordEnabled;
@ -2587,7 +2600,7 @@ var X86OpXX = {
* op=0xB8 (mov AX,imm16)
*/
opMOVAXw: function() {
this.regEAX = (this.regEAX & this.opMaskClear) | this.getIPWord();
this.regEAX = (this.regEAX & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2596,7 +2609,7 @@ var X86OpXX = {
* op=0xB9 (mov CX,imm16)
*/
opMOVCXw: function() {
this.regECX = (this.regECX & this.opMaskClear) | this.getIPWord();
this.regECX = (this.regECX & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2605,7 +2618,7 @@ var X86OpXX = {
* op=0xBA (mov DX,imm16)
*/
opMOVDXw: function() {
this.regEDX = (this.regEDX & this.opMaskClear) | this.getIPWord();
this.regEDX = (this.regEDX & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2614,7 +2627,7 @@ var X86OpXX = {
* op=0xBB (mov BX,imm16)
*/
opMOVBXw: function() {
this.regEBX = (this.regEBX & this.opMaskClear) | this.getIPWord();
this.regEBX = (this.regEBX & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2623,7 +2636,7 @@ var X86OpXX = {
* op=0xBC (mov SP,imm16)
*/
opMOVSPw: function() {
this.regESP = (this.regESP & this.opMaskClear) | this.getIPWord();
this.regESP = (this.regESP & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2632,7 +2645,7 @@ var X86OpXX = {
* op=0xBD (mov BP,imm16)
*/
opMOVBPw: function() {
this.regEBP = (this.regEBP & this.opMaskClear) | this.getIPWord();
this.regEBP = (this.regEBP & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2641,7 +2654,7 @@ var X86OpXX = {
* op=0xBE (mov SI,imm16)
*/
opMOVSIw: function() {
this.regESI = (this.regESI & this.opMaskClear) | this.getIPWord();
this.regESI = (this.regESI & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2650,7 +2663,7 @@ var X86OpXX = {
* op=0xBF (mov DI,imm16)
*/
opMOVDIw: function() {
this.regEDI = (this.regEDI & this.opMaskClear) | this.getIPWord();
this.regEDI = (this.regEDI & ~this.opMask) | this.getIPWord();
this.nStepCycles -= this.CYCLES.nOpCyclesLAHF;
},
/**
@ -2677,7 +2690,7 @@ var X86OpXX = {
opRETn: function() {
var n = this.getIPWord();
this.setIP(this.popWord());
this.regESP = (this.regESP & this.addrMaskClear) | ((this.regESP + (n << (this.opSize >> 2))) & this.addrMask);
this.regESP = (this.regESP & ~this.addrMask) | ((this.regESP + (n << (this.opSize >> 2))) & this.addrMask);
this.nStepCycles -= this.CYCLES.nOpCyclesRetn;
},
/**
@ -2773,13 +2786,13 @@ var X86OpXX = {
if (bLevel > 0) {
this.nStepCycles -= (bLevel << 2) + (bLevel > 1? 1 : 0);
while (--bLevel) {
this.regEBP = (this.regEBP & this.segSS.addrMaskClear) | ((this.regEBP - this.opSize) & this.segSS.addrMask);
this.regEBP = (this.regEBP & ~this.segSS.addrMask) | ((this.regEBP - this.opSize) & this.segSS.addrMask);
this.pushWord(this.getSOWord(this.segSS, this.regEBP & this.segSS.addrMask));
}
this.pushWord(wFrame);
}
this.regEBP = (this.regEBP & this.segSS.addrMaskClear) | wFrame;
this.regESP = (this.regESP & this.segSS.addrMaskClear) | ((this.regESP - wLocal) & this.segSS.addrMask);
this.regEBP = (this.regEBP & ~this.segSS.addrMask) | wFrame;
this.regESP = (this.regESP & ~this.segSS.addrMask) | ((this.regESP - wLocal) & this.segSS.addrMask);
},
/**
* @this {X86CPU}
@ -2789,8 +2802,8 @@ var X86OpXX = {
* op=0xC9 (leave) (80186/80188 and up)
*/
opLEAVE: function() {
this.regESP = (this.regESP & this.segSS.addrMaskClear) | (this.regEBP & this.segSS.addrMask);
this.regEBP = (this.regEBP & this.opMaskClear) | (this.popWord() & this.opMask);
this.regESP = (this.regESP & ~this.segSS.addrMask) | (this.regEBP & this.segSS.addrMask);
this.regEBP = (this.regEBP & ~this.opMask) | (this.popWord() & this.opMask);
/*
* NOTE: 5 is the cycle time for the 80286; the 80186/80188 has a cycle time of 8. However, accurate cycle
* counts for the 80186/80188 is low priority. TODO: Fix this someday.
@ -2976,7 +2989,7 @@ var X86OpXX = {
opLOOPNZ: function() {
var disp = this.getIPDisp();
if ((this.regECX = (this.regECX - 1) & 0xffff) && (this.resultValue & (this.resultSize - 1))) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesLoopNZ;
return;
}
@ -2990,7 +3003,7 @@ var X86OpXX = {
opLOOPZ: function() {
var disp = this.getIPDisp();
if ((this.regECX = (this.regECX - 1) & 0xffff) && !(this.resultValue & (this.resultSize - 1))) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesLoopZ;
return;
}
@ -3004,7 +3017,7 @@ var X86OpXX = {
opLOOP: function() {
var disp = this.getIPDisp();
if ((this.regECX = (this.regECX - 1) & 0xffff)) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesLoop;
return;
}
@ -3018,7 +3031,7 @@ var X86OpXX = {
opJCXZ: function() {
var disp = this.getIPDisp();
if (!this.regECX) {
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesLoopZ;
return;
}
@ -3031,7 +3044,7 @@ var X86OpXX = {
*/
opINb: function() {
var port = this.getIPByte();
this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(port, this.regEIP - 2);
this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(port, this.regLIP - 2);
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
this.nStepCycles -= this.CYCLES.nOpCyclesInP;
},
@ -3042,9 +3055,9 @@ var X86OpXX = {
*/
opINw: function() {
var port = this.getIPByte();
this.regEAX = this.bus.checkPortInputNotify(port, this.regEIP - 2);
this.regEAX = this.bus.checkPortInputNotify(port, this.regLIP - 2);
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
this.regEAX |= (this.bus.checkPortInputNotify((port + 1) & 0xffff, this.regEIP - 2) << 8);
this.regEAX |= (this.bus.checkPortInputNotify((port + 1) & 0xffff, this.regLIP - 2) << 8);
if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiIO;
this.nStepCycles -= this.CYCLES.nOpCyclesInP;
},
@ -3055,7 +3068,7 @@ var X86OpXX = {
*/
opOUTb: function() {
var port = this.getIPByte();
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regEIP - 2);
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 2);
this.nStepCycles -= this.CYCLES.nOpCyclesOutP;
},
/**
@ -3065,8 +3078,8 @@ var X86OpXX = {
*/
opOUTw: function() {
var port = this.getIPByte();
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regEIP - 2);
this.bus.checkPortOutputNotify((port + 1) & 0xffff, this.regEAX >> 8, this.regEIP - 2);
this.bus.checkPortOutputNotify(port, this.regEAX & 0xff, this.regLIP - 2);
this.bus.checkPortOutputNotify((port + 1) & 0xffff, this.regEAX >> 8, this.regLIP - 2);
this.nStepCycles -= this.CYCLES.nOpCyclesOutP;
},
/**
@ -3076,8 +3089,8 @@ var X86OpXX = {
*/
opCALL: function() {
var disp = this.getIPWord();
this.pushWord(this.regIP);
this.setIP(this.regIP + disp);
this.pushWord(this.regEIP);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesCall;
},
/**
@ -3087,7 +3100,7 @@ var X86OpXX = {
*/
opJMP: function() {
var disp = this.getIPWord();
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmp;
},
/**
@ -3106,7 +3119,7 @@ var X86OpXX = {
*/
opJMPs: function() {
var disp = this.getIPDisp();
this.setIP(this.regIP + disp);
this.setIP(this.regEIP + disp);
this.nStepCycles -= this.CYCLES.nOpCyclesJmp;
},
/**
@ -3115,7 +3128,7 @@ var X86OpXX = {
* op=0xEC (in AL,dx)
*/
opINDXb: function() {
this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(this.regEDX, this.regEIP - 1);
this.regEAX = (this.regEAX & ~0xff) | this.bus.checkPortInputNotify(this.regEDX, this.regLIP - 1);
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
this.nStepCycles -= this.CYCLES.nOpCyclesInDX;
},
@ -3125,9 +3138,9 @@ var X86OpXX = {
* op=0xED (in AX,dx)
*/
opINDXw: function() {
this.regEAX = this.bus.checkPortInputNotify(this.regEDX, this.regEIP - 1);
this.regEAX = this.bus.checkPortInputNotify(this.regEDX, this.regLIP - 1);
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiIO;
this.regEAX |= (this.bus.checkPortInputNotify((this.regEDX + 1) & 0xffff, this.regEIP - 1) << 8);
this.regEAX |= (this.bus.checkPortInputNotify((this.regEDX + 1) & 0xffff, this.regLIP - 1) << 8);
if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiIO;
this.nStepCycles -= this.CYCLES.nOpCyclesInDX;
},
@ -3137,7 +3150,7 @@ var X86OpXX = {
* op=0xEE (out dx,AL)
*/
opOUTDXb: function() {
this.bus.checkPortOutputNotify(this.regEDX, this.regEAX & 0xff, this.regEIP - 1);
this.bus.checkPortOutputNotify(this.regEDX, this.regEAX & 0xff, this.regLIP - 1);
this.nStepCycles -= this.CYCLES.nOpCyclesOutDX;
},
/**
@ -3146,8 +3159,8 @@ var X86OpXX = {
* op=0xEF (out dx,AX)
*/
opOUTDXw: function() {
this.bus.checkPortOutputNotify(this.regEDX, this.regEAX & 0xff, this.regEIP - 1);
this.bus.checkPortOutputNotify((this.regEDX + 1) & 0xffff, this.regEAX >> 8, this.regEIP - 1);
this.bus.checkPortOutputNotify(this.regEDX, this.regEAX & 0xff, this.regLIP - 1);
this.bus.checkPortOutputNotify((this.regEDX + 1) & 0xffff, this.regEAX >> 8, this.regLIP - 1);
this.nStepCycles -= this.CYCLES.nOpCyclesOutDX;
},
/**

View file

@ -58,6 +58,7 @@ function X86Seg(cpu, id, sName, fProt)
this.base = 0;
this.limit = 0xffff;
this.acc = 0;
this.ext = 0;
this.addrDesc = X86.ADDR_INVALID;
this.cpl = 0;
this.dpl = 0;
@ -117,7 +118,8 @@ X86Seg.ID = {
X86Seg.loadReal = function loadReal(sel, fSuppress)
{
this.sel = sel;
this.ext = 0;
this.opSize = this.addrSize = 2;
this.opMask = this.addrMask = 0xffff;
return this.base = sel << 4;
};
@ -204,11 +206,10 @@ X86Seg.loadRealIDT = function loadRealIDT(nIDT)
*
* TODO: Verify that 80286 real-mode actually enforces the above. See http://localhost:8088/pubs/pc/reference/intel/80286/progref/#page-260
*/
var offIDT = cpu.addrIDT + (nIDT << 2);
cpu.regIP = cpu.getWord(offIDT);
this.sel = cpu.getWord(offIDT + 2);
var addrIDT = cpu.addrIDT + (nIDT << 2);
cpu.regEIP = cpu.getWord(addrIDT);
cpu.regPS &= ~(X86.PS.TF | X86.PS.IF);
return this.base = this.sel << 4;
return this.load(cpu.getWord(addrIDT + 2));
};
/**
@ -422,7 +423,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest)
cpu.setWord(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY);
cpu.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY;
}
cpu.setWord(addrOld + X86.TSS.TASK_IP, cpu.regIP);
cpu.setWord(addrOld + X86.TSS.TASK_IP, cpu.regEIP);
cpu.setWord(addrOld + X86.TSS.TASK_PS, cpu.getPS());
cpu.setWord(addrOld + X86.TSS.TASK_AX, cpu.regEAX);
cpu.setWord(addrOld + X86.TSS.TASK_CX, cpu.regECX);
@ -640,7 +641,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
base = X86.ADDR_INVALID;
break;
}
cpu.regIP = limit;
cpu.regEIP = limit;
if (this.cpl < cplPrev) {
if (fCall !== true) {
cpu.assert(false);
@ -846,6 +847,13 @@ X86Seg.prototype.updateMode = function(fProt)
}
this.cpl = this.sel & X86.SEL.RPL;
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
if (this.cpu.model < X86.MODEL_80386 || !(this.ext & X86.DESC.EXT.BIG)) {
this.opSize = 2;
this.opMask = 0xffff;
} else {
this.opSize = 4;
this.opMask = 0xffffffff;
}
} else {
this.load = X86Seg.loadReal;
this.loadIDT = X86Seg.loadRealIDT;
@ -854,7 +862,11 @@ X86Seg.prototype.updateMode = function(fProt)
this.limit = 0xffff;
this.cpl = this.dpl = 0;
this.addrDesc = X86.ADDR_INVALID;
this.opSize = 2;
this.opMask = 0xffff;
}
this.addrSize = this.opSize;
this.addrMask = this.opMask;
return fProt;
};