CPU function reorg

This commit is contained in:
Jeff Parsons 2015-03-05 14:41:34 -08:00 committed by jeffpar
commit 1dc0aeccd6
16 changed files with 9794 additions and 9015 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -43,15 +43,14 @@
"X86": true, "X86": true,
"X86Seg": true, "X86Seg": true,
"X86CPU": true, "X86CPU": true,
"X86Grps": true, "X86Func": true,
"X86Help": true, "X86OpXX": true,
"X86Op0F": true,
"X86ModB": true, "X86ModB": true,
"X86ModW": true, "X86ModW": true,
"X86ModB32": true, "X86ModB32": true,
"X86ModW32": true, "X86ModW32": true,
"X86ModSIB": true, "X86ModSIB": true,
"X86OpXX": true,
"X86Op0F": true,
"str": true, "str": true,
"usr": true, "usr": true,
"web": true, "web": true,

View file

@ -11,7 +11,7 @@ So it's best to refer to these files generically as "modules", and more specific
whenever they implement a specific device (or set of devices, in the case of [*ChipSet*](/docs/pcjs/chipset/)). whenever they implement a specific device (or set of devices, in the case of [*ChipSet*](/docs/pcjs/chipset/)).
Examples of non-device modules include UI modules like [panel.js](panel.js) and [debugger.js](debugger.js), Examples of non-device modules include UI modules like [panel.js](panel.js) and [debugger.js](debugger.js),
and sub-modules like [x86opxx.js](x86opxx.js) and [x86help.js](x86help.js) that separate the CPU functionality and sub-modules like [x86opxx.js](x86opxx.js) and [x86func.js](x86func.js) that separate the CPU functionality
of [x86.js](x86.js) into more manageable pieces. of [x86.js](x86.js) into more manageable pieces.
These modules should always be loaded or compiled in the order listed by the *pcJSFiles* property in These modules should always be loaded or compiled in the order listed by the *pcJSFiles* property in
@ -37,8 +37,7 @@ At the time of this writing, the order is:
* [pcjs/x86.js](x86.js) * [pcjs/x86.js](x86.js)
* [pcjs/x86seg.js](x86seg.js) * [pcjs/x86seg.js](x86seg.js)
* [pcjs/x86cpu.js](x86cpu.js) * [pcjs/x86cpu.js](x86cpu.js)
* [pcjs/x86grps.js](x86grps.js) * [pcjs/x86func.js](x86func.js)
* [pcjs/x86help.js](x86help.js)
* [pcjs/x86modb.js](x86modb.js) * [pcjs/x86modb.js](x86modb.js)
* [pcjs/x86modw.js](x86modw.js) * [pcjs/x86modw.js](x86modw.js)
* [pcjs/x86modb16.js](x86modb16.js) * [pcjs/x86modb16.js](x86modb16.js)

View file

@ -2541,9 +2541,7 @@ if (DEBUGGER) {
* getByte(aAddr, inc) * getByte(aAddr, inc)
* *
* getByte() should be used for all Debugger memory reads (eg, doDump, doUnassemble), to ensure * getByte() should be used for all Debugger memory reads (eg, doDump, doUnassemble), to ensure
* all notification handlers are bypassed for physical addresses; for segmented addresses, we must * all notification handlers are bypassed for physical addresses.
* use the CPU's X86Seg load() logic, but we don't call the CPU's getSOByte() or getByte() functions,
* to avoid triggering any memory read notifications.
* *
* @this {Debugger} * @this {Debugger}
* @param {Array} aAddr * @param {Array} aAddr
@ -2689,7 +2687,7 @@ if (DEBUGGER) {
* aAddr[2] = this.getAddr(aAddr); * aAddr[2] = this.getAddr(aAddr);
* *
* The way to create a real-mode breakpoint that will break regardless of mode is to * The way to create a real-mode breakpoint that will break regardless of mode is to
* use the physical address of the real-mode memory location. * use the physical address of the real-mode memory location instead.
*/ */
aAddr[3] = fTemp; aAddr[3] = fTemp;
aBreak.push(aAddr); aBreak.push(aAddr);
@ -4670,7 +4668,7 @@ if (DEBUGGER) {
fUnknown = false; fUnknown = false;
switch(sRegMatch){ switch(sRegMatch){
case "MS": case "MS":
X86Help.opHelpLMSW.call(this.cpu, w); this.cpu.setMSW(w);
break; break;
case "TR": case "TR":
this.cpu.segTSS.load(w); this.cpu.segTSS.load(w);

View file

@ -240,8 +240,8 @@ var X86 = {
MASK: 0xfff8 // index of corresponding entry in GDT, LDT or IDT MASK: 0xfff8 // index of corresponding entry in GDT, LDT or IDT
}, },
RESULT: { RESULT: {
SIZE_BYTE: 0x00100, // mask for byte arithmetic instructions (after subtracting 1) SIZE_BYTE: 0x00100,
SIZE_WORD: 0x10000, // mask for word arithmetic instructions (after subtracting 1) SIZE_WORD: 0x10000,
AUXOVF_AF: 0x00010, AUXOVF_AF: 0x00010,
AUXOVF_OF: 0x08080, AUXOVF_OF: 0x08080,
AUXOVF_CF: 0x10100 AUXOVF_CF: 0x10100

View file

@ -42,12 +42,11 @@ if (typeof module !== 'undefined') {
var CPU = require("./cpu"); var CPU = require("./cpu");
var X86 = require("./x86"); var X86 = require("./x86");
var X86Seg = require("./x86seg"); var X86Seg = require("./x86seg");
var X86Grps = require("./x86grps"); var X86Func = require("./x86func");
var X86Help = require("./x86help");
var X86ModB = require("./x86modb");
var X86ModW = require("./x86modw");
var X86OpXX = require("./x86opxx"); var X86OpXX = require("./x86opxx");
var X86Op0F = require("./x86op0f"); var X86Op0F = require("./x86op0f");
var X86ModB = require("./x86modb");
var X86ModW = require("./x86modw");
} }
if (I386) { if (I386) {
@ -482,7 +481,7 @@ X86CPU.PREFETCH = {
* regLIP 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() * 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 * or getShortPrefetch() request, we force the queue to be filled with the necessary number
* of bytes first. * of bytes first.
* *
* @this {X86CPU} * @this {X86CPU}
@ -706,10 +705,10 @@ X86CPU.prototype.initProcessor = function()
*/ */
this.CYCLES = (this.model >= X86.MODEL_80286? X86CPU.CYCLES_80286 : X86CPU.CYCLES_8088); this.CYCLES = (this.model >= X86.MODEL_80286? X86CPU.CYCLES_80286 : X86CPU.CYCLES_8088);
this.aOps = X86OpXX.aOps; this.aOps = X86.aOps;
this.aOpGrp4b = X86Grps.aOpGrp4b; this.aOpGrp4b = X86.aOpGrp4b;
this.aOpGrp4w = X86Grps.aOpGrp4w; this.aOpGrp4w = X86.aOpGrp4w;
this.aOpGrp6 = X86Op0F.aOpGrp6Real; // setProtMode() will ensure that aOpGrp6 is switched this.aOpGrp6 = X86.aOpGrp6Real; // setProtMode() will ensure that aOpGrp6 is switched
if (this.model >= X86.MODEL_80186) { if (this.model >= X86.MODEL_80186) {
/* /*
@ -720,34 +719,34 @@ X86CPU.prototype.initProcessor = function()
* Instruction handlers that contain "hard-coded" 80286 cycle times include: opINSb, opINSw, opOUTSb, * Instruction handlers that contain "hard-coded" 80286 cycle times include: opINSb, opINSw, opOUTSb,
* opOUTSw, opENTER, and opLEAVE. * opOUTSw, opENTER, and opLEAVE.
*/ */
this.aOps = X86OpXX.aOps.slice(); // make copies of aOps and others before modifying them this.aOps = X86.aOps.slice(); // make copies of aOps and others before modifying them
this.aOpGrp4b = X86Grps.aOpGrp4b.slice(); this.aOpGrp4b = X86.aOpGrp4b.slice();
this.aOpGrp4w = X86Grps.aOpGrp4w.slice(); this.aOpGrp4w = X86.aOpGrp4w.slice();
this.nShiftCountMask = 0x1f; // on newer processors, all shift counts are MOD 32 this.nShiftCountMask = 0x1f; // on newer processors, all shift counts are MOD 32
this.aOps[0x0F] = X86Help.opHelpInvalid; this.aOps[0x0F] = X86.opInvalid;
this.aOps[X86.OPCODE.PUSHA] = X86OpXX.opPUSHA; this.aOps[X86.OPCODE.PUSHA] = X86.opPUSHA;
this.aOps[X86.OPCODE.POPA] = X86OpXX.opPOPA; this.aOps[X86.OPCODE.POPA] = X86.opPOPA;
this.aOps[X86.OPCODE.BOUND] = X86OpXX.opBOUND; this.aOps[X86.OPCODE.BOUND] = X86.opBOUND;
this.aOps[X86.OPCODE.ARPL] = X86Help.opHelpInvalid; this.aOps[X86.OPCODE.ARPL] = X86.opInvalid;
this.aOps[X86.OPCODE.FS] = X86Help.opHelpInvalid; this.aOps[X86.OPCODE.FS] = X86.opInvalid;
this.aOps[X86.OPCODE.GS] = X86Help.opHelpInvalid; this.aOps[X86.OPCODE.GS] = X86.opInvalid;
this.aOps[X86.OPCODE.OS] = X86Help.opHelpInvalid; this.aOps[X86.OPCODE.OS] = X86.opInvalid;
this.aOps[X86.OPCODE.AS] = X86Help.opHelpInvalid; this.aOps[X86.OPCODE.AS] = X86.opInvalid;
this.aOps[X86.OPCODE.PUSH16] = X86OpXX.opPUSH16; this.aOps[X86.OPCODE.PUSH16] = X86.opPUSH16;
this.aOps[X86.OPCODE.IMUL16] = X86OpXX.opIMUL16; this.aOps[X86.OPCODE.IMUL16] = X86.opIMUL16;
this.aOps[X86.OPCODE.PUSH8] = X86OpXX.opPUSH8; this.aOps[X86.OPCODE.PUSH8] = X86.opPUSH8;
this.aOps[X86.OPCODE.IMUL8] = X86OpXX.opIMUL8; this.aOps[X86.OPCODE.IMUL8] = X86.opIMUL8;
this.aOps[X86.OPCODE.INSB] = X86OpXX.opINSb; this.aOps[X86.OPCODE.INSB] = X86.opINSb;
this.aOps[X86.OPCODE.INSW] = X86OpXX.opINSw; this.aOps[X86.OPCODE.INSW] = X86.opINSw;
this.aOps[X86.OPCODE.OUTSB] = X86OpXX.opOUTSb; this.aOps[X86.OPCODE.OUTSB] = X86.opOUTSb;
this.aOps[X86.OPCODE.OUTSW] = X86OpXX.opOUTSw; this.aOps[X86.OPCODE.OUTSW] = X86.opOUTSw;
this.aOps[0xC0] = X86OpXX.opGrp2bi; this.aOps[0xC0] = X86.opGrp2bi;
this.aOps[0xC1] = X86OpXX.opGrp2wi; this.aOps[0xC1] = X86.opGrp2wi;
this.aOps[X86.OPCODE.ENTER] = X86OpXX.opENTER; this.aOps[X86.OPCODE.ENTER] = X86.opENTER;
this.aOps[X86.OPCODE.LEAVE] = X86OpXX.opLEAVE; this.aOps[X86.OPCODE.LEAVE] = X86.opLEAVE;
this.aOps[0xF1] = X86OpXX.opINT1; this.aOps[0xF1] = X86.opINT1;
this.aOpGrp4b[0x07] = X86Grps.opGrpInvalid; this.aOpGrp4b[0x07] = X86.fnGRPInvalid;
this.aOpGrp4w[0x07] = X86Grps.opGrpInvalid; this.aOpGrp4w[0x07] = X86.fnGRPInvalid;
if (this.model >= X86.MODEL_80286) { if (this.model >= X86.MODEL_80286) {
@ -756,19 +755,23 @@ X86CPU.prototype.initProcessor = function()
this.OPFLAG_NOINTR8086 = 0; // used with instructions that should *not* set NOINTR on an 80286 (eg, non-SS segment loads) this.OPFLAG_NOINTR8086 = 0; // used with instructions that should *not* set NOINTR on an 80286 (eg, non-SS segment loads)
this.aOps0F = X86Op0F.aOps0F; this.aOps0F = X86.aOps0F;
this.aOps[0x0F] = X86OpXX.op0F; this.aOps[0x0F] = X86.op0F;
this.aOps[X86.OPCODE.ARPL] = X86OpXX.opARPL; this.aOps[X86.OPCODE.ARPL] = X86.opARPL;
this.aOps[X86.OPCODE.PUSHSP] = X86OpXX.opPUSHSP; this.aOps[X86.OPCODE.PUSHSP] = X86.opPUSHSP;
if (I386 && this.model >= X86.MODEL_80386) { if (I386 && this.model >= X86.MODEL_80386) {
this.aOps[X86.OPCODE.FS] = X86OpXX.opFS; this.aOps[X86.OPCODE.FS] = X86.opFS;
this.aOps[X86.OPCODE.GS] = X86OpXX.opGS; this.aOps[X86.OPCODE.GS] = X86.opGS;
this.aOps[X86.OPCODE.OS] = X86OpXX.opOS; this.aOps[X86.OPCODE.OS] = X86.opOS;
this.aOps[X86.OPCODE.AS] = X86OpXX.opAS; this.aOps[X86.OPCODE.AS] = X86.opAS;
this.aOps0F = X86Op0F.aOps0F.slice(); this.aOps0F = X86.aOps0F.slice();
this.aOps0F[0x20] = X86Op0F.opMOVrcr; this.aOps0F[0x20] = X86.opMOVrcr;
this.aOps0F[0x22] = X86Op0F.opMOVcrr; this.aOps0F[0x22] = X86.opMOVcrr;
this.aOps = this.aOps.concat(this.aOps);
for (var bOpcode in X86.aOpsD) {
this.aOps[parseInt(bOpcode, 10) + 256] = X86.aOpsD[bOpcode];
}
} }
} }
} }
@ -896,7 +899,7 @@ X86CPU.prototype.resetRegs = function()
/* /*
* NOTE: Even though the 8086 doesn't have CR0 (aka MSW) and IDTR, we initialize them for ALL CPUs, so * NOTE: Even though the 8086 doesn't have CR0 (aka MSW) and IDTR, we initialize them for ALL CPUs, so
* that functions like X86Help.opHelpINT() can use the same code for both. The 8086/8088 have no direct * that functions like X86.fnINT() can use the same code for both. The 8086/8088 have no direct
* way of accessing or changing them, so this internal change should be perfectly safe for those processors. * way of accessing or changing them, so this internal change should be perfectly safe for those processors.
*/ */
this.regCR0 = X86.CR0.MSW.ON; this.regCR0 = X86.CR0.MSW.ON;
@ -1075,6 +1078,7 @@ X86CPU.prototype.setAddrSize = function()
X86CPU.prototype.setDataSize = function() X86CPU.prototype.setDataSize = function()
{ {
this.opMem = this.aaOpMem[this.dataSize]; this.opMem = this.aaOpMem[this.dataSize];
this.bOpcodeBias = (this.dataSize == 4? 256 : 0);
}; };
/** /**
@ -1091,6 +1095,7 @@ X86CPU.prototype.setSizes = function()
*/ */
this.addrSize = this.segCS.addrSize; this.addrSize = this.segCS.addrSize;
this.addrMask = this.segCS.addrMask; this.addrMask = this.segCS.addrMask;
/* /*
* It's also worth noting that instructions that implicitly use the stack also rely on STACK size, * It's also worth noting that instructions that implicitly use the stack also rely on STACK size,
* which is based on the BIG bit of the last descriptor loaded into SS; use the following segSS properties: * which is based on the BIG bit of the last descriptor loaded into SS; use the following segSS properties:
@ -1255,7 +1260,7 @@ X86CPU.prototype.setProtMode = function(fProt)
if (!fProt) { if (!fProt) {
this.printMessage("returning to real-mode"); this.printMessage("returning to real-mode");
} }
this.aOpGrp6 = (fProt? X86Op0F.aOpGrp6Prot : X86Op0F.aOpGrp6Real); this.aOpGrp6 = (fProt? X86.aOpGrp6Prot : X86.aOpGrp6Real);
this.segCS.updateMode(fProt); this.segCS.updateMode(fProt);
this.segDS.updateMode(fProt); this.segDS.updateMode(fProt);
this.segSS.updateMode(fProt); this.segSS.updateMode(fProt);
@ -1718,6 +1723,38 @@ X86CPU.prototype.setSP = function(off)
/** /**
* getCF() * getCF()
* *
* 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 could use (dst ^ ((dst ^ src) & (src ^ res))) >>> 15 to shift the calculated carry bit (bit 31)
* into the conventional SIZE_WORD position (bit 16); eg:
*
* resultZeroCarry = ((resultZeroCarry >>> 16) | (resultZeroCarry & 0xffff)) | (((dst ^ ((dst ^ src) & (src ^ resultZeroCarry))) >>> 15) & SIZE_WORD);
*
* Essentially, wed be cramming all 32 result bits into the low 16 bits (which would 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 would slow down 32-bit
* addition, but it would allow 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, allowing us to set SIZE_WORD to a
* 33-bit value, but sadly, we cannot do that in JavaScript.
*
* Alternatively, we could store the src and dst operands 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} * @this {X86CPU}
* @return {number} * @return {number}
*/ */
@ -2013,6 +2050,32 @@ X86CPU.prototype.getPS = function()
return (this.regPS & ~X86.PS.INDIRECT) | (this.getCF() | this.getPF() | this.getAF() | this.getZF() | this.getSF() | this.getOF()); return (this.regPS & ~X86.PS.INDIRECT) | (this.getCF() | this.getPF() | this.getAF() | this.getZF() | this.getSF() | this.getOF());
}; };
/**
* setMSW(w)
*
* Factored out of x86op0f.js, since both opLMSW and opLOADALL are capable of setting a new MSW.
* The caller is responsible for assessing the appropriate cycle cost.
*
* @this {X86CPU}
* @param {number} w
*/
X86CPU.prototype.setMSW = function(w)
{
/*
* This instruction is always allowed to set MSW.PE, but it cannot clear MSW.PE once set;
* therefore, we always OR the previous value of MSW.PE into the new value before loading.
*/
w |= (this.regCR0 & X86.CR0.MSW.PE) | X86.CR0.MSW.ON;
this.regCR0 = (this.regCR0 & ~X86.CR0.MSW.MASK) | (w & X86.CR0.MSW.MASK);
/*
* Since the 80286 cannot return to real-mode via this instruction, the only transition we
* must worry about is to protected-mode. And don't worry, there's no harm calling setProtMode()
* if the CPU is already in protected-mode (we could certainly optimize the call out in that
* case, but this instruction isn't used frequently enough to warrant it).
*/
if (this.regCR0 & X86.CR0.MSW.PE) this.setProtMode(true);
};
/** /**
* setPS(regPS) * setPS(regPS)
* *
@ -2598,9 +2661,9 @@ X86CPU.prototype.getBytePrefetch = function(addr)
}; };
/** /**
* getWordPrefetch(addr) * getShortPrefetch(addr)
* *
* Return the next word from the prefetch queue. There are 3 cases to consider: * Return the next short from the prefetch queue. There are 3 cases to consider:
* *
* 1) Both bytes have been prefetched; no bytes need be fetched from memory * 1) Both bytes have been prefetched; no bytes need be fetched from memory
* 2) Only the low byte has been prefetched; the high byte must be fetched from memory * 2) Only the low byte has been prefetched; the high byte must be fetched from memory
@ -2611,11 +2674,38 @@ X86CPU.prototype.getBytePrefetch = function(addr)
* *
* @this {X86CPU} * @this {X86CPU}
* @param {number} addr is a physical (non-segmented) address * @param {number} addr is a physical (non-segmented) address
* @return {number} word (16-bit) value at that address * @return {number} short (16-bit) value at that address
*/
X86CPU.prototype.getShortPrefetch = function(addr)
{
return this.getBytePrefetch(addr) | (this.getBytePrefetch(addr + 1) << 8);
};
/**
* getLongPrefetch(addr)
*
* Return the next long from the prefetch queue. Similar to getShortPrefetch(), we take the
* easy way out and call getShortPrefetch() twice.
*
* @this {X86CPU}
* @param {number} addr is a physical (non-segmented) address
* @return {number} long (32-bit) value at that address
*/
X86CPU.prototype.getLongPrefetch = function(addr)
{
return this.getShortPrefetch(addr) | (this.getShortPrefetch(addr + 2) << 16);
};
/**
* getWordPrefetch(addr)
*
* @this {X86CPU}
* @param {number} addr is a physical (non-segmented) address
* @return {number} short (16-bit) or long (32-bit value as appropriate
*/ */
X86CPU.prototype.getWordPrefetch = function(addr) X86CPU.prototype.getWordPrefetch = function(addr)
{ {
return this.getBytePrefetch(addr) | (this.getBytePrefetch(addr + 1) << 8); return (I386 && this.addrSize == 4? this.getLongPrefetch(addr) : this.getShortPrefetch(addr));
}; };
/** /**
@ -2716,6 +2806,46 @@ X86CPU.prototype.getIPDisp = function()
return w & (I386? this.addrMask : 0xffff); return w & (I386? this.addrMask : 0xffff);
}; };
/**
* getIPShort()
*
* @this {X86CPU}
* @return {number} short at the current IP; IP advanced by 2
*/
X86CPU.prototype.getIPShort = function()
{
var w = (PREFETCH? this.getShortPrefetch(this.regLIP) : this.getShort(this.regLIP));
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMemHi);
}
this.regLIP += 2;
if (this.regLIP > this.regLIPLimit) {
this.setIP(this.regLIP - this.segCS.base);
}
return w;
};
/**
* getIPLong()
*
* @this {X86CPU}
* @return {number} long at the current IP; IP advanced by 4
*/
X86CPU.prototype.getIPLong = function()
{
var l = (PREFETCH? this.getLongPrefetch(this.regLIP) : this.getLong(this.regLIP));
if (BACKTRACK) {
this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
this.bus.updateBackTrackCode(this.regLIP + 1, this.backTrack.btiMemHi);
}
this.regLIP += 4;
if (this.regLIP > this.regLIPLimit) {
this.setIP(this.regLIP - this.segCS.base);
}
return l;
};
/** /**
* getIPWord() * getIPWord()
* *
@ -2868,14 +2998,14 @@ X86CPU.prototype.checkINTR = function()
this.intFlags &= ~X86.INTFLAG.INTR; this.intFlags &= ~X86.INTFLAG.INTR;
if (nIDT >= 0) { if (nIDT >= 0) {
this.intFlags &= ~X86.INTFLAG.HALT; this.intFlags &= ~X86.INTFLAG.HALT;
X86Help.opHelpINT.call(this, nIDT, null, 11); X86.fnINT.call(this, nIDT, null, 11);
return true; return true;
} }
} }
} }
else if ((this.intFlags & X86.INTFLAG.TRAP)) { else if ((this.intFlags & X86.INTFLAG.TRAP)) {
this.intFlags &= ~X86.INTFLAG.TRAP; this.intFlags &= ~X86.INTFLAG.TRAP;
X86Help.opHelpINT.call(this, X86.EXCEPTION.TRAP, null, 11); X86.fnINT.call(this, X86.EXCEPTION.TRAP, null, 11);
return true; return true;
} }
} }
@ -3162,7 +3292,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
this.nSnapCycles = this.nStepCycles; this.nSnapCycles = this.nStepCycles;
} }
this.aOps[this.getIPByte()].call(this); this.aOps[this.getIPByte() + (I386? this.bOpcodeBias : 0)].call(this);
if (PREFETCH) { if (PREFETCH) {
var nSpareCycles = (this.nSnapCycles - this.nStepCycles) - this.nBusCycles; var nSpareCycles = (this.nSnapCycles - this.nStepCycles) - this.nBusCycles;
@ -3217,10 +3347,6 @@ if (typeof APP_PCJS !== 'undefined') {
APP_PCJS.X86 = X86; APP_PCJS.X86 = X86;
APP_PCJS.X86.X86CPU = X86CPU; APP_PCJS.X86.X86CPU = X86CPU;
APP_PCJS.X86.X86Seg = X86Seg; APP_PCJS.X86.X86Seg = X86Seg;
APP_PCJS.X86.X86Grps = X86Grps;
APP_PCJS.X86.X86Help = X86Help;
APP_PCJS.X86.X86Op0F = X86Op0F;
APP_PCJS.X86.X86OpXX = X86OpXX;
} }
if (typeof module !== 'undefined') module.exports = X86CPU; if (typeof module !== 'undefined') module.exports = X86CPU;

2444
modules/pcjs/lib/x86func.js Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,789 +0,0 @@
/**
* @fileoverview Implements PCjs 8086 opcode helpers.
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
* @version 1.0
* Created 2012-Sep-05
*
* Copyright © 2012-2015 Jeff Parsons <Jeff@pcjs.org>
*
* This file is part of PCjs, which is part of the JavaScript Machines Project (aka JSMachines)
* at <http://jsmachines.net/> and <http://pcjs.org/>.
*
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCjs. If not,
* see <http://www.gnu.org/licenses/gpl.html>.
*
* You are required to include the above copyright notice in every source code file of every
* copy or modified version of this work, and to display that copyright notice on every screen
* that loads or runs any version of this software (see Computer.sCopyright).
*
* Some PCjs files also attempt to load external resource files, such as character-image files,
* ROM files, and disk image files. Those external resource files are not considered part of the
* PCjs program for purposes of the GNU General Public License, and the author does not claim
* any copyright as to their contents.
*/
"use strict";
if (typeof module !== 'undefined') {
var X86 = require("./x86");
var Messages = require("./messages");
}
var X86Help = {
/**
* @this {X86CPU}
* @param {number} dst (current value, ignored)
* @param {number} src (new value)
* @return {number} dst (updated value, from src)
*/
opHelpMOV: function(dst, src) {
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesMovRR : this.CYCLES.nOpCyclesMovRM) : this.CYCLES.nOpCyclesMovMR);
return src;
},
/**
* @this {X86CPU}
* @param {number} dst (current value, ignored)
* @param {number} src (new value)
* @return {number} dst (src is overridden, replaced with regMD16, as specified by opMOVwsr())
*/
opHelpMOVMD16: function(dst, src) {
return X86Help.opHelpMOV.call(this, dst, this.regMD16);
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpTESTb: function(dst, src) {
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_BYTE;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpTESTw: function(dst, src) {
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = dst & src;
this.resultSize = X86.RESULT.SIZE_WORD;
this.nStepCycles -= (this.regEAWrite < 0? (this.regEA < 0? this.CYCLES.nOpCyclesTestRR : this.CYCLES.nOpCyclesTestRM) : this.CYCLES.nOpCyclesTestRM);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*
* 80286_and_80287_Programmers_Reference_Manual_1987.pdf, p.B-44 (p.254) notes that:
*
* "The low 16 bits of the product of a 16-bit signed multiply are the same as those of an
* unsigned multiply. The three operand IMUL instruction can be used for unsigned operands as well."
*
* However, we still sign-extend the operands before multiplying, making it easier to range-check the result.
*
* (80186/80188 and up)
*/
opHelpIMUL8: function(dst, src) {
var result = ((src << 16) >> 16) * ((this.getIPByte() << 24) >> 24);
this.resultZeroCarry = this.resultAuxOverflow = this.resultParitySign = result;
this.resultSize = X86.RESULT.SIZE_BYTE;
/*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
* but it somewhat defeats the purpose of the indirect result variables that we've set above.
*/
if (result > 32767 || result < -32768) {
this.setCF(); this.setOF();
} else {
this.clearCF(); this.clearOF();
}
result &= 0xffff;
if (DEBUG && DEBUGGER) this.traceLog('IMUL8', dst, src, null, this.getPS(), result);
/*
* NOTE: These are the cycle counts for the 80286; the 80186/80188 have slightly different values (ranges):
* 22-25 and 29-32 instead of 21 and 24, respectively. However, accurate cycle counts for the 80186/80188 is
* not super-critical. TODO: Fix this someday.
*/
this.nStepCycles -= (this.regEA < 0? 21 : 24);
return result;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*
* 80286_and_80287_Programmers_Reference_Manual_1987.pdf, p.B-44 (p.254) notes that:
*
* "The low 16 bits of the product of a 16-bit signed multiply are the same as those of an
* unsigned multiply. The three operand IMUL instruction can be used for unsigned operands as well."
*
* However, we still sign-extend the operands before multiplying, making it easier to range-check the result.
*
* (80186/80188 and up)
*/
opHelpIMUL16: function(dst, src) {
var result = ((src << 16) >> 16) * ((this.getIPWord() << 16) >> 16);
this.resultZeroCarry = this.resultAuxOverflow = this.resultParitySign = result;
this.resultSize = X86.RESULT.SIZE_WORD;
/*
* TODO: Look into a more efficient way of setting/synchronizing CF and OF; this code works,
* but it somewhat defeats the purpose of the indirect result variables that we've set above.
*/
if (result > 32767 || result < -32768) {
this.setCF(); this.setOF();
} else {
this.clearCF(); this.clearOF();
}
result &= 0xffff;
if (DEBUG && DEBUGGER) this.traceLog('IMUL16', dst, src, null, this.getPS(), result);
/*
* NOTE: These are the cycle counts for the 80286; the 80186/80188 have slightly different values (ranges):
* 22-25 and 29-32 instead of 21 and 24, respectively. However, accurate cycle counts for the 80186/80188 is
* not super-critical. TODO: Fix this someday.
*/
this.nStepCycles -= (this.regEA < 0? 21 : 24);
return result;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number} dst unchanged
*/
opHelpESC: function(dst, src) {
return dst;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpLEA: function(dst, src) {
if (this.regEA < 0) {
/*
* TODO: After reading http://www.os2museum.com/wp/undocumented-8086-opcodes/, it seems that this
* form of LEA (eg, "LEA AX,DX") simply returns the last calculated EA. Since we always reset regEA
* at the start of a new instruction, we would need to preserve the previous EA if we want to mimic
* that (undocumented) behavior.
*
* And for completeness, we would have to extend EA tracking beyond the usual ModRM instructions
* (eg, XLAT, instructions that modify the stack pointer, and string instructions). Anything else?
*/
X86Help.opHelpUndefined.call(this);
return dst;
}
this.nStepCycles -= this.CYCLES.nOpCyclesLEA;
return this.regEA;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpLDS: function(dst, src) {
if (this.regEA < 0) {
X86Help.opHelpUndefined.call(this);
return dst;
}
this.setDS(this.getShort(this.regEA + 2));
this.nStepCycles -= this.CYCLES.nOpCyclesLS;
return src;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpLES: function(dst, src) {
if (this.regEA < 0) {
X86Help.opHelpUndefined.call(this);
return dst;
}
this.setES(this.getShort(this.regEA + 2));
this.nStepCycles -= this.CYCLES.nOpCyclesLS;
return src;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpBOUND: function(dst, src) {
if (this.regEA < 0) {
/*
* Generate UD_FAULT (INT 0x06: Invalid Opcode) if src is not a memory operand.
*/
X86Help.opHelpInvalid.call(this);
return dst;
}
/*
* Note that BOUND performs signed comparisons, so we must transform all arguments into signed values.
*/
var wIndex = (dst << 16) >> 16;
var wLower = (this.getShort(this.regEA) << 16) >> 16;
var wUpper = (this.getShort(this.regEA + 2) << 16) >> 16;
this.nStepCycles -= this.CYCLES.nOpCyclesBound;
if (wIndex < wLower || wIndex > wUpper) {
/*
* The INT 0x05 handler must be called with CS:IP pointing to the BOUND instruction.
*
* TODO: Determine the cycle cost when a BOUND exception is triggered, over and above nOpCyclesBound.
*/
this.setIP(this.opLIP - this.segCS.base);
X86Help.opHelpINT.call(this, X86.EXCEPTION.BOUND_ERR, null, 0);
}
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpARPL: function(dst, src) {
this.nStepCycles -= (10 + (this.regEA < 0? 0 : 1));
if ((dst & X86.SEL.RPL) < (src & X86.SEL.RPL)) {
dst = (dst & ~X86.SEL.RPL) | (src & X86.SEL.RPL);
this.setZF();
return dst;
}
this.clearZF();
return dst;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpLAR: function(dst, src) {
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2));
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment.
*
* TODO: This instruction's 80286 documentation does not discuss conforming code segments; determine
* if we need a special check for them.
*/
if (this.segVER.load(src, true) != X86.ADDR_INVALID) {
if (this.segVER.dpl >= this.segCS.cpl && this.segVER.dpl >= (src & X86.SEL.RPL)) {
this.setZF();
return this.segVER.acc & X86.DESC.ACC.MASK;
}
}
this.clearZF();
return dst;
},
/**
* @this {X86CPU}
* @param {number} dst
* @param {number} src (the selector)
* @return {number}
*/
opHelpLSL: function(dst, src) {
/*
* TODO: Is this an invalid operation if regEAWrite is set? dst is required to be a register.
*/
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2));
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment.
*
* TODO: LSL is explicitly documented as ALSO requiring a non-null selector, so we check X86.SEL.MASK;
* are there any other instructions that were, um, less explicit but also require a non-null selector?
*/
if ((src & X86.SEL.MASK) && this.segVER.load(src, true) != X86.ADDR_INVALID) {
var fConforming = ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING);
if ((fConforming || this.segVER.dpl >= this.segCS.cpl) && this.segVER.dpl >= (src & X86.SEL.RPL)) {
this.setZF();
return this.segVER.limit;
}
}
this.clearZF();
return dst;
},
/**
* opHelpXCHGrb(dst, src)
*
* If an instruction like "XCHG AL,AH" was a traditional "op dst,src" instruction, dst would contain AL,
* src would contain AH, and we would return src, which the caller would then store in AL, and we'd be done.
*
* However, that's only half of what XCHG does, so THIS function must perform the other half; in the previous
* example, that entails storing AL (dst) into AH (src).
*
* BACKTRACK support is incomplete without also passing bti values as parameters, because the caller will
* store btiAH in btiAL, but the original btiAL will be lost. Similarly, if src is a memory operand, the
* caller will store btiEALo in btiAL, but again, the original btiAL will be lost.
*
* BACKTRACK support for memory operands could be fixed by decoding the dst register in order to determine the
* corresponding bti and then temporarily storing it in btiEALo around the setEAByte() call below. Register-only
* XCHGs would require a more extensive hack. For now, I'm going to live with one-way BACKTRACK support here.
*
* TODO: Implement full BACKTRACK support for XCHG instructions.
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpXCHGrb: function(dst, src) {
if (this.regEA < 0) {
/*
* Decode which register was src
*/
switch (this.bModRM & 0x7) {
case 0x0: // AL
this.regEAX = (this.regEAX & ~0xff) | dst;
break;
case 0x1: // CL
this.regECX = (this.regECX & ~0xff) | dst;
break;
case 0x2: // DL
this.regEDX = (this.regEDX & ~0xff) | dst;
break;
case 0x3: // BL
this.regEBX = (this.regEBX & ~0xff) | dst;
break;
case 0x4: // AH
this.regEAX = (this.regEAX & 0xff) | (dst << 8);
break;
case 0x5: // CH
this.regECX = (this.regECX & 0xff) | (dst << 8);
break;
case 0x6: // DH
this.regEDX = (this.regEDX & 0xff) | (dst << 8);
break;
case 0x7: // BH
this.regEBX = (this.regEBX & 0xff) | (dst << 8);
break;
default:
break; // there IS no other case, but JavaScript inspections don't know that
}
this.nStepCycles -= this.CYCLES.nOpCyclesXchgRR;
} else {
/*
* This is a case where the ModRM decoder that's calling us didn't know it should have called modEAByte()
* instead of getEAByte(), so we compensate by updating regEAWrite. However, setEAByte() has since been
* changed to revalidate the write using segEA:offEA, so updating regEAWrite here isn't strictly necessary.
*/
this.regEAWrite = this.regEA;
this.setEAByte(dst);
this.nStepCycles -= this.CYCLES.nOpCyclesXchgRM;
}
return src;
},
/**
* opHelpXCHGrw(dst, src)
*
* If an instruction like "XCHG AX,DX" was a traditional "op dst,src" instruction, dst would contain AX,
* src would contain DX, and we would return src, which the caller would then store in AX, and we'd be done.
*
* However, that's only half of what XCHG does, so THIS function must perform the other half; in the previous
* example, that entails storing AX (dst) into DX (src).
*
* TODO: Implement full BACKTRACK support for XCHG instructions (see opHelpXCHGrb comments).
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src
* @return {number}
*/
opHelpXCHGrw: function(dst, src) {
if (this.regEA < 0) {
/*
* Decode which register was src
*/
switch (this.bModRM & 0x7) {
case 0x0: // AX
this.regEAX = dst;
break;
case 0x1: // CX
this.regECX = dst;
break;
case 0x2: // DX
this.regEDX = dst;
break;
case 0x3: // BX
this.regEBX = dst;
break;
case 0x4: // SP
this.setSP(dst);
break;
case 0x5: // BP
this.regEBP = dst;
break;
case 0x6: // SI
this.regESI = dst;
break;
case 0x7: // DI
this.regEDI = dst;
break;
default:
break; // there IS no other case, but JavaScript inspections don't know that
}
this.nStepCycles -= this.CYCLES.nOpCyclesXchgRR;
} else {
/*
* This is a case where the ModRM decoder that's calling us didn't know it should have called modEAWord()
* instead of getEAWord(), so we compensate by updating regEAWrite. However, setEAWord() has since been
* changed to revalidate the write using segEA:offEA, so updating regEAWrite here isn't strictly necessary.
*/
this.regEAWrite = this.regEA;
this.setEAWord(dst);
this.nStepCycles -= this.CYCLES.nOpCyclesXchgRM;
}
return src;
},
/**
* opHelpLMSW(w)
*
* Factored out of x86op0f.js, since both opLMSW and opLOADALL are capable of loading a new MSW.
* The caller is responsible for assessing the appropriate cycle cost.
*
* @this {X86CPU}
* @param {number} w
*/
opHelpLMSW: function(w) {
/*
* This instruction is always allowed to set MSW.PE, but it cannot clear MSW.PE once set;
* therefore, we always OR the previous value of MSW.PE into the new value before loading.
*/
w |= (this.regCR0 & X86.CR0.MSW.PE) | X86.CR0.MSW.ON;
this.regCR0 = (this.regCR0 & ~X86.CR0.MSW.MASK) | (w & X86.CR0.MSW.MASK);
/*
* Since the 80286 cannot return to real-mode via this instruction, the only transition we
* must worry about is to protected-mode. And don't worry, there's no harm calling setProtMode()
* if the CPU is already in protected-mode (we could certainly optimize the call out in that
* case, but this instruction isn't used frequently enough to warrant it).
*/
if (this.regCR0 & X86.CR0.MSW.PE) this.setProtMode(true);
},
/**
* opHelpLCR0(l)
*
* This called on behalf of 80386 opcodes only (ie, MOV CR0,reg).
*
* TODO: Determine which CR0 bits, if any, cannot be modified by MOV CR0,reg.
*
* @this {X86CPU}
* @param {number} l
*/
opHelpLCR0: function(l) {
this.regCR0 = l;
this.setProtMode(!!(this.regCR0 & X86.CR0.MSW.PE));
},
/**
* opHelpCALLF(off, sel)
*
* For protected-mode, this function must attempt to load the new code segment first, because if the new segment
* requires a change in privilege level, the return address must be pushed on the NEW stack, not the current stack.
*
* @this {X86CPU}
* @param {number} off
* @param {number} sel
*/
opHelpCALLF: function(off, sel) {
var regCS = this.getCS();
var regEIP = this.getIP();
if (this.setCSIP(off, sel, true) != null) {
this.pushWord(regCS);
this.pushWord(regEIP);
}
},
/**
* opHelpRETF(n)
*
* For protected-mode, this function must be prepared to pop any arguments off the current stack AND
* whatever stack we may have switched to (setCSIP() returns true only when a stack switch has occurred).
*
* @this {X86CPU}
* @param {number} n
*/
opHelpRETF: function(n) {
var regEIP = this.popWord();
var regCS = this.popWord();
n <<= (this.dataSize >> 2);
if (n) this.setSP(this.getSP() + n); // TODO: optimize
if (this.setCSIP(regEIP, regCS, false)) {
if (n) this.setSP(this.getSP() + n); // TODO: optimize
/*
* As per Intel documentation: "If any of [the DS or ES] registers refer to segments whose DPL is
* less than the new CPL (excluding conforming code segments), the segment register is loaded with
* the null selector."
*
* TODO: I'm not clear on whether a conforming code segment must also be marked readable, so I'm playing
* it safe and using CODE_CONFORMING instead of CODE_CONFORMING_READABLE. Also, for the record, I've not
* seen this situation occur in OS/2 1.0 yet.
*/
if ((this.segDS.sel & X86.SEL.MASK) && this.segDS.dpl < this.segCS.cpl && (this.segDS.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) != X86.DESC.ACC.TYPE.CODE_CONFORMING) {
this.assert(false); // I'm not asserting this is bad, I just want to see it in action
this.segDS.load(0);
}
if ((this.segES.sel & X86.SEL.MASK) && this.segES.dpl < this.segCS.cpl && (this.segES.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) != X86.DESC.ACC.TYPE.CODE_CONFORMING) {
this.assert(false); // I'm not asserting this is bad, I just want to see it in action
this.segES.load(0);
}
}
if (n == 2 && this.cIntReturn) this.checkIntReturn(this.regLIP);
},
/**
* opHelpINT(nIDT, nError, nCycles)
*
* NOTE: We no longer use setCSIP(), because it always loads the new CS using segCS.load(), which
* only knows how to load GDT and LDT descriptors, whereas interrupts must use setCS.loadIDT(), which
* deals exclusively with IDT descriptors.
*
* This means we must take care to replicate critical features of setCSIP(); eg, setting segCS.fCall before
* calling loadIDT(), updating LIP, and flushing the prefetch queue.
*
* @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 loadIDT() fails, no cost may be assessed.
*/
this.nStepCycles -= this.CYCLES.nOpCyclesInt + nCycles;
this.segCS.fCall = true;
var regPS = this.getPS();
var regCS = this.getCS();
var regEIP = this.getIP();
var addr = this.segCS.loadIDT(nIDT);
if (addr != X86.ADDR_INVALID) {
this.regLIP = addr;
if (PREFETCH) this.flushPrefetch(this.regLIP);
this.pushWord(regPS);
this.pushWord(regCS);
this.pushWord(regEIP);
if (nError != null) this.pushWord(nError);
this.nFault = -1;
}
},
/**
* opHelpIRET()
*
* @this {X86CPU}
*/
opHelpIRET: function() {
/*
* TODO: We assess a fixed cycle cost up front, because at the moment, switchTSS() doesn't assess anything.
*/
this.nStepCycles -= this.CYCLES.nOpCyclesIRet;
if (this.regCR0 & X86.CR0.MSW.PE) {
if (this.regPS & X86.PS.NT) {
var addrNew = this.segTSS.base;
var sel = this.getShort(addrNew + X86.TSS.PREV_TSS);
X86Seg.switchTSS.call(this.segCS, sel, false);
return;
}
}
var cpl = this.segCS.cpl;
var regEIP = this.popWord();
var regCS = this.popWord();
var regPS = this.popWord();
if (this.setCSIP(regEIP, regCS, false) != null) {
this.setPS(regPS, cpl);
if (this.cIntReturn) this.checkIntReturn(this.regLIP);
}
},
/**
* opHelpDIVOverflow()
*
* @this {X86CPU}
*/
opHelpDIVOverflow: function() {
this.setIP(this.opLIP - this.segCS.base);
/*
* TODO: Determine the proper cycle cost.
*/
X86Help.opHelpINT.call(this, X86.EXCEPTION.DIV_ERR, null, 2);
},
/**
* opHelpFault(nFault, nError, fHalt)
*
* Helper to dispatch faults.
*
* @this {X86CPU}
* @param {number} nFault
* @param {number} [nError]
* @param {boolean} [fHalt] will halt the CPU if true *and* a Debugger is loaded
*/
opHelpFault: function(nFault, nError, fHalt)
{
if (!this.aFlags.fComplete) {
this.printMessage("Fault " + str.toHexByte(nFault) + " blocked by Debugger", Messages.WARN);
this.setIP(this.opLIP - this.segCS.base);
return;
}
var fDispatch = false;
if (this.model >= X86.MODEL_80186) {
if (this.nFault < 0) {
/*
* Single-fault (error code is passed through, and the responsible instruction is restartable)
*/
this.setIP(this.opLIP - this.segCS.base);
fDispatch = true;
} else if (this.nFault != X86.EXCEPTION.DF_FAULT) {
/*
* Double-fault (error code is always zero, and the responsible instruction is not restartable)
*/
nError = 0;
nFault = X86.EXCEPTION.DF_FAULT;
fDispatch = true;
} else {
/*
* Triple-fault (usually referred to in Intel literature as a "shutdown", but at least on the 80286,
* it's actually a "reset")
*/
X86Help.opHelpFaultMessage.call(this, -1, 0, fHalt);
this.resetRegs();
return;
}
}
if (X86Help.opHelpFaultMessage.call(this, nFault, nError, fHalt)) {
fDispatch = false;
}
if (fDispatch) X86Help.opHelpINT.call(this, this.nFault = nFault, nError, 0);
/*
* Since this fault is likely being issued in the context of an instruction that hasn't finished
* executing, and since we currently don't do anything to interrupt that execution (eg, throw a
* JavaScript exception), we should shut off all further reads/writes for the current instruction.
*
* That's easy for any EA-based memory accesses: simply set both the NOREAD and NOWRITE flags.
* However, there are also direct, non-EA-based memory accesses to consider. A perfect example is
* opPUSHA(): if a GP fault occurs on any PUSH other than the last, a subsequent PUSH is likely to
* cause another fault, which we will misinterpret as a double-fault.
*
* TODO: Throw a special JavaScript exception that cpu.js must intercept and quietly ignore.
*/
this.opFlags &= ~(X86.OPFLAG.NOREAD | X86.OPFLAG.NOWRITE);
},
/**
* opHelpFaultMessage()
*
* Aside from giving the Debugger an opportunity to report every fault, this also gives us the ability to
* halt exception processing in tracks: return true to prevent the fault handler from being dispatched.
*
* At the moment, the only Debugger control you have over fault interception is setting MESSAGE.FAULT, which
* will display faults as they occur, and MESSAGE.HALT, which will halt after any Debugger message, including
* MESSAGE.FAULT. If you want execution to continue after halting, clear MESSAGE.FAULT and/or MESSAGE.HALT,
* or single-step over the offending instruction, which will allow the fault to be dispatched.
*
* @this {X86CPU}
* @param {number} nFault
* @param {number} [nError]
* @param {boolean} [fHalt] true if the CPU should always be halted, false if "it depends"
* @return {boolean|undefined} true to block the fault (often desirable when fHalt is true), otherwise dispatch it
*/
opHelpFaultMessage: function(nFault, nError, fHalt)
{
var bitsMessage = Messages.FAULT;
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
* reset and return to real-mode, and these resets happen quite frequently during boot; for example,
* OS/2 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 an INT3 (0xCC) opcode,
* and so whenever we see that opcode, we ignore the caller's fHalt flag, and suppress FAULT messages
* unless CPU messages are also enabled.
*
* When a triple fault shows up, nFault is -1; it displays as "ff" because we display nFault as a byte.
*/
if (bOpcode == X86.OPCODE.INT3) {
fHalt = false;
bitsMessage |= Messages.CPU;
}
/*
* Similarly, the PC AT ROM BIOS deliberately generates a couple of GP faults as part of the POST
* (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 the LIP being in the range %0F0000 to %0FFFFF.
*/
if (this.regLIP >= 0x0F0000 && this.regLIP <= 0x0FFFFF) {
fHalt = false;
}
/*
* However, the foregoing notwithstanding, if MESSAGE.HALT is enabled along with all the other required
* MESSAGE bits, then we want to halt regardless.
*/
if (this.messageEnabled(bitsMessage | Messages.HALT)) {
fHalt = true;
}
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 " + this.dbg.hexOffset(this.getIP(), this.getCS()) + " (%" + str.toHex(this.regLIP, 6) + ")";
var fRunning = this.aFlags.fRunning;
if (this.printMessage(sMessage, bitsMessage)) {
if (fHalt) {
/*
* By setting fHalt to fRunning (which is true while running but false while single-stepping),
* this allows a fault to be dispatched when you single-step over a faulting instruction; you can
* then continue single-stepping into the fault handler, or start running again.
*
* Note that we had to capture fRunning before calling printMessage(), because if MESSAGE.HALT
* is set, printMessage() will have already halted the CPU.
*/
fHalt = fRunning;
this.dbg.stopCPU();
}
} else {
/*
* If printMessage() returned false, then messageEnabled() must have returned false as well, which
* means that fHalt must be true. Which means we should shut the machine down.
*/
this.assert(fHalt);
this.notice(sMessage);
this.stopCPU();
}
}
return fHalt;
},
/**
* @this {X86CPU}
*/
opHelpInvalid: function() {
X86Help.opHelpFault.call(this, X86.EXCEPTION.UD_FAULT);
this.stopCPU();
},
/**
* @this {X86CPU}
*/
opHelpUndefined: function() {
this.setIP(this.opLIP - this.segCS.base);
this.setError("Undefined opcode 0x" + str.toHexByte(this.bus.getByteDirect(this.regLIP)) + " at 0x" + str.toHex(this.regLIP));
this.stopCPU();
}
};
if (typeof module !== 'undefined') module.exports = X86Help;

View file

@ -34,35 +34,36 @@
if (typeof module !== 'undefined') { if (typeof module !== 'undefined') {
var X86 = require("./x86"); var X86 = require("./x86");
var X86Grps = require("./x86grps");
var X86Help = require("./x86help");
} }
var X86Op0F = {
/** /**
* op=0x0F,0x00 (GRP6 rm) * op=0x0F,0x00 (GRP6 rm)
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opGrp6: function() { X86.opGrp6 = function GRP6()
{
var bModRM = this.getIPByte(); var bModRM = this.getIPByte();
if ((bModRM & 0x38) < 0x10) { // possible reg values: 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38 if ((bModRM & 0x38) < 0x10) { // possible reg values: 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
this.opFlags |= X86.OPFLAG.NOREAD; this.opFlags |= X86.OPFLAG.NOREAD;
} }
this.aOpModGrpWord[bModRM].call(this, this.aOpGrp6, X86Grps.opGrpNoSrc); this.aOpModGrpWord[bModRM].call(this, this.aOpGrp6, X86.fnGRPSrcNone);
}, };
/** /**
* op=0x0F,0x01 (GRP7 rm) * op=0x0F,0x01 (GRP7 rm)
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opGrp7: function() { X86.opGrp7 = function GRP7()
{
var bModRM = this.getIPByte(); var bModRM = this.getIPByte();
if (!(bModRM & 0x10)) { if (!(bModRM & 0x10)) {
this.opFlags |= X86.OPFLAG.NOREAD; this.opFlags |= X86.OPFLAG.NOREAD;
} }
this.aOpModGrpWord[bModRM].call(this, X86Op0F.aOpGrp7, X86Grps.opGrpNoSrc); this.aOpModGrpWord[bModRM].call(this, X86.aOpGrp7, X86.fnGRPSrcNone);
}, };
/** /**
* opLAR() * opLAR()
* *
@ -70,9 +71,11 @@ var X86Op0F = {
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opLAR: function() { X86.opLAR = function LAR()
this.aOpModRegWord[this.getIPByte()].call(this, X86Help.opHelpLAR); {
}, this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLAR);
};
/** /**
* opLSL() * opLSL()
* *
@ -80,9 +83,11 @@ var X86Op0F = {
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opLSL: function() { X86.opLSL = function LSL()
this.aOpModRegWord[this.getIPByte()].call(this, X86Help.opHelpLSL); {
}, this.aOpModRegWord[this.getIPByte()].call(this, X86.fnLSL);
};
/** /**
* opLOADALL() * opLOADALL()
* *
@ -124,15 +129,16 @@ var X86Op0F = {
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opLOADALL: function() { X86.opLOADALL = function LOADALL()
{
if (this.segCS.cpl) { if (this.segCS.cpl) {
/* /*
* You're not allowed to use LOADALL if the current privilege level is something other than zero * You're not allowed to use LOADALL if the current privilege level is something other than zero
*/ */
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true); X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true);
return; return;
} }
X86Help.opHelpLMSW.call(this, this.getShort(0x806)); this.setMSW(this.getShort(0x806));
this.regEDI = this.getShort(0x826); this.regEDI = this.getShort(0x826);
this.regESI = this.getShort(0x828); this.regESI = this.getShort(0x828);
this.regEBP = this.getShort(0x82A); this.regEBP = this.getShort(0x82A);
@ -170,7 +176,8 @@ var X86Op0F = {
* TODO: LOADALL operation still needs to be verified in protected mode.... * TODO: LOADALL operation still needs to be verified in protected mode....
*/ */
if (DEBUG && DEBUGGER && (this.regCR0 & X86.CR0.MSW.PE)) this.stopCPU(); if (DEBUG && DEBUGGER && (this.regCR0 & X86.CR0.MSW.PE)) this.stopCPU();
}, };
/** /**
* opCLTS() * opCLTS()
* *
@ -178,321 +185,16 @@ var X86Op0F = {
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opCLTS: function() { X86.opCLTS = function CLTS()
{
if (this.segCS.cpl) { if (this.segCS.cpl) {
X86Help.opHelpFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true); X86.fnFault.call(this, X86.EXCEPTION.GP_FAULT, 0, true);
return; return;
} }
this.regCR0 &= ~X86.CR0.MSW.TS; this.regCR0 &= ~X86.CR0.MSW.TS;
this.nStepCycles -= 2; this.nStepCycles -= 2;
}, };
/**
* opSLDT(dst, src)
*
* op=0x0F,0x00,reg=0x0 (GRP6:SLDT)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opSLDT: function(dst, src) {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1));
return this.segLDT.sel;
},
/**
* opSTR(dst, src)
*
* op=0x0F,0x00,reg=0x1 (GRP6:STR)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opSTR: function(dst, src) {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1));
return this.segTSS.sel;
},
/**
* opLLDT(dst, src)
*
* op=0x0F,0x00,reg=0x2 (GRP6:LLDT)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opLLDT: function(dst, src) {
this.opFlags |= X86.OPFLAG.NOWRITE;
this.segLDT.load(dst);
this.nStepCycles -= (17 + (this.regEA < 0? 0 : 2));
return dst;
},
/**
* opLTR(dst, src)
*
* op=0x0F,0x00,reg=0x3 (GRP6:LTR)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opLTR: function(dst, src) {
this.opFlags |= X86.OPFLAG.NOWRITE;
if (this.segTSS.load(dst) != X86.ADDR_INVALID) {
this.setShort(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;
},
/**
* opVERR(dst, src)
*
* op=0x0F,0x00,reg=0x4 (GRP6:VERR)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opVERR: function(dst, src) {
this.opFlags |= X86.OPFLAG.NOWRITE;
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment.
*/
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2));
if (this.segVER.load(dst, true) != X86.ADDR_INVALID) {
/*
* Verify that this is a readable segment; that is, of these four combinations (code+readable,
* code+nonreadable, data+writable, date+nonwritable), make sure we're not the second combination.
*/
if ((this.segVER.acc & (X86.DESC.ACC.TYPE.READABLE | X86.DESC.ACC.TYPE.CODE)) != X86.DESC.ACC.TYPE.CODE) {
/*
* For VERR, if the code segment is readable and conforming, the descriptor privilege level
* (DPL) can be any value.
*
* Otherwise, DPL must be greater than or equal to (have less or the same privilege as) both the
* current privilege level and the selector's RPL.
*/
if (this.segVER.dpl >= this.segCS.cpl && this.segVER.dpl >= (dst & X86.SEL.RPL) ||
(this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING) {
this.setZF();
return dst;
}
}
}
this.clearZF();
return dst;
},
/**
* opVERW(dst, src)
*
* op=0x0F,0x00,reg=0x5 (GRP6:VERW)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opVERW: function(dst, src) {
this.opFlags |= X86.OPFLAG.NOWRITE;
/*
* Currently, segVER.load() will return an error only if the selector is beyond the bounds of the
* descriptor table or the descriptor is not for a segment.
*/
this.nStepCycles -= (14 + (this.regEA < 0? 0 : 2));
if (this.segVER.load(dst, true) != X86.ADDR_INVALID) {
/*
* Verify that this is a writable data segment
*/
if ((this.segVER.acc & (X86.DESC.ACC.TYPE.WRITABLE | X86.DESC.ACC.TYPE.CODE)) == X86.DESC.ACC.TYPE.WRITABLE) {
/*
* DPL must be greater than or equal to (have less or the same privilege as) both the current
* privilege level and the selector's RPL.
*/
if (this.segVER.dpl >= this.segCS.cpl && this.segVER.dpl >= (dst & X86.SEL.RPL)) {
this.setZF();
return dst;
}
}
}
this.clearZF();
return dst;
},
/**
* opSGDT(dst, src)
*
* op=0x0F,0x01,reg=0x0 (GRP7:SGDT)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opSGDT: function(dst, src) {
if (this.regEA < 0) {
X86Help.opHelpInvalid.call(this);
} else {
/*
* We don't need to setShort() the first word of the operand, because the ModRM group decoder that
* calls us does that automatically with the value we return (dst).
*/
dst = this.addrGDTLimit - this.addrGDT;
this.setShort(this.regEA + 2, this.addrGDT);
/*
* We previously left the 6th byte of the target operand "undefined". But it turns out we have to set
* it to *something*, because there's processor detection in PC-DOS 7.0 (at least in the SETUP portion)
* that looks like this:
*
* 145E:4B84 9C PUSHF
* 145E:4B85 55 PUSH BP
* 145E:4B86 8BEC MOV BP,SP
* 145E:4B88 B80000 MOV AX,0000
* 145E:4B8B 50 PUSH AX
* 145E:4B8C 9D POPF
* 145E:4B8D 9C PUSHF
* 145E:4B8E 58 POP AX
* 145E:4B8F 2500F0 AND AX,F000
* 145E:4B92 3D00F0 CMP AX,F000
* 145E:4B95 7511 JNZ 4BA8
* 145E:4BA8 C8060000 ENTER 0006,00
* 145E:4BAC 0F0146FA SGDT [BP-06]
* 145E:4BB0 807EFFFF CMP [BP-01],FF
* 145E:4BB4 C9 LEAVE
* 145E:4BB5 BA8603 MOV DX,0386
* 145E:4BB8 7503 JNZ 4BBD
* 145E:4BBA BA8602 MOV DX,0286
* 145E:4BBD 89163004 MOV [0430],DX
* 145E:4BC1 5D POP BP
* 145E:4BC2 9D POPF
* 145E:4BC3 CB RETF
*
* This code is expecting SGDT on an 80286 to set the 6th "undefined" byte to 0xFF. So we use setShort()
* instead of setByte() and force the upper byte to 0xFF.
*
* TODO: Remove the 0xFF00 below on post-80286 processors; also, determine whether this behavior is unique to real-mode.
*/
this.setShort(this.regEA + 4, 0xFF00 | (this.addrGDT >> 16));
this.nStepCycles -= 11;
}
return dst;
},
/**
* opSIDT(dst, src)
*
* op=0x0F,0x01,reg=0x1 (GRP7:SIDT)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opSIDT: function(dst, src) {
if (this.regEA < 0) {
X86Help.opHelpInvalid.call(this);
} else {
/*
* We don't need to setShort() the first word of the operand, because the ModRM group decoder that calls
* us does that automatically with the value we return (dst).
*/
dst = this.addrIDTLimit - this.addrIDT;
this.setShort(this.regEA + 2, this.addrIDT);
/*
* As with SGDT, the 6th byte is technically "undefined" on an 80286, but we now set it to 0xFF, for the
* same reasons discussed in SGDT (above).
*
* TODO: Remove the 0xFF00 below on post-80286 processors; also, determine whether this behavior is unique to real-mode.
*/
this.setShort(this.regEA + 4, 0xFF00 | (this.addrIDT >> 16));
this.nStepCycles -= 12;
}
return dst;
},
/**
* opLGDT(dst, src)
*
* op=0x0F,0x01,reg=0x2 (GRP7:LGDT)
*
* The 80286 LGDT instruction expects a 40-bit operand: a 16-bit limit, followed by a 24-bit address;
* the ModRM decoder has already supplied the first word of the operand (in dst), which corresponds to the
* limit, so we must fetch the remaining 24 bits ourselves.
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opLGDT: function(dst, src) {
if (this.regEA < 0) {
X86Help.opHelpInvalid.call(this);
} else {
this.addrGDT = this.getShort(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
this.addrGDTLimit = this.addrGDT + dst;
this.opFlags |= X86.OPFLAG.NOWRITE;
this.nStepCycles -= 11;
}
return dst;
},
/**
* opLIDT(dst, src)
*
* op=0x0F,0x01,reg=0x3 (GRP7:LIDT)
*
* The 80286 LIDT instruction expects a 40-bit operand: a 16-bit limit, followed by a 24-bit address;
* the ModRM decoder has already supplied the first word of the operand (in dst), which corresponds to the
* limit, so we must fetch the remaining 24 bits ourselves.
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opLIDT: function(dst, src) {
if (this.regEA < 0) {
X86Help.opHelpInvalid.call(this);
} else {
this.addrIDT = this.getShort(this.regEA + 2) | (this.getByte(this.regEA + 4) << 16);
this.addrIDTLimit = this.addrIDT + dst;
this.opFlags |= X86.OPFLAG.NOWRITE;
this.nStepCycles -= 12;
}
return dst;
},
/**
* opSMSW(dst, src)
*
* op=0x0F,0x01,reg=0x4 (GRP7:SMSW)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opSMSW: function(dst, src) {
this.nStepCycles -= (2 + (this.regEA < 0? 0 : 1));
return this.regCR0;
},
/**
* opLMSW(dst, src)
*
* op=0x0F,0x01,reg=0x6 (GRP7:LMSW)
*
* @this {X86CPU}
* @param {number} dst
* @param {number} src (null)
* @return {number}
*/
opLMSW: function(dst, src) {
X86Help.opHelpLMSW.call(this, dst);
this.nStepCycles -= (this.regEA < 0? 3 : 6);
this.opFlags |= X86.OPFLAG.NOWRITE;
return dst;
},
/** /**
* opMOVrcr() * opMOVrcr()
* *
@ -504,14 +206,15 @@ var X86Op0F = {
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opMOVrcr: function() { X86.opMOVrcr = function MOVrcr()
{
var bModRM = this.getIPByte() | 0xc0; var bModRM = this.getIPByte() | 0xc0;
/* /*
* Unlike, say, opcode 0x8C (MOV word,sr), this opcode supports only registers, not memory; * Unlike, say, opcode 0x8C (MOV word,sr), this opcode supports only registers, not memory;
* however, the 80386 apparently ignores the mod bits, treating any combination as if it was 0xc0. * however, the 80386 apparently ignores the mod bits, treating any combination as if it was 0xc0.
* *
if ((bModRM & 0xc0) != 0xc0) { if ((bModRM & 0xc0) != 0xc0) {
X86Help.opHelpInvalid.call(this); X86.opInvalid.call(this);
return; return;
} }
*/ */
@ -530,7 +233,7 @@ var X86Op0F = {
this.regMD16 = this.regCR3; this.regMD16 = this.regCR3;
break; break;
default: default:
X86Help.opHelpUndefined.call(this); X86.opUndefined.call(this);
return; return;
} }
/* /*
@ -539,8 +242,9 @@ var X86Op0F = {
* *
* this.opFlags |= X86.OPFLAG.NOREAD; * this.opFlags |= X86.OPFLAG.NOREAD;
*/ */
this.aOpModRegWord[bModRM].call(this, X86Help.opHelpMOVMD16); this.aOpModRegWord[bModRM].call(this, X86.fnMOVMD16);
}, };
/** /**
* opMOVcrr() * opMOVcrr()
* *
@ -552,7 +256,8 @@ var X86Op0F = {
* *
* @this {X86CPU} * @this {X86CPU}
*/ */
opMOVcrr: function() { X86.opMOVcrr = function MOVcrr()
{
var temp; var temp;
var bModRM = this.getIPByte() | 0xc0; var bModRM = this.getIPByte() | 0xc0;
/* /*
@ -560,7 +265,7 @@ var X86Op0F = {
* however, the 80386 apparently ignores the mod bits, treating any combination as if it was 0xc0. * however, the 80386 apparently ignores the mod bits, treating any combination as if it was 0xc0.
* *
if ((bModRM & 0xc0) != 0xc0) { if ((bModRM & 0xc0) != 0xc0) {
X86Help.opHelpInvalid.call(this); X86.opInvalid.call(this);
return; return;
} }
*/ */
@ -579,15 +284,15 @@ var X86Op0F = {
temp = this.regEBX; temp = this.regEBX;
break; break;
default: default:
X86Help.opHelpInvalid.call(this); X86.opInvalid.call(this);
return; return;
} }
this.aOpModRegWord[bModRM].call(this, X86Help.opHelpMOV); this.aOpModRegWord[bModRM].call(this, X86.fnMOV);
switch (reg) { switch (reg) {
case 0x0: case 0x0:
reg = this.regEAX; reg = this.regEAX;
this.regEAX = temp; this.regEAX = temp;
X86Help.opHelpLCR0.call(this, reg); X86.fnLCR0.call(this, reg);
break; break;
case 0x1: case 0x1:
this.regCR1 = this.regECX; this.regCR1 = this.regECX;
@ -604,78 +309,77 @@ var X86Op0F = {
default: default:
break; // there IS no other case, but JavaScript inspections don't know that break; // there IS no other case, but JavaScript inspections don't know that
} }
}
}; };
X86Op0F.aOps0F = [ X86.aOps0F = [
X86Op0F.opGrp6, X86Op0F.opGrp7, X86Op0F.opLAR, X86Op0F.opLSL, // 0x00-0x03 X86.opGrp6, X86.opGrp7, X86.opLAR, X86.opLSL, // 0x00-0x03
X86Help.opHelpUndefined,X86Op0F.opLOADALL, X86Op0F.opCLTS, X86Help.opHelpUndefined,// 0x04-0x07 X86.opUndefined, X86.opLOADALL, X86.opCLTS, X86.opUndefined, // 0x04-0x07
/* /*
* On all processors (except the 8086/8088, of course), 0x0F,0x0B is also referred to as "UD2": an * On all processors (except the 8086/8088, of course), 0x0F,0x0B is also referred to as "UD2": an
* instruction guaranteed to raise a #UD (Invalid Opcode) exception (INT 0x06) on all future x86 processors. * instruction guaranteed to raise a #UD (Invalid Opcode) exception (INT 0x06) on all future x86 processors.
*/ */
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpInvalid, // 0x08-0x0B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opInvalid, // 0x08-0x0B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x0C-0x0F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x0C-0x0F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x10-0x13 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x10-0x13
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x14-0x17 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x14-0x17
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x18-0x1B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x18-0x1B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x1C-0x1F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x1C-0x1F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x20-0x23 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x20-0x23
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x24-0x27 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x24-0x27
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x28-0x2B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x28-0x2B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x2C-0x2F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x2C-0x2F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x30-0x33 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x30-0x33
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x34-0x37 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x34-0x37
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x38-0x3B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x38-0x3B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x3C-0x3F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x3C-0x3F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x40-0x43 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x40-0x43
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x44-0x47 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x44-0x47
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x48-0x4B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x48-0x4B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x4C-0x4F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x4C-0x4F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x50-0x53 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x50-0x53
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x54-0x57 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x54-0x57
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x58-0x5B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x58-0x5B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x5C-0x5F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x5C-0x5F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x60-0x63 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x60-0x63
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x64-0x67 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x64-0x67
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x68-0x6B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x68-0x6B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x6C-0x6F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x6C-0x6F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x70-0x73 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x70-0x73
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x74-0x77 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x74-0x77
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x78-0x7B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x78-0x7B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x7C-0x7F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x7C-0x7F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x80-0x83 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x80-0x83
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x84-0x87 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x84-0x87
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x88-0x8B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x88-0x8B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x8C-0x8F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x8C-0x8F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x90-0x93 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x90-0x93
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x94-0x97 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x94-0x97
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x98-0x9B X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x98-0x9B
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0x9C-0x9F X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0x9C-0x9F
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xA0-0xA3 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xA0-0xA3
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xA4-0xA7 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xA4-0xA7
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xA8-0xAB X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xA8-0xAB
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xAC-0xAF X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xAC-0xAF
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xB0-0xB3 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xB0-0xB3
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xB4-0xB7 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xB4-0xB7
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xB8-0xBB X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xB8-0xBB
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xBC-0xBF X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xBC-0xBF
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xC0-0xC3 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xC0-0xC3
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xC4-0xC7 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xC4-0xC7
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xC8-0xCB X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xC8-0xCB
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xCC-0xCF X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xCC-0xCF
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xD0-0xD3 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xD0-0xD3
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xD4-0xD7 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xD4-0xD7
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xD8-0xDB X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xD8-0xDB
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xDC-0xDF X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xDC-0xDF
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xE0-0xE3 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xE0-0xE3
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xE4-0xE7 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xE4-0xE7
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xE8-0xEB X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xE8-0xEB
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xEC-0xEF X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xEC-0xEF
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xF0-0xF3 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xF0-0xF3
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xF4-0xF7 X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xF4-0xF7
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,// 0xF8-0xFB X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined, // 0xF8-0xFB
X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined,X86Help.opHelpUndefined // 0xFC-0xFF X86.opUndefined, X86.opUndefined, X86.opUndefined, X86.opUndefined // 0xFC-0xFF
]; ];
/* /*
@ -685,23 +389,21 @@ X86Op0F.aOps0F = [
* getEAWord() should be disabled *prior* to calling the ModRM helper function. This latter case requires that * getEAWord() should be disabled *prior* to calling the ModRM helper function. This latter case requires that
* we decode the reg field of the ModRM byte before dispatching. * we decode the reg field of the ModRM byte before dispatching.
*/ */
X86Op0F.aOpGrp6Prot = [ X86.aOpGrp6Prot = [
X86Op0F.opSLDT, X86Op0F.opSTR, X86Op0F.opLLDT, X86Op0F.opLTR, // 0x0F,0x00(reg=0x0-0x3) X86.fnSLDT, X86.fnSTR, X86.fnLLDT, X86.fnLTR, // 0x0F,0x00(reg=0x0-0x3)
X86Op0F.opVERR, X86Op0F.opVERW, X86Grps.opGrpUndefined, X86Grps.opGrpUndefined // 0x0F,0x00(reg=0x4-0x7) X86.fnVERR, X86.fnVERW, X86.fnGRPUndefined, X86.fnGRPUndefined // 0x0F,0x00(reg=0x4-0x7)
]; ];
X86Op0F.aOpGrp6Real = [ X86.aOpGrp6Real = [
X86Grps.opGrpInvalid, X86Grps.opGrpInvalid, X86Grps.opGrpInvalid, X86Grps.opGrpInvalid, // 0x0F,0x00(reg=0x0-0x3) X86.fnGRPInvalid, X86.fnGRPInvalid, X86.fnGRPInvalid, X86.fnGRPInvalid, // 0x0F,0x00(reg=0x0-0x3)
X86Grps.opGrpInvalid, X86Grps.opGrpInvalid, X86Grps.opGrpUndefined, X86Grps.opGrpUndefined // 0x0F,0x00(reg=0x4-0x7) X86.fnGRPInvalid, X86.fnGRPInvalid, X86.fnGRPUndefined, X86.fnGRPUndefined // 0x0F,0x00(reg=0x4-0x7)
]; ];
/* /*
* Unlike Grp6, Grp7 does not require separate real-mode and protected-mode dispatch tables, because all Grp7 * Unlike Grp6, Grp7 does not require separate real-mode and protected-mode dispatch tables, because all Grp7
* instructions are valid in both modes. * instructions are valid in both modes.
*/ */
X86Op0F.aOpGrp7 = [ X86.aOpGrp7 = [
X86Op0F.opSGDT, X86Op0F.opSIDT, X86Op0F.opLGDT, X86Op0F.opLIDT, // 0x0F,0x01(reg=0x0-0x3) X86.fnSGDT, X86.fnSIDT, X86.fnLGDT, X86.fnLIDT, // 0x0F,0x01(reg=0x0-0x3)
X86Op0F.opSMSW, X86Grps.opGrpUndefined, X86Op0F.opLMSW, X86Grps.opGrpUndefined // 0x0F,0x01(reg=0x4-0x7) X86.fnSMSW, X86.fnGRPUndefined, X86.fnLMSW, X86.fnGRPUndefined // 0x0F,0x01(reg=0x4-0x7)
]; ];
if (typeof module !== 'undefined') module.exports = X86Op0F;

File diff suppressed because it is too large Load diff

View file

@ -36,7 +36,6 @@ if (typeof module !== 'undefined') {
var str = require("../../shared/lib/strlib"); var str = require("../../shared/lib/strlib");
var Messages = require("./messages"); var Messages = require("./messages");
var X86 = require("./x86"); var X86 = require("./x86");
var X86Help = require("./x86help");
} }
/** /**
@ -190,7 +189,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
return this.loadDesc8(addrDesc, sel, fSuppress); return this.loadDesc8(addrDesc, sel, fSuppress);
} }
if (!fSuppress) { if (!fSuppress) {
X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel); X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel);
} }
} }
return X86.ADDR_INVALID; return X86.ADDR_INVALID;
@ -237,14 +236,14 @@ X86Seg.loadIDTProt = function loadIDTProt(nIDT)
if (addrDesc + 7 <= cpu.addrIDTLimit) { if (addrDesc + 7 <= cpu.addrIDTLimit) {
return this.loadDesc8(addrDesc, nIDT) + cpu.regEIP; return this.loadDesc8(addrDesc, nIDT) + cpu.regEIP;
} }
X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, nIDT | X86.ERRCODE.IDT | X86.ERRCODE.EXT, true); X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, nIDT | X86.ERRCODE.IDT | X86.ERRCODE.EXT, true);
return X86.ADDR_INVALID; return X86.ADDR_INVALID;
}; };
/** /**
* checkReadReal(off, cb, fSuppress) * checkReadReal(off, cb, fSuppress)
* *
* TODO: Invoke X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1; * TODO: Invoke X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1;
* also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode. * also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode.
* *
* @this {X86Seg} * @this {X86Seg}
@ -261,7 +260,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
/** /**
* checkWriteReal(off, cb, fSuppress) * checkWriteReal(off, cb, fSuppress)
* *
* TODO: Invoke X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1; * TODO: Invoke X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off is 0xffff and cb is 1;
* also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode. * also, whether or not the opHelpFault() call should include an error code, since this is happening in real-mode.
* *
* @this {X86Seg} * @this {X86Seg}
@ -321,7 +320,7 @@ X86Seg.checkReadProtDown = function checkReadProtDown(off, cb, fSuppress)
X86Seg.checkReadProtDisallowed = function checkReadProtDisallowed(off, cb, fSuppress) X86Seg.checkReadProtDisallowed = function checkReadProtDisallowed(off, cb, fSuppress)
{ {
if (!fSuppress) { if (!fSuppress) {
X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0); X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
} }
return X86.ADDR_INVALID; return X86.ADDR_INVALID;
}; };
@ -372,7 +371,7 @@ X86Seg.checkWriteProtDown = function checkWriteProtDown(off, cb, fSuppress)
X86Seg.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb, fSuppress) X86Seg.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb, fSuppress)
{ {
if (!fSuppress) { if (!fSuppress) {
X86Help.opHelpFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0); X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
} }
return X86.ADDR_INVALID; return X86.ADDR_INVALID;
}; };
@ -411,7 +410,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest)
var selOld = cpu.segTSS.sel; var selOld = cpu.segTSS.sel;
if (!fNest) { if (!fNest) {
if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) { if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) {
X86Help.opHelpFault.call(cpu, X86.EXCEPTION.TS_FAULT, selNew, true); X86.fnFault.call(cpu, X86.EXCEPTION.TS_FAULT, selNew, true);
return false; return false;
} }
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS); cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS);
@ -425,7 +424,7 @@ X86Seg.switchTSS = function switchTSS(selNew, fNest)
} }
if (fNest) { if (fNest) {
if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) { if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) {
X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true); X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true);
return false; return false;
} }
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY); cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY);
@ -502,7 +501,7 @@ X86Seg.prototype.loadAcc = function(sel, fGDT)
return cpu.getShort(addrDesc + X86.DESC.ACC.OFFSET); return cpu.getShort(addrDesc + X86.DESC.ACC.OFFSET);
} }
} }
X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel); X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel);
return X86.DESC.ACC.INVALID; return X86.DESC.ACC.INVALID;
}; };
@ -684,13 +683,13 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
return this.base; return this.base;
} }
cpu.assert(false); cpu.assert(false);
if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, nFaultError, true); if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, nFaultError, true);
base = X86.ADDR_INVALID; base = X86.ADDR_INVALID;
break; break;
} }
else if (fGate !== false) { else if (fGate !== false) {
cpu.assert(false); cpu.assert(false);
if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true); if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
base = X86.ADDR_INVALID; base = X86.ADDR_INVALID;
break; break;
} }
@ -719,7 +718,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
* *
* Anyway, because of this, if acc is zero, we won't set fHalt on this GP_FAULT. * Anyway, because of this, if acc is zero, we won't set fHalt on this GP_FAULT.
*/ */
if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, !!acc); if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, !!acc);
base = X86.ADDR_INVALID; base = X86.ADDR_INVALID;
break; break;
} }
@ -727,14 +726,14 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
} }
else if (this.id == X86Seg.ID.STACK) { else if (this.id == X86Seg.ID.STACK) {
if (!selMasked || type < X86.DESC.ACC.TYPE.DATA_READONLY || (type & (X86.DESC.ACC.TYPE.CODE | X86.DESC.ACC.TYPE.READABLE)) == X86.DESC.ACC.TYPE.CODE) { if (!selMasked || type < X86.DESC.ACC.TYPE.DATA_READONLY || (type & (X86.DESC.ACC.TYPE.CODE | X86.DESC.ACC.TYPE.READABLE)) == X86.DESC.ACC.TYPE.CODE) {
if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true); if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
base = X86.ADDR_INVALID; base = X86.ADDR_INVALID;
break; break;
} }
} }
else if (this.id == X86Seg.ID.TSS) { else if (this.id == X86Seg.ID.TSS) {
if (!selMasked || type != X86.DESC.ACC.TYPE.TSS && type != X86.DESC.ACC.TYPE.TSS_BUSY) { if (!selMasked || type != X86.DESC.ACC.TYPE.TSS && type != X86.DESC.ACC.TYPE.TSS_BUSY) {
if (!fSuppress) X86Help.opHelpFault.call(cpu, X86.EXCEPTION.TS_FAULT, sel, true); if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.TS_FAULT, sel, true);
base = X86.ADDR_INVALID; base = X86.ADDR_INVALID;
break; break;
} }

View file

@ -106,8 +106,9 @@
"./modules/pcjs/lib/x86.js", "./modules/pcjs/lib/x86.js",
"./modules/pcjs/lib/x86seg.js", "./modules/pcjs/lib/x86seg.js",
"./modules/pcjs/lib/x86cpu.js", "./modules/pcjs/lib/x86cpu.js",
"./modules/pcjs/lib/x86grps.js", "./modules/pcjs/lib/x86func.js",
"./modules/pcjs/lib/x86help.js", "./modules/pcjs/lib/x86opxx.js",
"./modules/pcjs/lib/x86op0f.js",
"./modules/pcjs/lib/x86modb.js", "./modules/pcjs/lib/x86modb.js",
"./modules/pcjs/lib/x86modw.js", "./modules/pcjs/lib/x86modw.js",
"./modules/pcjs/lib/x86modb16.js", "./modules/pcjs/lib/x86modb16.js",
@ -115,8 +116,6 @@
"./modules/pcjs/lib/x86modb32.js", "./modules/pcjs/lib/x86modb32.js",
"./modules/pcjs/lib/x86modw32.js", "./modules/pcjs/lib/x86modw32.js",
"./modules/pcjs/lib/x86modsib.js", "./modules/pcjs/lib/x86modsib.js",
"./modules/pcjs/lib/x86opxx.js",
"./modules/pcjs/lib/x86op0f.js",
"./modules/pcjs/lib/chipset.js", "./modules/pcjs/lib/chipset.js",
"./modules/pcjs/lib/rom.js", "./modules/pcjs/lib/rom.js",
"./modules/pcjs/lib/ram.js", "./modules/pcjs/lib/ram.js",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff