Author: aandrejevic Date: Sat Jan 31 21:34:56 2015 New Revision: 66131
URL: http://svn.reactos.org/svn/reactos?rev=66131&view=rev Log: [FAST486] Implement FSTENV and FSAVE. Keep track of the last FPU instruction and operand.
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h trunk/reactos/lib/fast486/fpu.c trunk/reactos/lib/fast486/fpu.h
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fast48... ============================================================================== --- trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] (original) +++ trunk/reactos/include/reactos/libs/fast486/fast486.h [iso-8859-1] Sat Jan 31 21:34:56 2015 @@ -508,6 +508,10 @@ FAST486_FPU_STATUS_REG FpuStatus; FAST486_FPU_CONTROL_REG FpuControl; USHORT FpuTag; + FAST486_REG FpuLastInstPtr; + USHORT FpuLastCodeSel; + FAST486_REG FpuLastOpPtr; + USHORT FpuLastDataSel; #endif };
Modified: trunk/reactos/lib/fast486/fpu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.c?rev=66131... ============================================================================== --- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Sat Jan 31 21:34:56 2015 @@ -919,6 +919,43 @@ } }
+static inline BOOLEAN FASTCALL +Fast486FpuSaveEnvironment(PFAST486_STATE State, + INT Segment, + ULONG Address, + BOOLEAN Size) +{ + UCHAR Buffer[28]; + + /* Check if this is a 32-bit save or a 16-bit save */ + if (Size) + { + PULONG Data = (PULONG)Buffer; + + Data[0] = (ULONG)State->FpuControl.Value; + Data[1] = (ULONG)State->FpuStatus.Value; + Data[2] = (ULONG)State->FpuTag; + Data[3] = State->FpuLastInstPtr.Long; + Data[4] = (ULONG)State->FpuLastCodeSel; + Data[5] = State->FpuLastOpPtr.Long; + Data[6] = (ULONG)State->FpuLastDataSel; + } + else + { + PUSHORT Data = (PUSHORT)Buffer; + + Data[0] = State->FpuControl.Value; + Data[1] = State->FpuStatus.Value; + Data[2] = State->FpuTag; + Data[3] = State->FpuLastInstPtr.LowWord; + Data[4] = State->FpuLastCodeSel; + Data[5] = State->FpuLastOpPtr.LowWord; + Data[6] = State->FpuLastDataSel; + } + + return Fast486WriteMemory(State, Segment, Address, Buffer, (Size + 1) * 14); +} + #endif
/* PUBLIC FUNCTIONS ***********************************************************/ @@ -930,6 +967,8 @@ PFAST486_FPU_DATA_REG SourceOperand, DestOperand; FAST486_FPU_DATA_REG MemoryData;
+ TOGGLE_ADSIZE(AddressSize); + /* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { @@ -940,6 +979,8 @@ FPU_CHECK();
#ifndef FAST486_NO_FPU + + FPU_SAVE_LAST_INST();
/* The destination operand is ST0 */ DestOperand = &FPU_ST(0); @@ -976,6 +1017,8 @@
Fast486FpuFromSingleReal(State, Value, &MemoryData); SourceOperand = &MemoryData; + + FPU_SAVE_LAST_OPERAND(); } else { @@ -1008,12 +1051,14 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC) +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9) { FAST486_MOD_REG_RM ModRegRm; - BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; - PFAST486_FPU_DATA_REG SourceOperand, DestOperand; - FAST486_FPU_DATA_REG MemoryData; + BOOLEAN OperandSize, AddressSize; + + OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; + TOGGLE_OPSIZE(OperandSize); + TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) @@ -1028,100 +1073,6 @@
if (ModRegRm.Memory) { - ULONGLONG Value; - - /* The destination operand is ST0 */ - DestOperand = &FPU_ST(0); - - if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) - { - /* Raise the invalid operation exception */ - State->FpuStatus.Ie = TRUE; - - if (State->FpuControl.Im) - { - /* Return the indefinite NaN */ - DestOperand->Sign = TRUE; - DestOperand->Exponent = FPU_MAX_EXPONENT + 1; - DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA; - - FPU_SET_TAG(0, FPU_TAG_SPECIAL); - } - else Fast486FpuException(State); - - return; - } - - /* Load the source operand from memory */ - 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; - } - else - { - /* The source operand is ST0 */ - SourceOperand = &FPU_ST(0); - - /* Load the destination operand from an FPU register */ - DestOperand = &FPU_ST(ModRegRm.SecondRegister); - - if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) - || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)) - { - /* Raise the invalid operation exception */ - State->FpuStatus.Ie = TRUE; - - if (State->FpuControl.Im) - { - /* Return the indefinite NaN */ - DestOperand->Sign = TRUE; - DestOperand->Exponent = FPU_MAX_EXPONENT + 1; - DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA; - - FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL); - } - else Fast486FpuException(State); - - return; - } - } - - /* Perform the requested operation */ - Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand); - -#endif -} - - -FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9) -{ - FAST486_MOD_REG_RM ModRegRm; - BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; - - /* Get the operands */ - if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) - { - /* Exception occurred */ - return; - } - - FPU_CHECK(); - -#ifndef FAST486_NO_FPU - - if (ModRegRm.Memory) - { switch (ModRegRm.Register) { /* FLD */ @@ -1129,6 +1080,9 @@ { ULONG Value; FAST486_FPU_DATA_REG MemoryData; + + FPU_SAVE_LAST_INST(); + FPU_SAVE_LAST_OPERAND();
if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) { @@ -1148,6 +1102,9 @@ case 3: { ULONG Value = FPU_REAL4_INDEFINITE; + + FPU_SAVE_LAST_INST(); + FPU_SAVE_LAST_OPERAND();
if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) { @@ -1195,9 +1152,11 @@ /* FSTENV */ case 6: { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; - + Fast486FpuSaveEnvironment(State, + (State->PrefixFlags & FAST486_PREFIX_SEG) + ? FAST486_REG_DS : State->SegmentOverride, + ModRegRm.MemoryAddress, + OperandSize); break; }
@@ -1233,6 +1192,8 @@ LONG Value; FAST486_FPU_DATA_REG MemoryData;
+ TOGGLE_ADSIZE(AddressSize); + /* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { @@ -1243,6 +1204,8 @@ FPU_CHECK();
#ifndef FAST486_NO_FPU + + FPU_SAVE_LAST_INST();
if (!ModRegRm.Memory) { @@ -1271,6 +1234,8 @@
return; } + + FPU_SAVE_LAST_OPERAND();
/* Load the source operand from memory */ if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, (PULONG)&Value)) @@ -1315,6 +1280,8 @@ FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+ TOGGLE_ADSIZE(AddressSize); + /* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { @@ -1328,6 +1295,9 @@
if (ModRegRm.Memory) { + FPU_SAVE_LAST_INST(); + FPU_SAVE_LAST_OPERAND(); + switch (ModRegRm.Register) { /* FILD */ @@ -1531,10 +1501,14 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD) +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; + + TOGGLE_ADSIZE(AddressSize);
/* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) @@ -1547,6 +1521,107 @@
#ifndef FAST486_NO_FPU
+ FPU_SAVE_LAST_INST(); + + if (ModRegRm.Memory) + { + ULONGLONG Value; + + /* The destination operand is ST0 */ + DestOperand = &FPU_ST(0); + + if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) + { + /* Raise the invalid operation exception */ + State->FpuStatus.Ie = TRUE; + + if (State->FpuControl.Im) + { + /* Return the indefinite NaN */ + DestOperand->Sign = TRUE; + DestOperand->Exponent = FPU_MAX_EXPONENT + 1; + DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA; + + FPU_SET_TAG(0, FPU_TAG_SPECIAL); + } + else Fast486FpuException(State); + + return; + } + + /* Load the source operand from memory */ + 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; + + FPU_SAVE_LAST_OPERAND(); + } + else + { + /* The source operand is ST0 */ + SourceOperand = &FPU_ST(0); + + /* Load the destination operand from an FPU register */ + DestOperand = &FPU_ST(ModRegRm.SecondRegister); + + if ((FPU_GET_TAG(0) == FPU_TAG_EMPTY) + || (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY)) + { + /* Raise the invalid operation exception */ + State->FpuStatus.Ie = TRUE; + + if (State->FpuControl.Im) + { + /* Return the indefinite NaN */ + DestOperand->Sign = TRUE; + DestOperand->Exponent = FPU_MAX_EXPONENT + 1; + DestOperand->Mantissa = FPU_INDEFINITE_MANTISSA; + + FPU_SET_TAG(ModRegRm.SecondRegister, FPU_TAG_SPECIAL); + } + else Fast486FpuException(State); + + return; + } + } + + /* Perform the requested operation */ + Fast486FpuArithmeticOperation(State, ModRegRm.Register, SourceOperand, DestOperand); + +#endif +} + +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD) +{ + FAST486_MOD_REG_RM ModRegRm; + BOOLEAN OperandSize, AddressSize; + + OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; + TOGGLE_OPSIZE(OperandSize); + TOGGLE_ADSIZE(AddressSize); + + /* Get the operands */ + if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return; + } + + FPU_CHECK(); + +#ifndef FAST486_NO_FPU + if (ModRegRm.Memory) { switch (ModRegRm.Register) @@ -1556,6 +1631,9 @@ { ULONGLONG Value; FAST486_FPU_DATA_REG MemoryData; + + FPU_SAVE_LAST_INST(); + FPU_SAVE_LAST_OPERAND();
if (!Fast486ReadMemory(State, (State->PrefixFlags & FAST486_PREFIX_SEG) @@ -1582,6 +1660,9 @@ { ULONGLONG Value = FPU_REAL8_INDEFINITE;
+ FPU_SAVE_LAST_INST(); + FPU_SAVE_LAST_OPERAND(); + if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) { /* Raise the invalid operation exception */ @@ -1626,8 +1707,40 @@ /* FSAVE */ case 6: { - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; + INT i; + UCHAR AllRegs[80]; + + FPU_SAVE_LAST_INST(); + + /* Save the environment */ + if (!Fast486FpuSaveEnvironment(State, + (State->PrefixFlags & FAST486_PREFIX_SEG) + ? FAST486_REG_DS : State->SegmentOverride, + ModRegRm.MemoryAddress, + OperandSize)) + { + /* Exception occurred */ + return; + } + + /* Save the registers */ + for (i = 0; i < FAST486_NUM_FPU_REGS; i++) + { + *((PULONGLONG)&AllRegs[i * 10]) = State->FpuRegisters[i].Mantissa; + *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) = State->FpuRegisters[i].Exponent; + + if (State->FpuRegisters[i].Sign) + { + *((PUSHORT)&AllRegs[(i * 10) + sizeof(ULONGLONG)]) |= 0x8000; + } + } + + Fast486WriteMemory(State, + (State->PrefixFlags & FAST486_PREFIX_SEG) + ? FAST486_REG_DS : State->SegmentOverride, + ModRegRm.MemoryAddress + (OperandSize + 1) * 14, + AllRegs, + sizeof(AllRegs));
break; } @@ -1635,6 +1748,9 @@ /* FSTSW */ case 7: { + FPU_SAVE_LAST_INST(); + FPU_SAVE_LAST_OPERAND(); + Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->FpuStatus.Value); break; } @@ -1648,6 +1764,8 @@ } else { + FPU_SAVE_LAST_INST(); + switch (ModRegRm.Register) { /* FFREE */ @@ -1731,6 +1849,8 @@ BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; PFAST486_FPU_DATA_REG SourceOperand, DestOperand;
+ TOGGLE_ADSIZE(AddressSize); + /* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { @@ -1741,6 +1861,8 @@ FPU_CHECK();
#ifndef FAST486_NO_FPU + + FPU_SAVE_LAST_INST();
if (ModRegRm.Memory) { @@ -1778,6 +1900,8 @@
Fast486FpuFromInteger(State, (LONGLONG)Value, &MemoryData); SourceOperand = &MemoryData; + + FPU_SAVE_LAST_OPERAND(); } else { @@ -1818,6 +1942,8 @@ FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+ TOGGLE_ADSIZE(AddressSize); + /* Get the operands */ if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) { @@ -1829,8 +1955,12 @@
#ifndef FAST486_NO_FPU
+ FPU_SAVE_LAST_INST(); + if (ModRegRm.Memory) { + FPU_SAVE_LAST_OPERAND(); + switch (ModRegRm.Register) { /* FILD */
Modified: trunk/reactos/lib/fast486/fpu.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.h?rev=66131... ============================================================================== --- trunk/reactos/lib/fast486/fpu.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fpu.h [iso-8859-1] Sat Jan 31 21:34:56 2015 @@ -42,6 +42,15 @@ State->FpuTag |= ((t) & 3) << (FPU_INDEX(i) * 2); \ } #define FPU_UPDATE_TAG(i) FPU_SET_TAG((i), Fast486FpuGetValueTag(&FPU_ST(i))) +#define FPU_SAVE_LAST_INST() { \ + State->FpuLastInstPtr = State->SavedInstPtr; \ + State->FpuLastCodeSel = State->SegmentRegs[FAST486_REG_CS].Selector; \ + } +#define FPU_SAVE_LAST_OPERAND() { \ + State->FpuLastOpPtr.Long = ModRegRm.MemoryAddress; \ + State->FpuLastDataSel = (State->PrefixFlags & FAST486_PREFIX_SEG) \ + ? State->SegmentOverride : FAST486_REG_DS; \ + }
#define FPU_REAL4_BIAS 0x7F #define FPU_REAL8_BIAS 0x3FF