More 80386 instructions
This commit is contained in:
parent
f098335db9
commit
f9cb8a5bec
15 changed files with 2873 additions and 1673 deletions
|
|
@ -40,3 +40,7 @@ When arrive here:
|
|||
and we complain that the IDTR limit for the real-mode IDT isn't 0x3FF (it's been set to 0xFFFF instead).
|
||||
That may be OK, but I need to verify that that's what the ROM intended. If it is, then I'll probably need
|
||||
to change our assertion from "cpu.addrIDTLimit == 0x03FF" to "cpu.addrIDTLimit >= 0x03FF".
|
||||
|
||||
Checkpoint
|
||||
---
|
||||
The BIOS now progresses as far as F000:F747 (PUSH GS).
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -15,12 +15,13 @@
|
|||
"PCJSCLASS": true,
|
||||
"DEBUGGER": true,
|
||||
"PREFETCH": true,
|
||||
"EAFUNCS": true,
|
||||
"FATARRAYS": true,
|
||||
"TYPEDARRAYS": true,
|
||||
"BACKTRACK": true,
|
||||
"SAMPLER": true,
|
||||
"BUGS_8086": true,
|
||||
"I386": true,
|
||||
"COMPAQ386": true,
|
||||
"Component": true,
|
||||
"State": true,
|
||||
"Bus": true,
|
||||
|
|
@ -61,6 +62,8 @@
|
|||
"DataView": false,
|
||||
"FileReader": false,
|
||||
"Uint8Array": false,
|
||||
"Uint16Array": false,
|
||||
"Int32Array": false,
|
||||
"setTimeout": false,
|
||||
"clearTimeout": false,
|
||||
"webkitAudioContext": false,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ if (typeof module !== 'undefined') {
|
|||
var str = require("../../shared/lib/strlib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Memory = require("./memory");
|
||||
var Messages = require("./messages");
|
||||
var State = require("./state");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ function ChipSet(parmsChipSet)
|
|||
Component.subclass(Component, ChipSet);
|
||||
|
||||
/*
|
||||
* Supported Models
|
||||
* Supported model numbers
|
||||
*
|
||||
* Unless otherwise noted, all BIOS references refer to the *original* BIOS released with each model.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1654,7 +1654,7 @@ if (DEBUGGER) {
|
|||
* @return {number}
|
||||
*/
|
||||
Debugger.prototype.getRegIndex = function(sReg) {
|
||||
return Debugger.REGS.indexOf(sReg.toUpperCase())
|
||||
return Debugger.REGS.indexOf(sReg.toUpperCase());
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ if (typeof module !== 'undefined') {
|
|||
*/
|
||||
function Disk(controller, drive, mode)
|
||||
{
|
||||
Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + ++Disk.nDisks}, Disk, Messages.DISK);
|
||||
Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + (++Disk.nDisks)}, Disk, Messages.DISK);
|
||||
|
||||
/*
|
||||
* Route all non-Debugger messages (eg, notice() and println() calls) through
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ Memory.writeLongChecked = function writeLongChecked(off, l)
|
|||
this.dbg.checkMemoryWrite(this.addr + off) ||
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 1) ||
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 2) ||
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 3)
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 3);
|
||||
}
|
||||
this.writeLongDirect(off, l);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ Panel.prototype.updateAnimation = function()
|
|||
var cBlocksRemaining = this.stats.cBlocks;
|
||||
for (i = 0; i < this.stats.cRegions; i++) {
|
||||
var cBlocksRegion = (this.stats.aRegions[i] >> Bus.BLOCK.COUNT_SHIFT) & Bus.BLOCK.COUNT_MASK;
|
||||
this.stats.aRects.push(rect = rectAvail.subDivide(cBlocksRegion, cBlocksRemaining, i == 0));
|
||||
this.stats.aRects.push(rect = rectAvail.subDivide(cBlocksRegion, cBlocksRemaining, !i));
|
||||
if (MAXDEBUG) this.log("region " + i + " rectangle: (" + rect.x + "," + rect.y + " " + rect.cx + "," + rect.cy + ")");
|
||||
cBlocksRemaining -= cBlocksRegion;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,12 +165,7 @@ RAM.prototype.reset = function()
|
|||
if (this.bus.addMemory(this.addrRAM, this.sizeRAM, Memory.TYPE.RAM)) {
|
||||
this.fAllocated = true;
|
||||
|
||||
var status = Math.floor(this.sizeRAM / 1024) + "Kb";
|
||||
if (this.comment) {
|
||||
status += " (" + this.comment + ")";
|
||||
this.comment = null;
|
||||
}
|
||||
this.status(status);
|
||||
this.status(Math.floor(this.sizeRAM / 1024) + "Kb");
|
||||
|
||||
/*
|
||||
* NOTE: I'm specifying MAXDEBUG for status() messages because I'm not yet sure I want these
|
||||
|
|
|
|||
|
|
@ -425,6 +425,21 @@ X86CPU.CYCLES_80286 = {
|
|||
nOpCyclesXLAT: 5
|
||||
};
|
||||
|
||||
X86CPU.CYCLES_80386 = {
|
||||
nOpCyclesBitSetR: 6,
|
||||
nOpCyclesBitSetM: 8,
|
||||
nOpCyclesBitSetMExtra: 5, // extra cycle cost for non-immediate BTC/BTR/BTS opcodes
|
||||
nOpCyclesBitTestR: 3,
|
||||
nOpCyclesBitTestM: 6,
|
||||
nOpCyclesBitTestMExtra: 6, // extra cycle cost for non-immediate BT opcode
|
||||
nOpCyclesIMulR: 9,
|
||||
nOpCyclesIMulM: 12,
|
||||
nOpCyclesSetR: 4,
|
||||
nOpCyclesSetM: 5,
|
||||
nOpCyclesShiftDR: 3,
|
||||
nOpCyclesShiftDM: 7
|
||||
};
|
||||
|
||||
/**
|
||||
* Memory Simulation Notes
|
||||
*
|
||||
|
|
@ -708,7 +723,7 @@ X86CPU.prototype.initProcessor = function()
|
|||
this.aOps = X86.aOps;
|
||||
this.aOpGrp4b = X86.aOpGrp4b;
|
||||
this.aOpGrp4w = X86.aOpGrp4w;
|
||||
this.aOpGrp6 = X86.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) {
|
||||
/*
|
||||
|
|
@ -724,27 +739,27 @@ X86CPU.prototype.initProcessor = function()
|
|||
this.aOpGrp4w = X86.aOpGrp4w.slice();
|
||||
this.nShiftCountMask = 0x1f; // on newer processors, all shift counts are MOD 32
|
||||
this.aOps[0x0F] = X86.opInvalid;
|
||||
this.aOps[X86.OPCODE.PUSHA] = X86.opPUSHA;
|
||||
this.aOps[X86.OPCODE.POPA] = X86.opPOPA;
|
||||
this.aOps[X86.OPCODE.BOUND] = X86.opBOUND;
|
||||
this.aOps[X86.OPCODE.ARPL] = X86.opInvalid;
|
||||
this.aOps[X86.OPCODE.FS] = X86.opInvalid;
|
||||
this.aOps[X86.OPCODE.GS] = X86.opInvalid;
|
||||
this.aOps[X86.OPCODE.OS] = X86.opInvalid;
|
||||
this.aOps[X86.OPCODE.AS] = X86.opInvalid;
|
||||
this.aOps[X86.OPCODE.PUSH16] = X86.opPUSH16;
|
||||
this.aOps[X86.OPCODE.IMUL16] = X86.opIMUL16;
|
||||
this.aOps[X86.OPCODE.PUSH8] = X86.opPUSH8;
|
||||
this.aOps[X86.OPCODE.IMUL8] = X86.opIMUL8;
|
||||
this.aOps[X86.OPCODE.INSB] = X86.opINSb;
|
||||
this.aOps[X86.OPCODE.INSW] = X86.opINSw;
|
||||
this.aOps[X86.OPCODE.OUTSB] = X86.opOUTSb;
|
||||
this.aOps[X86.OPCODE.OUTSW] = X86.opOUTSw;
|
||||
this.aOps[0xC0] = X86.opGrp2bi;
|
||||
this.aOps[0xC1] = X86.opGrp2wi;
|
||||
this.aOps[X86.OPCODE.ENTER] = X86.opENTER;
|
||||
this.aOps[X86.OPCODE.LEAVE] = X86.opLEAVE;
|
||||
this.aOps[0xF1] = X86.opINT1;
|
||||
this.aOps[X86.OPCODE.PUSHA] = X86.opPUSHA; // 0x60
|
||||
this.aOps[X86.OPCODE.POPA] = X86.opPOPA; // 0x61
|
||||
this.aOps[X86.OPCODE.BOUND] = X86.opBOUND; // 0x62
|
||||
this.aOps[X86.OPCODE.ARPL] = X86.opInvalid; // 0x63
|
||||
this.aOps[X86.OPCODE.FS] = X86.opInvalid; // 0x64
|
||||
this.aOps[X86.OPCODE.GS] = X86.opInvalid; // 0x65
|
||||
this.aOps[X86.OPCODE.OS] = X86.opInvalid; // 0x66
|
||||
this.aOps[X86.OPCODE.AS] = X86.opInvalid; // 0x67
|
||||
this.aOps[X86.OPCODE.PUSH16] = X86.opPUSH16; // 0x68
|
||||
this.aOps[X86.OPCODE.IMUL16] = X86.opIMUL16; // 0x69
|
||||
this.aOps[X86.OPCODE.PUSH8] = X86.opPUSH8; // 0x6A
|
||||
this.aOps[X86.OPCODE.IMUL8] = X86.opIMUL8; // 0x6B
|
||||
this.aOps[X86.OPCODE.INSB] = X86.opINSb; // 0x6C
|
||||
this.aOps[X86.OPCODE.INSW] = X86.opINSw; // 0x6D
|
||||
this.aOps[X86.OPCODE.OUTSB] = X86.opOUTSb; // 0x6E
|
||||
this.aOps[X86.OPCODE.OUTSW] = X86.opOUTSw; // 0x6F
|
||||
this.aOps[0xC0] = X86.opGRP2bn; // 0xC0
|
||||
this.aOps[0xC1] = X86.opGRP2wn; // 0xC1
|
||||
this.aOps[X86.OPCODE.ENTER] = X86.opENTER; // 0xC8
|
||||
this.aOps[X86.OPCODE.LEAVE] = X86.opLEAVE; // 0xC9
|
||||
this.aOps[0xF1] = X86.opINT1; // 0xF1
|
||||
this.aOpGrp4b[0x07] = X86.fnGRPInvalid;
|
||||
this.aOpGrp4w[0x07] = X86.fnGRPInvalid;
|
||||
|
||||
|
|
@ -757,15 +772,15 @@ X86CPU.prototype.initProcessor = function()
|
|||
|
||||
this.aOps0F = X86.aOps0F;
|
||||
this.aOps[0x0F] = X86.op0F;
|
||||
this.aOps[X86.OPCODE.ARPL] = X86.opARPL;
|
||||
this.aOps[X86.OPCODE.PUSHSP] = X86.opPUSHSP;
|
||||
this.aOps[X86.OPCODE.PUSHSP] = X86.opPUSHSP; // 0x54
|
||||
this.aOps[X86.OPCODE.ARPL] = X86.opARPL; // 0x63
|
||||
|
||||
if (I386 && this.model >= X86.MODEL_80386) {
|
||||
var bOpcode;
|
||||
this.aOps[X86.OPCODE.FS] = X86.opFS;
|
||||
this.aOps[X86.OPCODE.GS] = X86.opGS;
|
||||
this.aOps[X86.OPCODE.OS] = X86.opOS;
|
||||
this.aOps[X86.OPCODE.AS] = X86.opAS;
|
||||
this.aOps[X86.OPCODE.FS] = X86.opFS; // 0x64
|
||||
this.aOps[X86.OPCODE.GS] = X86.opGS; // 0x65
|
||||
this.aOps[X86.OPCODE.OS] = X86.opOS; // 0x66
|
||||
this.aOps[X86.OPCODE.AS] = X86.opAS; // 0x67
|
||||
this.aOps0F = X86.aOps0F.slice();
|
||||
for (bOpcode in X86.aOps0F386) {
|
||||
this.aOps0F[+bOpcode] = X86.aOps0F386[bOpcode];
|
||||
|
|
@ -1619,7 +1634,7 @@ X86CPU.prototype.getIP = function()
|
|||
*/
|
||||
X86CPU.prototype.setIP = function(off)
|
||||
{
|
||||
this.regLIP = this.segCS.base + (off & (I386? this.addrMask : 0xffff));
|
||||
this.regLIP = this.segCS.base + (off & (I386? this.dataMask : 0xffff));
|
||||
if (PREFETCH) this.flushPrefetch(this.regLIP);
|
||||
};
|
||||
|
||||
|
|
@ -1778,8 +1793,12 @@ X86CPU.prototype.setArithResult = function(dst, src, value, type, fSubtract)
|
|||
* setLogicResult(value, type, carry, overflow)
|
||||
*
|
||||
* Updates the flags for logical instructions (eg, AND, OR, TEST, XOR); ie, instructions
|
||||
* that update PF, ZF, and SF, while clearing CF and OF. AF is considered undefined. CF and OF
|
||||
* are automatically cleared unless explicitly set.
|
||||
* that update PF, ZF, and SF, while clearing CF and OF (although CF and OF can be explicitly
|
||||
* set via the carry and overflow parameters as needed). AF is always considered undefined.
|
||||
*
|
||||
* TODO: We should observe the behavior of AF on real CPUs, and determine if there is a
|
||||
* well-defined behavior, even though none is documented. Ditto for OF on shift instructions
|
||||
* when the shift count > 1.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} value
|
||||
|
|
@ -1797,6 +1816,25 @@ X86CPU.prototype.setLogicResult = function(value, type, carry, overflow)
|
|||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* setRotateResult(result, carry, size)
|
||||
*
|
||||
* Used by all rotate instructions (ie, RCL, RCR, ROL, ROR) to update CF and OF.
|
||||
*
|
||||
* TODO: We should observe the behavior of OF on real CPUs whenever the rotate count > 1,
|
||||
* and determine if there is a well-defined behavior, even though none is documented.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} result
|
||||
* @param {number} carry
|
||||
* @param {number} size
|
||||
*/
|
||||
X86CPU.prototype.setRotateResult = function(result, carry, size)
|
||||
{
|
||||
if (carry & size) this.setCF(); else this.clearCF();
|
||||
if ((result ^ carry) & size) this.setOF(); else this.clearOF();
|
||||
};
|
||||
|
||||
/**
|
||||
* getCarry()
|
||||
*
|
||||
|
|
@ -2949,22 +2987,6 @@ X86CPU.prototype.getIPByte = function()
|
|||
return b;
|
||||
};
|
||||
|
||||
/**
|
||||
* getIPDisp()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number} sign-extended value from the byte at the current IP; IP advanced by 1
|
||||
*/
|
||||
X86CPU.prototype.getIPDisp = function()
|
||||
{
|
||||
var w = ((PREFETCH? this.getBytePrefetch(this.regLIP) : this.getByte(this.regLIP)) << 24) >> 24;
|
||||
if (BACKTRACK) this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
|
||||
if (++this.regLIP > this.regLIPLimit) {
|
||||
this.setIP(this.regLIP - this.segCS.base);
|
||||
}
|
||||
return w & (I386? this.addrMask : 0xffff);
|
||||
};
|
||||
|
||||
/**
|
||||
* getIPShort()
|
||||
*
|
||||
|
|
@ -3025,6 +3047,34 @@ X86CPU.prototype.getIPWord = function()
|
|||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* getIPDisp()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number} sign-extended value from the byte at the current IP; IP advanced by 1
|
||||
*/
|
||||
X86CPU.prototype.getIPDisp = function()
|
||||
{
|
||||
var w = ((PREFETCH? this.getBytePrefetch(this.regLIP) : this.getByte(this.regLIP)) << 24) >> 24;
|
||||
if (BACKTRACK) this.bus.updateBackTrackCode(this.regLIP, this.backTrack.btiMemLo);
|
||||
if (++this.regLIP > this.regLIPLimit) {
|
||||
this.setIP(this.regLIP - this.segCS.base);
|
||||
}
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* getIPDispWord()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number} sign-extended value from the word at the current IP; IP advanced by 2 or 4
|
||||
*/
|
||||
X86CPU.prototype.getIPDispWord = function()
|
||||
{
|
||||
var w = this.getIPWord();
|
||||
return (this.dataSize == 2? ((w << 16) >> 16) : w);
|
||||
};
|
||||
|
||||
/**
|
||||
* getSIBAddr(mod)
|
||||
*
|
||||
|
|
@ -3348,7 +3398,7 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
|
|||
* Once we snap fStarting, we clear it, because technically, we've moved beyond "starting" and have
|
||||
* officially "started" now.
|
||||
*/
|
||||
var nDebugState = nMinCycles == 0? -1 : (this.aFlags.fStarting? 0 : 1);
|
||||
var nDebugState = (!nMinCycles)? -1 : (this.aFlags.fStarting? 0 : 1);
|
||||
this.aFlags.fStarting = false;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -204,6 +204,70 @@ X86.fnBOUND = function BOUND(dst, src)
|
|||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnBT(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnBT = function BT(dst, src)
|
||||
{
|
||||
if (dst & (1 << (src & 0x1f))) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesBitTestR : X86CPU.CYCLES_80386.nOpCyclesBitTestM);
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnBTC(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnBTC = function BTC(dst, src)
|
||||
{
|
||||
var bit = 1 << (src & 0x1f);
|
||||
if (dst & bit) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesBitSetR : X86CPU.CYCLES_80386.nOpCyclesBitSetM);
|
||||
return dst ^ bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnBTR(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnBTR = function BTR(dst, src)
|
||||
{
|
||||
var bit = 1 << (src & 0x1f);
|
||||
if (dst & bit) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesBitSetR : X86CPU.CYCLES_80386.nOpCyclesBitSetM);
|
||||
return dst & ~bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnBTS(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnBTS = function BTS(dst, src)
|
||||
{
|
||||
var bit = 1 << (src & 0x1f);
|
||||
if (dst & bit) this.setCF(); else this.clearCF();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesBitSetR : X86CPU.CYCLES_80386.nOpCyclesBitSetM);
|
||||
return dst | bit;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnCALLw(dst, src)
|
||||
*
|
||||
|
|
@ -688,6 +752,48 @@ X86.fnIMULw = function IMULw(dst, src)
|
|||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnIMULrw(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnIMULrw = function IMULrw(dst, src)
|
||||
{
|
||||
var result = ((dst << 16) >> 16) * ((src << 16) >> 16);
|
||||
if (result > 32767 || result < -32768) {
|
||||
this.setCF(); this.setOF();
|
||||
} else {
|
||||
this.clearCF(); this.clearOF();
|
||||
}
|
||||
result &= 0xffff;
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesIMulR : X86CPU.CYCLES_80386.nOpCyclesIMulM);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnIMULrd(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnIMULrd = function IMULrd(dst, src)
|
||||
{
|
||||
var result = dst * src;
|
||||
if (result > 2147483647 || result < -2147483648) {
|
||||
this.setCF(); this.setOF();
|
||||
} else {
|
||||
this.clearCF(); this.clearOF();
|
||||
}
|
||||
result |= 0;
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesIMulR : X86CPU.CYCLES_80386.nOpCyclesIMulM);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnINCb(dst, src)
|
||||
*
|
||||
|
|
@ -1103,14 +1209,14 @@ X86.fnMOV = function MOV(dst, src)
|
|||
};
|
||||
|
||||
/**
|
||||
* fnMOVimm(dst, src)
|
||||
* fnMOVn(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (current value, ignored)
|
||||
* @param {number} src (new value)
|
||||
* @return {number} dst (updated value, from src)
|
||||
*/
|
||||
X86.fnMOVImm = function MOVImm(dst, src)
|
||||
X86.fnMOVn = function MOVn(dst, src)
|
||||
{
|
||||
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? this.CYCLES.nOpCyclesMovRI : this.CYCLES.nOpCyclesMovMI);
|
||||
return src;
|
||||
|
|
@ -1337,17 +1443,17 @@ X86.fnRCLb = function RCLb(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = this.getCarry();
|
||||
shift %= 9;
|
||||
if (!shift) {
|
||||
count %= 9;
|
||||
if (!count) {
|
||||
carry <<= 7;
|
||||
} else {
|
||||
result = ((dst << shift) | (carry << (shift - 1)) | (dst >> (9 - shift))) & 0xff;
|
||||
carry = dst << (shift - 1);
|
||||
result = ((dst << count) | (carry << (count - 1)) | (dst >> (9 - count))) & 0xff;
|
||||
carry = dst << (count - 1);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.BYTE);
|
||||
this.setRotateResult(result, carry, X86.RESULT.BYTE);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RCLB', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1365,17 +1471,17 @@ X86.fnRCLw = function RCLw(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = this.getCarry();
|
||||
shift %= 17;
|
||||
if (!shift) {
|
||||
count %= 17;
|
||||
if (!count) {
|
||||
carry <<= 15;
|
||||
} else {
|
||||
result = ((dst << shift) | (carry << (shift - 1)) | (dst >> (17 - shift))) & 0xffff;
|
||||
carry = dst << (shift - 1);
|
||||
result = ((dst << count) | (carry << (count - 1)) | (dst >> (17 - count))) & 0xffff;
|
||||
carry = dst << (count - 1);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.WORD);
|
||||
this.setRotateResult(result, carry, X86.RESULT.WORD);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RCLW', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1393,17 +1499,17 @@ X86.fnRCLd = function RCLd(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask; // Yes, this 32-bit-only function could mask with 0x1f directly
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask; // Yes, this 32-bit-only function could mask with 0x1f directly
|
||||
if (count) {
|
||||
var carry = this.getCarry();
|
||||
/*
|
||||
* JavaScript Alert: much like a post-8086 Intel CPU, JavaScript shift counts are mod 32,
|
||||
* so "dst >>> 32" is equivalent to "dst >>> 0", which doesn't shift any bits at all. To
|
||||
* compensate, we shift one bit less than the maximum, and then shift one bit farther.
|
||||
*/
|
||||
result = (dst << shift) | (carry << (shift - 1)) | ((dst >>> (32 - shift)) >>> 1);
|
||||
carry = dst << (shift - 1);
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.DWORD);
|
||||
result = (dst << count) | (carry << (count - 1)) | ((dst >>> (32 - count)) >>> 1);
|
||||
carry = dst << (count - 1);
|
||||
this.setRotateResult(result, carry, X86.RESULT.DWORD);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RCLD', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1421,17 +1527,17 @@ X86.fnRCRb = function RCRb(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = this.getCarry();
|
||||
shift %= 9;
|
||||
if (!shift) {
|
||||
count %= 9;
|
||||
if (!count) {
|
||||
carry <<= 7;
|
||||
} else {
|
||||
result = ((dst >> shift) | (carry << (8 - shift)) | (dst << (9 - shift))) & 0xff;
|
||||
carry = dst << (8 - shift);
|
||||
result = ((dst >> count) | (carry << (8 - count)) | (dst << (9 - count))) & 0xff;
|
||||
carry = dst << (8 - count);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.BYTE);
|
||||
this.setRotateResult(result, carry, X86.RESULT.BYTE);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RCRB', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1449,17 +1555,17 @@ X86.fnRCRw = function RCRw(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = this.getCarry();
|
||||
shift %= 17;
|
||||
if (!shift) {
|
||||
count %= 17;
|
||||
if (!count) {
|
||||
carry <<= 15;
|
||||
} else {
|
||||
result = ((dst >> shift) | (carry << (16 - shift)) | (dst << (17 - shift))) & 0xffff;
|
||||
carry = dst << (16 - shift);
|
||||
result = ((dst >> count) | (carry << (16 - count)) | (dst << (17 - count))) & 0xffff;
|
||||
carry = dst << (16 - count);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.WORD);
|
||||
this.setRotateResult(result, carry, X86.RESULT.WORD);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RCRW', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1477,17 +1583,17 @@ X86.fnRCRd = function RCRd(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask; // Yes, this 32-bit-only function could mask with 0x1f directly
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask; // Yes, this 32-bit-only function could mask with 0x1f directly
|
||||
if (count) {
|
||||
var carry = this.getCarry();
|
||||
/*
|
||||
* JavaScript Alert: much like a post-8086 Intel CPU, JavaScript shift counts are mod 32,
|
||||
* so "dst << 32" is equivalent to "dst << 0", which doesn't shift any bits at all. To
|
||||
* compensate, we shift one bit less than the maximum, and then shift one bit farther.
|
||||
*/
|
||||
result = (dst >>> shift) | (carry << (32 - shift)) | ((dst << (32 - shift)) << 1);
|
||||
carry = dst << (32 - shift);
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.DWORD);
|
||||
result = (dst >>> count) | (carry << (32 - count)) | ((dst << (32 - count)) << 1);
|
||||
carry = dst << (32 - count);
|
||||
this.setRotateResult(result, carry, X86.RESULT.DWORD);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RCRD', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1543,17 +1649,17 @@ X86.fnROLb = function ROLb(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry;
|
||||
shift &= 0x7;
|
||||
if (!shift) {
|
||||
count &= 0x7;
|
||||
if (!count) {
|
||||
carry = dst << 7;
|
||||
} else {
|
||||
result = ((dst << shift) | (dst >> (8 - shift))) & 0xff;
|
||||
carry = dst << (shift - 1);
|
||||
result = ((dst << count) | (dst >> (8 - count))) & 0xff;
|
||||
carry = dst << (count - 1);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.BYTE);
|
||||
this.setRotateResult(result, carry, X86.RESULT.BYTE);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('ROLB', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1571,17 +1677,17 @@ X86.fnROLw = function ROLw(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry;
|
||||
shift &= 0xf;
|
||||
if (!shift) {
|
||||
count &= 0xf;
|
||||
if (!count) {
|
||||
carry = dst << 15;
|
||||
} else {
|
||||
result = ((dst << shift) | (dst >> (16 - shift))) & 0xffff;
|
||||
carry = dst << (shift - 1);
|
||||
result = ((dst << count) | (dst >> (16 - count))) & 0xffff;
|
||||
carry = dst << (count - 1);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.WORD);
|
||||
this.setRotateResult(result, carry, X86.RESULT.WORD);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('ROLW', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1599,17 +1705,17 @@ X86.fnRORb = function RORb(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry;
|
||||
shift &= 0x7;
|
||||
if (!shift) {
|
||||
count &= 0x7;
|
||||
if (!count) {
|
||||
carry = dst;
|
||||
} else {
|
||||
result = ((dst >> shift) | (dst << (8 - shift))) & 0xff;
|
||||
carry = dst << (8 - shift);
|
||||
result = ((dst >> count) | (dst << (8 - count))) & 0xff;
|
||||
carry = dst << (8 - count);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.BYTE);
|
||||
this.setRotateResult(result, carry, X86.RESULT.BYTE);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RORB', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1627,17 +1733,17 @@ X86.fnRORw = function RORw(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry;
|
||||
shift &= 0xf;
|
||||
if (!shift) {
|
||||
count &= 0xf;
|
||||
if (!count) {
|
||||
carry = dst;
|
||||
} else {
|
||||
result = ((dst >> shift) | (dst << (16 - shift))) & 0xffff;
|
||||
carry = dst << (16 - shift);
|
||||
result = ((dst >> count) | (dst << (16 - count))) & 0xffff;
|
||||
carry = dst << (16 - count);
|
||||
}
|
||||
X86.setRotateResult.call(this, result, carry, X86.RESULT.WORD);
|
||||
this.setRotateResult(result, carry, X86.RESULT.WORD);
|
||||
}
|
||||
if (DEBUG && DEBUGGER) this.traceLog('RORW', dst, src, flagsIn, this.getPS(), result);
|
||||
return result;
|
||||
|
|
@ -1646,10 +1752,6 @@ X86.fnRORw = function RORw(dst, src)
|
|||
/**
|
||||
* fnSARb(dst, src)
|
||||
*
|
||||
* NOTE: Although we set all the arithmetic flags for shift instructions, AF isn't actually
|
||||
* defined on a real 8086/8088. Similarly, OF is undefined for shifts > 1. See fnSHLb() for
|
||||
* more details.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
|
||||
|
|
@ -1657,12 +1759,12 @@ X86.fnRORw = function RORw(dst, src)
|
|||
*/
|
||||
X86.fnSARb = function SARb(dst, src)
|
||||
{
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
if (shift > 8) shift = 9;
|
||||
var temp = ((dst << 24) >> 24) >> (shift - 1);
|
||||
dst = (temp >> 1) & 0xff;
|
||||
this.setLogicResult(dst, X86.RESULT.BYTE, temp & 0x1);
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
if (count > 8) count = 9;
|
||||
var carry = ((dst << 24) >> 24) >> (count - 1);
|
||||
dst = (carry >> 1) & 0xff;
|
||||
this.setLogicResult(dst, X86.RESULT.BYTE, carry & 0x1);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1670,10 +1772,6 @@ X86.fnSARb = function SARb(dst, src)
|
|||
/**
|
||||
* fnSARw(dst, src)
|
||||
*
|
||||
* NOTE: Although we set all the arithmetic flags for shift instructions, AF isn't actually
|
||||
* defined on a real 8086/8088. Similarly, OF is undefined for shifts > 1. See fnSHLb() for
|
||||
* more details.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
|
||||
|
|
@ -1681,12 +1779,12 @@ X86.fnSARb = function SARb(dst, src)
|
|||
*/
|
||||
X86.fnSARw = function SARw(dst, src)
|
||||
{
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
if (shift > 16) shift = 17;
|
||||
var temp = ((dst << 16) >> 16) >> (shift - 1);
|
||||
dst = (temp >> 1) & 0xffff;
|
||||
this.setLogicResult(dst, X86.RESULT.WORD, temp & 0x1);
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
if (count > 16) count = 17;
|
||||
var carry = ((dst << 16) >> 16) >> (count - 1);
|
||||
dst = (carry >> 1) & 0xffff;
|
||||
this.setLogicResult(dst, X86.RESULT.WORD, carry & 0x1);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1723,6 +1821,227 @@ X86.fnSBBw = function SBBw(dst, src)
|
|||
return w & 0xffff;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETcc()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {function(number,number)} fnSet
|
||||
*/
|
||||
X86.fnSETcc = function SETcc(fnSet)
|
||||
{
|
||||
this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.aOpModMemByte[this.getIPByte()].call(this, fnSet);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesSetR : X86CPU.CYCLES_80386.nOpCyclesSetM);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETO(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETO = function SETO(dst, src)
|
||||
{
|
||||
return (this.getOF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNO(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNO = function SETNO(dst, src)
|
||||
{
|
||||
return (this.getOF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETC(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETC = function SETC(dst, src)
|
||||
{
|
||||
return (this.getCF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNC(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNC = function SETNC(dst, src)
|
||||
{
|
||||
return (this.getCF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETZ(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETZ = function SETZ(dst, src)
|
||||
{
|
||||
return (this.getZF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNZ(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNZ = function SETNZ(dst, src)
|
||||
{
|
||||
return (this.getZF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETBE(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETBE = function SETBE(dst, src)
|
||||
{
|
||||
return (this.getCF() || this.getZF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNBE(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNBE = function SETNBE(dst, src)
|
||||
{
|
||||
return (this.getCF() || this.getZF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETS(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETS = function SETS(dst, src)
|
||||
{
|
||||
return (this.getSF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNS(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNS = function SETNS(dst, src)
|
||||
{
|
||||
return (this.getSF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETP(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETP = function SETP(dst, src)
|
||||
{
|
||||
return (this.getPF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNP(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNP = function SETNP(dst, src)
|
||||
{
|
||||
return (this.getPF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETL(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETL = function SETL(dst, src)
|
||||
{
|
||||
return (!this.getSF() != !this.getOF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNL(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNL = function SETNL(dst, src)
|
||||
{
|
||||
return (!this.getSF() != !this.getOF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETLE(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETLE = function SETLE(dst, src)
|
||||
{
|
||||
return (this.getZF() || !this.getSF() != !this.getOF()? 1 : 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSETNLE(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst (ignored)
|
||||
* @param {number} src (ignored)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSETNLE = function SETNLE(dst, src)
|
||||
{
|
||||
return (this.getZF() || !this.getSF() != !this.getOF()? 0 : 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSGDT(dst, src)
|
||||
*
|
||||
|
|
@ -1786,15 +2105,6 @@ X86.fnSGDT = function SGDT(dst, src)
|
|||
/**
|
||||
* fnSHLb(dst, src)
|
||||
*
|
||||
* NOTE: Although we set all the arithmetic flags for shift instructions, AF isn't actually
|
||||
* defined on a real 8086/8088. Similarly, OF is undefined for shifts > 1.
|
||||
*
|
||||
* For example, when AL=09, "SHL AL,1" may clear AF on a real CPU, whereas we will set it.
|
||||
* However, until I find or produce documented 8086/8088 behaviors for AF and OF, and/or code
|
||||
* that depends on them, I'll continue setting AF and OF "normally".
|
||||
*
|
||||
* See also: AND, OR, TEST, and XOR (those instructions leave AF undefined as well).
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
|
||||
|
|
@ -1804,13 +2114,13 @@ X86.fnSHLb = function SHLb(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = 0;
|
||||
if (shift > 8) {
|
||||
if (count > 8) {
|
||||
result = 0;
|
||||
} else {
|
||||
carry = dst << (shift - 1);
|
||||
carry = dst << (count - 1);
|
||||
result = (carry << 1) & 0xff;
|
||||
}
|
||||
this.setLogicResult(result, X86.RESULT.BYTE, carry & X86.RESULT.BYTE, (result ^ carry) & X86.RESULT.BYTE);
|
||||
|
|
@ -1822,10 +2132,6 @@ X86.fnSHLb = function SHLb(dst, src)
|
|||
/**
|
||||
* fnSHLw(dst, src)
|
||||
*
|
||||
* NOTE: Although we set all the arithmetic flags for shift instructions, AF isn't actually
|
||||
* defined on a real 8086/8088. Similarly, OF is undefined for shifts > 1. See fnSHLb() for
|
||||
* more details.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
|
||||
|
|
@ -1835,13 +2141,13 @@ X86.fnSHLw = function SHLw(dst, src)
|
|||
{
|
||||
var result = dst;
|
||||
var flagsIn = (DEBUG? this.getPS() : 0);
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = 0;
|
||||
if (shift > 16) {
|
||||
if (count > 16) {
|
||||
result = 0;
|
||||
} else {
|
||||
carry = dst << (shift - 1);
|
||||
carry = dst << (count - 1);
|
||||
result = (carry << 1) & 0xffff;
|
||||
}
|
||||
this.setLogicResult(result, X86.RESULT.WORD, carry & X86.RESULT.WORD, (result ^ carry) & X86.RESULT.WORD);
|
||||
|
|
@ -1851,11 +2157,101 @@ X86.fnSHLw = function SHLw(dst, src)
|
|||
};
|
||||
|
||||
/**
|
||||
* fnSHRb(dst, src)
|
||||
* fnSHLDw(dst, src, count)
|
||||
*
|
||||
* NOTE: Although we set all the arithmetic flags for shift instructions, AF isn't actually
|
||||
* defined on a real 8086/8088. Similarly, OF is undefined for shifts > 1. See fnSHLb() for
|
||||
* more details.
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @param {number} count (0-31)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHLDw = function SHLDw(dst, src, count)
|
||||
{
|
||||
if (count) {
|
||||
if (count > 16) {
|
||||
dst = src;
|
||||
count -= 16;
|
||||
}
|
||||
var carry = dst << (count - 1);
|
||||
dst = ((carry << 1) | (src >> (16 - count))) & 0xffff;
|
||||
this.setLogicResult(dst, X86.RESULT.WORD, carry & X86.RESULT.WORD);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHLDd(dst, src, count)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @param {number} count
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHLDd = function SHLDd(dst, src, count)
|
||||
{
|
||||
if (count) {
|
||||
var carry = dst << (count - 1);
|
||||
dst = (carry << 1) | (src >> (32 - count));
|
||||
this.setLogicResult(dst, X86.RESULT.DWORD, carry & X86.RESULT.DWORD);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHLDwi(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHLDwi = function SHLDwi(dst, src)
|
||||
{
|
||||
return X86.fnSHLDw.call(this, dst, src, this.getIPByte());
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHLDdi(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHLDdi = function SHLDdi(dst, src)
|
||||
{
|
||||
return X86.fnSHLDd.call(this, dst, src, this.getIPByte());
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHLDwCL(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHLDwCL = function SHLDwCL(dst, src)
|
||||
{
|
||||
return X86.fnSHLDw.call(this, dst, src, this.regECX & 0x1f);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHLDdCL(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHLDdCL = function SHLDdCL(dst, src)
|
||||
{
|
||||
return X86.fnSHLDd.call(this, dst, src, this.regECX & 0x1f);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRb(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
|
|
@ -1864,11 +2260,11 @@ X86.fnSHLw = function SHLw(dst, src)
|
|||
*/
|
||||
X86.fnSHRb = function SHRb(dst, src)
|
||||
{
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var temp = (shift > 8? 0 : (dst >> (shift - 1)));
|
||||
dst = (temp >> 1) & 0xff;
|
||||
this.setLogicResult(dst, X86.RESULT.BYTE, temp & 0x1, dst & X86.RESULT.BYTE);
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = (count > 8? 0 : (dst >> (count - 1)));
|
||||
dst = (carry >> 1) & 0xff;
|
||||
this.setLogicResult(dst, X86.RESULT.BYTE, carry & 0x1, dst & X86.RESULT.BYTE);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
|
@ -1876,10 +2272,6 @@ X86.fnSHRb = function SHRb(dst, src)
|
|||
/**
|
||||
* fnSHRw(dst, src)
|
||||
*
|
||||
* NOTE: Although we set all the arithmetic flags for shift instructions, AF isn't actually
|
||||
* defined on a real 8086/8088. Similarly, OF is undefined for shifts > 1. See fnSHLb() for
|
||||
* more details.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src (1 or CL, or an immediate byte for 80186/80188 and up)
|
||||
|
|
@ -1887,15 +2279,109 @@ X86.fnSHRb = function SHRb(dst, src)
|
|||
*/
|
||||
X86.fnSHRw = function SHRw(dst, src)
|
||||
{
|
||||
var shift = src & this.nShiftCountMask;
|
||||
if (shift) {
|
||||
var temp = (shift > 16? 0 : (dst >> (shift - 1)));
|
||||
dst = (temp >> 1) & 0xffff;
|
||||
this.setLogicResult(dst, X86.RESULT.WORD, temp & 0x1, dst & X86.RESULT.WORD);
|
||||
var count = src & this.nShiftCountMask;
|
||||
if (count) {
|
||||
var carry = (count > 16? 0 : (dst >> (count - 1)));
|
||||
dst = (carry >> 1) & 0xffff;
|
||||
this.setLogicResult(dst, X86.RESULT.WORD, carry & 0x1, dst & X86.RESULT.WORD);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRDw(dst, src, count)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @param {number} count (0-31)
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHRDw = function SHRDw(dst, src, count)
|
||||
{
|
||||
if (count) {
|
||||
if (count > 16) {
|
||||
dst = src;
|
||||
count -= 16;
|
||||
}
|
||||
var carry = dst >> (count - 1);
|
||||
dst = ((carry >> 1) | (src << (16 - count))) & 0xffff;
|
||||
this.setLogicResult(dst, X86.RESULT.WORD, carry & 0x1);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRDd(dst, src, count)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @param {number} count
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHRDd = function SHRDd(dst, src, count)
|
||||
{
|
||||
if (count) {
|
||||
var carry = dst >> (count - 1);
|
||||
dst = (carry >> 1) | (src << (32 - count));
|
||||
this.setLogicResult(dst, X86.RESULT.DWORD, carry & 0x1);
|
||||
}
|
||||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRDwi(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHRDwi = function SHRDwi(dst, src)
|
||||
{
|
||||
return X86.fnSHRDw.call(this, dst, src, this.getIPByte());
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRDdi(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHRDdi = function SHRDdi(dst, src)
|
||||
{
|
||||
return X86.fnSHRDd.call(this, dst, src, this.getIPByte());
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRDwCL(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHRDwCL = function SHRDwCL(dst, src)
|
||||
{
|
||||
return X86.fnSHRDw.call(this, dst, src, this.regECX & 0x1f);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSHRDdCL(dst, src)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSHRDdCL = function SHRDdCL(dst, src)
|
||||
{
|
||||
return X86.fnSHRDd.call(this, dst, src, this.regECX & 0x1f);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnSIDT(dst, src)
|
||||
*
|
||||
|
|
@ -2351,26 +2837,6 @@ X86.fnTBD = function TBD(dst, src)
|
|||
return dst;
|
||||
};
|
||||
|
||||
/**
|
||||
* setRotateResult(result, carry, size)
|
||||
*
|
||||
* Used by all rotate instructions (RCL, RCR, ROL, ROR) to update CF and OF.
|
||||
*
|
||||
* NOTE: Although I've yet to find confirmation of this for the 8086/8088, OF is undefined on modern x86 CPUs
|
||||
* for shift counts > 1 (in fact, on modern CPUs, OF tends to be clear in those situations). Since I set OF the
|
||||
* same way for all shift counts, my well-defined behavior may or may not match Intel's undefined behavior.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} result
|
||||
* @param {number} carry
|
||||
* @param {number} size
|
||||
*/
|
||||
X86.setRotateResult = function(result, carry, size)
|
||||
{
|
||||
if (carry & size) this.setCF(); else this.clearCF();
|
||||
if ((result ^ carry) & size) this.setOF(); else this.clearOF();
|
||||
};
|
||||
|
||||
/**
|
||||
* fnGRPFault(dst, src)
|
||||
*
|
||||
|
|
@ -2453,12 +2919,12 @@ X86.fnSrcCountCL = function SrcCountCL()
|
|||
};
|
||||
|
||||
/**
|
||||
* fnSrcCountImm()
|
||||
* fnSrcCountN()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
*/
|
||||
X86.fnSrcCountImm = function SrcCountImm()
|
||||
X86.fnSrcCountN = function SrcCountN()
|
||||
{
|
||||
var count = this.getIPByte();
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? this.CYCLES.nOpCyclesShiftCR : this.CYCLES.nOpCyclesShiftCM) + (count << this.CYCLES.nOpCyclesShiftCS);
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ if (typeof module !== 'undefined') {
|
|||
}
|
||||
|
||||
/**
|
||||
* op=0x0F,0x00 (GRP6 rm)
|
||||
* op=0x0F,0x00 (GRP6 mem/reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp6 = function GRP6()
|
||||
X86.opGRP6 = function GRP6()
|
||||
{
|
||||
var bModRM = this.getIPByte();
|
||||
if ((bModRM & 0x38) < 0x10) { // possible reg values: 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
|
||||
|
|
@ -51,11 +51,11 @@ X86.opGrp6 = function GRP6()
|
|||
};
|
||||
|
||||
/**
|
||||
* op=0x0F,0x01 (GRP7 rm)
|
||||
* op=0x0F,0x01 (GRP7 mem/reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp7 = function GRP7()
|
||||
X86.opGRP7 = function GRP7()
|
||||
{
|
||||
var bModRM = this.getIPByte();
|
||||
if (!(bModRM & 0x10)) {
|
||||
|
|
@ -67,7 +67,7 @@ X86.opGrp7 = function GRP7()
|
|||
/**
|
||||
* opLAR()
|
||||
*
|
||||
* op=0x0F,0x02 (LAR reg,rm)
|
||||
* op=0x0F,0x02 (LAR reg,mem/reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
|
|
@ -79,7 +79,7 @@ X86.opLAR = function LAR()
|
|||
/**
|
||||
* opLSL()
|
||||
*
|
||||
* op=0x0F,0x03 (LSL reg,rm)
|
||||
* op=0x0F,0x03 (LSL reg,mem/reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
|
|
@ -311,6 +311,486 @@ X86.opMOVcrr = function MOVcrr()
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* opJOw()
|
||||
*
|
||||
* op=0x0F,0x80 (JO rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJOw = function JOw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNOw()
|
||||
*
|
||||
* op=0x0F,0x81 (JNO rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNOw = function JNOw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJCw()
|
||||
*
|
||||
* op=0x0F,0x82 (JC rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJCw = function JCw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getCF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNCw()
|
||||
*
|
||||
* op=0x0F,0x83 (JNC rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNCw = function JNCw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getCF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJZw()
|
||||
*
|
||||
* op=0x0F,0x84 (JZ rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJZw = function JZw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNZw()
|
||||
*
|
||||
* op=0x0F,0x85 (JNZ rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNZw = function JNZw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJBEw()
|
||||
*
|
||||
* op=0x0F,0x86 (JBE rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJBEw = function JBEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getCF() || this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNBEw()
|
||||
*
|
||||
* op=0x0F,0x87 (JNBE rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNBEw = function JNBEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getCF() && !this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJSw()
|
||||
*
|
||||
* op=0x0F,0x88 (JS rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJSw = function JSw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getSF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNSw()
|
||||
*
|
||||
* op=0x0F,0x89 (JNS rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNSw = function JNSw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getSF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJPw()
|
||||
*
|
||||
* op=0x0F,0x8A (JP rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJPw = function JPw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getPF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNPw()
|
||||
*
|
||||
* op=0x0F,0x8B (JNP rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNPw = function JNPw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getPF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJLw()
|
||||
*
|
||||
* op=0x0F,0x8C (JL rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJLw = function JLw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getSF() != !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNLw()
|
||||
*
|
||||
* op=0x0F,0x8D (JNL rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNLw = function JNLw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getSF() == !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJLEw()
|
||||
*
|
||||
* op=0x0F,0x8E (JLE rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJLEw = function JLEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (this.getZF() || !this.getSF() != !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opJNLEw()
|
||||
*
|
||||
* op=0x0F,0x8F (JNLE rel16/rel32)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opJNLEw = function JNLEw()
|
||||
{
|
||||
var disp = this.getIPDispWord();
|
||||
if (!this.getZF() && !this.getSF() == !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpCFall;
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETO()
|
||||
*
|
||||
* op=0x0F,0x90 (SETO b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETO = function SETO()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETO);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNO()
|
||||
*
|
||||
* op=0x0F,0x91 (SETNO b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNO = function SETNO()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETO);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETC()
|
||||
*
|
||||
* op=0x0F,0x92 (SETC b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETC = function SETC()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETC);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNC()
|
||||
*
|
||||
* op=0x0F,0x93 (SETNC b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNC = function SETNC()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNC);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETZ()
|
||||
*
|
||||
* op=0x0F,0x94 (SETZ b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETZ = function SETZ()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETZ);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNZ()
|
||||
*
|
||||
* op=0x0F,0x95 (SETNZ b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNZ = function SETNZ()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNZ);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETBE()
|
||||
*
|
||||
* op=0x0F,0x96 (SETBE b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETBE = function SETBE()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETBE);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNBE()
|
||||
*
|
||||
* op=0x0F,0x97 (SETNBE b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNBE = function SETNBE()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNBE);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETS()
|
||||
*
|
||||
* op=0x0F,0x98 (SETS b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETS = function SETS()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETS);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNS()
|
||||
*
|
||||
* op=0x0F,0x99 (SETNS b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNS = function SETNS()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNS);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETP()
|
||||
*
|
||||
* op=0x0F,0x9A (SETP b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETP = function SETP()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETP);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNP()
|
||||
*
|
||||
* op=0x0F,0x9B (SETNP b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNP = function SETNP()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNP);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETL()
|
||||
*
|
||||
* op=0x0F,0x9C (SETL b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETL = function SETL()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETL);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNL()
|
||||
*
|
||||
* op=0x0F,0x9D (SETNL b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNL = function SETNL()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNL);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETLE()
|
||||
*
|
||||
* op=0x0F,0x9E (SETLE b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETLE = function SETLE()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETLE);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSETNLE()
|
||||
*
|
||||
* op=0x0F,0x9F (SETNLE b)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSETNLE = function SETNLE()
|
||||
{
|
||||
X86.fnSETcc.call(this, X86.fnSETNLE);
|
||||
};
|
||||
|
||||
/**
|
||||
* opPUSHFS()
|
||||
*
|
||||
|
|
@ -337,6 +817,55 @@ X86.opPOPFS = function POPFS()
|
|||
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
|
||||
};
|
||||
|
||||
/**
|
||||
* opBT()
|
||||
*
|
||||
* op=0x0F,0xA3 (BT mem/reg,reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opBT = function BT()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBT);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= X86CPU.CYCLES_80386.nOpCyclesBitTestMExtra;
|
||||
};
|
||||
|
||||
/**
|
||||
* opSHLDn()
|
||||
*
|
||||
* op=0x0F,0xA4 (SHLD mem/reg,imm8)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSHLDn = function SHLDn()
|
||||
{
|
||||
/*
|
||||
* TODO: While we rely on bOpcodeBias to dispatch OPERAND-appropriate handlers for the primary opcode bytes,
|
||||
* we don't (yet) have a similar dispatch mechanism for secondary opcode bytes (ie, 0x0F), so the dispatch check
|
||||
* has to happen below.
|
||||
*/
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHLDwi : X86.fnSHLDdi);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesShiftDR : X86CPU.CYCLES_80386.nOpCyclesShiftDM);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSHLDcl()
|
||||
*
|
||||
* op=0x0F,0xA5 (SHLD mem/reg,CL)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSHLDcl = function SHLDcl()
|
||||
{
|
||||
/*
|
||||
* TODO: While we rely on bOpcodeBias to dispatch OPERAND-appropriate handlers for the primary opcode bytes,
|
||||
* we don't (yet) have a similar dispatch mechanism for secondary opcode bytes (ie, 0x0F), so the dispatch check
|
||||
* has to happen below.
|
||||
*/
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHLDwCL : X86.fnSHLDdCL);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesShiftDR : X86CPU.CYCLES_80386.nOpCyclesShiftDM);
|
||||
};
|
||||
|
||||
/**
|
||||
* opPUSHGS()
|
||||
*
|
||||
|
|
@ -363,10 +892,112 @@ X86.opPOPGS = function POPGS()
|
|||
this.nStepCycles -= this.CYCLES.nOpCyclesPopReg;
|
||||
};
|
||||
|
||||
/**
|
||||
* opBTS()
|
||||
*
|
||||
* op=0x0F,0xAB (BTC mem/reg,reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opBTS = function BTS()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTS);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= X86CPU.CYCLES_80386.nOpCyclesBitSetMExtra;
|
||||
};
|
||||
|
||||
/**
|
||||
* opSHRDn()
|
||||
*
|
||||
* op=0x0F,0xAC (SHRD mem/reg,imm8)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSHRDn = function SHRDn()
|
||||
{
|
||||
/*
|
||||
* TODO: While we rely on bOpcodeBias to dispatch OPERAND-appropriate handlers for the primary opcode bytes,
|
||||
* we don't (yet) have a similar dispatch mechanism for secondary opcode bytes (ie, 0x0F), so the dispatch check
|
||||
* has to happen below.
|
||||
*/
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHRDwi : X86.fnSHRDdi);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesShiftDR : X86CPU.CYCLES_80386.nOpCyclesShiftDM);
|
||||
};
|
||||
|
||||
/**
|
||||
* opSHRDcl()
|
||||
*
|
||||
* op=0x0F,0xAD (SHRD mem/reg,CL)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opSHRDcl = function SHRDcl()
|
||||
{
|
||||
/*
|
||||
* TODO: While we rely on bOpcodeBias to dispatch OPERAND-appropriate handlers for the primary opcode bytes,
|
||||
* we don't (yet) have a similar dispatch mechanism for secondary opcode bytes (ie, 0x0F), so the dispatch check
|
||||
* has to happen below.
|
||||
*/
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnSHRDwCL : X86.fnSHRDdCL);
|
||||
this.nStepCycles -= (this.regEA === X86.ADDR_INVALID? X86CPU.CYCLES_80386.nOpCyclesShiftDR : X86CPU.CYCLES_80386.nOpCyclesShiftDM);
|
||||
};
|
||||
|
||||
/**
|
||||
* opIMUL()
|
||||
*
|
||||
* op=0x0F,0xAF (IMUL reg,mem/reg) (80386 and up)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opIMUL = function IMUL()
|
||||
{
|
||||
/*
|
||||
* TODO: While we rely on bOpcodeBias to dispatch OPERAND-appropriate handlers for the primary opcode bytes,
|
||||
* we don't (yet) have a similar dispatch mechanism for secondary opcode bytes (ie, 0x0F), so the dispatch check
|
||||
* has to happen below.
|
||||
*/
|
||||
this.aOpModRegWord[this.getIPByte()].call(this, this.dataSize == 2? X86.fnIMULrw : X86.fnIMULrd);
|
||||
};
|
||||
|
||||
/**
|
||||
* opBTR()
|
||||
*
|
||||
* op=0x0F,0xB3 (BTC mem/reg,reg) (80386 and up)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opBTR = function BTR()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTR);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= X86CPU.CYCLES_80386.nOpCyclesBitSetMExtra;
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0x0F,0xBA (GRP8 mem/reg) (80386 and up)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGRP8 = function GRP8()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp8, this.getIPByte);
|
||||
};
|
||||
|
||||
/**
|
||||
* opBTC()
|
||||
*
|
||||
* op=0x0F,0xBB (BTC mem/reg,reg)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opBTC = function BTC()
|
||||
{
|
||||
this.aOpModMemWord[this.getIPByte()].call(this, X86.fnBTC);
|
||||
if (this.regEA !== X86.ADDR_INVALID) this.nStepCycles -= X86CPU.CYCLES_80386.nOpCyclesBitSetMExtra;
|
||||
};
|
||||
|
||||
X86.aOps0F = new Array(256);
|
||||
|
||||
X86.aOps0F[0x00] = X86.opGrp6;
|
||||
X86.aOps0F[0x01] = X86.opGrp7;
|
||||
X86.aOps0F[0x00] = X86.opGRP6;
|
||||
X86.aOps0F[0x01] = X86.opGRP7;
|
||||
X86.aOps0F[0x02] = X86.opLAR;
|
||||
X86.aOps0F[0x03] = X86.opLSL;
|
||||
X86.aOps0F[0x05] = X86.opLOADALL;
|
||||
|
|
@ -386,14 +1017,56 @@ if (I386) {
|
|||
X86.aOps0F386 = [];
|
||||
X86.aOps0F386[0x20] = X86.opMOVrcr;
|
||||
X86.aOps0F386[0x22] = X86.opMOVcrr;
|
||||
X86.aOps0F386[0x80] = X86.opJOw;
|
||||
X86.aOps0F386[0x81] = X86.opJNOw;
|
||||
X86.aOps0F386[0x82] = X86.opJCw;
|
||||
X86.aOps0F386[0x83] = X86.opJNCw;
|
||||
X86.aOps0F386[0x84] = X86.opJZw;
|
||||
X86.aOps0F386[0x85] = X86.opJNZw;
|
||||
X86.aOps0F386[0x86] = X86.opJBEw;
|
||||
X86.aOps0F386[0x87] = X86.opJNBEw;
|
||||
X86.aOps0F386[0x88] = X86.opJSw;
|
||||
X86.aOps0F386[0x89] = X86.opJNSw;
|
||||
X86.aOps0F386[0x8A] = X86.opJPw;
|
||||
X86.aOps0F386[0x8B] = X86.opJNPw;
|
||||
X86.aOps0F386[0x8C] = X86.opJLw;
|
||||
X86.aOps0F386[0x8D] = X86.opJNLw;
|
||||
X86.aOps0F386[0x8E] = X86.opJLEw;
|
||||
X86.aOps0F386[0x8F] = X86.opJNLEw;
|
||||
X86.aOps0F386[0x90] = X86.opSETO;
|
||||
X86.aOps0F386[0x91] = X86.opSETNO;
|
||||
X86.aOps0F386[0x92] = X86.opSETC;
|
||||
X86.aOps0F386[0x93] = X86.opSETNC;
|
||||
X86.aOps0F386[0x94] = X86.opSETZ;
|
||||
X86.aOps0F386[0x95] = X86.opSETNZ;
|
||||
X86.aOps0F386[0x96] = X86.opSETBE;
|
||||
X86.aOps0F386[0x97] = X86.opSETNBE;
|
||||
X86.aOps0F386[0x98] = X86.opSETS;
|
||||
X86.aOps0F386[0x99] = X86.opSETNS;
|
||||
X86.aOps0F386[0x9A] = X86.opSETP;
|
||||
X86.aOps0F386[0x9B] = X86.opSETNP;
|
||||
X86.aOps0F386[0x9C] = X86.opSETL;
|
||||
X86.aOps0F386[0x9D] = X86.opSETNL;
|
||||
X86.aOps0F386[0x9E] = X86.opSETLE;
|
||||
X86.aOps0F386[0x9F] = X86.opSETNLE;
|
||||
X86.aOps0F386[0xA0] = X86.opPUSHFS;
|
||||
X86.aOps0F386[0xA1] = X86.opPOPFS;
|
||||
X86.aOps0F386[0xA3] = X86.opBT;
|
||||
X86.aOps0F386[0xA4] = X86.opSHLDn;
|
||||
X86.aOps0F386[0xA5] = X86.opSHLDcl;
|
||||
X86.aOps0F386[0xA8] = X86.opPUSHGS;
|
||||
X86.aOps0F386[0xA9] = X86.opPOPGS;
|
||||
X86.aOps0F386[0xAB] = X86.opBTS;
|
||||
X86.aOps0F386[0xAC] = X86.opSHRDn;
|
||||
X86.aOps0F386[0xAD] = X86.opSHRDcl;
|
||||
X86.aOps0F386[0xAF] = X86.opIMUL;
|
||||
X86.aOps0F386[0xB3] = X86.opBTR;
|
||||
X86.aOps0F386[0xBA] = X86.opGRP8;
|
||||
X86.aOps0F386[0xBB] = X86.opBTC;
|
||||
}
|
||||
|
||||
/*
|
||||
* These instruction groups are not as orthogonal as the original 8086/8088 groups (Grp1 through Grp4): some of
|
||||
* These instruction groups are not as orthogonal as the original 8086/8088 groups (Grp1 through Grp4); some of
|
||||
* the instructions in Grp6 and Grp7 only read their dst operand (eg, LLDT), which means the ModRM helper function
|
||||
* must insure that setEAWord() is disabled, while others only write their dst operand (eg, SLDT), which means that
|
||||
* getEAWord() should be disabled *prior* to calling the ModRM helper function. This latter case requires that
|
||||
|
|
@ -410,10 +1083,15 @@ X86.aOpGrp6Real = [
|
|||
];
|
||||
|
||||
/*
|
||||
* Unlike Grp6, Grp7 does not require separate real-mode and protected-mode dispatch tables, because all Grp7
|
||||
* instructions are valid in both modes.
|
||||
* Unlike Grp6, Grp7 does not require separate real-mode and protected-mode dispatch tables,
|
||||
* because all Grp7 instructions are valid in both modes.
|
||||
*/
|
||||
X86.aOpGrp7 = [
|
||||
X86.fnSGDT, X86.fnSIDT, X86.fnLGDT, X86.fnLIDT, // 0x0F,0x01(reg=0x0-0x3)
|
||||
X86.fnSMSW, X86.fnGRPUndefined, X86.fnLMSW, X86.fnGRPUndefined // 0x0F,0x01(reg=0x4-0x7)
|
||||
];
|
||||
|
||||
X86.aOpGrp8 = [
|
||||
X86.fnGRPUndefined, X86.fnGRPUndefined, X86.fnGRPUndefined, X86.fnGRPUndefined, // 0x0F,0xBA(reg=0x0-0x3)
|
||||
X86.fnBT, X86.fnBTS, X86.fnBTR, X86.fnBTC // 0x0F,0xBA(reg=0x4-0x7)
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1962,7 +1962,7 @@ X86.opJNP = function JNP()
|
|||
X86.opJL = function JL()
|
||||
{
|
||||
var disp = this.getIPDisp();
|
||||
if (!this.getSF() != !this.getOF()) { // jshint ignore:line
|
||||
if (!this.getSF() != !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
|
|
@ -1978,7 +1978,7 @@ X86.opJL = function JL()
|
|||
X86.opJNL = function JNL()
|
||||
{
|
||||
var disp = this.getIPDisp();
|
||||
if (!this.getSF() == !this.getOF()) { // jshint ignore:line
|
||||
if (!this.getSF() == !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
|
|
@ -1994,7 +1994,7 @@ X86.opJNL = function JNL()
|
|||
X86.opJLE = function JLE()
|
||||
{
|
||||
var disp = this.getIPDisp();
|
||||
if (this.getZF() || !this.getSF() != !this.getOF()) { // jshint ignore:line
|
||||
if (this.getZF() || !this.getSF() != !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
|
|
@ -2010,7 +2010,7 @@ X86.opJLE = function JLE()
|
|||
X86.opJNLE = function JNLE()
|
||||
{
|
||||
var disp = this.getIPDisp();
|
||||
if (!this.getZF() && !this.getSF() == !this.getOF()) { // jshint ignore:line
|
||||
if (!this.getZF() && !this.getSF() == !this.getOF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesJmpC;
|
||||
return;
|
||||
|
|
@ -2023,7 +2023,7 @@ X86.opJNLE = function JNLE()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp1b = function GRP1b()
|
||||
X86.opGRP1b = function GRP1b()
|
||||
{
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp1b, this.getIPByte);
|
||||
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.CYCLES.nOpCyclesArithMID);
|
||||
|
|
@ -2034,7 +2034,7 @@ X86.opGrp1b = function GRP1b()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp1w = function GRP1w()
|
||||
X86.opGRP1w = function GRP1w()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPWord);
|
||||
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.CYCLES.nOpCyclesArithMID);
|
||||
|
|
@ -2045,7 +2045,7 @@ X86.opGrp1w = function GRP1w()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp1sw = function GRP1sw()
|
||||
X86.opGRP1sw = function GRP1sw()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp1w, this.getIPDisp);
|
||||
this.nStepCycles -= (this.regEAWrite === X86.ADDR_INVALID? 1 : this.CYCLES.nOpCyclesArithMID);
|
||||
|
|
@ -3266,9 +3266,9 @@ X86.opMOVDIw = function MOVDIw()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2bi = function GRP2bi()
|
||||
X86.opGRP2bn = function GRP2bn()
|
||||
{
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSrcCountImm);
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSrcCountN);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3276,9 +3276,9 @@ X86.opGrp2bi = function GRP2bi()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2wi = function GRP2wi()
|
||||
X86.opGRP2wn = function GRP2wn()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnSrcCountImm);
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnSrcCountN);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3286,9 +3286,9 @@ X86.opGrp2wi = function GRP2wi()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2di = function GRP2di()
|
||||
X86.opGRP2dn = function GRP2dn()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnSrcCountImm);
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnSrcCountN);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3352,7 +3352,7 @@ X86.opMOVb = function MOVb()
|
|||
* Like other MOV operations, the destination does not need to be read, just written.
|
||||
*/
|
||||
this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrpMOVImm, this.getIPByte);
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrpMOVn, this.getIPByte);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3366,7 +3366,7 @@ X86.opMOVw = function MOVw()
|
|||
* Like other MOV operations, the destination does not need to be read, just written.
|
||||
*/
|
||||
this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrpMOVImm, this.getIPWord);
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrpMOVn, this.getIPWord);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -3509,7 +3509,7 @@ X86.opIRET = function IRET()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2b1 = function GRP2b1()
|
||||
X86.opGRP2b1 = function GRP2b1()
|
||||
{
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSrcCount1);
|
||||
};
|
||||
|
|
@ -3519,7 +3519,7 @@ X86.opGrp2b1 = function GRP2b1()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2w1 = function GRP2w1()
|
||||
X86.opGRP2w1 = function GRP2w1()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnSrcCount1);
|
||||
};
|
||||
|
|
@ -3529,7 +3529,7 @@ X86.opGrp2w1 = function GRP2w1()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2d1 = function GRP2d1()
|
||||
X86.opGRP2d1 = function GRP2d1()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnSrcCount1);
|
||||
};
|
||||
|
|
@ -3539,7 +3539,7 @@ X86.opGrp2d1 = function GRP2d1()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2bCL = function GRP2bCL()
|
||||
X86.opGRP2bCL = function GRP2bCL()
|
||||
{
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp2b, X86.fnSrcCountCL);
|
||||
};
|
||||
|
|
@ -3549,7 +3549,7 @@ X86.opGrp2bCL = function GRP2bCL()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2wCL = function GRP2wCL()
|
||||
X86.opGRP2wCL = function GRP2wCL()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2w, X86.fnSrcCountCL);
|
||||
};
|
||||
|
|
@ -3559,7 +3559,7 @@ X86.opGrp2wCL = function GRP2wCL()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp2dCL = function GRP2dCL()
|
||||
X86.opGRP2dCL = function GRP2dCL()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp2d, X86.fnSrcCountCL);
|
||||
};
|
||||
|
|
@ -3995,7 +3995,7 @@ X86.opCMC = function CMC()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp3b = function GRP3b()
|
||||
X86.opGRP3b = function GRP3b()
|
||||
{
|
||||
this.regMD16 = -1;
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp3b, X86.fnSrcNone);
|
||||
|
|
@ -4021,7 +4021,7 @@ X86.opGrp3b = function GRP3b()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp3w = function GRP3w()
|
||||
X86.opGRP3w = function GRP3w()
|
||||
{
|
||||
this.regMD16 = -1;
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp3w, X86.fnSrcNone);
|
||||
|
|
@ -4103,7 +4103,7 @@ X86.opSTD = function STD()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp4b = function GRP4b()
|
||||
X86.opGRP4b = function GRP4b()
|
||||
{
|
||||
this.aOpModGrpByte[this.getIPByte()].call(this, X86.aOpGrp4b, X86.fnSrcNone);
|
||||
};
|
||||
|
|
@ -4113,7 +4113,7 @@ X86.opGrp4b = function GRP4b()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opGrp4w = function GRP4w()
|
||||
X86.opGRP4w = function GRP4w()
|
||||
{
|
||||
this.aOpModGrpWord[this.getIPByte()].call(this, X86.aOpGrp4w, X86.fnSrcNone);
|
||||
};
|
||||
|
|
@ -4205,7 +4205,7 @@ X86.aOps = [
|
|||
* to opcode 0x82 as a "reserved" instruction, but also cryptically refers to it as "MOVB AL,imm". This is
|
||||
* assumed to be an error in the manual, because as far as I know, 0x82 has always mirrored 0x80.
|
||||
*/
|
||||
X86.opGrp1b, X86.opGrp1w, X86.opGrp1b, X86.opGrp1sw, // 0x80-0x83
|
||||
X86.opGRP1b, X86.opGRP1w, X86.opGRP1b, X86.opGRP1sw, // 0x80-0x83
|
||||
X86.opTESTrb, X86.opTESTrw, X86.opXCHGrb, X86.opXCHGrw, // 0x84-0x87
|
||||
X86.opMOVmb, X86.opMOVmw, X86.opMOVrb, X86.opMOVrw, // 0x88-0x8B
|
||||
X86.opMOVwsr, X86.opLEA, X86.opMOVsrw, X86.opPOPmw, // 0x8C-0x8F
|
||||
|
|
@ -4228,7 +4228,7 @@ X86.aOps = [
|
|||
X86.opLES, X86.opLDS, X86.opMOVb, X86.opMOVw, // 0xC4-0xC7
|
||||
X86.opRETFn, X86.opRETF, X86.opRETFn, X86.opRETF, // 0xC8-0xCB
|
||||
X86.opINT3, X86.opINTn, X86.opINTO, X86.opIRET, // 0xCC-0xCF
|
||||
X86.opGrp2b1, X86.opGrp2w1, X86.opGrp2bCL, X86.opGrp2wCL, // 0xD0-0xD3
|
||||
X86.opGRP2b1, X86.opGRP2w1, X86.opGRP2bCL, X86.opGRP2wCL, // 0xD0-0xD3
|
||||
/*
|
||||
* Even as of the Pentium, opcode 0xD6 is still marked as "reserved", but it's always been SALC (aka SETALC).
|
||||
*/
|
||||
|
|
@ -4246,9 +4246,9 @@ X86.aOps = [
|
|||
* As of the Pentium, opcode 0xF1 is still marked "reserved".
|
||||
*/
|
||||
X86.opLOCK, X86.opLOCK, X86.opREPNZ, X86.opREPZ, // 0xF0-0xF3
|
||||
X86.opHLT, X86.opCMC, X86.opGrp3b, X86.opGrp3w, // 0xF4-0xF7
|
||||
X86.opHLT, X86.opCMC, X86.opGRP3b, X86.opGRP3w, // 0xF4-0xF7
|
||||
X86.opCLC, X86.opSTC, X86.opCLI, X86.opSTI, // 0xF8-0xFB
|
||||
X86.opCLD, X86.opSTD, X86.opGrp4b, X86.opGrp4w // 0xFC-0xFF
|
||||
X86.opCLD, X86.opSTD, X86.opGRP4b, X86.opGRP4w // 0xFC-0xFF
|
||||
];
|
||||
|
||||
/*
|
||||
|
|
@ -4261,8 +4261,8 @@ X86.aOps = [
|
|||
* Opcodes Intel PCjs PC Mag TechRef
|
||||
* ------- ----- ---- --------------
|
||||
* 0x80-0x83 Grp1 Grp1b and Grp1w Group A
|
||||
* 0xC0-0xC1 Grp2 Grp2b and Grp2w (opGrp2bi/wi) Group B
|
||||
* 0xD0-0xD3 Grp2 Grp2b and Grp2w (opGrp2b1/w1 and opGrp2bCL/wCL) Group B
|
||||
* 0xC0-0xC1 Grp2 Grp2b and Grp2w (opGRP2bn/wn) Group B
|
||||
* 0xD0-0xD3 Grp2 Grp2b and Grp2w (opGRP2b1/w1 and opGRP2bCL/wCL) Group B
|
||||
* 0xF6-0xF7 Grp3 Grp3b and Grp3w Group C
|
||||
* 0xFE Grp4 Grp4b Group D
|
||||
* 0xFF Grp5 Grp4w Group E
|
||||
|
|
@ -4278,7 +4278,7 @@ X86.aOps = [
|
|||
* remaining group numbers remain in sync with Intel's.
|
||||
*
|
||||
* To the above list, I also add these "groups of 1": opcode 0x8F uses GrpPOPw, and opcodes 0xC6/0xC7 use
|
||||
* GrpMOVImm. In both of these groups, the only valid (documented) instruction is where reg=0x0.
|
||||
* GrpMOVn. In both of these groups, the only valid (documented) instruction is where reg=0x0.
|
||||
*
|
||||
* TODO: Test what happens on real hardware when the reg field is non-zero for opcodes 0x8F and 0xC6/0xC7.
|
||||
*/
|
||||
|
|
@ -4297,8 +4297,8 @@ X86.aOpGrpPOPw = [
|
|||
X86.fnGRPFault, X86.fnGRPFault, X86.fnGRPFault, X86.fnGRPFault // 0x8F(reg=0x4-0x7)
|
||||
];
|
||||
|
||||
X86.aOpGrpMOVImm = [
|
||||
X86.fnMOVImm, X86.fnGRPUndefined, X86.fnGRPUndefined, X86.fnGRPUndefined, // 0xC6/0xC7(reg=0x0-0x3)
|
||||
X86.aOpGrpMOVn = [
|
||||
X86.fnMOVn, X86.fnGRPUndefined, X86.fnGRPUndefined, X86.fnGRPUndefined, // 0xC6/0xC7(reg=0x0-0x3)
|
||||
X86.fnGRPUndefined, X86.fnGRPUndefined, X86.fnGRPUndefined, X86.fnGRPUndefined // 0xC6/0xC7(reg=0x4-0x7)
|
||||
];
|
||||
|
||||
|
|
@ -4366,8 +4366,8 @@ if (I386) {
|
|||
0x39: X86.opTBD, // opCMPmd()
|
||||
0x3B: X86.opTBD, // opCMPrd()
|
||||
0x3D: X86.opTBD, // opCMPAXd()
|
||||
0xC1: X86.opGrp2di,
|
||||
0xD1: X86.opGrp2d1,
|
||||
0xD3: X86.opGrp2dCL
|
||||
0xC1: X86.opGRP2dn,
|
||||
0xD1: X86.opGRP2d1,
|
||||
0xD3: X86.opGRP2dCL
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue