* 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
*/
#include "common.h"
+#include "fpu.h"
/* PUBLIC FUNCTIONS ***********************************************************/
+#if defined (__GNUC__)
+ #define CountLeadingZeros64(x) __builtin_clzll(x)
+#elif (_MSC_VER >= 1500) && defined(_WIN64)
+ #define CountLeadingZeros64(x) __lzcnt64(x)
+#elif (_MSC_VER >= 1500)
+ #define CountLeadingZeros64(x) ((x) > 0xFFFFFFFFULL) ? __lzcnt((x) >> 32) \
+ : (__lzcnt(x) + 32)
+#else
+ static FORCEINLINE
+ ULONG CountLeadingZeros64(ULONGLONG Value)
+ {
+ ULONG Count = 0;
+ ULONGLONG Mask = 1ULL << 63;
+
+ while (!(Value & Mask))
+ {
+ Count++;
+ Mask >>= 1;
+ }
+
+ return Count;
+ }
+#endif
+
FORCEINLINE
INT
Fast486GetCurrentPrivLevel(PFAST486_STATE State)
return TRUE;
}
-FORCEINLINE
-BOOLEAN
-Fast486GetIntVector(PFAST486_STATE State,
- UCHAR Number,
- PFAST486_IDT_ENTRY IdtEntry)
-{
- ULONG FarPointer;
-
- /* Check for protected mode */
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
- {
- /* Read from the IDT */
- if (!Fast486ReadLinearMemory(State,
- State->Idtr.Address
- + Number * sizeof(*IdtEntry),
- IdtEntry,
- sizeof(*IdtEntry)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- else
- {
- /* Read from the real-mode IVT */
-
- /* Paging is always disabled in real mode */
- State->MemReadCallback(State,
- State->Idtr.Address
- + Number * sizeof(FarPointer),
- &FarPointer,
- sizeof(FarPointer));
-
- /* Fill a fake IDT entry */
- IdtEntry->Offset = LOWORD(FarPointer);
- IdtEntry->Selector = HIWORD(FarPointer);
- IdtEntry->Zero = 0;
- IdtEntry->Type = FAST486_IDT_INT_GATE;
- IdtEntry->Storage = FALSE;
- IdtEntry->Dpl = 0;
- IdtEntry->Present = TRUE;
- IdtEntry->OffsetHigh = 0;
- }
-
- return TRUE;
-}
-
FORCEINLINE
BOOLEAN
Fast486CalculateParity(UCHAR Number)
return TRUE;
}
+#ifndef FAST486_NO_FPU
+
+FORCEINLINE
+VOID
+Fast486FpuNormalize(PFAST486_STATE State, PFAST486_FPU_DATA_REG Data)
+{
+ UINT LeadingZeros;
+
+ if (FPU_IS_NORMALIZED(Data)) return;
+ if (FPU_IS_ZERO(Data))
+ {
+ Data->Exponent = 0;
+ return;
+ }
+
+ LeadingZeros = CountLeadingZeros64(Data->Mantissa);
+
+ 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 */