+++ /dev/null
-/*
- * Fast486 386/486 CPU Emulation Library
- * common.inl
- *
- * Copyright (C) 2015 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
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#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
- FORCEINLINE
- ULONG
- CountLeadingZeros64(ULONGLONG Value)
- {
- ULONG Count = 0;
- Value = ~Value;
- while ((LONGLONG)Value < 0)
- {
- Count++;
- Value <<= 1;
- }
- return Count;
- }
-#endif
-
-FORCEINLINE
-UINT
-FASTCALL
-Fast486GetCurrentPrivLevel(PFAST486_STATE State)
-{
- /* Return the CPL, or 3 if we're in virtual 8086 mode */
- return (!State->Flags.Vm) ? State->Cpl : 3;
-}
-
-FORCEINLINE
-ULONG
-FASTCALL
-Fast486GetPageTableEntry(PFAST486_STATE State,
- ULONG VirtualAddress,
- BOOLEAN MarkAsDirty)
-{
- ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
- ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
- FAST486_PAGE_DIR DirectoryEntry;
- FAST486_PAGE_TABLE TableEntry;
- ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
-
- if ((State->Tlb != NULL)
- && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
- {
- /* Return the cached entry */
- return State->Tlb[VirtualAddress >> 12];
- }
-
- /* Read the directory entry */
- State->MemReadCallback(State,
- PageDirectory + PdeIndex * sizeof(ULONG),
- &DirectoryEntry.Value,
- sizeof(DirectoryEntry));
-
- /* Make sure it is present */
- if (!DirectoryEntry.Present) return 0;
-
- /* Was the directory entry accessed before? */
- if (!DirectoryEntry.Accessed)
- {
- /* Well, it is now */
- DirectoryEntry.Accessed = TRUE;
-
- /* Write back the directory entry */
- State->MemWriteCallback(State,
- PageDirectory + PdeIndex * sizeof(ULONG),
- &DirectoryEntry.Value,
- sizeof(DirectoryEntry));
- }
-
- /* Read the table entry */
- State->MemReadCallback(State,
- (DirectoryEntry.TableAddress << 12)
- + PteIndex * sizeof(ULONG),
- &TableEntry.Value,
- sizeof(TableEntry));
-
- /* Make sure it is present */
- if (!TableEntry.Present) return 0;
-
- /* Do we need to change any flags? */
- if (!TableEntry.Accessed || (MarkAsDirty && !TableEntry.Dirty))
- {
- /* Mark it as accessed and optionally dirty too */
- TableEntry.Accessed = TRUE;
- if (MarkAsDirty) TableEntry.Dirty = TRUE;
-
- /* Write back the table entry */
- State->MemWriteCallback(State,
- (DirectoryEntry.TableAddress << 12)
- + PteIndex * sizeof(ULONG),
- &TableEntry.Value,
- sizeof(TableEntry));
- }
-
- /*
- * The resulting permissions depend on the permissions
- * in the page directory table too
- */
- TableEntry.Writeable &= DirectoryEntry.Writeable;
- TableEntry.Usermode &= DirectoryEntry.Usermode;
-
- if (State->Tlb != NULL)
- {
- /* Set the TLB entry */
- State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
- State->TlbEmpty = FALSE;
- }
-
- /* Return the table entry */
- return TableEntry.Value;
-}
-
-FORCEINLINE
-VOID
-FASTCALL
-Fast486FlushTlb(PFAST486_STATE State)
-{
- if (!State->Tlb || State->TlbEmpty) return;
- RtlFillMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG), 0xFF);
- State->TlbEmpty = TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ReadLinearMemory(PFAST486_STATE State,
- ULONG LinearAddress,
- PVOID Buffer,
- ULONG Size,
- BOOLEAN CheckPrivilege)
-{
- /* Check if paging is enabled */
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
- {
- ULONG Page;
- FAST486_PAGE_TABLE TableEntry;
- INT Cpl = Fast486GetCurrentPrivLevel(State);
- ULONG BufferOffset = 0;
-
- for (Page = PAGE_ALIGN(LinearAddress);
- Page <= PAGE_ALIGN(LinearAddress + Size - 1);
- Page += FAST486_PAGE_SIZE)
- {
- ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
-
- /* Get the table entry */
- TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
-
- /* Check if this is the first page */
- if (Page == PAGE_ALIGN(LinearAddress))
- {
- /* Start reading from the offset from the beginning of the page */
- PageOffset = PAGE_OFFSET(LinearAddress);
- PageLength -= PageOffset;
- }
-
- if (CheckPrivilege && (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0))))
- {
- State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset;
-
- /* Exception */
- Fast486ExceptionWithErrorCode(State,
- FAST486_EXCEPTION_PF,
- TableEntry.Present | (State->Cpl ? 0x04 : 0));
- return FALSE;
- }
-
- /* Check if this is the last page */
- if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
- {
- /* Read only a part of the page */
- PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
- }
-
- /* Read the memory */
- State->MemReadCallback(State,
- (TableEntry.Address << 12) | PageOffset,
- (PVOID)((ULONG_PTR)Buffer + BufferOffset),
- PageLength);
-
- BufferOffset += PageLength;
- }
- }
- else
- {
- /* Read the memory */
- State->MemReadCallback(State, LinearAddress, Buffer, Size);
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486WriteLinearMemory(PFAST486_STATE State,
- ULONG LinearAddress,
- PVOID Buffer,
- ULONG Size,
- BOOLEAN CheckPrivilege)
-{
- /* Check if paging is enabled */
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
- {
- ULONG Page;
- FAST486_PAGE_TABLE TableEntry;
- INT Cpl = Fast486GetCurrentPrivLevel(State);
- ULONG BufferOffset = 0;
-
- for (Page = PAGE_ALIGN(LinearAddress);
- Page <= PAGE_ALIGN(LinearAddress + Size - 1);
- Page += FAST486_PAGE_SIZE)
- {
- ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
-
- /* Get the table entry */
- TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
-
- /* Check if this is the first page */
- if (Page == PAGE_ALIGN(LinearAddress))
- {
- /* Start writing from the offset from the beginning of the page */
- PageOffset = PAGE_OFFSET(LinearAddress);
- PageLength -= PageOffset;
- }
-
- if (CheckPrivilege
- && ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
- || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
- && !TableEntry.Writeable)))
- {
- State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset;
-
- /* Exception */
- Fast486ExceptionWithErrorCode(State,
- FAST486_EXCEPTION_PF,
- TableEntry.Present | 0x02 | (State->Cpl ? 0x04 : 0));
- return FALSE;
- }
-
- /* Check if this is the last page */
- if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
- {
- /* Write only a part of the page */
- PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
- }
-
- /* Write the memory */
- State->MemWriteCallback(State,
- (TableEntry.Address << 12) | PageOffset,
- (PVOID)((ULONG_PTR)Buffer + BufferOffset),
- PageLength);
-
- BufferOffset += PageLength;
- }
- }
- else
- {
- /* Write the memory */
- State->MemWriteCallback(State, LinearAddress, Buffer, Size);
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-VOID
-FASTCALL
-Fast486Exception(PFAST486_STATE State,
- FAST486_EXCEPTIONS ExceptionCode)
-{
- /* Call the internal function */
- Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486StackPushInternal(PFAST486_STATE State, BOOLEAN Size, ULONG Value)
-{
- ULONG StackPointer = State->GeneralRegs[FAST486_REG_ESP].Long;
-
- if (Size)
- {
- /* Check if ESP is between 1 and 3 */
- if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
- && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
- {
- Fast486Exception(State, FAST486_EXCEPTION_SS);
- return FALSE;
- }
-
- /* Store the value in SS:[ESP - 4] */
- if (!Fast486WriteMemory(State,
- FAST486_REG_SS,
- State->SegmentRegs[FAST486_REG_SS].Size
- ? StackPointer - sizeof(ULONG)
- : LOWORD(StackPointer - sizeof(ULONG)),
- &Value,
- sizeof(ULONG)))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- if (State->SegmentRegs[FAST486_REG_SS].Size)
- {
- /* Subtract ESP by 4 */
- State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
- }
- else
- {
- /* Subtract SP by 4 */
- State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(ULONG);
- }
- }
- else
- {
- /* Check if SP is 1 */
- if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
- {
- Fast486Exception(State, FAST486_EXCEPTION_SS);
- return FALSE;
- }
-
- /* Store the value in SS:[SP - 2] */
- if (!Fast486WriteMemory(State,
- FAST486_REG_SS,
- State->SegmentRegs[FAST486_REG_SS].Size
- ? StackPointer - sizeof(USHORT)
- : LOWORD(StackPointer - sizeof(USHORT)),
- &Value,
- sizeof(USHORT)))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- if (State->SegmentRegs[FAST486_REG_SS].Size)
- {
- /* Subtract ESP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(USHORT);
- }
- else
- {
- /* Subtract SP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486StackPush(PFAST486_STATE State, ULONG Value)
-{
- BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
-
- /* The OPSIZE prefix toggles the size */
- TOGGLE_OPSIZE(Size);
-
- /* Call the internal function */
- return Fast486StackPushInternal(State, Size, Value);
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486StackPop(PFAST486_STATE State,
- PULONG Value)
-{
- BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
-
- /* The OPSIZE prefix toggles the size */
- TOGGLE_OPSIZE(Size);
-
- if (Size)
- {
- /* 32-bit size */
- ULONG LongValue;
-
- /* Check if ESP is 0xFFFFFFFF */
- if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
- {
- Fast486Exception(State, FAST486_EXCEPTION_SS);
- return FALSE;
- }
-
- /* Read the value from SS:ESP */
- if (!Fast486ReadMemory(State,
- FAST486_REG_SS,
- State->SegmentRegs[FAST486_REG_SS].Size
- ? State->GeneralRegs[FAST486_REG_ESP].Long
- : State->GeneralRegs[FAST486_REG_ESP].LowWord,
- FALSE,
- &LongValue,
- sizeof(LongValue)))
- {
- /* An exception occurred */
- return FALSE;
- }
-
- if (State->SegmentRegs[FAST486_REG_SS].Size)
- {
- /* Increment ESP by 4 */
- State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
- }
- else
- {
- /* Increment SP by 4 */
- State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(ULONG);
- }
-
- /* Store the value in the result */
- *Value = LongValue;
- }
- else
- {
- /* 16-bit size */
- USHORT ShortValue;
-
- /* Check if SP is 0xFFFF */
- if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
- {
- Fast486Exception(State, FAST486_EXCEPTION_SS);
- return FALSE;
- }
-
- /* Read the value from SS:SP */
- if (!Fast486ReadMemory(State,
- FAST486_REG_SS,
- State->SegmentRegs[FAST486_REG_SS].Size
- ? State->GeneralRegs[FAST486_REG_ESP].Long
- : State->GeneralRegs[FAST486_REG_ESP].LowWord,
- FALSE,
- &ShortValue,
- sizeof(ShortValue)))
- {
- /* An exception occurred */
- return FALSE;
- }
-
- if (State->SegmentRegs[FAST486_REG_SS].Size)
- {
- /* Increment ESP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(USHORT);
- }
- else
- {
- /* Increment SP by 2 */
- State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
- }
-
- /* Store the value in the result */
- *Value = ShortValue;
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ReadDescriptorEntry(PFAST486_STATE State,
- USHORT Selector,
- PBOOLEAN EntryValid,
- PFAST486_GDT_ENTRY Entry)
-{
- if (!(Selector & SEGMENT_TABLE_INDICATOR))
- {
- /* Make sure the GDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
- {
- *EntryValid = FALSE;
- return TRUE;
- }
-
- /* Read the GDT */
- if (!Fast486ReadLinearMemory(State,
- State->Gdtr.Address
- + GET_SEGMENT_INDEX(Selector),
- Entry,
- sizeof(*Entry),
- FALSE))
- {
- /* Exception occurred */
- *EntryValid = FALSE;
- return FALSE;
- }
- }
- else
- {
- /* Make sure the LDT contains the entry */
- if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1u))
- {
- *EntryValid = FALSE;
- return TRUE;
- }
-
- /* Read the LDT */
- if (!Fast486ReadLinearMemory(State,
- State->Ldtr.Base
- + GET_SEGMENT_INDEX(Selector),
- Entry,
- sizeof(*Entry),
- FALSE))
- {
- /* Exception occurred */
- *EntryValid = FALSE;
- return FALSE;
- }
- }
-
- *EntryValid = TRUE;
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486LoadSegmentInternal(PFAST486_STATE State,
- FAST486_SEG_REGS Segment,
- USHORT Selector,
- FAST486_EXCEPTIONS Exception)
-{
- PFAST486_SEG_REG CachedDescriptor;
- BOOLEAN Valid;
- FAST486_GDT_ENTRY GdtEntry;
-
- ASSERT(Segment < FAST486_NUM_SEG_REGS);
-
- /* Get the cached descriptor */
- CachedDescriptor = &State->SegmentRegs[Segment];
-
- /* Check for protected mode */
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
- {
- /* Check for VM86 mode */
- if (State->Flags.Vm)
- {
- /* Update the cached descriptor with VM86 values */
- CachedDescriptor->Selector = Selector;
- CachedDescriptor->Base = Selector << 4;
- CachedDescriptor->Limit = 0xFFFF;
- CachedDescriptor->ReadWrite = TRUE;
- CachedDescriptor->DirConf = FALSE;
- CachedDescriptor->SystemType = TRUE;
- CachedDescriptor->Dpl = CachedDescriptor->Rpl = 3;
- CachedDescriptor->Present = TRUE;
- CachedDescriptor->Size = FALSE;
- return TRUE;
- }
-
- if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- if (!Valid)
- {
- /* Invalid selector */
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if (Segment == FAST486_REG_SS)
- {
- /* Loading the stack segment */
-
- if (!(Selector & SEGMENT_TABLE_INDICATOR) && GET_SEGMENT_INDEX(Selector) == 0)
- {
- Fast486Exception(State, Exception);
- return FALSE;
- }
-
- if (!GdtEntry.SystemType)
- {
- /* This is a special descriptor */
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if (GdtEntry.Executable || !GdtEntry.ReadWrite)
- {
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
- || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
- {
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if (!GdtEntry.Present)
- {
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
- return FALSE;
- }
- }
- else if (Segment == FAST486_REG_CS)
- {
- /* Loading the code segment */
-
-#ifndef FAST486_NO_PREFETCH
- /* Invalidate the prefetch */
- State->PrefetchValid = FALSE;
-#endif
-
- if (!(Selector & SEGMENT_TABLE_INDICATOR) && GET_SEGMENT_INDEX(Selector) == 0)
- {
- Fast486Exception(State, Exception);
- return FALSE;
- }
-
- if (!GdtEntry.SystemType)
- {
- /* Must be a segment descriptor */
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if (!GdtEntry.Present)
- {
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
- return FALSE;
- }
-
- if (!GdtEntry.Executable)
- {
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if (GdtEntry.DirConf)
- {
- /* Conforming Code Segment */
-
- if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
- {
- /* Must be accessed from lower-privileged code */
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
- }
- else
- {
- /* Regular code segment */
-
- if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State)))
- {
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
- }
- }
- else
- {
- /* Loading a data segment */
-
- if (GET_SEGMENT_INDEX(Selector) != 0 || (Selector & SEGMENT_TABLE_INDICATOR))
- {
- if (!GdtEntry.SystemType)
- {
- /* This is a special descriptor */
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
- || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
- {
- Fast486ExceptionWithErrorCode(State, Exception, Selector);
- return FALSE;
- }
-
- if (!GdtEntry.Present)
- {
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
- return FALSE;
- }
- }
- else
- {
- /* This is a NULL selector */
- RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
- }
- }
-
- /* Update the cache entry */
- CachedDescriptor->Selector = Selector;
- CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
- CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
- CachedDescriptor->Accessed = GdtEntry.Accessed;
- CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
- CachedDescriptor->DirConf = GdtEntry.DirConf;
- CachedDescriptor->Executable = GdtEntry.Executable;
- CachedDescriptor->SystemType = GdtEntry.SystemType;
- CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
- CachedDescriptor->Dpl = GdtEntry.Dpl;
- CachedDescriptor->Present = GdtEntry.Present;
- CachedDescriptor->Size = GdtEntry.Size;
-
- /* Check for page granularity */
- if (GdtEntry.Granularity)
- {
- CachedDescriptor->Limit <<= 12;
- CachedDescriptor->Limit |= 0x00000FFF;
- }
- }
- else
- {
- /* Update the selector and base */
- CachedDescriptor->Selector = Selector;
- CachedDescriptor->Base = Selector << 4;
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486LoadSegment(PFAST486_STATE State,
- FAST486_SEG_REGS Segment,
- USHORT Selector)
-{
- return Fast486LoadSegmentInternal(State,
- Segment,
- Selector,
- FAST486_EXCEPTION_GP);
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call)
-{
- BOOLEAN Valid;
- FAST486_SYSTEM_DESCRIPTOR Descriptor;
-
- if (!Fast486ReadDescriptorEntry(State,
- Selector,
- &Valid,
- (PFAST486_GDT_ENTRY)&Descriptor))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- if (!Valid)
- {
- /* Invalid selector */
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
- }
-
- switch (Descriptor.Signature)
- {
- case FAST486_TASK_GATE_SIGNATURE:
- {
- Fast486TaskSwitch(State,
- Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
- ((PFAST486_IDT_ENTRY)&Descriptor)->Selector);
-
- return FALSE;
- }
-
- case FAST486_TSS_16_SIGNATURE:
- case FAST486_BUSY_TSS_16_SIGNATURE:
- case FAST486_TSS_SIGNATURE:
- case FAST486_BUSY_TSS_SIGNATURE:
- {
- Fast486TaskSwitch(State,
- Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
- Selector);
-
- return FALSE;
- }
-
- case FAST486_CALL_GATE_16_SIGNATURE:
- case FAST486_CALL_GATE_SIGNATURE:
- {
- if ((Descriptor.Dpl < Fast486GetCurrentPrivLevel(State))
- && (Descriptor.Dpl < GET_SEGMENT_RPL(Selector)))
- {
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
- }
-
- if (!Descriptor.Present)
- {
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
- return FALSE;
- }
-
- Fast486CallGate(State, (PFAST486_CALL_GATE)&Descriptor, Call);
-
- /* The gate has been processed here, so return FALSE */
- return FALSE;
- }
-
- default:
- {
- /* Security check for jumps and calls only */
- if (State->Cpl != Descriptor.Dpl)
- {
- Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
- return FALSE;
- }
-
- return TRUE;
- }
- }
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486FetchByte(PFAST486_STATE State,
- PUCHAR Data)
-{
- PFAST486_SEG_REG CachedDescriptor;
- ULONG Offset;
-#ifndef FAST486_NO_PREFETCH
- ULONG LinearAddress;
-#endif
-
- /* Get the cached descriptor of CS */
- CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
-
- Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
- : State->InstPtr.LowWord;
-#ifndef FAST486_NO_PREFETCH
- LinearAddress = CachedDescriptor->Base + Offset;
-
- if (State->PrefetchValid
- && (LinearAddress >= State->PrefetchAddress)
- && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
- {
- *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
- }
- else
-#endif
- {
- /* Read from memory */
- if (!Fast486ReadMemory(State,
- FAST486_REG_CS,
- Offset,
- TRUE,
- Data,
- sizeof(UCHAR)))
- {
- /* Exception occurred during instruction fetch */
- return FALSE;
- }
- }
-
- /* Advance the instruction pointer */
- if (CachedDescriptor->Size) State->InstPtr.Long++;
- else State->InstPtr.LowWord++;
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486FetchWord(PFAST486_STATE State,
- PUSHORT Data)
-{
- PFAST486_SEG_REG CachedDescriptor;
- ULONG Offset;
-#ifndef FAST486_NO_PREFETCH
- ULONG LinearAddress;
-#endif
-
- /* Get the cached descriptor of CS */
- CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
-
- Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
- : State->InstPtr.LowWord;
-
-#ifndef FAST486_NO_PREFETCH
- LinearAddress = CachedDescriptor->Base + Offset;
-
- if (State->PrefetchValid
- && (LinearAddress >= State->PrefetchAddress)
- && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
- {
- *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
- }
- else
-#endif
- {
- /* Read from memory */
- // FIXME: Fix byte order on big-endian machines
- if (!Fast486ReadMemory(State,
- FAST486_REG_CS,
- Offset,
- TRUE,
- Data,
- sizeof(USHORT)))
- {
- /* Exception occurred during instruction fetch */
- return FALSE;
- }
- }
-
- /* Advance the instruction pointer */
- if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
- else State->InstPtr.LowWord += sizeof(USHORT);
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486FetchDword(PFAST486_STATE State,
- PULONG Data)
-{
- PFAST486_SEG_REG CachedDescriptor;
- ULONG Offset;
-#ifndef FAST486_NO_PREFETCH
- ULONG LinearAddress;
-#endif
-
- /* Get the cached descriptor of CS */
- CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
-
- Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
- : State->InstPtr.LowWord;
-
-#ifndef FAST486_NO_PREFETCH
- LinearAddress = CachedDescriptor->Base + Offset;
-
- if (State->PrefetchValid
- && (LinearAddress >= State->PrefetchAddress)
- && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
- {
- *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
- }
- else
-#endif
- {
- /* Read from memory */
- // FIXME: Fix byte order on big-endian machines
- if (!Fast486ReadMemory(State,
- FAST486_REG_CS,
- Offset,
- TRUE,
- Data,
- sizeof(ULONG)))
- {
- /* Exception occurred during instruction fetch */
- return FALSE;
- }
- }
-
- /* Advance the instruction pointer */
- if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
- else State->InstPtr.LowWord += sizeof(ULONG);
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486CalculateParity(UCHAR Number)
-{
- // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
- return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ParseModRegRm(PFAST486_STATE State,
- BOOLEAN AddressSize,
- PFAST486_MOD_REG_RM ModRegRm)
-{
- UCHAR ModRmByte, Mode, RegMem;
-
- /* Fetch the MOD REG R/M byte */
- if (!Fast486FetchByte(State, &ModRmByte))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Unpack the mode and R/M */
- Mode = ModRmByte >> 6;
- RegMem = ModRmByte & 0x07;
-
- /* Set the register operand */
- ModRegRm->Register = (ModRmByte >> 3) & 0x07;
-
- /* Check the mode */
- if (Mode == 3)
- {
- /* The second operand is also a register */
- ModRegRm->Memory = FALSE;
- ModRegRm->SecondRegister = RegMem;
-
- /* Done parsing */
- return TRUE;
- }
-
- /* The second operand is memory */
- ModRegRm->Memory = TRUE;
-
- if (AddressSize)
- {
- if (RegMem == FAST486_REG_ESP)
- {
- UCHAR SibByte;
- ULONG Scale, Index, Base;
-
- /* Fetch the SIB byte */
- if (!Fast486FetchByte(State, &SibByte))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Unpack the scale, index and base */
- Scale = 1 << (SibByte >> 6);
- Index = (SibByte >> 3) & 0x07;
- if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
- else Index = 0;
-
- if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
- {
- /* Use the register a base */
- Base = State->GeneralRegs[SibByte & 0x07].Long;
- }
- else
- {
- /* Fetch the base */
- if (!Fast486FetchDword(State, &Base))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
-
- if (((SibByte & 0x07) == FAST486_REG_ESP)
- || ((SibByte & 0x07) == FAST486_REG_EBP && Mode != 0))
- {
- /* Check if there is no segment override */
- if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
- {
- /* Add a SS: prefix */
- State->PrefixFlags |= FAST486_PREFIX_SEG;
- State->SegmentOverride = FAST486_REG_SS;
- }
- }
-
- /* Calculate the address */
- ModRegRm->MemoryAddress = Base + Index * Scale;
- }
- else if (RegMem == FAST486_REG_EBP)
- {
- if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
- else ModRegRm->MemoryAddress = 0;
- }
- else
- {
- /* Get the base from the register */
- ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
- }
-
- /* Check if there is no segment override */
- if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
- {
- /* Check if the default segment should be SS */
- if ((RegMem == FAST486_REG_EBP) && Mode)
- {
- /* Add a SS: prefix */
- State->PrefixFlags |= FAST486_PREFIX_SEG;
- State->SegmentOverride = FAST486_REG_SS;
- }
- }
-
- if (Mode == 1)
- {
- CHAR Offset;
-
- /* Fetch the byte */
- if (!Fast486FetchByte(State, (PUCHAR)&Offset))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Add the signed offset to the address */
- ModRegRm->MemoryAddress += (LONG)Offset;
- }
- else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
- {
- LONG Offset;
-
- /* Fetch the dword */
- if (!Fast486FetchDword(State, (PULONG)&Offset))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Add the signed offset to the address */
- ModRegRm->MemoryAddress += Offset;
- }
- }
- else
- {
- /* Check the operand */
- switch (RegMem)
- {
- case 0:
- {
- /* [BX + SI] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
- + State->GeneralRegs[FAST486_REG_ESI].LowWord;
- break;
- }
-
- case 1:
- {
- /* [BX + DI] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
- + State->GeneralRegs[FAST486_REG_EDI].LowWord;
- break;
- }
-
- case 2:
- {
- /* SS:[BP + SI] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
- + State->GeneralRegs[FAST486_REG_ESI].LowWord;
- break;
- }
-
- case 3:
- {
- /* SS:[BP + DI] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
- + State->GeneralRegs[FAST486_REG_EDI].LowWord;
- break;
- }
-
- case 4:
- {
- /* [SI] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
- break;
- }
-
- case 5:
- {
- /* [DI] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
- break;
- }
-
- case 6:
- {
- if (Mode)
- {
- /* [BP] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
- }
- else
- {
- /* [constant] (added later) */
- ModRegRm->MemoryAddress = 0;
- }
-
- break;
- }
-
- case 7:
- {
- /* [BX] */
- ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
- break;
- }
- }
-
- /* Check if there is no segment override */
- if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
- {
- /* Check if the default segment should be SS */
- if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
- {
- /* Add a SS: prefix */
- State->PrefixFlags |= FAST486_PREFIX_SEG;
- State->SegmentOverride = FAST486_REG_SS;
- }
- }
-
- if (Mode == 1)
- {
- CHAR Offset;
-
- /* Fetch the byte */
- if (!Fast486FetchByte(State, (PUCHAR)&Offset))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Add the signed offset to the address */
- ModRegRm->MemoryAddress += (LONG)Offset;
- }
- else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
- {
- SHORT Offset;
-
- /* Fetch the word */
- if (!Fast486FetchWord(State, (PUSHORT)&Offset))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- /* Add the signed offset to the address */
- ModRegRm->MemoryAddress += (LONG)Offset;
- }
-
- /* Clear the top 16 bits */
- ModRegRm->MemoryAddress &= 0x0000FFFF;
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ReadModrmByteOperands(PFAST486_STATE State,
- PFAST486_MOD_REG_RM ModRegRm,
- PUCHAR RegValue,
- PUCHAR RmValue)
-{
- FAST486_SEG_REGS Segment = FAST486_REG_DS;
-
- if (RegValue)
- {
- /* Get the register value */
- if (ModRegRm->Register & 0x04)
- {
- /* AH, CH, DH, BH */
- *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
- }
- else
- {
- /* AL, CL, DL, BL */
- *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
- }
- }
-
- if (RmValue)
- {
- if (!ModRegRm->Memory)
- {
- /* Get the second register value */
- if (ModRegRm->SecondRegister & 0x04)
- {
- /* AH, CH, DH, BH */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
- }
- else
- {
- /* AL, CL, DL, BL */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
- }
- }
- else
- {
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
- {
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
- }
-
- /* Read memory */
- if (!Fast486ReadMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- FALSE,
- RmValue,
- sizeof(UCHAR)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ReadModrmWordOperands(PFAST486_STATE State,
- PFAST486_MOD_REG_RM ModRegRm,
- PUSHORT RegValue,
- PUSHORT RmValue)
-{
- FAST486_SEG_REGS Segment = FAST486_REG_DS;
-
- if (RegValue)
- {
- /* Get the register value */
- *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
- }
-
- if (RmValue)
- {
- if (!ModRegRm->Memory)
- {
- /* Get the second register value */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
- }
- else
- {
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
- {
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
- }
-
- /* Read memory */
- if (!Fast486ReadMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- FALSE,
- RmValue,
- sizeof(USHORT)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486ReadModrmDwordOperands(PFAST486_STATE State,
- PFAST486_MOD_REG_RM ModRegRm,
- PULONG RegValue,
- PULONG RmValue)
-{
- FAST486_SEG_REGS Segment = FAST486_REG_DS;
-
- if (RegValue)
- {
- /* Get the register value */
- *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
- }
-
- if (RmValue)
- {
- if (!ModRegRm->Memory)
- {
- /* Get the second register value */
- *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
- }
- else
- {
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
- {
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
- }
-
- /* Read memory */
- if (!Fast486ReadMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- FALSE,
- RmValue,
- sizeof(ULONG)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486WriteModrmByteOperands(PFAST486_STATE State,
- PFAST486_MOD_REG_RM ModRegRm,
- BOOLEAN WriteRegister,
- UCHAR Value)
-{
- FAST486_SEG_REGS Segment = FAST486_REG_DS;
-
- if (WriteRegister)
- {
- /* Store the value in the register */
- if (ModRegRm->Register & 0x04)
- {
- /* AH, CH, DH, BH */
- State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
- }
- else
- {
- /* AL, CL, DL, BL */
- State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
- }
- }
- else
- {
- if (!ModRegRm->Memory)
- {
- /* Store the value in the second register */
- if (ModRegRm->SecondRegister & 0x04)
- {
- /* AH, CH, DH, BH */
- State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
- }
- else
- {
- /* AL, CL, DL, BL */
- State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
- }
- }
- else
- {
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
- {
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
- }
-
- /* Write memory */
- if (!Fast486WriteMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- &Value,
- sizeof(UCHAR)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486WriteModrmWordOperands(PFAST486_STATE State,
- PFAST486_MOD_REG_RM ModRegRm,
- BOOLEAN WriteRegister,
- USHORT Value)
-{
- FAST486_SEG_REGS Segment = FAST486_REG_DS;
-
- if (WriteRegister)
- {
- /* Store the value in the register */
- State->GeneralRegs[ModRegRm->Register].LowWord = Value;
- }
- else
- {
- if (!ModRegRm->Memory)
- {
- /* Store the value in the second register */
- State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
- }
- else
- {
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
- {
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
- }
-
- /* Write memory */
- if (!Fast486WriteMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- &Value,
- sizeof(USHORT)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486WriteModrmDwordOperands(PFAST486_STATE State,
- PFAST486_MOD_REG_RM ModRegRm,
- BOOLEAN WriteRegister,
- ULONG Value)
-{
- FAST486_SEG_REGS Segment = FAST486_REG_DS;
-
- if (WriteRegister)
- {
- /* Store the value in the register */
- State->GeneralRegs[ModRegRm->Register].Long = Value;
- }
- else
- {
- if (!ModRegRm->Memory)
- {
- /* Store the value in the second register */
- State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
- }
- else
- {
- /* Check for the segment override */
- if (State->PrefixFlags & FAST486_PREFIX_SEG)
- {
- /* Use the override segment instead */
- Segment = State->SegmentOverride;
- }
-
- /* Write memory */
- if (!Fast486WriteMemory(State,
- Segment,
- ModRegRm->MemoryAddress,
- &Value,
- sizeof(ULONG)))
- {
- /* Exception occurred */
- return FALSE;
- }
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486IoPrivilegeCheck(PFAST486_STATE State, USHORT Port)
-{
- UCHAR Bits;
- ULONG Location;
- FAST486_TSS Tss;
-
- /* Access is always allowed if the CPL is less than or equal to the IOPL */
- if (State->Cpl <= State->Flags.Iopl) return TRUE;
-
- /* Legacy Task State Segments have no IOPB */
- if (!State->TaskReg.Modern) return FALSE;
-
- /* Read the TSS */
- if (!Fast486ReadLinearMemory(State, State->TaskReg.Base, &Tss, sizeof(FAST486_TSS), FALSE))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- Location = State->TaskReg.Base + HIWORD(Tss.IopbOffset) + (Port >> 3);
-
- if (Location > State->TaskReg.Limit)
- {
- /* Access denied */
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
- }
-
- /* Read the appropriate bit from the TSS IOPB */
- if (!Fast486ReadLinearMemory(State, Location, &Bits, sizeof(UCHAR), FALSE))
- {
- /* Exception occurred */
- return FALSE;
- }
-
- if (Bits & (1 << (Port & 0x07)))
- {
- /* Access denied */
- Fast486Exception(State, FAST486_EXCEPTION_GP);
- return FALSE;
- }
-
- return TRUE;
-}
-
-#ifndef FAST486_NO_FPU
-
-FORCEINLINE
-VOID
-FASTCALL
-Fast486FpuExceptionCheck(PFAST486_STATE State)
-{
- /* Check if an unmasked exception occurred */
- if ((State->FpuStatus.Ie && !State->FpuControl.Im)
- || (State->FpuStatus.De && !State->FpuControl.Dm)
- || (State->FpuStatus.Ze && !State->FpuControl.Zm)
- || (State->FpuStatus.Oe && !State->FpuControl.Om)
- || (State->FpuStatus.Ue && !State->FpuControl.Um)
- || (State->FpuStatus.Pe && !State->FpuControl.Pm))
- {
- if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_NE)
- {
- /* Call the #MF handler */
- Fast486Exception(State, FAST486_EXCEPTION_MF);
- }
- else
- {
- /* Use the external interrupt */
- State->FpuCallback(State);
- }
- }
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486FpuNormalize(PFAST486_STATE State,
- PFAST486_FPU_DATA_REG Data)
-{
- UINT LeadingZeros;
-
- if (FPU_IS_ZERO(Data))
- {
- Data->Exponent = 0;
- return TRUE;
- }
-
- if (FPU_IS_NORMALIZED(Data)) return TRUE;
-
- LeadingZeros = CountLeadingZeros64(Data->Mantissa);
-
- if (LeadingZeros < Data->Exponent)
- {
- Data->Mantissa <<= LeadingZeros;
- Data->Exponent -= LeadingZeros;
- }
- else
- {
- /* Raise the underflow exception */
- State->FpuStatus.Ue = TRUE;
-
- if (State->FpuControl.Um)
- {
- /* Make it denormalized */
- Data->Mantissa <<= Data->Exponent - 1;
- Data->Exponent = 1;
- }
- else
- {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-FORCEINLINE
-USHORT
-FASTCALL
-Fast486FpuGetValueTag(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
-BOOLEAN
-FASTCALL
-Fast486FpuPush(PFAST486_STATE State,
- PCFAST486_FPU_DATA_REG Data)
-{
- State->FpuStatus.Top--;
-
- if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
- {
- FPU_ST(0) = *Data;
- FPU_UPDATE_TAG(0);
-
- return TRUE;
- }
- else
- {
- /* Raise the stack fault and invalid operation exception */
- State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
-
- /* Set the C1 condition code bit (stack overflow) */
- State->FpuStatus.Code1 = TRUE;
-
- return FALSE;
- }
-}
-
-FORCEINLINE
-BOOLEAN
-FASTCALL
-Fast486FpuPop(PFAST486_STATE State)
-{
- if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
- {
- FPU_SET_TAG(0, FPU_TAG_EMPTY);
- State->FpuStatus.Top++;
-
- return TRUE;
- }
- else
- {
- /* Raise the stack fault and invalid operation exception */
- State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
-
- /* Clear the C1 condition code bit (stack underflow) */
- State->FpuStatus.Code1 = FALSE;
-
- return FALSE;
- }
-}
-
-#endif
-
-/* EOF */