Author: aandrejevic Date: Fri Oct 10 23:07:14 2014 New Revision: 64656
URL: http://svn.reactos.org/svn/reactos?rev=64656&view=rev Log: [FAST486] Update the copyright year. Implement the first batch of FPU instructions. These are still experimental.
Modified: trunk/reactos/include/reactos/libs/fast486/fast486.h trunk/reactos/lib/fast486/common.c trunk/reactos/lib/fast486/common.h trunk/reactos/lib/fast486/common.inl trunk/reactos/lib/fast486/extraops.c trunk/reactos/lib/fast486/extraops.h trunk/reactos/lib/fast486/fast486.c trunk/reactos/lib/fast486/fpu.c trunk/reactos/lib/fast486/fpu.h trunk/reactos/lib/fast486/opcodes.c trunk/reactos/lib/fast486/opcodes.h trunk/reactos/lib/fast486/opgroups.c trunk/reactos/lib/fast486/opgroups.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] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * fast486.h * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -90,6 +90,8 @@ #define FAST486_PREFIX_LOCK (1 << 3) #define FAST486_PREFIX_REPNZ (1 << 4) #define FAST486_PREFIX_REP (1 << 5) + +#define FAST486_FPU_DEFAULT_CONTROL 0x037F
struct _FAST486_STATE; typedef struct _FAST486_STATE FAST486_STATE, *PFAST486_STATE; @@ -420,6 +422,7 @@ { ULONGLONG Mantissa; USHORT Exponent; + UCHAR Sign; } FAST486_FPU_DATA_REG, *PFAST486_FPU_DATA_REG;
typedef union _FAST486_FPU_STATUS_REG @@ -490,10 +493,12 @@ FAST486_INT_STATUS IntStatus; UCHAR PendingIntNum; PULONG Tlb; +#ifndef FAST486_NO_FPU FAST486_FPU_DATA_REG FpuRegisters[FAST486_NUM_FPU_REGS]; FAST486_FPU_STATUS_REG FpuStatus; FAST486_FPU_CONTROL_REG FpuControl; USHORT FpuTag; +#endif };
/* FUNCTIONS ******************************************************************/
Modified: trunk/reactos/lib/fast486/common.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.c?rev=64... ============================================================================== --- trunk/reactos/lib/fast486/common.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/common.c [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * common.c * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License
Modified: trunk/reactos/lib/fast486/common.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.h?rev=64... ============================================================================== --- trunk/reactos/lib/fast486/common.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/common.h [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * common.h * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License
Modified: trunk/reactos/lib/fast486/common.inl URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/common.inl?rev=... ============================================================================== --- trunk/reactos/lib/fast486/common.inl [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/common.inl [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * common.inl * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ */
#include "common.h" +#include "fpu.h"
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -1330,4 +1331,76 @@ return TRUE; }
+#ifndef FAST486_NO_FPU + +FORCEINLINE +VOID +Fast486FpuNormalize(PFAST486_STATE State, PFAST486_FPU_DATA_REG Data) +{ + UINT LeadingZeros = 0; + + if (FPU_IS_NORMALIZED(Data)) return; + if (FPU_IS_ZERO(Data)) + { + Data->Exponent = 0; + return; + } + + /* Count the leading zeros */ + while (!(Data->Mantissa & (1 << (63 - LeadingZeros)))) LeadingZeros++; + + if (LeadingZeros < Data->Exponent) + { + Data->Mantissa <<= LeadingZeros; + Data->Exponent -= LeadingZeros; + } + else + { + /* Make it denormalized */ + Data->Mantissa <<= Data->Exponent - 1; + Data->Exponent = 1; + + /* Underflow */ + State->FpuStatus.Ue = TRUE; + } +} + +FORCEINLINE +USHORT +Fast486GetValueTag(PFAST486_FPU_DATA_REG Data) +{ + if (FPU_IS_ZERO(Data)) return FPU_TAG_ZERO; + else if (FPU_IS_NAN(Data)) return FPU_TAG_SPECIAL; + else return FPU_TAG_VALID; +} + +FORCEINLINE +VOID +Fast486FpuPush(PFAST486_STATE State, + PFAST486_FPU_DATA_REG Data) +{ + State->FpuStatus.Top--; + + if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) + { + FPU_ST(0) = *Data; + FPU_SET_TAG(0, Fast486GetValueTag(Data)); + } + else State->FpuStatus.Ie = TRUE; +} + +FORCEINLINE +VOID +Fast486FpuPop(PFAST486_STATE State) +{ + if (FPU_GET_TAG(0) != FPU_TAG_EMPTY) + { + FPU_SET_TAG(0, FPU_TAG_EMPTY); + State->FpuStatus.Top++; + } + else State->FpuStatus.Ie = TRUE; +} + +#endif + /* EOF */
Modified: trunk/reactos/lib/fast486/extraops.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/extraops.c?rev=... ============================================================================== --- trunk/reactos/lib/fast486/extraops.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/extraops.c [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * extraops.c * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License
Modified: trunk/reactos/lib/fast486/extraops.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/extraops.h?rev=... ============================================================================== --- trunk/reactos/lib/fast486/extraops.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/extraops.h [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * extraops.h * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License
Modified: trunk/reactos/lib/fast486/fast486.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fast486.c?rev=6... ============================================================================== --- trunk/reactos/lib/fast486/fast486.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fast486.c [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * fast486.c * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -282,6 +282,11 @@ #ifndef FAST486_NO_FPU /* Initialize CR0 */ State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET; + + /* Initialize the FPU control and tag registers */ + State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL; + State->FpuStatus.Value = 0; + State->FpuTag = 0xFFFF; #endif
/* Restore the callbacks and TLB */
Modified: trunk/reactos/lib/fast486/fpu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.c?rev=64656... ============================================================================== --- trunk/reactos/lib/fast486/fpu.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fpu.c [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * fpu.c * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,12 +28,416 @@
#include <fast486.h> #include "common.h" -#include "opcodes.h" #include "fpu.h"
+/* PRIVATE FUNCTIONS **********************************************************/ + +static ULONGLONG UnsignedMult128(ULONGLONG Multiplicand, + ULONGLONG Multiplier, + ULONGLONG *HighProduct) +{ + ULONG MultiplicandLow, MultiplicandHigh, MultiplierLow, MultiplierHigh; + ULONG IntermediateLow, IntermediateHigh; + ULONGLONG LowProduct, Intermediate, Intermediate1, Intermediate2; + + MultiplicandLow = (ULONG)(Multiplicand & 0xFFFFFFFFULL); + MultiplicandHigh = (ULONG)(Multiplicand >> 32); + MultiplierLow = (ULONG)(Multiplier & 0xFFFFFFFFULL); + MultiplierHigh = (ULONG)(Multiplier >> 32); + + LowProduct = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierLow; + Intermediate1 = (ULONGLONG)MultiplicandLow * (ULONGLONG)MultiplierHigh; + Intermediate2 = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierLow; + *HighProduct = (ULONGLONG)MultiplicandHigh * (ULONGLONG)MultiplierHigh; + + Intermediate = Intermediate1 + Intermediate2; + if (Intermediate < Intermediate1) *HighProduct += 1ULL << 32; + + IntermediateLow = (ULONG)(Intermediate & 0xFFFFFFFFULL); + IntermediateHigh = (ULONG)(Intermediate >> 32); + + LowProduct += (ULONGLONG)IntermediateLow << 32; + if ((ULONG)(LowProduct >> 32) < IntermediateLow) (*HighProduct)++; + + *HighProduct += IntermediateHigh; + return LowProduct; +} + +static VOID Fast486FpuGetSingleReal(PFAST486_STATE State, + ULONG Value, + PFAST486_FPU_DATA_REG Result) +{ + /* Extract the sign, exponent and mantissa */ + Result->Sign = (UCHAR)(Value >> 31); + Result->Exponent = (USHORT)((Value >> 23) & 0xFF); + Result->Mantissa = (((ULONGLONG)Value & 0x7FFFFFULL) | 0x800000ULL) << 40; + + /* If this is a zero, we're done */ + if (Value == 0) return; + + if (Result->Exponent == 0xFF) Result->Exponent = FPU_MAX_EXPONENT + 1; + else + { + /* Adjust the exponent bias */ + Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL4_BIAS); + } +} + +static VOID Fast486FpuGetDoubleReal(PFAST486_STATE State, + ULONGLONG Value, + PFAST486_FPU_DATA_REG Result) +{ + /* Extract the sign, exponent and mantissa */ + Result->Sign = (UCHAR)(Value >> 63); + Result->Exponent = (USHORT)((Value >> 52) & 0x7FF); + Result->Mantissa = (((ULONGLONG)Value & 0xFFFFFFFFFFFFFULL) | 0x10000000000000ULL) << 11; + + /* If this is a zero, we're done */ + if (Value == 0) return; + + if (Result->Exponent == 0x3FF) Result->Exponent = FPU_MAX_EXPONENT + 1; + else + { + /* Adjust the exponent bias */ + Result->Exponent += (FPU_REAL10_BIAS - FPU_REAL8_BIAS); + } +} + +static VOID Fast486FpuAdd(PFAST486_STATE State, + PFAST486_FPU_DATA_REG FirstOperand, + PFAST486_FPU_DATA_REG SecondOperand, + PFAST486_FPU_DATA_REG Result) +{ + FAST486_FPU_DATA_REG FirstAdjusted = *FirstOperand; + FAST486_FPU_DATA_REG SecondAdjusted = *SecondOperand; + FAST486_FPU_DATA_REG TempResult; + + if (!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)) + { + /* Denormalized */ + State->FpuStatus.De = TRUE; + } + + /* Find the largest exponent */ + TempResult.Exponent = max(FirstOperand->Exponent, SecondOperand->Exponent); + + /* Adjust the first operand to it */ + if (FirstAdjusted.Exponent < TempResult.Exponent) + { + FirstAdjusted.Mantissa >>= (TempResult.Exponent - FirstAdjusted.Exponent); + FirstAdjusted.Exponent = TempResult.Exponent; + } + + /* ... and the second one too */ + if (SecondAdjusted.Exponent < TempResult.Exponent) + { + SecondAdjusted.Mantissa >>= (TempResult.Exponent - SecondAdjusted.Exponent); + SecondAdjusted.Exponent = TempResult.Exponent; + } + + if (FirstAdjusted.Sign == SecondAdjusted.Sign) + { + /* Calculate the mantissa and sign of the result */ + TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa; + TempResult.Sign = FirstAdjusted.Sign; + } + else + { + /* Calculate the sign of the result */ + if (FirstAdjusted.Mantissa > SecondAdjusted.Mantissa) TempResult.Sign = FirstAdjusted.Sign; + else if (FirstAdjusted.Mantissa < SecondAdjusted.Mantissa) TempResult.Sign = SecondAdjusted.Sign; + else TempResult.Sign = FALSE; + + /* Invert the negative mantissa */ + if (FirstAdjusted.Sign) FirstAdjusted.Mantissa = -FirstAdjusted.Mantissa; + if (SecondAdjusted.Sign) SecondAdjusted.Mantissa = -SecondAdjusted.Mantissa; + + /* Calculate the mantissa of the result */ + TempResult.Mantissa = FirstAdjusted.Mantissa + SecondAdjusted.Mantissa; + } + + /* Did it overflow? */ + if (FPU_IS_NORMALIZED(&FirstAdjusted) && FPU_IS_NORMALIZED(&SecondAdjusted)) + { + if (TempResult.Exponent == FPU_MAX_EXPONENT) + { + /* Total overflow, return infinity */ + TempResult.Mantissa = FPU_MANTISSA_HIGH_BIT; + TempResult.Exponent = FPU_MAX_EXPONENT + 1; + + /* Update flags */ + State->FpuStatus.Oe = TRUE; + } + else + { + /* Lose the LSB in favor of the carry */ + TempResult.Mantissa >>= 1; + TempResult.Mantissa |= FPU_MANTISSA_HIGH_BIT; + TempResult.Exponent++; + } + } + + /* Normalize the result and return it */ + Fast486FpuNormalize(State, &TempResult); + *Result = TempResult; +} + +static VOID Fast486FpuSubtract(PFAST486_STATE State, + PFAST486_FPU_DATA_REG FirstOperand, + PFAST486_FPU_DATA_REG SecondOperand, + PFAST486_FPU_DATA_REG Result) +{ + FAST486_FPU_DATA_REG NegativeSecondOperand = *SecondOperand; + + /* Invert the sign */ + NegativeSecondOperand.Sign = !NegativeSecondOperand.Sign; + + /* And perform an addition instead */ + Fast486FpuAdd(State, Result, FirstOperand, &NegativeSecondOperand); +} + +static VOID Fast486FpuCompare(PFAST486_STATE State, + PFAST486_FPU_DATA_REG FirstOperand, + PFAST486_FPU_DATA_REG SecondOperand) +{ + if (FPU_IS_NAN(FirstOperand) || FPU_IS_NAN(SecondOperand)) + { + if (FPU_IS_POS_INF(FirstOperand) && FPU_IS_NEG_INF(SecondOperand)) + { + State->FpuStatus.Code0 = FALSE; + State->FpuStatus.Code2 = FALSE; + State->FpuStatus.Code3 = FALSE; + } + else if (FPU_IS_NEG_INF(FirstOperand) && FPU_IS_POS_INF(SecondOperand)) + { + State->FpuStatus.Code0 = TRUE; + State->FpuStatus.Code2 = FALSE; + State->FpuStatus.Code3 = FALSE; + } + else + { + State->FpuStatus.Code0 = TRUE; + State->FpuStatus.Code2 = TRUE; + State->FpuStatus.Code3 = TRUE; + } + } + else + { + FAST486_FPU_DATA_REG TempResult; + + Fast486FpuSubtract(State, FirstOperand, SecondOperand, &TempResult); + + if (FPU_IS_ZERO(&TempResult)) + { + State->FpuStatus.Code0 = FALSE; + State->FpuStatus.Code2 = FALSE; + State->FpuStatus.Code3 = TRUE; + } + else if (TempResult.Sign) + { + State->FpuStatus.Code0 = TRUE; + State->FpuStatus.Code2 = FALSE; + State->FpuStatus.Code3 = FALSE; + } + else + { + State->FpuStatus.Code0 = FALSE; + State->FpuStatus.Code2 = FALSE; + State->FpuStatus.Code3 = FALSE; + } + } +} + +static VOID Fast486FpuMultiply(PFAST486_STATE State, + PFAST486_FPU_DATA_REG FirstOperand, + PFAST486_FPU_DATA_REG SecondOperand, + PFAST486_FPU_DATA_REG Result) +{ + FAST486_FPU_DATA_REG TempResult; + + if (!FPU_IS_NORMALIZED(FirstOperand) || !FPU_IS_NORMALIZED(SecondOperand)) + { + /* Denormalized */ + State->FpuStatus.De = TRUE; + } + + UnsignedMult128(FirstOperand->Mantissa, + SecondOperand->Mantissa, + &TempResult.Mantissa); + + TempResult.Exponent = FirstOperand->Exponent + SecondOperand->Exponent; + TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign; + + /* Normalize the result */ + Fast486FpuNormalize(State, &TempResult); + *Result = TempResult; +} + +static VOID Fast486FpuDivide(PFAST486_STATE State, + PFAST486_FPU_DATA_REG FirstOperand, + PFAST486_FPU_DATA_REG SecondOperand, + PFAST486_FPU_DATA_REG Result) +{ + FAST486_FPU_DATA_REG TempResult; + + if (FPU_IS_ZERO(SecondOperand)) + { + /* Division by zero */ + State->FpuStatus.Ze = TRUE; + return; + } + + TempResult.Exponent = FirstOperand->Exponent - SecondOperand->Exponent; + TempResult.Sign = FirstOperand->Sign ^ SecondOperand->Sign; + + // TODO: NOT IMPLEMENTED + UNREFERENCED_PARAMETER(TempResult); + UNIMPLEMENTED; +} + /* PUBLIC FUNCTIONS ***********************************************************/
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8) +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8DC) +{ + 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 FALSE; + } + + FPU_CHECK(); + +#ifndef FAST486_NO_FPU + + 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 FALSE; + } + + Fast486FpuGetDoubleReal(State, Value, &MemoryData); + } + else + { + ULONG Value; + + if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value)) + { + /* Exception occurred */ + return FALSE; + } + + Fast486FpuGetSingleReal(State, Value, &MemoryData); + } + + SourceOperand = &MemoryData; + } + else + { + /* Load the source operand from an FPU register */ + SourceOperand = &FPU_ST(ModRegRm.SecondRegister); + + if (FPU_GET_TAG(ModRegRm.SecondRegister) == FPU_TAG_EMPTY) + { + /* Invalid operation */ + State->FpuStatus.Ie = TRUE; + return FALSE; + } + } + + /* The destination operand is always ST0 */ + DestOperand = &FPU_ST(0); + + if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) + { + /* Invalid operation */ + State->FpuStatus.Ie = TRUE; + return FALSE; + } + + /* Check the operation */ + switch (ModRegRm.Register) + { + /* FADD */ + case 0: + { + Fast486FpuAdd(State, DestOperand, SourceOperand, DestOperand); + break; + } + + /* FMUL */ + case 1: + { + Fast486FpuMultiply(State, DestOperand, SourceOperand, DestOperand); + break; + } + + /* FCOM */ + case 2: + /* FCOMP */ + case 3: + { + Fast486FpuCompare(State, DestOperand, SourceOperand); + if (ModRegRm.Register == 3) Fast486FpuPop(State); + + break; + } + + /* FSUB */ + case 4: + { + Fast486FpuSubtract(State, DestOperand, SourceOperand, DestOperand); + break; + } + + /* FSUBR */ + case 5: + { + Fast486FpuSubtract(State, SourceOperand, DestOperand, DestOperand); + break; + } + + /* FDIV */ + case 6: + { + Fast486FpuDivide(State, DestOperand, SourceOperand, DestOperand); + break; + } + + /* FDIVR */ + case 7: + { + Fast486FpuDivide(State, SourceOperand, DestOperand, DestOperand); + break; + } + } + +#endif + + return TRUE; +} + +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9) { FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; @@ -58,7 +462,7 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD9) +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA) { FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; @@ -83,7 +487,84 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDA) +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB) +{ + FAST486_MOD_REG_RM ModRegRm; + BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; + + /* Get the operands */ + if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + FPU_CHECK(); + +#ifndef FAST486_NO_FPU + + if (ModRegRm.Memory) + { + // TODO: NOT IMPLEMENTED + UNIMPLEMENTED; + } + else + { + /* Only a few of these instructions have any meaning on a 487 */ + switch ((ModRegRm.SecondRegister << 3) | ModRegRm.Register) + { + /* FCLEX */ + case 0x22: + { + /* Clear exception data */ + State->FpuStatus.Ie = + State->FpuStatus.De = + State->FpuStatus.Ze = + State->FpuStatus.Oe = + State->FpuStatus.Ue = + State->FpuStatus.Pe = + State->FpuStatus.Sf = + State->FpuStatus.Es = + State->FpuStatus.Busy = FALSE; + + break; + } + + /* FINIT */ + case 0x23: + { + /* Restore the state */ + State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL; + State->FpuStatus.Value = 0; + State->FpuTag = 0xFFFF; + + break; + } + + /* FENI */ + case 0x20: + /* FDISI */ + case 0x21: + { + /* These do nothing */ + break; + } + + /* Invalid */ + default: + { + Fast486Exception(State, FAST486_EXCEPTION_UD); + return FALSE; + } + } + } + +#endif + + return TRUE; +} + +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD) { FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; @@ -108,7 +589,7 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDB) +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE) { FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; @@ -133,7 +614,7 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDC) +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF) { FAST486_MOD_REG_RM ModRegRm; BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; @@ -158,79 +639,4 @@ #endif }
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDD) -{ - FAST486_MOD_REG_RM ModRegRm; - BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; - - /* Get the operands */ - if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) - { - /* Exception occurred */ - return FALSE; - } - - FPU_CHECK(); - -#ifndef FAST486_NO_FPU - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; - - return FALSE; -#else - /* Do nothing */ - return TRUE; -#endif -} - -FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDE) -{ - FAST486_MOD_REG_RM ModRegRm; - BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; - - /* Get the operands */ - if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) - { - /* Exception occurred */ - return FALSE; - } - - FPU_CHECK(); - -#ifndef FAST486_NO_FPU - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; - - return FALSE; -#else - /* Do nothing */ - return TRUE; -#endif -} - -FAST486_OPCODE_HANDLER(Fast486FpuOpcodeDF) -{ - FAST486_MOD_REG_RM ModRegRm; - BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size; - - /* Get the operands */ - if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm)) - { - /* Exception occurred */ - return FALSE; - } - - FPU_CHECK(); - -#ifndef FAST486_NO_FPU - // TODO: NOT IMPLEMENTED - UNIMPLEMENTED; - - return FALSE; -#else - /* Do nothing */ - return TRUE; -#endif -} - /* EOF */
Modified: trunk/reactos/lib/fast486/fpu.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/fpu.h?rev=64656... ============================================================================== --- trunk/reactos/lib/fast486/fpu.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/fpu.h [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * fpu.h * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,6 +24,8 @@
#pragma once
+#include "opcodes.h" + /* DEFINES ********************************************************************/
#define FPU_CHECK() if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_EM) \ @@ -32,6 +34,24 @@ return FALSE; \ } #define FPU_ST(i) State->FpuRegisters[(State->FpuStatus.Top + (i)) % FAST486_NUM_FPU_REGS] +#define FPU_GET_TAG(i) ((State->FpuTag >> ((i) * 2)) & 3) +#define FPU_SET_TAG(i, t) { \ + State->FpuTag &= ~((1 << ((i) * 2)) | (1 << (((i) * 2) + 1))); \ + State->FpuTag |= ((t) & 3) << ((i) * 2); \ + } + +#define FPU_REAL4_BIAS 0x7F +#define FPU_REAL8_BIAS 0x3FF +#define FPU_REAL10_BIAS 0x3FFF +#define FPU_MAX_EXPONENT 0x7FFE +#define FPU_MANTISSA_HIGH_BIT 0x8000000000000000ULL + +#define FPU_IS_NORMALIZED(x) (!FPU_IS_ZERO(x) && (((x)->Mantissa & FPU_MANTISSA_HIGH_BIT) != 0ULL)) +#define FPU_IS_ZERO(x) ((x)->Mantissa == 0ULL) +#define FPU_IS_NAN(x) ((x)->Exponent == (FPU_MAX_EXPONENT + 1)) +#define FPU_IS_INFINITY(x) (FPU_IS_NAN(x) && (x)->Mantissa & FPU_MANTISSA_HIGH_BIT) +#define FPU_IS_POS_INF(x) (FPU_IS_INFINITY(x) && !(x)->Sign) +#define FPU_IS_NEG_INF(x) (FPU_IS_INFINITY(x) && (x)->Sign)
enum { @@ -48,11 +68,10 @@ FPU_TAG_EMPTY = 3 };
-FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8); +FAST486_OPCODE_HANDLER(Fast486FpuOpcodeD8DC); 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=6... ============================================================================== --- trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/opcodes.c [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * opcodes.c * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -254,11 +254,11 @@ Fast486OpcodeAad, Fast486OpcodeSalc, Fast486OpcodeXlat, - Fast486FpuOpcodeD8, + Fast486FpuOpcodeD8DC, Fast486FpuOpcodeD9, Fast486FpuOpcodeDA, Fast486FpuOpcodeDB, - Fast486FpuOpcodeDC, + Fast486FpuOpcodeD8DC, Fast486FpuOpcodeDD, Fast486FpuOpcodeDE, Fast486FpuOpcodeDF,
Modified: trunk/reactos/lib/fast486/opcodes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opcodes.h?rev=6... ============================================================================== --- trunk/reactos/lib/fast486/opcodes.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/opcodes.h [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * opcodes.h * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License
Modified: trunk/reactos/lib/fast486/opgroups.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opgroups.c?rev=... ============================================================================== --- trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/opgroups.c [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * opgroups.c * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License
Modified: trunk/reactos/lib/fast486/opgroups.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/fast486/opgroups.h?rev=... ============================================================================== --- trunk/reactos/lib/fast486/opgroups.h [iso-8859-1] (original) +++ trunk/reactos/lib/fast486/opgroups.h [iso-8859-1] Fri Oct 10 23:07:14 2014 @@ -2,7 +2,7 @@ * Fast486 386/486 CPU Emulation Library * opgroups.h * - * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> + * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License