Author: aandrejevic
Date: Fri Jan 2 18:29:30 2015
New Revision: 65940
URL:
http://svn.reactos.org/svn/reactos?rev=65940&view=rev
Log:
[FAST486]
Split the D8/DC opcode handler into two handlers to eliminate the extra branch.
Implement opcode DF (New instructions: FBLD and FBSTP).
Modified:
trunk/reactos/lib/fast486/fpu.c
trunk/reactos/lib/fast486/fpu.h
trunk/reactos/lib/fast486/opcodes.c
Modified: trunk/reactos/lib/fast486/fpu.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.c?rev=6594…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Fri Jan 2 18:29:30 2015
@@ -291,6 +291,61 @@
return TRUE;
}
+static inline BOOLEAN FASTCALL
+Fast486FpuFromPackedBcd(PFAST486_STATE State,
+ PUCHAR Value,
+ PFAST486_FPU_DATA_REG Result)
+{
+ INT i;
+ LONGLONG IntVal = 0LL;
+
+ for (i = 8; i >= 0; i--)
+ {
+ if (((Value[i] & 0x0F) > 9) || ((Value[i] >> 4) > 9))
+ {
+ /* Invalid BCD */
+ State->FpuStatus.Ie = TRUE;
+ return FALSE;
+ }
+
+ IntVal *= 100LL;
+ IntVal += (Value[i] >> 4) * 10 + (Value[i] & 0x0F);
+ }
+
+ /* Apply the sign */
+ if (Value[9] & 0x80) IntVal = -IntVal;
+
+ /* Now convert the integer to FP80 */
+ Fast486FpuFromInteger(State, IntVal, Result);
+ return TRUE;
+}
+
+static inline BOOLEAN FASTCALL
+Fast486FpuToPackedBcd(PFAST486_STATE State,
+ PFAST486_FPU_DATA_REG Value,
+ PUCHAR Result)
+{
+ INT i;
+ LONGLONG IntVal;
+
+ /* Convert it to an integer first */
+ if (!Fast486FpuToInteger(State, Value, &IntVal)) return FALSE;
+
+ if (IntVal < 0LL)
+ {
+ IntVal = -IntVal;
+ Result[9] = 0x80;
+ }
+
+ for (i = 0; i < 9; i++)
+ {
+ Result[i] = (UCHAR)((IntVal % 10) + (((IntVal / 10) % 10) << 4));
+ IntVal /= 100LL;
+ }
+
+ return TRUE;
+}
+
static inline VOID FASTCALL
Fast486FpuAdd(PFAST486_STATE State,
PFAST486_FPU_DATA_REG FirstOperand,
@@ -558,7 +613,7 @@
/* PUBLIC FUNCTIONS ***********************************************************/
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8DC)
+FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8)
{
FAST486_MOD_REG_RM ModRegRm;
BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
@@ -586,38 +641,15 @@
if (ModRegRm.Memory)
{
/* Load the source operand from memory */
-
- if (Opcode == 0xDC)
- {
- ULONGLONG Value;
-
- if (!Fast486ReadMemory(State,
- (State->PrefixFlags & FAST486_PREFIX_SEG)
- ? State->SegmentOverride : FAST486_REG_DS,
- ModRegRm.MemoryAddress,
- FALSE,
- &Value,
- sizeof(ULONGLONG)))
- {
- /* Exception occurred */
- return;
- }
-
- Fast486FpuFromDoubleReal(State, Value, &MemoryData);
- }
- else
- {
- ULONG Value;
-
- if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
- {
- /* Exception occurred */
- return;
- }
-
- Fast486FpuFromSingleReal(State, Value, &MemoryData);
- }
-
+ ULONG Value;
+
+ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuFromSingleReal(State, Value, &MemoryData);
SourceOperand = &MemoryData;
/* The destination operand is ST0 */
@@ -632,22 +664,11 @@
return;
}
- if (Opcode == 0xDC)
- {
- /* The source operand is ST0 */
- SourceOperand = &FPU_ST(0);
-
- /* Load the destination operand from an FPU register */
- DestOperand = &FPU_ST(ModRegRm.SecondRegister);
- }
- else
- {
- /* Load the source operand from an FPU register */
- SourceOperand = &FPU_ST(ModRegRm.SecondRegister);
-
- /* The destination operand is ST0 */
- DestOperand = &FPU_ST(0);
- }
+ /* Load the source operand from an FPU register */
+ SourceOperand = &FPU_ST(ModRegRm.SecondRegister);
+
+ /* The destination operand is ST0 */
+ DestOperand = &FPU_ST(0);
}
/* Perform the requested operation */
@@ -655,6 +676,77 @@
#endif
}
+
+FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC)
+{
+ FAST486_MOD_REG_RM ModRegRm;
+ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+ PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
+ FAST486_FPU_DATA_REG MemoryData;
+
+ /* Get the operands */
+ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ FPU_CHECK();
+
+#ifndef FAST486_NO_FPU
+
+ if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
+ {
+ /* Invalid operation */
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ if (ModRegRm.Memory)
+ {
+ /* Load the source operand from memory */
+ ULONGLONG Value;
+
+ if (!Fast486ReadMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ FALSE,
+ &Value,
+ sizeof(ULONGLONG)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuFromDoubleReal(State, Value, &MemoryData);
+ SourceOperand = &MemoryData;
+
+ /* The destination operand is ST0 */
+ DestOperand = &FPU_ST(0);
+ }
+ else
+ {
+ if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
+ {
+ /* Invalid operation */
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ /* The source operand is ST0 */
+ SourceOperand = &FPU_ST(0);
+
+ /* Load the destination operand from an FPU register */
+ DestOperand = &FPU_ST(ModRegRm.SecondRegister);
+ }
+
+ /* Perform the requested operation */
+ Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand);
+
+#endif
+}
+
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9)
{
@@ -1222,10 +1314,270 @@
FPU_CHECK();
#ifndef FAST486_NO_FPU
- // TODO: NOT IMPLEMENTED
- UNIMPLEMENTED;
-#else
- /* Do nothing */
+
+ if (ModRegRm.Memory)
+ {
+ switch (ModRegRm.Register)
+ {
+ /* FILD */
+ case 0:
+ {
+ SHORT Value;
+ FAST486_FPU_DATA_REG Temp;
+
+ if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL,
(PUSHORT)&Value))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
+ Fast486FpuPush(State, &Temp);
+
+ break;
+ }
+
+ /* FIST */
+ case 2:
+ /* FISTP */
+ case 3:
+ {
+ LONGLONG Temp;
+
+ if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) ==
FPU_TAG_SPECIAL))
+ {
+ /* Fail */
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ /* Check if it can fit in a signed 16-bit integer */
+ if ((((ULONGLONG)Temp >> 15) + 1ULL) > 1ULL)
+ {
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE,
(USHORT)((SHORT)Temp)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (ModRegRm.Register == 3)
+ {
+ /* Pop the FPU stack too */
+ Fast486FpuPop(State);
+ }
+
+ break;
+ }
+
+ /* FBLD */
+ case 4:
+ {
+ FAST486_FPU_DATA_REG Value;
+ UCHAR Buffer[10];
+
+ if (!Fast486ReadMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ FALSE,
+ Buffer,
+ sizeof(Buffer)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Fast486FpuFromPackedBcd(State, Buffer, &Value))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuPush(State, &Value);
+ break;
+ }
+
+ /* FILD (64-bit int) */
+ case 5:
+ {
+ LONGLONG Value;
+ FAST486_FPU_DATA_REG Temp;
+
+ if (!Fast486ReadMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ FALSE,
+ &Value,
+ sizeof(LONGLONG)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuFromInteger(State, (LONGLONG)Value, &Temp);
+ Fast486FpuPush(State, &Temp);
+
+ break;
+ }
+
+ /* FBSTP */
+ case 6:
+ {
+ UCHAR Buffer[10];
+
+ if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
+ {
+ /* Fail */
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ if (!Fast486FpuToPackedBcd(State, &FPU_ST(0), Buffer))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Fast486WriteMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ Buffer,
+ sizeof(Buffer)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ Fast486FpuPop(State);
+ break;
+ }
+
+ /* FISTP (64-bit int) */
+ case 7:
+ {
+ LONGLONG Temp;
+
+ if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) || (FPU_GET_TAG(0) ==
FPU_TAG_SPECIAL))
+ {
+ /* Fail */
+ State->FpuStatus.Ie = TRUE;
+ return;
+ }
+
+ if (!Fast486FpuToInteger(State, &FPU_ST(0), &Temp))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ if (!Fast486WriteMemory(State,
+ (State->PrefixFlags & FAST486_PREFIX_SEG)
+ ? State->SegmentOverride : FAST486_REG_DS,
+ ModRegRm.MemoryAddress,
+ &Temp,
+ sizeof(LONGLONG)))
+ {
+ /* Exception occurred */
+ return;
+ }
+
+ /* Pop the FPU stack too */
+ Fast486FpuPop(State);
+
+ break;
+ }
+
+ /* Invalid */
+ default:
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ }
+ }
+ }
+ else
+ {
+ switch (ModRegRm.Register)
+ {
+ /* FFREEP */
+ case 0:
+ {
+ FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_EMPTY);
+ Fast486FpuPop(State);
+
+ break;
+ }
+
+ /* FXCH */
+ case 1:
+ {
+ FAST486_FPU_DATA_REG Temp;
+
+ if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY)
+ || FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)
+ {
+ State->FpuStatus.Ie = TRUE;
+ break;
+ }
+
+ /* Exchange */
+ Temp = FPU_ST(0);
+ FPU_ST(0) = FPU_ST(ModRegRm.SecondRegister);
+ FPU_ST(ModRegRm.SecondRegister) = Temp;
+
+ FPU_UPDATE_TAG(0);
+ FPU_UPDATE_TAG(ModRegRm.SecondRegister);
+
+ break;
+ }
+
+ /* FSTP */
+ case 2:
+ case 3:
+ {
+ FPU_ST(ModRegRm.SecondRegister) = FPU_ST(0);
+ FPU_UPDATE_TAG(ModRegRm.SecondRegister);
+ Fast486FpuPop(State);
+
+ break;
+ }
+
+ /* FSTSW */
+ case 4:
+ {
+ if (ModRegRm.SecondRegister != 0)
+ {
+ /* Invalid */
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ return;
+ }
+
+ /* Store the status word in AX */
+ State->GeneralRegs[FAST486_REG_EAX].LowWord =
State->FpuStatus.Value;
+
+ break;
+ }
+
+ /* Invalid */
+ default:
+ {
+ Fast486Exception(State, FAST486_EXCEPTION_UD);
+ return;
+ }
+ }
+ }
+
#endif
}
Modified: trunk/reactos/lib/fast486/fpu.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.h?rev=6594…
==============================================================================
--- trunk/reactos/lib/fast486/fpu.h [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/fpu.h [iso-8859-1] Fri Jan 2 18:29:30 2015
@@ -78,10 +78,11 @@
FPU_ROUND_TRUNCATE = 3
};
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8DC);
+FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8);
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9);
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA);
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB);
+FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC);
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD);
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE);
FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF);
Modified: trunk/reactos/lib/fast486/opcodes.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opcodes.c?rev=…
==============================================================================
--- trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] (original)
+++ trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] Fri Jan 2 18:29:30 2015
@@ -254,11 +254,11 @@
Fast486OpcodeAad, /* 0xD5 */
Fast486OpcodeSalc, /* 0xD6 */
Fast486OpcodeXlat, /* 0xD7 */
- Fast486FpuOpcodeD8DC, /* 0xD8 - 0xDF */
+ Fast486FpuOpcodeD8, /* 0xD8 - 0xDF */
Fast486FpuOpcodeD9,
Fast486FpuOpcodeDA,
Fast486FpuOpcodeDB,
- Fast486FpuOpcodeD8DC,
+ Fast486FpuOpcodeDC,
Fast486FpuOpcodeDD,
Fast486FpuOpcodeDE,
Fast486FpuOpcodeDF,