Getting ready to retire old 16-bit flags code
This commit is contained in:
parent
76932246ec
commit
72cf8d1f4d
12 changed files with 4078 additions and 3318 deletions
|
|
@ -124,8 +124,8 @@ memory.
|
|||
> The B0 stepping became available around the middle of 1986. As is the case with earlier steppings, the
|
||||
"B0" marking can sometimes be found on the outside of the device. If not, the code "S40336" or "S40337" may
|
||||
appear. Starting with the B0 stepping, the 80386 would leave the component identifier, 3, in DH and the
|
||||
revision identifier, also 3, in DL [Surprisingly, these are the same values that the B1 stepping reports
|
||||
as well. -JP]
|
||||
revision identifier, also 3, in DL [These B0 values need to be independently confirmed, because they are
|
||||
the same values reported for the B1 stepping. -JP]
|
||||
|
||||
> + *Interrupts and Privilege Violations*: If a hardware interrupt occurs immediately before an IOPL-sensitive
|
||||
instruction when CPL is greater than IOPL, the 80386 behaves erratically. Generally, it will produce spurious
|
||||
|
|
@ -164,7 +164,7 @@ either the loop counter or the string index.
|
|||
new ones were either introduced or discovered. The best known of these was the widely publicized multiply
|
||||
failure discovered in mid-1987. The B1 stepping is identifiable either by the "B1" mark or by the code
|
||||
"S40343," "S40344," or "S40362." As is the case with the B0 stepping, the B1 revision leaves a binary three
|
||||
in DL after reset. [Surprisingly, these are the same values that the B0 stepping reports as well. -JP]
|
||||
in DL after reset. [Again, I would like to see the B0 values independently confirmed. -JP]
|
||||
|
||||
> + *IBTS and XBTS Instructions Removed*: The Insert Bit String (IBTS) and Extract Bit String (XBTS)
|
||||
instructions were removed from the 80386's instruction set. It was determined that they took up too much
|
||||
|
|
@ -213,13 +213,12 @@ in the first byte of a page that will cause a page fault (either because it is n
|
|||
impending privilege violation), the 80386 hangs. The processor will remain hung until it receives an interrupt.
|
||||
[See Intel Errata #17 below]
|
||||
|
||||
> The following sample program has been calculated to produce the [multiplication] error. An 80386 that
|
||||
fails one or more of these multiply instructions is obviously faulty. However, passing does not guarantee
|
||||
a perfect part. To their credit, Intel agreed to test all 80386s for a limited time and report on their
|
||||
> The following sample program has been calculated to produce the [aforementioned multiplication] error.
|
||||
An 80386 that fails one or more of these multiply instructions is obviously faulty. However, passing does not
|
||||
guarantee a perfect part. To their credit, Intel agreed to test all 80386s for a limited time and report on their
|
||||
success or failure. Since then, all 80386s have been tested before shipping. Those that fail have been marked
|
||||
"For Sixteen-Bit Software Only." [I believe the exact marking was "16 BIT S/W ONLY" -JP] Those that passed
|
||||
have been marked with a double sigma sign. All 80386s produced after the B1 stepping should be free of this
|
||||
defect.
|
||||
"For Sixteen-Bit Software Only." [To be exact: "16 BIT S/W ONLY" -JP] Those that passed have been marked with
|
||||
a double sigma sign. All 80386s produced after the B1 stepping should be free of this defect.
|
||||
|
||||
; Perform various 16-bit and 32-bit multiply operations...
|
||||
|
||||
|
|
@ -324,8 +323,9 @@ Most of the information I have obtained about the 80386 begins with the B1 stepp
|
|||
ii m c i '85 '86 |
|
||||
|
|
||||
|
||||
So, the B1 stepping set DL to 0x03 on reset. It also seems a safe bet that the revision number
|
||||
for a B0 stepping was 0x02. Does that mean the revision number for the A0 was 0x01? I can only guess.
|
||||
So, the B1 stepping set DL to 0x03 on reset. This would lead one to believe that the revision number
|
||||
for a B0 stepping was 0x02, but according to Turley (see above), the B0 and B1 steppings report the *same*
|
||||
revision; as I noted above, it would be nice to see some independent confirmation.
|
||||
|
||||
The 80386 CPU on my Compaq DeskPro 386 "Version 2" System Board is labeled as:
|
||||
|
||||
|
|
@ -589,7 +589,7 @@ Here's more information on the opcodes (IBTS and XBTS) that were removed from th
|
|||
+++++++++++++++++++++++
|
||||
Physical Form: IBTS r/m16,AX,CL,r16
|
||||
IBTS r/m32,EAX,CL,r32
|
||||
COP (Code of Operation) : 0FH A7H Postbyte
|
||||
COP (Code of Operation) : 0FH A7H
|
||||
|
||||
Clocks: IBTS
|
||||
80386: 12/19
|
||||
|
|
@ -623,7 +623,7 @@ Here's more information on the opcodes (IBTS and XBTS) that were removed from th
|
|||
+++++++++++++++++++++++
|
||||
Physical Form: XBTS r16,r/m16,AX,CL
|
||||
XBTS r32,r/m32,EAX,CL
|
||||
COP (Code of Operation) : 0FH A6H Postbyte
|
||||
COP (Code of Operation) : 0FH A6H
|
||||
|
||||
Clocks: XBTS
|
||||
80386: 6/13
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -424,26 +424,28 @@ CPU.prototype.displayChecksum = function()
|
|||
};
|
||||
|
||||
/**
|
||||
* displayReg(sReg, nVal, cch)
|
||||
* displayValue(sLabel, nValue, cch)
|
||||
*
|
||||
* This is principally for displaying register values, but in reality, it can be used to display any
|
||||
* numeric (hex) value bound to the given label.
|
||||
*
|
||||
* @this {CPU}
|
||||
* @param {string} sReg
|
||||
* @param {number} nVal
|
||||
* @param {number} [cch] default is 4
|
||||
* @param {string} sLabel
|
||||
* @param {number} nValue
|
||||
* @param {number} cch
|
||||
*/
|
||||
CPU.prototype.displayReg = function(sReg, nVal, cch)
|
||||
CPU.prototype.displayValue = function(sLabel, nValue, cch)
|
||||
{
|
||||
if (this.bindings[sReg]) {
|
||||
if (cch === undefined) cch = 4;
|
||||
if (nVal === undefined) {
|
||||
this.setError("Register " + sReg + " is invalid");
|
||||
if (this.bindings[sLabel]) {
|
||||
if (nValue === undefined) {
|
||||
this.setError("Value for " + sLabel + " is invalid");
|
||||
this.stopCPU();
|
||||
}
|
||||
var sVal;
|
||||
if (!this.aFlags.fRunning || this.aFlags.fDisplayLiveRegs) {
|
||||
sVal = str.toHex(nVal, cch);
|
||||
sVal = str.toHex(nValue, cch);
|
||||
} else {
|
||||
sVal = "----".substr(0, cch);
|
||||
sVal = "--------".substr(0, cch);
|
||||
}
|
||||
/*
|
||||
* TODO: Determine if this test actually avoids any redrawing when a register hasn't changed, and/or if
|
||||
|
|
@ -451,7 +453,7 @@ CPU.prototype.displayReg = function(sReg, nVal, cch)
|
|||
* string values that will have to garbage-collected), and/or if this is actually slower, and/or if I'm being
|
||||
* too obsessive.
|
||||
*/
|
||||
if (this.bindings[sReg].textContent != sVal) this.bindings[sReg].textContent = sVal;
|
||||
if (this.bindings[sLabel].textContent != sVal) this.bindings[sLabel].textContent = sVal;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,13 @@ var BUGS_8086 = false;
|
|||
*/
|
||||
var I386 = true;
|
||||
|
||||
/**
|
||||
* @define {boolean}
|
||||
*
|
||||
* Retain support for old flags.
|
||||
*/
|
||||
var OLDFLAGS = true;
|
||||
|
||||
/**
|
||||
* @define {boolean}
|
||||
*
|
||||
|
|
|
|||
|
|
@ -244,8 +244,8 @@ RAM.init = function()
|
|||
*
|
||||
* DeskPro 386 machines came with a minimum of 1Mb of RAM, which could be configured (via jumpers)
|
||||
* for 256Kb, 512Kb or 640Kb of conventional memory, starting at address 0x00000000, with the
|
||||
* remainder (768Kb, 512Kb, or 384Kb) accessible only at addresses just below 0x01000000. This
|
||||
* second chunk of RAM must have an ID of "ramCPQ".
|
||||
* remainder (768Kb, 512Kb, or 384Kb) accessible only at addresses just below 0x01000000. In PCjs,
|
||||
* this second chunk of RAM must be separately allocated, with an ID of "ramCPQ".
|
||||
*
|
||||
* The typical configuration was 640Kb of conventional memory, leaving 384Kb accessible at 0x00FA0000.
|
||||
* Presumably, the other configurations (256Kb and 512Kb) would leave 768Kb and 512Kb accessible at
|
||||
|
|
@ -253,8 +253,11 @@ RAM.init = function()
|
|||
*
|
||||
* The DeskPro 386 also contained two memory-mapped registers at 0x80C00000. The first is a write-only
|
||||
* mapping register that provides the ability to map the 128Kb at 0x00FE0000 to 0x000E0000, replacing
|
||||
* any ROMs in the range 0x000E0000-0x000FFFFF, and optionally write-protecting that 128Kb. The second
|
||||
* register is a read-only diagnostics register that indicates jumper configuration and parity errors.
|
||||
* any ROMs in the range 0x000E0000-0x000FFFFF, and optionally write-protecting that 128Kb; internally,
|
||||
* this register corresponds to bMapping.
|
||||
*
|
||||
* The second register is a read-only diagnostics register that indicates jumper configuration and
|
||||
* parity errors; internally, this register corresponds to bSettings.
|
||||
*
|
||||
* To emulate the memory-mapped registers at 0x80C00000, the RAM component allocates a block at that
|
||||
* address using this custom controller once it sees an allocation for "ramCPQ".
|
||||
|
|
|
|||
|
|
@ -241,11 +241,57 @@ var X86 = {
|
|||
MASK: 0xfff8 // index of corresponding entry in GDT, LDT or IDT
|
||||
},
|
||||
RESULT: {
|
||||
/*
|
||||
* Flags were originally computed based on the following:
|
||||
*
|
||||
* CF: resultZeroCarry & resultSize
|
||||
* PF: resultParitySign & 0xff
|
||||
* AF: (resultParitySign ^ resultAuxOverflow) & 0x0010 (AUXOVF_AF)
|
||||
* ZF: resultZeroCarry & (resultSize - 1)
|
||||
* SF: resultParitySign & (resultSize >> 1)
|
||||
* OF: (resultParitySign ^ resultAuxOverflow ^ (resultParitySign >> 1)) & (resultSize >> 1)
|
||||
*
|
||||
* I386 builds now rely on the following result variables:
|
||||
*
|
||||
* resultDst, resultSrc, resultArith, resultLogic, resultType, and resultFlags
|
||||
*
|
||||
* and the flags are computed as follows:
|
||||
*
|
||||
* CF: ((resultDst ^ ((resultDst ^ resultSrc) & (resultSrc ^ resultArith))) & resultType)
|
||||
* PF: (resultLogic & 0xff)
|
||||
* AF: ((resultArith ^ (resultDst ^ resultSrc)) & AUXOVF_AF)
|
||||
* ZF: (resultLogic & ((resultType - 1) | resultType))
|
||||
* SF: (resultLogic & resultType)
|
||||
* OF: (((resultDst ^ resultArith) & (resultSrc ^ resultArith)) & resultType)
|
||||
*
|
||||
* Arithmetic operations should call:
|
||||
*
|
||||
* setArithResult(dst, src, value, type)
|
||||
* eg:
|
||||
* setArithResult(dst, src, dst+src, X86.RESULT.BYTE | X86.RESULT.ALL)
|
||||
*
|
||||
* The 4th parameter, type, indicates both the size of the result (BYTE, WORD or DWORD) and which of
|
||||
* the flags should now be considered "cached" by the new result variables. If the previous resultType
|
||||
* specifies any flags not contained in the new type parameter, then those flags must be immediately
|
||||
* calculated and written to the appropriate bit(s) in resultFlags.
|
||||
*/
|
||||
BYTE: 0x80,
|
||||
WORD: 0x8000,
|
||||
DWORD: 0x80000000|0,
|
||||
TYPE: 0x80008080|0,
|
||||
CF: 0x01,
|
||||
PF: 0x02,
|
||||
AF: 0x04,
|
||||
ZF: 0x08,
|
||||
SF: 0x10,
|
||||
OF: 0x20,
|
||||
ALL: 0x3F,
|
||||
LOGIC: 0x1A,
|
||||
NOTCF: 0x3E,
|
||||
SIZE_BYTE: 0x00100,
|
||||
SIZE_WORD: 0x10000,
|
||||
AUXOVF_AF: 0x00010,
|
||||
AUXOVF_OF: 0x08080,
|
||||
AUXOVF_CF: 0x10100
|
||||
AUXOVF_OF: 0x08080
|
||||
},
|
||||
/*
|
||||
* Bit values for opFlags, which are all reset to zero prior to each instruction
|
||||
|
|
|
|||
|
|
@ -768,6 +768,12 @@ X86CPU.prototype.initProcessor = function()
|
|||
this.aOps0F = X86.aOps0F.slice();
|
||||
this.aOps0F[0x20] = X86.opMOVrcr;
|
||||
this.aOps0F[0x22] = X86.opMOVcrr;
|
||||
/*
|
||||
* Extend the opcode table by creating a mirror of the first 256 opcodes, but with dword-based
|
||||
* opcode handlers (as defined in aOpsD) instead word-based opcode handlers. Whenever dataSize
|
||||
* is changed from 2 bytes to 4, we trigger the appropriate set of opcode handlers by changing
|
||||
* bOpcodeBias from 0 to 256.
|
||||
*/
|
||||
this.aOps = this.aOps.concat(this.aOps);
|
||||
for (var bOpcode in X86.aOpsD) {
|
||||
this.aOps[parseInt(bOpcode, 10) + 256] = X86.aOpsD[bOpcode];
|
||||
|
|
@ -890,6 +896,11 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.addrIDT = 0; this.addrIDTLimit = 0x03FF;
|
||||
this.nIOPL = 0; // this should be set before the first setPS() call
|
||||
|
||||
/*
|
||||
* Define the result variables that setPS() relies on for arithmetic and logical flags
|
||||
*/
|
||||
this.resultDst = this.resultSrc = this.resultArith = this.resultLogic = 0;
|
||||
|
||||
/*
|
||||
* This is set by opHelpFault() and reset (to -1) by resetRegs() and opIRET(); its initial purpose is to
|
||||
* "help" opHelpFault() determine when a nested fault should be converted into either a double-fault (DF_FAULT)
|
||||
|
|
@ -1713,12 +1724,123 @@ X86CPU.prototype.setSP = function(off)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setArithResult(dst, src, value, type, fSubtract)
|
||||
*
|
||||
* Updates the flags for arithmetic instructions; use setLogicResult() for logical instructions.
|
||||
*
|
||||
* The type parameter indicates both the size of the result (BYTE, WORD or DWORD) and which of the
|
||||
* flags should now be considered "cached" by the new result variables. If the previous resultType
|
||||
* specifies any flags not contained in the new type parameter, then those flags must be immediately
|
||||
* calculated and written to the appropriate bit(s) in resultFlags.
|
||||
*
|
||||
* The fSubtract parameter is used to indicate a "subtracted" result (eg, CMP, DEC, SUB, SBB); the
|
||||
* default assumes an "added" result (eg, ADD, ADC, INC).
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
* @param {number} src
|
||||
* @param {number} value
|
||||
* @param {number} type
|
||||
* @param {boolean} [fSubtract]
|
||||
*/
|
||||
X86CPU.prototype.setArithResult = function(dst, src, value, type, fSubtract)
|
||||
{
|
||||
if ((type & X86.RESULT.ALL) != X86.RESULT.ALL && type != this.resultType) {
|
||||
var diff = ((type ^ this.resultType) & this.resultType);
|
||||
if (diff) {
|
||||
if (diff & X86.RESULT.CF) this.getCF();
|
||||
if (diff & X86.RESULT.PF) this.getPF();
|
||||
if (diff & X86.RESULT.AF) this.getAF();
|
||||
if (diff & X86.RESULT.ZF) this.getZF();
|
||||
if (diff & X86.RESULT.SF) this.getSF();
|
||||
if (diff & X86.RESULT.OF) this.getOF();
|
||||
}
|
||||
}
|
||||
if (!fSubtract) {
|
||||
this.resultDst = dst;
|
||||
this.resultArith = value;
|
||||
} else {
|
||||
this.resultDst = value;
|
||||
this.resultArith = dst;
|
||||
}
|
||||
this.resultSrc = src;
|
||||
this.resultLogic = value;
|
||||
this.resultType = type;
|
||||
if (DEBUG) this.verifyFlags(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} value
|
||||
* @param {number} type
|
||||
* @param {number} [carry]
|
||||
* @param {number} [overflow]
|
||||
* @return {number} value
|
||||
*/
|
||||
X86CPU.prototype.setLogicResult = function(value, type, carry, overflow)
|
||||
{
|
||||
this.resultType = type | X86.RESULT.LOGIC;
|
||||
this.resultLogic = value;
|
||||
if (carry) this.setCF(); else this.clearCF();
|
||||
if (overflow) this.setOF(); else this.clearOF();
|
||||
if (DEBUG) this.verifyFlags(X86.RESULT.LOGIC | X86.RESULT.CF | X86.RESULT.OF);
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* verifyFlags(flags)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} flags
|
||||
*/
|
||||
X86CPU.prototype.verifyFlags = function(flags)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (flags & X86.RESULT.CF) {
|
||||
this.assert(!this.getCF() == !(this.resultFlags & X86.PS.CF));
|
||||
}
|
||||
if (flags & X86.RESULT.PF) {
|
||||
this.assert(!this.getPF() == !(this.resultFlags & X86.PS.PF));
|
||||
}
|
||||
if (flags & X86.RESULT.AF) {
|
||||
this.assert(!this.getAF() == !(this.resultFlags & X86.PS.AF));
|
||||
}
|
||||
if (flags & X86.RESULT.ZF) {
|
||||
this.assert(!this.getZF() == !(this.resultFlags & X86.PS.ZF));
|
||||
}
|
||||
if (flags & X86.RESULT.SF) {
|
||||
this.assert(!this.getSF() == !(this.resultFlags & X86.PS.SF));
|
||||
}
|
||||
if (flags & X86.RESULT.OF) {
|
||||
this.assert(!this.getOF() == !(this.resultFlags & X86.PS.OF));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* getCarry()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number} 0 or 1, depending on whether CF is clear or set
|
||||
*/
|
||||
X86CPU.prototype.getCarry = function()
|
||||
{
|
||||
return this.getCF()? 1 : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* getCF()
|
||||
*
|
||||
* Notes regarding carry following a 32-bit addition:
|
||||
* Notes regarding carry following an I386 addition:
|
||||
*
|
||||
* The following table summarizes bit 31 of dst, src, and result, along with the expected carry bit:
|
||||
* The following table summarizes bit 31 of dst, src, and result, along with the expected carry:
|
||||
*
|
||||
* dst src res carry
|
||||
* --- --- --- -----
|
||||
|
|
@ -1731,29 +1853,27 @@ X86CPU.prototype.setSP = function(off)
|
|||
* 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:
|
||||
* So, we use the following calculation:
|
||||
*
|
||||
* resultZeroCarry = ((resultZeroCarry >>> 16) | (resultZeroCarry & 0xffff)) | (((dst ^ ((dst ^ src) & (src ^ resultZeroCarry))) >>> 15) & SIZE_WORD);
|
||||
*
|
||||
* Essentially, we’d 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.
|
||||
* (resultDst ^ ((resultDst ^ resultSrc) & (resultSrc ^ resultArith))) & resultType
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.CF
|
||||
*/
|
||||
X86CPU.prototype.getCF = function()
|
||||
{
|
||||
return (this.resultZeroCarry & this.resultSize)? X86.PS.CF : 0;
|
||||
var flag = (this.resultZeroCarry & this.resultSize)? X86.PS.CF : 0;
|
||||
if (I386) {
|
||||
if (this.resultType & X86.RESULT.CF) {
|
||||
this.resultFlags &= ~X86.PS.CF;
|
||||
if ((this.resultDst ^ ((this.resultDst ^ this.resultSrc) & (this.resultSrc ^ this.resultArith))) & (this.resultType & X86.RESULT.TYPE)) {
|
||||
this.resultFlags |= X86.PS.CF;
|
||||
}
|
||||
this.resultType &= ~X86.RESULT.CF;
|
||||
}
|
||||
if (!OLDFLAGS) return this.resultFlags & X86.PS.CF;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1779,63 +1899,162 @@ X86CPU.prototype.getCF = function()
|
|||
* has EVEN parity; the above calculation yields ODD parity, so we use the conditional operator to invert the result.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.PF
|
||||
*/
|
||||
X86CPU.prototype.getPF = function()
|
||||
{
|
||||
var v = this.resultParitySign;
|
||||
return ((0x6996 >> ((v ^ (v >> 4)) & 0xf)) & 1)? 0 : X86.PS.PF;
|
||||
var flag = this.resultParitySign;
|
||||
flag = ((0x6996 >> ((flag ^ (flag >> 4)) & 0xf)) & 1)? 0 : X86.PS.PF;
|
||||
if (I386) {
|
||||
if (this.resultType & X86.RESULT.PF) {
|
||||
this.resultFlags &= ~X86.PS.PF;
|
||||
if ((0x9669 >> ((this.resultLogic ^ (this.resultLogic >> 4)) & 0xf)) & 1) {
|
||||
this.resultFlags |= X86.PS.PF;
|
||||
}
|
||||
this.resultType &= ~X86.RESULT.PF;
|
||||
}
|
||||
if (!OLDFLAGS) return this.resultFlags & X86.PS.PF;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* getAF()
|
||||
*
|
||||
* Notes regarding auxiliary carry following an I386 addition:
|
||||
*
|
||||
* To determine if there's been a carry out of the low 4 bits of an arithmetic operation,
|
||||
* we look at all the possible inputs for bit 4, and calculate AF = PS^(D^S):
|
||||
*
|
||||
* D S A D^S AF
|
||||
* - - - --- --
|
||||
* 0 0 0 0 0
|
||||
* 0 0 1 0 1
|
||||
* 0 1 0 1 1
|
||||
* 0 1 1 1 0
|
||||
* 1 0 0 1 1
|
||||
* 1 0 1 1 0
|
||||
* 1 1 0 0 0
|
||||
* 1 1 1 0 1
|
||||
*
|
||||
* The final calculation looks like:
|
||||
*
|
||||
* (resultArith ^ (resultDst ^ resultSrc)) & AUXOVF_AF
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.AF
|
||||
*/
|
||||
X86CPU.prototype.getAF = function()
|
||||
{
|
||||
return ((this.resultParitySign ^ this.resultAuxOverflow) & X86.RESULT.AUXOVF_AF)? X86.PS.AF : 0;
|
||||
var flag = ((this.resultParitySign ^ this.resultAuxOverflow) & X86.RESULT.AUXOVF_AF)? X86.PS.AF : 0;
|
||||
if (I386) {
|
||||
if (this.resultType & X86.RESULT.AF) {
|
||||
this.resultFlags &= ~X86.PS.AF;
|
||||
if ((this.resultArith ^ (this.resultDst ^ this.resultSrc)) & X86.RESULT.AUXOVF_AF) {
|
||||
this.resultFlags |= X86.PS.AF;
|
||||
}
|
||||
this.resultType &= ~X86.RESULT.AF;
|
||||
}
|
||||
if (!OLDFLAGS) return this.resultFlags & X86.PS.AF;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* getZF()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.ZF
|
||||
*/
|
||||
X86CPU.prototype.getZF = function()
|
||||
{
|
||||
return (this.resultZeroCarry & (this.resultSize - 1))? 0 : X86.PS.ZF;
|
||||
var flag = (this.resultZeroCarry & (this.resultSize - 1))? 0 : X86.PS.ZF;
|
||||
if (I386) {
|
||||
if (this.resultType & X86.RESULT.ZF) {
|
||||
this.resultFlags &= ~X86.PS.ZF;
|
||||
if (!(this.resultLogic & (((this.resultType & X86.RESULT.TYPE) - 1) | (this.resultType & X86.RESULT.TYPE)))) {
|
||||
this.resultFlags |= X86.PS.ZF;
|
||||
}
|
||||
this.resultType &= ~X86.RESULT.ZF;
|
||||
}
|
||||
if (!OLDFLAGS) return this.resultFlags & X86.PS.ZF;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* getSF()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.SF
|
||||
*/
|
||||
X86CPU.prototype.getSF = function()
|
||||
{
|
||||
return (this.resultParitySign & (this.resultSize >> 1))? X86.PS.SF : 0;
|
||||
var flag = (this.resultParitySign & (this.resultSize >> 1))? X86.PS.SF : 0;
|
||||
if (I386) {
|
||||
if (this.resultType & X86.RESULT.SF) {
|
||||
this.resultFlags &= ~X86.PS.SF;
|
||||
if (this.resultLogic & (this.resultType & X86.RESULT.TYPE)) {
|
||||
this.resultFlags |= X86.PS.SF;
|
||||
}
|
||||
this.resultType &= ~X86.RESULT.SF;
|
||||
}
|
||||
if (!OLDFLAGS) return this.resultFlags & X86.PS.SF;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* getOF()
|
||||
*
|
||||
* Overflow was originally calculated as:
|
||||
*
|
||||
* (resultParitySign ^ resultAuxOverflow ^ (resultParitySign >> 1)) & (resultSize >> 1)
|
||||
*
|
||||
* but as you can see, that calculation depends on the carry out of the 8/16/32-bit result in
|
||||
* resultParitySign, which we don't have access to for 32-bit results. So we fall-back to the
|
||||
* following:
|
||||
*
|
||||
* ((resultDst ^ resultArith) & (resultSrc ^ resultArith)) & resultType
|
||||
*
|
||||
* which you can verify from the following table of sign bits (where x1 is resultDst ^ resultArith,
|
||||
* and x2 is resultSrc ^ resultArith):
|
||||
*
|
||||
* D S A x1 x2 OF
|
||||
* - - - -- -- --
|
||||
* 0 0 0 0 0 0
|
||||
* 0 0 1 1 1 1 (adding two positive values yielded a negative value)
|
||||
* 0 1 0 0 1 0
|
||||
* 0 1 1 1 0 0
|
||||
* 1 0 0 1 0 0
|
||||
* 1 0 1 0 1 0
|
||||
* 1 1 0 1 1 1 (adding two negative values yielded a positive value)
|
||||
* 1 1 1 0 0 0
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.OF
|
||||
*/
|
||||
X86CPU.prototype.getOF = function()
|
||||
{
|
||||
return ((this.resultParitySign ^ this.resultAuxOverflow ^ (this.resultParitySign >> 1)) & (this.resultSize >> 1))? X86.PS.OF : 0;
|
||||
var flag = ((this.resultParitySign ^ this.resultAuxOverflow ^ (this.resultParitySign >> 1)) & (this.resultSize >> 1))? X86.PS.OF : 0;
|
||||
if (I386) {
|
||||
if (this.resultType & X86.RESULT.OF) {
|
||||
this.resultFlags &= ~X86.PS.OF;
|
||||
if (((this.resultDst ^ this.resultArith) & (this.resultSrc ^ this.resultArith)) & (this.resultType & X86.RESULT.TYPE)) {
|
||||
this.resultFlags |= X86.PS.OF;
|
||||
}
|
||||
this.resultType &= ~X86.RESULT.OF;
|
||||
}
|
||||
if (!OLDFLAGS) return this.resultFlags & X86.PS.OF;
|
||||
}
|
||||
return flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* getTF()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.TF
|
||||
*/
|
||||
X86CPU.prototype.getTF = function()
|
||||
{
|
||||
|
|
@ -1846,7 +2065,7 @@ X86CPU.prototype.getTF = function()
|
|||
* getIF()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.IF
|
||||
*/
|
||||
X86CPU.prototype.getIF = function()
|
||||
{
|
||||
|
|
@ -1857,7 +2076,7 @@ X86CPU.prototype.getIF = function()
|
|||
* getDF()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {number}
|
||||
* @return {number} 0 or X86.PS.DF
|
||||
*/
|
||||
X86CPU.prototype.getDF = function()
|
||||
{
|
||||
|
|
@ -1872,6 +2091,10 @@ X86CPU.prototype.getDF = function()
|
|||
X86CPU.prototype.clearCF = function()
|
||||
{
|
||||
this.resultZeroCarry &= ~this.resultSize;
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.CF;
|
||||
this.resultFlags &= ~X86.PS.CF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1882,6 +2105,10 @@ X86CPU.prototype.clearCF = function()
|
|||
X86CPU.prototype.clearPF = function()
|
||||
{
|
||||
if (this.getPF()) this.resultParitySign ^= 0x1;
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.PF;
|
||||
this.resultFlags &= ~X86.PS.PF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1892,6 +2119,10 @@ X86CPU.prototype.clearPF = function()
|
|||
X86CPU.prototype.clearAF = function()
|
||||
{
|
||||
this.resultAuxOverflow = (this.resultParitySign & X86.RESULT.AUXOVF_AF) | (this.resultAuxOverflow & ~X86.RESULT.AUXOVF_AF);
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.AF;
|
||||
this.resultFlags &= ~X86.PS.AF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1902,6 +2133,10 @@ X86CPU.prototype.clearAF = function()
|
|||
X86CPU.prototype.clearZF = function()
|
||||
{
|
||||
this.resultZeroCarry |= (this.resultSize - 1);
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.ZF;
|
||||
this.resultFlags &= ~X86.PS.ZF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1915,6 +2150,10 @@ X86CPU.prototype.clearSF = function()
|
|||
this.resultParitySign ^= (this.resultSize >> 1) | (this.resultSize >> 2);
|
||||
this.resultAuxOverflow ^= X86.RESULT.AUXOVF_OF;
|
||||
}
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.SF;
|
||||
this.resultFlags &= ~X86.PS.SF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1946,6 +2185,10 @@ X86CPU.prototype.clearOF = function()
|
|||
{
|
||||
this.resultParitySign &= ~this.resultSize;
|
||||
this.resultAuxOverflow = (this.resultParitySign & X86.RESULT.AUXOVF_OF) | (this.resultAuxOverflow & ~X86.RESULT.AUXOVF_OF);
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.OF;
|
||||
this.resultFlags &= ~X86.PS.OF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1956,6 +2199,10 @@ X86CPU.prototype.clearOF = function()
|
|||
X86CPU.prototype.setCF = function()
|
||||
{
|
||||
this.resultZeroCarry |= this.resultSize;
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.CF;
|
||||
this.resultFlags |= X86.PS.CF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1966,6 +2213,10 @@ X86CPU.prototype.setCF = function()
|
|||
X86CPU.prototype.setPF = function()
|
||||
{
|
||||
if (!this.getPF()) this.resultParitySign ^= 0x1;
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.PF;
|
||||
this.resultFlags |= X86.PS.PF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1976,6 +2227,10 @@ X86CPU.prototype.setPF = function()
|
|||
X86CPU.prototype.setAF = function()
|
||||
{
|
||||
this.resultAuxOverflow = ~(this.resultParitySign & X86.RESULT.AUXOVF_AF) & X86.RESULT.AUXOVF_AF | (this.resultAuxOverflow & ~X86.RESULT.AUXOVF_AF);
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.AF;
|
||||
this.resultFlags |= X86.PS.AF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1986,6 +2241,10 @@ X86CPU.prototype.setAF = function()
|
|||
X86CPU.prototype.setZF = function()
|
||||
{
|
||||
this.resultZeroCarry &= ~(this.resultSize - 1);
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.ZF;
|
||||
this.resultFlags |= X86.PS.ZF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1999,6 +2258,10 @@ X86CPU.prototype.setSF = function()
|
|||
this.resultParitySign ^= (this.resultSize >> 1) | (this.resultSize >> 2);
|
||||
this.resultAuxOverflow ^= X86.RESULT.AUXOVF_OF;
|
||||
}
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.SF;
|
||||
this.resultFlags |= X86.PS.SF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2028,6 +2291,10 @@ X86CPU.prototype.setDF = function()
|
|||
*/
|
||||
X86CPU.prototype.setOF = function()
|
||||
{
|
||||
if (I386) {
|
||||
this.resultType &= ~X86.RESULT.OF;
|
||||
this.resultFlags |= X86.PS.OF;
|
||||
}
|
||||
this.resultParitySign |= this.resultSize;
|
||||
this.resultAuxOverflow = (this.resultParitySign & X86.RESULT.AUXOVF_OF) | (this.resultAuxOverflow & ~X86.RESULT.AUXOVF_OF);
|
||||
};
|
||||
|
|
@ -2078,15 +2345,20 @@ X86CPU.prototype.setMSW = function(w)
|
|||
*/
|
||||
X86CPU.prototype.setPS = function(regPS, cpl)
|
||||
{
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE; // NOTE: We could have chosen SIZE_WORD, too; it's irrelevant
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = 0;
|
||||
|
||||
if (regPS & X86.PS.CF) this.setCF();
|
||||
if (!(regPS & X86.PS.PF)) this.resultParitySign |= 0x1;
|
||||
if (regPS & X86.PS.AF) this.resultAuxOverflow |= X86.RESULT.AUXOVF_AF;
|
||||
if (!(regPS & X86.PS.ZF)) this.clearZF();
|
||||
if (regPS & X86.PS.SF) this.setSF();
|
||||
if (regPS & X86.PS.OF) this.setOF();
|
||||
if (I386) {
|
||||
this.resultType = X86.RESULT.BYTE;
|
||||
this.resultFlags = regPS & (X86.PS.CF | X86.PS.PF | X86.PS.AF | X86.PS.ZF | X86.PS.SF | X86.PS.OF);
|
||||
}
|
||||
if (OLDFLAGS) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = 0;
|
||||
if (regPS & X86.PS.CF) this.setCF();
|
||||
if (!(regPS & X86.PS.PF)) this.resultParitySign |= 0x1;
|
||||
if (regPS & X86.PS.AF) this.resultAuxOverflow |= X86.RESULT.AUXOVF_AF;
|
||||
if (!(regPS & X86.PS.ZF)) this.clearZF();
|
||||
if (regPS & X86.PS.SF) this.setSF();
|
||||
if (regPS & X86.PS.OF) this.setOF();
|
||||
}
|
||||
|
||||
/*
|
||||
* OS/2 1.0 discriminates between an 80286 and an 80386 based on whether an IRET in real-mode that
|
||||
|
|
@ -2166,37 +2438,46 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
|
|||
{
|
||||
var fBound = false;
|
||||
switch (sBinding) {
|
||||
case "AX":
|
||||
case "BX":
|
||||
case "CX":
|
||||
case "DX":
|
||||
case "SP":
|
||||
case "BP":
|
||||
case "SI":
|
||||
case "DI":
|
||||
case "CS":
|
||||
case "DS":
|
||||
case "SS":
|
||||
case "ES":
|
||||
case "IP":
|
||||
case "PC": // deprecated as an alias for "IP" (still used by older XML files, like the one at http://tpoindex.github.io/crobots/)
|
||||
case "PS": // this refers to "Processor Status", aka the 16-bit flags register (although DEBUG.COM refers to this as "PC", surprisingly)
|
||||
case "C":
|
||||
case "P":
|
||||
case "A":
|
||||
case "Z":
|
||||
case "S":
|
||||
case "T":
|
||||
case "I":
|
||||
case "D":
|
||||
case "V":
|
||||
this.bindings[sBinding] = control;
|
||||
this.cLiveRegs++;
|
||||
fBound = true;
|
||||
break;
|
||||
default:
|
||||
fBound = this.parent.setBinding.call(this, sHTMLType, sBinding, control);
|
||||
break;
|
||||
case "EAX":
|
||||
case "EBX":
|
||||
case "ECX":
|
||||
case "EDX":
|
||||
case "ESP":
|
||||
case "EBP":
|
||||
case "ESI":
|
||||
case "EDI":
|
||||
case "EIP":
|
||||
case "AX":
|
||||
case "BX":
|
||||
case "CX":
|
||||
case "DX":
|
||||
case "SP":
|
||||
case "BP":
|
||||
case "SI":
|
||||
case "DI":
|
||||
case "IP":
|
||||
case "PC": // deprecated as an alias for "IP" (still used by older XML files, like the one at http://tpoindex.github.io/crobots/)
|
||||
case "CS":
|
||||
case "DS":
|
||||
case "SS":
|
||||
case "ES":
|
||||
case "PS": // this refers to "Processor Status", aka the 16-bit flags register (although DEBUG.COM refers to this as "PC", surprisingly)
|
||||
case "C":
|
||||
case "P":
|
||||
case "A":
|
||||
case "Z":
|
||||
case "S":
|
||||
case "T":
|
||||
case "I":
|
||||
case "D":
|
||||
case "V":
|
||||
this.bindings[sBinding] = control;
|
||||
this.cLiveRegs++;
|
||||
fBound = true;
|
||||
break;
|
||||
default:
|
||||
fBound = this.parent.setBinding.call(this, sHTMLType, sBinding, control);
|
||||
break;
|
||||
}
|
||||
return fBound;
|
||||
};
|
||||
|
|
@ -3055,14 +3336,44 @@ X86CPU.prototype.delayINTR = function()
|
|||
this.opFlags |= X86.OPFLAG.NOINTR;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateReg(sReg, nValue)
|
||||
*
|
||||
* This function helps updateStatus() by massaging the register names and values according to
|
||||
* CPU type before passing the call to displayValue(); in the "old days", updateStatus() called
|
||||
* displayValue() directly (although then it was called displayReg()).
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {string} sReg
|
||||
* @param {number} nValue
|
||||
*/
|
||||
X86CPU.prototype.updateReg = function(sReg, nValue)
|
||||
{
|
||||
var cch = 4;
|
||||
if (sReg.length == 1) {
|
||||
cch = 1;
|
||||
nValue = nValue? 1 : 0;
|
||||
}
|
||||
if (this.model < 80386) {
|
||||
if (sReg.length > 2) {
|
||||
sReg = sReg.substr(0, 2);
|
||||
}
|
||||
} else {
|
||||
if (sReg == "PS" || sReg.length > 2) {
|
||||
cch = 8;
|
||||
}
|
||||
}
|
||||
this.displayValue(sReg, nValue, cch);
|
||||
};
|
||||
|
||||
/**
|
||||
* updateStatus()
|
||||
*
|
||||
* This provides periodic Control Panel updates (eg, a few times per second; see STATUS_UPDATES_PER_SECOND).
|
||||
* this is where we take care of any DOM updates (eg, register values) while the CPU is running.
|
||||
*
|
||||
* Any high-frequency updates should be performed in updateVideo(), which should avoid DOM updates, since
|
||||
* updateVideo() can be called up to 60 times per second (see VIDEO_UPDATES_PER_SECOND).
|
||||
* Any high-frequency updates should be performed in updateVideo(), which should avoid DOM updates, since updateVideo()
|
||||
* can be called up to 60 times per second (see VIDEO_UPDATES_PER_SECOND).
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {boolean} [fForce] (true will display registers even if the CPU is running and "live" registers are not enabled)
|
||||
|
|
@ -3071,30 +3382,30 @@ X86CPU.prototype.updateStatus = function(fForce)
|
|||
{
|
||||
if (this.cLiveRegs) {
|
||||
if (fForce || !this.aFlags.fRunning || this.aFlags.fDisplayLiveRegs) {
|
||||
this.displayReg("AX", this.regEAX);
|
||||
this.displayReg("BX", this.regEBX);
|
||||
this.displayReg("CX", this.regECX);
|
||||
this.displayReg("DX", this.regEDX);
|
||||
this.displayReg("SP", this.getSP());
|
||||
this.displayReg("BP", this.regEBP);
|
||||
this.displayReg("SI", this.regESI);
|
||||
this.displayReg("DI", this.regEDI);
|
||||
this.displayReg("CS", this.getCS());
|
||||
this.displayReg("DS", this.getDS());
|
||||
this.displayReg("SS", this.getSS());
|
||||
this.displayReg("ES", this.getES());
|
||||
this.displayReg("IP", this.getIP());
|
||||
this.updateReg("EAX", this.regEAX);
|
||||
this.updateReg("EBX", this.regEBX);
|
||||
this.updateReg("ECX", this.regECX);
|
||||
this.updateReg("EDX", this.regEDX);
|
||||
this.updateReg("ESP", this.getSP());
|
||||
this.updateReg("EBP", this.regEBP);
|
||||
this.updateReg("ESI", this.regESI);
|
||||
this.updateReg("EDI", this.regEDI);
|
||||
this.updateReg("CS", this.getCS());
|
||||
this.updateReg("DS", this.getDS());
|
||||
this.updateReg("SS", this.getSS());
|
||||
this.updateReg("ES", this.getES());
|
||||
this.updateReg("EIP", this.getIP());
|
||||
var regPS = this.getPS();
|
||||
this.displayReg("PS", regPS);
|
||||
this.displayReg("V", (regPS & X86.PS.OF)? 1 : 0, 1);
|
||||
this.displayReg("D", (regPS & X86.PS.DF)? 1 : 0, 1);
|
||||
this.displayReg("I", (regPS & X86.PS.IF)? 1 : 0, 1);
|
||||
this.displayReg("T", (regPS & X86.PS.TF)? 1 : 0, 1);
|
||||
this.displayReg("S", (regPS & X86.PS.SF)? 1 : 0, 1);
|
||||
this.displayReg("Z", (regPS & X86.PS.ZF)? 1 : 0, 1);
|
||||
this.displayReg("A", (regPS & X86.PS.AF)? 1 : 0, 1);
|
||||
this.displayReg("P", (regPS & X86.PS.PF)? 1 : 0, 1);
|
||||
this.displayReg("C", (regPS & X86.PS.CF)? 1 : 0, 1);
|
||||
this.updateReg("PS", regPS);
|
||||
this.updateReg("V", (regPS & X86.PS.OF));
|
||||
this.updateReg("D", (regPS & X86.PS.DF));
|
||||
this.updateReg("I", (regPS & X86.PS.IF));
|
||||
this.updateReg("T", (regPS & X86.PS.TF));
|
||||
this.updateReg("S", (regPS & X86.PS.SF));
|
||||
this.updateReg("Z", (regPS & X86.PS.ZF));
|
||||
this.updateReg("A", (regPS & X86.PS.AF));
|
||||
this.updateReg("P", (regPS & X86.PS.PF));
|
||||
this.updateReg("C", (regPS & X86.PS.CF));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -544,7 +544,7 @@ X86.opANDAX = function ANDAX()
|
|||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opANDEAX = function ANDEAX()
|
||||
X86.opANDAXd = function ANDAXd()
|
||||
{
|
||||
this.regEAX = X86.fnANDd.call(this, this.regEAX, this.getIPLong());
|
||||
if (BACKTRACK) {
|
||||
|
|
@ -581,20 +581,27 @@ X86.opES = function ES()
|
|||
X86.opDAA = function DAA()
|
||||
{
|
||||
var AL = this.regEAX & 0xff;
|
||||
var fAuxCarry = this.getAF();
|
||||
var fCarry = (this.resultZeroCarry & this.resultSize);
|
||||
if ((AL & 0xf) > 9 || fAuxCarry) {
|
||||
var AF = this.getAF();
|
||||
var CF = this.getCF();
|
||||
if ((AL & 0xf) > 9 || AF) {
|
||||
AL += 0x6;
|
||||
fAuxCarry = true;
|
||||
AF = X86.PS.AF;
|
||||
}
|
||||
if (AL > 0x9f || fCarry) {
|
||||
if (AL > 0x9f || CF) {
|
||||
AL += 0x60;
|
||||
fCarry = true;
|
||||
CF = X86.PS.CF;
|
||||
}
|
||||
this.regEAX = (this.regEAX & ~0xff) | (this.resultZeroCarry = this.resultParitySign = (AL & 0xff));
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
var b = (AL & 0xff);
|
||||
this.regEAX = (this.regEAX & ~0xff) | b;
|
||||
if (OLDFLAGS) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry = this.resultParitySign = b;
|
||||
}
|
||||
if (I386) {
|
||||
this.setLogicResult(b, X86.RESULT.BYTE);
|
||||
}
|
||||
if (CF) this.setCF(); else this.clearCF();
|
||||
if (AF) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAA have the same cycle times
|
||||
};
|
||||
|
||||
|
|
@ -696,20 +703,27 @@ X86.opCS = function CS()
|
|||
X86.opDAS = function DAS()
|
||||
{
|
||||
var AL = this.regEAX & 0xff;
|
||||
var fAuxCarry = this.getAF();
|
||||
var fCarry = (this.resultZeroCarry & this.resultSize);
|
||||
if ((AL & 0xf) > 9 || fAuxCarry) {
|
||||
var AF = this.getAF();
|
||||
var CF = this.getCF();
|
||||
if ((AL & 0xf) > 9 || AF) {
|
||||
AL -= 0x6;
|
||||
fAuxCarry = true;
|
||||
AF = X86.PS.AF;
|
||||
}
|
||||
if (AL > 0x9f || fCarry) {
|
||||
if (AL > 0x9f || CF) {
|
||||
AL -= 0x60;
|
||||
fCarry = true;
|
||||
CF = X86.PS.CF;
|
||||
}
|
||||
this.regEAX = (this.regEAX & ~0xff) | (this.resultZeroCarry = this.resultParitySign = (AL & 0xff));
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
var b = (AL & 0xff);
|
||||
this.regEAX = (this.regEAX & ~0xff) | b;
|
||||
if (OLDFLAGS) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry = this.resultParitySign = b;
|
||||
}
|
||||
if (I386) {
|
||||
this.setLogicResult(b, X86.RESULT.BYTE);
|
||||
}
|
||||
if (CF) this.setCF(); else this.clearCF();
|
||||
if (AF) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and DAS have the same cycle times
|
||||
};
|
||||
|
||||
|
|
@ -753,6 +767,16 @@ X86.opXORrw = function XORrw()
|
|||
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnXORw);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0x33 (XOR reg,dword)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opXORrd = function XORrd()
|
||||
{
|
||||
this.aOpModRegWord[this.getIPByte()].call(this, X86.fnXORd);
|
||||
};
|
||||
|
||||
/**
|
||||
* op=0x34 (XOR AL,imm8)
|
||||
*
|
||||
|
|
@ -763,8 +787,8 @@ X86.opXORALb = function XORALb()
|
|||
this.regEAX = (this.regEAX & ~0xff) | X86.fnXORb.call(this, this.regEAX & 0xff, this.getIPByte());
|
||||
if (BACKTRACK) this.backTrack.btiAL = this.backTrack.btiMemLo;
|
||||
/*
|
||||
* In the absence of any EA calculations, opGrpXORb() will deduct nOpCyclesArithRR, and for all CPUs through
|
||||
* the 80286, we need deduct only one more cycle.
|
||||
* In the absence of any EA calculations, opGrpXORb() will deduct nOpCyclesArithRR, and for all CPUs
|
||||
* through the 80286, we need deduct only one more cycle.
|
||||
*/
|
||||
this.nStepCycles--;
|
||||
};
|
||||
|
|
@ -781,8 +805,8 @@ X86.opXORAXw = function XORAXw()
|
|||
this.backTrack.btiAL = this.backTrack.btiMemLo; this.backTrack.btiAH = this.backTrack.btiMemHi;
|
||||
}
|
||||
/*
|
||||
* In the absence of any EA calculations, opGrpXORw() will deduct nOpCyclesArithRR, and for all CPUs through
|
||||
* the 80286, we need deduct only one more cycle.
|
||||
* In the absence of any EA calculations, opGrpXORw() will deduct nOpCyclesArithRR, and for all CPUs
|
||||
* through the 80286, we need deduct only one more cycle.
|
||||
*/
|
||||
this.nStepCycles--;
|
||||
};
|
||||
|
|
@ -810,21 +834,19 @@ X86.opSS = function SS()
|
|||
*/
|
||||
X86.opAAA = function AAA()
|
||||
{
|
||||
var CF, AF;
|
||||
var AL = this.regEAX & 0xff;
|
||||
var AH = this.regEAX >> 8;
|
||||
var fCarry;
|
||||
var fAuxCarry = this.getAF();
|
||||
if ((AL & 0xf) > 9 || fAuxCarry) {
|
||||
var AH = (this.regEAX >> 8) & 0xff;
|
||||
if ((AL & 0xf) > 9 || this.getAF()) {
|
||||
AL = (AL + 0x6) & 0xf;
|
||||
AH = (AH + 1) & 0xff;
|
||||
fCarry = fAuxCarry = true;
|
||||
CF = AF = 1;
|
||||
} else {
|
||||
fCarry = fAuxCarry = false;
|
||||
CF = AF = 0;
|
||||
}
|
||||
this.regEAX = (this.regEAX & ~0xffff) | (AH << 8) | (this.resultZeroCarry = AL);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
this.regEAX = (this.regEAX & ~0xffff) | ((AH << 8) | AL);
|
||||
if (CF) this.setCF(); else this.clearCF();
|
||||
if (AF) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
|
||||
};
|
||||
|
||||
|
|
@ -917,32 +939,23 @@ X86.opDS = function DS()
|
|||
/**
|
||||
* op=0x3D (AAS)
|
||||
*
|
||||
* From "The 8086 Book":
|
||||
*
|
||||
* 1. If the low-order four bits of the AL register are between 0 and 9 and the AF flag is 0, then go to Step 3.
|
||||
* 2. If the low-order four bits of the AL register are between A and F or the AF flag is 1, then subtract 6 from the AL register, subtract 1 from the AH register, and set the AF flag to 1.
|
||||
* 3. Clear the high-order four bits of the AL register.
|
||||
* 4. Set the CF flag to the value of the AF flag.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opAAS = function AAS()
|
||||
{
|
||||
var CF, AF;
|
||||
var AL = this.regEAX & 0xff;
|
||||
var AH = this.regEAX >> 8;
|
||||
var fCarry;
|
||||
var fAuxCarry = this.getAF();
|
||||
if ((AL & 0xf) > 9 || fAuxCarry) {
|
||||
var AH = (this.regEAX >> 8) & 0xff;
|
||||
if ((AL & 0xf) > 9 || this.getAF()) {
|
||||
AL = (AL - 0x6) & 0xf;
|
||||
AH = (AH - 1) & 0xff;
|
||||
fCarry = fAuxCarry = true;
|
||||
CF = AF = 1;
|
||||
} else {
|
||||
fCarry = fAuxCarry = false;
|
||||
CF = AF = 0;
|
||||
}
|
||||
this.regEAX = (this.regEAX & ~0xffff) | (AH << 8) | (this.resultZeroCarry = AL);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
if (fCarry) this.resultZeroCarry |= this.resultSize;
|
||||
if (fAuxCarry) this.setAF(); else this.clearAF();
|
||||
this.regEAX = (this.regEAX & ~0xffff) | ((AH << 8) | AL);
|
||||
if (CF) this.setCF(); else this.clearCF();
|
||||
if (AF) this.setAF(); else this.clearAF();
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA; // AAA and AAS have the same cycle times
|
||||
};
|
||||
|
||||
|
|
@ -953,16 +966,7 @@ X86.opAAS = function AAS()
|
|||
*/
|
||||
X86.opINCAX = function INCAX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEAX) + 1;
|
||||
if (I386) {
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEAX) & this.dataMask) >>> 16) | (this.regEAX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEAX = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEAX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regEAX = X86.fnINCr.call(this, this.regEAX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -972,16 +976,7 @@ X86.opINCAX = function INCAX()
|
|||
*/
|
||||
X86.opINCCX = function INCCX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regECX) + 1;
|
||||
if (I386) {
|
||||
this.regECX = (this.regECX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regECX) & this.dataMask) >>> 16) | (this.regECX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regECX = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regECX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regECX = X86.fnINCr.call(this, this.regECX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -991,16 +986,7 @@ X86.opINCCX = function INCCX()
|
|||
*/
|
||||
X86.opINCDX = function INCDX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDX) + 1;
|
||||
if (I386) {
|
||||
this.regEDX = (this.regEDX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEDX) & this.dataMask) >>> 16) | (this.regEDX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEDX = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEDX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regEDX = X86.fnINCr.call(this, this.regEDX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1010,16 +996,7 @@ X86.opINCDX = function INCDX()
|
|||
*/
|
||||
X86.opINCBX = function INCBX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBX) + 1;
|
||||
if (I386) {
|
||||
this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEBX) & this.dataMask) >>> 16) | (this.regEBX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEBX = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEBX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regEBX = X86.fnINCr.call(this, this.regEBX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1029,12 +1006,7 @@ X86.opINCBX = function INCBX()
|
|||
*/
|
||||
X86.opINCSP = function INCSP()
|
||||
{
|
||||
var regESP;
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.getSP()) + 1;
|
||||
this.setSP(regESP = (this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign & this.dataMask));
|
||||
this.resultZeroCarry = (((regESP) & this.dataMask) >>> 16) | (regESP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.setSP(X86.fnINCr.call(this, this.getSP()));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1044,16 +1016,7 @@ X86.opINCSP = function INCSP()
|
|||
*/
|
||||
X86.opINCBP = function INCBP()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBP) + 1;
|
||||
if (I386) {
|
||||
this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEBP) & this.dataMask) >>> 16) | (this.regEBP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEBP = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEBP | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regEBP = X86.fnINCr.call(this, this.regEBP);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1063,16 +1026,7 @@ X86.opINCBP = function INCBP()
|
|||
*/
|
||||
X86.opINCSI = function INCSI()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regESI) + 1;
|
||||
if (I386) {
|
||||
this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regESI) & this.dataMask) >>> 16) | (this.regESI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regESI = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regESI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regESI = X86.fnINCr.call(this, this.regESI);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1082,16 +1036,7 @@ X86.opINCSI = function INCSI()
|
|||
*/
|
||||
X86.opINCDI = function INCDI()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDI) + 1;
|
||||
if (I386) {
|
||||
this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEDI) & this.dataMask) >>> 16) | (this.regEDI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEDI = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEDI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of INC takes 2 cycles on all CPUs
|
||||
this.regEDI = X86.fnINCr.call(this, this.regEDI);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1101,16 +1046,7 @@ X86.opINCDI = function INCDI()
|
|||
*/
|
||||
X86.opDECAX = function DECAX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEAX) - 1;
|
||||
if (I386) {
|
||||
this.regEAX = (this.regEAX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEAX) & this.dataMask) >>> 16) | (this.regEAX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEAX = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEAX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regEAX = X86.fnDECr.call(this, this.regEAX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1120,11 +1056,7 @@ X86.opDECAX = function DECAX()
|
|||
*/
|
||||
X86.opDECCX = function DECCX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regECX) - 1;
|
||||
this.regECX = (I386? (this.regECX & ~this.dataMask) | (this.resultParitySign & this.dataMask) : this.resultParitySign & 0xffff);
|
||||
this.resultZeroCarry = this.regECX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regECX = X86.fnDECr.call(this, this.regECX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1134,11 +1066,7 @@ X86.opDECCX = function DECCX()
|
|||
*/
|
||||
X86.opDECDX = function DECDX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDX) - 1;
|
||||
this.regEDX = (I386? (this.regEDX & ~this.dataMask) | (this.resultParitySign & this.dataMask) : this.resultParitySign & 0xffff);
|
||||
this.resultZeroCarry = this.regEDX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regEDX = X86.fnDECr.call(this, this.regEDX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1148,16 +1076,7 @@ X86.opDECDX = function DECDX()
|
|||
*/
|
||||
X86.opDECBX = function DECBX()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBX) - 1;
|
||||
if (I386) {
|
||||
this.regEBX = (this.regEBX & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEBX) & this.dataMask) >>> 16) | (this.regEBX & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEBX = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEBX | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regEBX = X86.fnDECr.call(this, this.regEBX);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1167,12 +1086,7 @@ X86.opDECBX = function DECBX()
|
|||
*/
|
||||
X86.opDECSP = function DECSP()
|
||||
{
|
||||
var regESP;
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.getSP()) - 1;
|
||||
this.setSP(regESP = (this.resultAuxOverflow & ~this.dataMask) | (this.resultParitySign & this.dataMask));
|
||||
this.resultZeroCarry = (((regESP) & this.dataMask) >>> 16) | (regESP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.setSP(X86.fnDECr.call(this, this.getSP()));
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1182,16 +1096,7 @@ X86.opDECSP = function DECSP()
|
|||
*/
|
||||
X86.opDECBP = function DECBP()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEBP) - 1;
|
||||
if (I386) {
|
||||
this.regEBP = (this.regEBP & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEBP) & this.dataMask) >>> 16) | (this.regEBP & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEBP = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEBP | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regEBP = X86.fnDECr.call(this, this.regEBP);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1201,16 +1106,7 @@ X86.opDECBP = function DECBP()
|
|||
*/
|
||||
X86.opDECSI = function DECSI()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regESI) - 1;
|
||||
if (I386) {
|
||||
this.regESI = (this.regESI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regESI) & this.dataMask) >>> 16) | (this.regESI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regESI = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regESI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regESI = X86.fnDECr.call(this, this.regESI);
|
||||
};
|
||||
|
||||
/**`
|
||||
|
|
@ -1220,16 +1116,7 @@ X86.opDECSI = function DECSI()
|
|||
*/
|
||||
X86.opDECDI = function DECDI()
|
||||
{
|
||||
this.resultParitySign = (this.resultAuxOverflow = this.regEDI) - 1;
|
||||
if (I386) {
|
||||
this.regEDI = (this.regEDI & ~this.dataMask) | (this.resultParitySign & this.dataMask);
|
||||
this.resultZeroCarry = (((this.regEDI) & this.dataMask) >>> 16) | (this.regEDI & 0xffff) | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
} else {
|
||||
this.regEDI = this.resultParitySign & 0xffff;
|
||||
this.resultZeroCarry = this.regEDI | (((this.resultZeroCarry & this.resultSize)? 1 : 0) << 16);
|
||||
}
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
this.nStepCycles -= 2; // this form of DEC takes 2 cycles on all CPUs
|
||||
this.regEDI = X86.fnDECr.call(this, this.regEDI);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2921,8 +2808,14 @@ X86.opCMPSw = function CMPSw()
|
|||
*/
|
||||
X86.opTESTALb = function TESTALb()
|
||||
{
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = this.regEAX & this.getIPByte();
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
var src = this.getIPByte();
|
||||
if (OLDFLAGS) {
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = this.regEAX & src;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
}
|
||||
if (I386) {
|
||||
this.setLogicResult(this.regEAX & src, X86.RESULT.BYTE);
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
|
||||
};
|
||||
|
||||
|
|
@ -2933,8 +2826,14 @@ X86.opTESTALb = function TESTALb()
|
|||
*/
|
||||
X86.opTESTAXw = function TESTAXw()
|
||||
{
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = this.regEAX & this.getIPWord();
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
var src = this.getIPWord();
|
||||
if (OLDFLAGS) {
|
||||
this.resultZeroCarry = this.resultParitySign = this.resultAuxOverflow = this.regEAX & src;
|
||||
this.resultSize = X86.RESULT.SIZE_WORD;
|
||||
}
|
||||
if (I386) {
|
||||
this.setLogicResult(this.regEAX & src, X86.RESULT.WORD);
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAA;
|
||||
};
|
||||
|
||||
|
|
@ -3654,23 +3553,32 @@ X86.opGrp2wCL = function GRP2wCL()
|
|||
*
|
||||
* From "The 8086 Book":
|
||||
*
|
||||
* 1. Divide the AL register by OA16. Store the quotient in the AH register. Store the remainder in the AL register.
|
||||
* 2. Set the flags in the following manner:
|
||||
* Parity: based on the AL register
|
||||
* Sign : based on the high-order bit of the AL register Zero: based on the AL register
|
||||
* Carry, Overflow, and Arithmetic: undefined
|
||||
* 1. Divide AL by 0x0A; store the quotient in AH and the remainder in AL
|
||||
* 2. Set PF, SF, and ZF based on the AL register (CF, OF, and AF are undefined)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opAAM = function AAM()
|
||||
{
|
||||
var bDivisor = this.getIPByte();
|
||||
if (!bDivisor) {
|
||||
/*
|
||||
* TODO: Generate a divide-by-zero exception, if appropriate for the current CPU
|
||||
*/
|
||||
return;
|
||||
}
|
||||
var AL = this.regEAX & 0xff;
|
||||
var bQuotient = (AL / bDivisor) & 0xff;
|
||||
var bRemainder = AL % bDivisor;
|
||||
this.regEAX = (bQuotient << 8) | bRemainder;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry = this.resultParitySign = AL;
|
||||
this.regEAX = (this.regEAX & ~0xffff) | ((AL / bDivisor) << 8) | (AL % bDivisor);
|
||||
if (OLDFLAGS) {
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.resultZeroCarry = this.resultParitySign = this.regEAX;
|
||||
}
|
||||
if (I386) {
|
||||
/*
|
||||
* setLogicResult() is slightly overkill, because technically, we don't need to clear CF and OF....
|
||||
*/
|
||||
this.setLogicResult(this.regEAX, X86.RESULT.BYTE);
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAM;
|
||||
};
|
||||
|
||||
|
|
@ -3679,22 +3587,25 @@ X86.opAAM = function AAM()
|
|||
*
|
||||
* From "The 8086 Book":
|
||||
*
|
||||
* 1. Multiply the contents of the AH register by 0x0A
|
||||
* 2. Add AH to AL.
|
||||
* 3. Store 0x00 into the AH register.
|
||||
* 4. Set the flags in the following manner:
|
||||
* Parity: based on the AL register
|
||||
* Zero: based on the AL register
|
||||
* Sign: based on the high-order bit of the AL register
|
||||
* Carry, Overflow, Arithmetic: undefined
|
||||
* 1. Multiply AH by 0x0A, add AH to AL, and store 0x00 in AH
|
||||
* 2. Set PF, SF, and ZF based on the AL register (CF, OF, and AF are undefined)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opAAD = function AAD()
|
||||
{
|
||||
var bMultiplier = this.getIPByte();
|
||||
this.resultZeroCarry = this.resultParitySign = this.regEAX = (((this.regEAX >> 8) * bMultiplier) + this.regEAX) & 0xff;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
this.regEAX = (this.regEAX & ~0xffff) | (((((this.regEAX >> 8) & 0xff) * bMultiplier) + this.regEAX) & 0xff);
|
||||
if (OLDFLAGS) {
|
||||
this.resultZeroCarry = this.resultParitySign = this.regEAX;
|
||||
this.resultSize = X86.RESULT.SIZE_BYTE;
|
||||
}
|
||||
if (I386) {
|
||||
/*
|
||||
* setLogicResult() is slightly overkill, because technically, we don't need to clear CF and OF....
|
||||
*/
|
||||
this.setLogicResult(this.regEAX, X86.RESULT.BYTE);
|
||||
}
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesAAD;
|
||||
};
|
||||
|
||||
|
|
@ -3747,7 +3658,7 @@ X86.opESC = function ESC()
|
|||
X86.opLOOPNZ = function LOOPNZ()
|
||||
{
|
||||
var disp = this.getIPDisp();
|
||||
if ((this.regECX = (this.regECX - 1) & this.addrMask) && (this.resultZeroCarry & (this.resultSize - 1))) {
|
||||
if ((this.regECX = (this.regECX - 1) & this.addrMask) && !this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesLoopNZ;
|
||||
return;
|
||||
|
|
@ -3763,7 +3674,7 @@ X86.opLOOPNZ = function LOOPNZ()
|
|||
X86.opLOOPZ = function LOOPZ()
|
||||
{
|
||||
var disp = this.getIPDisp();
|
||||
if ((this.regECX = (this.regECX - 1) & this.addrMask) && !(this.resultZeroCarry & (this.resultSize - 1))) {
|
||||
if ((this.regECX = (this.regECX - 1) & this.addrMask) && this.getZF()) {
|
||||
this.setIP(this.getIP() + disp);
|
||||
this.nStepCycles -= this.CYCLES.nOpCyclesLoopZ;
|
||||
return;
|
||||
|
|
@ -4121,7 +4032,7 @@ X86.opGrp3w = function GRP3w()
|
|||
*/
|
||||
X86.opCLC = function CLC()
|
||||
{
|
||||
this.resultZeroCarry &= ~this.resultSize;
|
||||
this.clearCF();
|
||||
this.nStepCycles -= 2; // CLC takes 2 cycles on all CPUs
|
||||
};
|
||||
|
||||
|
|
@ -4132,7 +4043,7 @@ X86.opCLC = function CLC()
|
|||
*/
|
||||
X86.opSTC = function STC()
|
||||
{
|
||||
this.resultZeroCarry |= this.resultSize;
|
||||
this.setCF();
|
||||
this.nStepCycles -= 2; // STC takes 2 cycles on all CPUs
|
||||
};
|
||||
|
||||
|
|
@ -4224,6 +4135,17 @@ X86.opUndefined = function()
|
|||
this.stopCPU();
|
||||
};
|
||||
|
||||
/**
|
||||
* opTBDd()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86.opTBDd = function()
|
||||
{
|
||||
this.printMessage("unimplemented 80386 opcode", true);
|
||||
this.stopCPU();
|
||||
};
|
||||
|
||||
/*
|
||||
* This 256-entry array of opcode functions is at the heart of the CPU engine: stepCPU(n).
|
||||
*
|
||||
|
|
@ -4405,9 +4327,33 @@ X86.aOpGrp4w = [
|
|||
];
|
||||
|
||||
if (I386) {
|
||||
/*
|
||||
* Until we have *d() forms of all *w() opcode handlers, we need to put in placeholders (ie, opTBDd())
|
||||
*/
|
||||
X86.aOpsD = {
|
||||
0x21: X86.opANDmd,
|
||||
0x23: X86.opANDrd,
|
||||
0x25: X86.opANDEAX
|
||||
0x01: X86.opTBDd, // opADDmd()
|
||||
0x03: X86.opTBDd, // opADDrd()
|
||||
0x05: X86.opTBDd, // opADDAXd()
|
||||
0x09: X86.opTBDd, // opORmd()
|
||||
0x0B: X86.opTBDd, // opORrd()
|
||||
0x0D: X86.opTBDd, // opORAXd()
|
||||
0x11: X86.opTBDd, // opADCmd()
|
||||
0x13: X86.opTBDd, // opADCrd()
|
||||
0x15: X86.opTBDd, // opADCAXd()
|
||||
0x19: X86.opTBDd, // opSBBmd()
|
||||
0x1B: X86.opTBDd, // opSBBrd()
|
||||
0x1D: X86.opTBDd, // opSBBAXd()
|
||||
0x21: X86.opANDmd,
|
||||
0x23: X86.opANDrd,
|
||||
0x25: X86.opANDAXd,
|
||||
0x29: X86.opTBDd, // opSUBmd()
|
||||
0x2B: X86.opTBDd, // opSUBrd()
|
||||
0x2D: X86.opTBDd, // opSUBAXd()
|
||||
0x31: X86.opTBDd, // opXORmd()
|
||||
0x33: X86.opXORrd,
|
||||
0x35: X86.opTBDd, // opXORAXd()
|
||||
0x39: X86.opTBDd, // opCMPmd()
|
||||
0x3B: X86.opTBDd, // opCMPrd()
|
||||
0x3D: X86.opTBDd // opCMPAXd()
|
||||
};
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue