2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 /* PUBLIC FUNCTIONS ***********************************************************/
27 #if defined (__GNUC__)
28 #define CountLeadingZeros64(x) __builtin_clzll(x)
31 #elif (_MSC_VER >= 1500) && defined(_WIN64)
32 #define CountLeadingZeros64(x) __lzcnt64(x)
33 #elif (_MSC_VER >= 1500)
34 #define CountLeadingZeros64(x) ((x) > 0xFFFFFFFFULL) ? __lzcnt((x) >> 32) \
41 CountLeadingZeros64(ULONGLONG Value)
45 while ((LONGLONG)Value < 0)
57 Fast486GetCurrentPrivLevel(PFAST486_STATE State)
59 /* Return the CPL, or 3 if we're in virtual 8086 mode */
60 return (!State->Flags.Vm) ? State->Cpl : 3;
66 Fast486GetPageTableEntry(PFAST486_STATE State,
70 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
71 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
72 FAST486_PAGE_DIR DirectoryEntry;
73 FAST486_PAGE_TABLE TableEntry;
74 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
76 if ((State->Tlb != NULL)
77 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
79 /* Return the cached entry */
80 return State->Tlb[VirtualAddress >> 12];
83 /* Read the directory entry */
84 State->MemReadCallback(State,
85 PageDirectory + PdeIndex * sizeof(ULONG),
86 &DirectoryEntry.Value,
87 sizeof(DirectoryEntry));
89 /* Make sure it is present */
90 if (!DirectoryEntry.Present) return 0;
92 /* Was the directory entry accessed before? */
93 if (!DirectoryEntry.Accessed)
96 DirectoryEntry.Accessed = TRUE;
98 /* Write back the directory entry */
99 State->MemWriteCallback(State,
100 PageDirectory + PdeIndex * sizeof(ULONG),
101 &DirectoryEntry.Value,
102 sizeof(DirectoryEntry));
105 /* Read the table entry */
106 State->MemReadCallback(State,
107 (DirectoryEntry.TableAddress << 12)
108 + PteIndex * sizeof(ULONG),
112 /* Make sure it is present */
113 if (!TableEntry.Present) return 0;
115 /* Do we need to change any flags? */
116 if (!TableEntry.Accessed || (MarkAsDirty && !TableEntry.Dirty))
118 /* Mark it as accessed and optionally dirty too */
119 TableEntry.Accessed = TRUE;
120 if (MarkAsDirty) TableEntry.Dirty = TRUE;
122 /* Write back the table entry */
123 State->MemWriteCallback(State,
124 (DirectoryEntry.TableAddress << 12)
125 + PteIndex * sizeof(ULONG),
131 * The resulting permissions depend on the permissions
132 * in the page directory table too
134 TableEntry.Writeable &= DirectoryEntry.Writeable;
135 TableEntry.Usermode &= DirectoryEntry.Usermode;
137 if (State->Tlb != NULL)
139 /* Set the TLB entry */
140 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
143 /* Return the table entry */
144 return TableEntry.Value;
150 Fast486ReadLinearMemory(PFAST486_STATE State,
155 /* Check if paging is enabled */
156 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
159 FAST486_PAGE_TABLE TableEntry;
160 INT Cpl = Fast486GetCurrentPrivLevel(State);
161 ULONG BufferOffset = 0;
163 for (Page = PAGE_ALIGN(LinearAddress);
164 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
165 Page += FAST486_PAGE_SIZE)
167 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
169 /* Get the table entry */
170 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
172 /* Check if this is the first page */
173 if (Page == PAGE_ALIGN(LinearAddress))
175 /* Start reading from the offset from the beginning of the page */
176 PageOffset = PAGE_OFFSET(LinearAddress);
177 PageLength -= PageOffset;
180 if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
182 State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset;
185 Fast486ExceptionWithErrorCode(State,
186 FAST486_EXCEPTION_PF,
187 TableEntry.Present | (State->Cpl ? 0x04 : 0));
191 /* Check if this is the last page */
192 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
194 /* Read only a part of the page */
195 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
198 /* Read the memory */
199 State->MemReadCallback(State,
200 (TableEntry.Address << 12) | PageOffset,
201 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
204 BufferOffset += PageLength;
209 /* Read the memory */
210 State->MemReadCallback(State, LinearAddress, Buffer, Size);
219 Fast486WriteLinearMemory(PFAST486_STATE State,
224 /* Check if paging is enabled */
225 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
228 FAST486_PAGE_TABLE TableEntry;
229 INT Cpl = Fast486GetCurrentPrivLevel(State);
230 ULONG BufferOffset = 0;
232 for (Page = PAGE_ALIGN(LinearAddress);
233 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
234 Page += FAST486_PAGE_SIZE)
236 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
238 /* Get the table entry */
239 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
241 /* Check if this is the first page */
242 if (Page == PAGE_ALIGN(LinearAddress))
244 /* Start writing from the offset from the beginning of the page */
245 PageOffset = PAGE_OFFSET(LinearAddress);
246 PageLength -= PageOffset;
249 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
250 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
251 && !TableEntry.Writeable))
253 State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset;
256 Fast486ExceptionWithErrorCode(State,
257 FAST486_EXCEPTION_PF,
258 TableEntry.Present | 0x02 | (State->Cpl ? 0x04 : 0));
262 /* Check if this is the last page */
263 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
265 /* Write only a part of the page */
266 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
269 /* Write the memory */
270 State->MemWriteCallback(State,
271 (TableEntry.Address << 12) | PageOffset,
272 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
275 BufferOffset += PageLength;
280 /* Write the memory */
281 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
290 Fast486Exception(PFAST486_STATE State,
291 FAST486_EXCEPTIONS ExceptionCode)
293 /* Call the internal function */
294 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
300 Fast486StackPush(PFAST486_STATE State,
303 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
304 ULONG StackPointer = State->GeneralRegs[FAST486_REG_ESP].Long;
306 /* The OPSIZE prefix toggles the size */
313 /* Check if ESP is between 1 and 3 */
314 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
315 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
317 Fast486Exception(State, FAST486_EXCEPTION_SS);
321 /* Store the value in SS:[ESP - 4] */
322 if (!Fast486WriteMemory(State,
324 State->SegmentRegs[FAST486_REG_SS].Size
325 ? StackPointer - sizeof(ULONG)
326 : LOWORD(StackPointer - sizeof(ULONG)),
330 /* Exception occurred */
334 if (State->SegmentRegs[FAST486_REG_SS].Size)
336 /* Subtract ESP by 4 */
337 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
341 /* Subtract SP by 4 */
342 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(ULONG);
348 USHORT ShortValue = LOWORD(Value);
350 /* Check if SP is 1 */
351 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
353 Fast486Exception(State, FAST486_EXCEPTION_SS);
357 /* Store the value in SS:[SP - 2] */
358 if (!Fast486WriteMemory(State,
360 State->SegmentRegs[FAST486_REG_SS].Size
361 ? StackPointer - sizeof(USHORT)
362 : LOWORD(StackPointer - sizeof(USHORT)),
366 /* Exception occurred */
370 if (State->SegmentRegs[FAST486_REG_SS].Size)
372 /* Subtract ESP by 2 */
373 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(USHORT);
377 /* Subtract SP by 2 */
378 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
388 Fast486StackPop(PFAST486_STATE State,
391 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
393 /* The OPSIZE prefix toggles the size */
401 /* Check if ESP is 0xFFFFFFFF */
402 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
404 Fast486Exception(State, FAST486_EXCEPTION_SS);
408 /* Read the value from SS:ESP */
409 if (!Fast486ReadMemory(State,
411 State->SegmentRegs[FAST486_REG_SS].Size
412 ? State->GeneralRegs[FAST486_REG_ESP].Long
413 : State->GeneralRegs[FAST486_REG_ESP].LowWord,
418 /* An exception occurred */
422 if (State->SegmentRegs[FAST486_REG_SS].Size)
424 /* Increment ESP by 4 */
425 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
429 /* Increment SP by 4 */
430 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(ULONG);
433 /* Store the value in the result */
441 /* Check if SP is 0xFFFF */
442 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
444 Fast486Exception(State, FAST486_EXCEPTION_SS);
448 /* Read the value from SS:SP */
449 if (!Fast486ReadMemory(State,
451 State->SegmentRegs[FAST486_REG_SS].Size
452 ? State->GeneralRegs[FAST486_REG_ESP].Long
453 : State->GeneralRegs[FAST486_REG_ESP].LowWord,
458 /* An exception occurred */
462 if (State->SegmentRegs[FAST486_REG_SS].Size)
464 /* Increment ESP by 2 */
465 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(USHORT);
469 /* Increment SP by 2 */
470 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
473 /* Store the value in the result */
483 Fast486ReadDescriptorEntry(PFAST486_STATE State,
486 PFAST486_GDT_ENTRY Entry)
488 if (!(Selector & SEGMENT_TABLE_INDICATOR))
490 /* Make sure the GDT contains the entry */
491 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
498 if (!Fast486ReadLinearMemory(State,
500 + GET_SEGMENT_INDEX(Selector),
504 /* Exception occurred */
511 /* Make sure the LDT contains the entry */
512 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1u))
519 if (!Fast486ReadLinearMemory(State,
521 + GET_SEGMENT_INDEX(Selector),
525 /* Exception occurred */
538 Fast486LoadSegmentInternal(PFAST486_STATE State,
539 FAST486_SEG_REGS Segment,
541 FAST486_EXCEPTIONS Exception)
543 PFAST486_SEG_REG CachedDescriptor;
545 FAST486_GDT_ENTRY GdtEntry;
547 ASSERT(Segment < FAST486_NUM_SEG_REGS);
549 /* Get the cached descriptor */
550 CachedDescriptor = &State->SegmentRegs[Segment];
552 /* Check for protected mode */
553 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
555 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
557 /* Exception occurred */
563 /* Invalid selector */
564 Fast486ExceptionWithErrorCode(State, Exception, Selector);
568 if (Segment == FAST486_REG_SS)
570 /* Loading the stack segment */
572 if (GET_SEGMENT_INDEX(Selector) == 0)
574 Fast486Exception(State, Exception);
578 if (!GdtEntry.SystemType)
580 /* This is a special descriptor */
581 Fast486ExceptionWithErrorCode(State, Exception, Selector);
585 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
587 Fast486ExceptionWithErrorCode(State, Exception, Selector);
591 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
592 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
594 Fast486ExceptionWithErrorCode(State, Exception, Selector);
598 if (!GdtEntry.Present)
600 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
604 else if (Segment == FAST486_REG_CS)
606 /* Loading the code segment */
608 #ifndef FAST486_NO_PREFETCH
609 /* Invalidate the prefetch */
610 State->PrefetchValid = FALSE;
613 if (GET_SEGMENT_INDEX(Selector) == 0)
615 Fast486Exception(State, Exception);
619 if (!GdtEntry.SystemType)
621 /* Must be a segment descriptor */
622 Fast486ExceptionWithErrorCode(State, Exception, Selector);
626 if (!GdtEntry.Present)
628 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
632 if (!GdtEntry.Executable)
634 Fast486ExceptionWithErrorCode(State, Exception, Selector);
638 if (GdtEntry.DirConf)
640 /* Conforming Code Segment */
642 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
644 /* Must be accessed from lower-privileged code */
645 Fast486ExceptionWithErrorCode(State, Exception, Selector);
651 /* Regular code segment */
653 if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State)))
655 Fast486ExceptionWithErrorCode(State, Exception, Selector);
662 /* Loading a data segment */
664 if (GET_SEGMENT_INDEX(Selector) != 0)
666 if (!GdtEntry.SystemType)
668 /* This is a special descriptor */
669 Fast486ExceptionWithErrorCode(State, Exception, Selector);
673 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
674 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
676 Fast486ExceptionWithErrorCode(State, Exception, Selector);
680 if (!GdtEntry.Present)
682 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
688 /* This is a NULL selector */
689 RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
693 /* Update the cache entry */
694 CachedDescriptor->Selector = Selector;
695 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
696 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
697 CachedDescriptor->Accessed = GdtEntry.Accessed;
698 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
699 CachedDescriptor->DirConf = GdtEntry.DirConf;
700 CachedDescriptor->Executable = GdtEntry.Executable;
701 CachedDescriptor->SystemType = GdtEntry.SystemType;
702 CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
703 CachedDescriptor->Dpl = GdtEntry.Dpl;
704 CachedDescriptor->Present = GdtEntry.Present;
705 CachedDescriptor->Size = GdtEntry.Size;
707 /* Check for page granularity */
708 if (GdtEntry.Granularity)
710 CachedDescriptor->Limit <<= 12;
711 CachedDescriptor->Limit |= 0x00000FFF;
716 /* Update the selector and base */
717 CachedDescriptor->Selector = Selector;
718 CachedDescriptor->Base = Selector << 4;
727 Fast486LoadSegment(PFAST486_STATE State,
728 FAST486_SEG_REGS Segment,
731 return Fast486LoadSegmentInternal(State,
734 FAST486_EXCEPTION_GP);
740 Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call)
743 FAST486_SYSTEM_DESCRIPTOR Descriptor;
745 if (!Fast486ReadDescriptorEntry(State,
748 (PFAST486_GDT_ENTRY)&Descriptor))
750 /* Exception occurred */
756 /* Invalid selector */
757 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
761 switch (Descriptor.Signature)
763 case FAST486_TASK_GATE_SIGNATURE:
765 Fast486TaskSwitch(State,
766 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
767 ((PFAST486_IDT_ENTRY)&Descriptor)->Selector);
772 case FAST486_TSS_SIGNATURE:
774 Fast486TaskSwitch(State,
775 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
781 case FAST486_CALL_GATE_SIGNATURE:
783 // TODO: NOT IMPLEMENTED
789 /* Security check for jumps and calls only */
790 if (State->Cpl != Descriptor.Dpl)
792 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
804 Fast486FetchByte(PFAST486_STATE State,
807 PFAST486_SEG_REG CachedDescriptor;
809 #ifndef FAST486_NO_PREFETCH
813 /* Get the cached descriptor of CS */
814 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
816 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
817 : State->InstPtr.LowWord;
818 #ifndef FAST486_NO_PREFETCH
819 LinearAddress = CachedDescriptor->Base + Offset;
821 if (State->PrefetchValid
822 && (LinearAddress >= State->PrefetchAddress)
823 && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
825 *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
830 /* Read from memory */
831 if (!Fast486ReadMemory(State,
838 /* Exception occurred during instruction fetch */
843 /* Advance the instruction pointer */
844 if (CachedDescriptor->Size) State->InstPtr.Long++;
845 else State->InstPtr.LowWord++;
853 Fast486FetchWord(PFAST486_STATE State,
856 PFAST486_SEG_REG CachedDescriptor;
858 #ifndef FAST486_NO_PREFETCH
862 /* Get the cached descriptor of CS */
863 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
865 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
866 : State->InstPtr.LowWord;
868 #ifndef FAST486_NO_PREFETCH
869 LinearAddress = CachedDescriptor->Base + Offset;
871 if (State->PrefetchValid
872 && (LinearAddress >= State->PrefetchAddress)
873 && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
875 *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
880 /* Read from memory */
881 // FIXME: Fix byte order on big-endian machines
882 if (!Fast486ReadMemory(State,
889 /* Exception occurred during instruction fetch */
894 /* Advance the instruction pointer */
895 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
896 else State->InstPtr.LowWord += sizeof(USHORT);
904 Fast486FetchDword(PFAST486_STATE State,
907 PFAST486_SEG_REG CachedDescriptor;
909 #ifndef FAST486_NO_PREFETCH
913 /* Get the cached descriptor of CS */
914 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
916 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
917 : State->InstPtr.LowWord;
919 #ifndef FAST486_NO_PREFETCH
920 LinearAddress = CachedDescriptor->Base + Offset;
922 if (State->PrefetchValid
923 && (LinearAddress >= State->PrefetchAddress)
924 && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
926 *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
931 /* Read from memory */
932 // FIXME: Fix byte order on big-endian machines
933 if (!Fast486ReadMemory(State,
940 /* Exception occurred during instruction fetch */
945 /* Advance the instruction pointer */
946 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
947 else State->InstPtr.LowWord += sizeof(ULONG);
955 Fast486CalculateParity(UCHAR Number)
957 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
958 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
964 Fast486ParseModRegRm(PFAST486_STATE State,
966 PFAST486_MOD_REG_RM ModRegRm)
968 UCHAR ModRmByte, Mode, RegMem;
970 /* Fetch the MOD REG R/M byte */
971 if (!Fast486FetchByte(State, &ModRmByte))
973 /* Exception occurred */
977 /* Unpack the mode and R/M */
978 Mode = ModRmByte >> 6;
979 RegMem = ModRmByte & 0x07;
981 /* Set the register operand */
982 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
987 /* The second operand is also a register */
988 ModRegRm->Memory = FALSE;
989 ModRegRm->SecondRegister = RegMem;
995 /* The second operand is memory */
996 ModRegRm->Memory = TRUE;
1000 if (RegMem == FAST486_REG_ESP)
1003 ULONG Scale, Index, Base;
1005 /* Fetch the SIB byte */
1006 if (!Fast486FetchByte(State, &SibByte))
1008 /* Exception occurred */
1012 /* Unpack the scale, index and base */
1013 Scale = 1 << (SibByte >> 6);
1014 Index = (SibByte >> 3) & 0x07;
1015 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
1018 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
1020 /* Use the register a base */
1021 Base = State->GeneralRegs[SibByte & 0x07].Long;
1025 /* Fetch the base */
1026 if (!Fast486FetchDword(State, &Base))
1028 /* Exception occurred */
1033 if ((SibByte & 0x07) == FAST486_REG_ESP)
1035 /* Check if there is no segment override */
1036 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1038 /* Add a SS: prefix */
1039 State->PrefixFlags |= FAST486_PREFIX_SEG;
1040 State->SegmentOverride = FAST486_REG_SS;
1044 /* Calculate the address */
1045 ModRegRm->MemoryAddress = Base + Index * Scale;
1047 else if (RegMem == FAST486_REG_EBP)
1049 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
1050 else ModRegRm->MemoryAddress = 0;
1054 /* Get the base from the register */
1055 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
1058 /* Check if there is no segment override */
1059 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1061 /* Check if the default segment should be SS */
1062 if ((RegMem == FAST486_REG_EBP) && Mode)
1064 /* Add a SS: prefix */
1065 State->PrefixFlags |= FAST486_PREFIX_SEG;
1066 State->SegmentOverride = FAST486_REG_SS;
1074 /* Fetch the byte */
1075 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1077 /* Exception occurred */
1081 /* Add the signed offset to the address */
1082 ModRegRm->MemoryAddress += (LONG)Offset;
1084 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
1088 /* Fetch the dword */
1089 if (!Fast486FetchDword(State, (PULONG)&Offset))
1091 /* Exception occurred */
1095 /* Add the signed offset to the address */
1096 ModRegRm->MemoryAddress += Offset;
1101 /* Check the operand */
1107 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1108 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1115 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1116 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1123 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1124 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1131 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1132 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1139 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
1146 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
1155 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
1159 /* [constant] (added later) */
1160 ModRegRm->MemoryAddress = 0;
1169 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
1174 /* Check if there is no segment override */
1175 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1177 /* Check if the default segment should be SS */
1178 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
1180 /* Add a SS: prefix */
1181 State->PrefixFlags |= FAST486_PREFIX_SEG;
1182 State->SegmentOverride = FAST486_REG_SS;
1190 /* Fetch the byte */
1191 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1193 /* Exception occurred */
1197 /* Add the signed offset to the address */
1198 ModRegRm->MemoryAddress += (LONG)Offset;
1200 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
1204 /* Fetch the word */
1205 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
1207 /* Exception occurred */
1211 /* Add the signed offset to the address */
1212 ModRegRm->MemoryAddress += (LONG)Offset;
1215 /* Clear the top 16 bits */
1216 ModRegRm->MemoryAddress &= 0x0000FFFF;
1225 Fast486ReadModrmByteOperands(PFAST486_STATE State,
1226 PFAST486_MOD_REG_RM ModRegRm,
1230 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1234 /* Get the register value */
1235 if (ModRegRm->Register & 0x04)
1237 /* AH, CH, DH, BH */
1238 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
1242 /* AL, CL, DL, BL */
1243 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
1249 if (!ModRegRm->Memory)
1251 /* Get the second register value */
1252 if (ModRegRm->SecondRegister & 0x04)
1254 /* AH, CH, DH, BH */
1255 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1259 /* AL, CL, DL, BL */
1260 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1265 /* Check for the segment override */
1266 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1268 /* Use the override segment instead */
1269 Segment = State->SegmentOverride;
1273 if (!Fast486ReadMemory(State,
1275 ModRegRm->MemoryAddress,
1280 /* Exception occurred */
1292 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1293 PFAST486_MOD_REG_RM ModRegRm,
1297 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1301 /* Get the register value */
1302 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1307 if (!ModRegRm->Memory)
1309 /* Get the second register value */
1310 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1314 /* Check for the segment override */
1315 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1317 /* Use the override segment instead */
1318 Segment = State->SegmentOverride;
1322 if (!Fast486ReadMemory(State,
1324 ModRegRm->MemoryAddress,
1329 /* Exception occurred */
1341 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1342 PFAST486_MOD_REG_RM ModRegRm,
1346 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1350 /* Get the register value */
1351 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1356 if (!ModRegRm->Memory)
1358 /* Get the second register value */
1359 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1363 /* Check for the segment override */
1364 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1366 /* Use the override segment instead */
1367 Segment = State->SegmentOverride;
1371 if (!Fast486ReadMemory(State,
1373 ModRegRm->MemoryAddress,
1378 /* Exception occurred */
1390 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1391 PFAST486_MOD_REG_RM ModRegRm,
1392 BOOLEAN WriteRegister,
1395 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1399 /* Store the value in the register */
1400 if (ModRegRm->Register & 0x04)
1402 /* AH, CH, DH, BH */
1403 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1407 /* AL, CL, DL, BL */
1408 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1413 if (!ModRegRm->Memory)
1415 /* Store the value in the second register */
1416 if (ModRegRm->SecondRegister & 0x04)
1418 /* AH, CH, DH, BH */
1419 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1423 /* AL, CL, DL, BL */
1424 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1429 /* Check for the segment override */
1430 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1432 /* Use the override segment instead */
1433 Segment = State->SegmentOverride;
1437 if (!Fast486WriteMemory(State,
1439 ModRegRm->MemoryAddress,
1443 /* Exception occurred */
1455 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1456 PFAST486_MOD_REG_RM ModRegRm,
1457 BOOLEAN WriteRegister,
1460 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1464 /* Store the value in the register */
1465 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1469 if (!ModRegRm->Memory)
1471 /* Store the value in the second register */
1472 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1476 /* Check for the segment override */
1477 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1479 /* Use the override segment instead */
1480 Segment = State->SegmentOverride;
1484 if (!Fast486WriteMemory(State,
1486 ModRegRm->MemoryAddress,
1490 /* Exception occurred */
1502 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1503 PFAST486_MOD_REG_RM ModRegRm,
1504 BOOLEAN WriteRegister,
1507 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1511 /* Store the value in the register */
1512 State->GeneralRegs[ModRegRm->Register].Long = Value;
1516 if (!ModRegRm->Memory)
1518 /* Store the value in the second register */
1519 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1523 /* Check for the segment override */
1524 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1526 /* Use the override segment instead */
1527 Segment = State->SegmentOverride;
1531 if (!Fast486WriteMemory(State,
1533 ModRegRm->MemoryAddress,
1537 /* Exception occurred */
1546 #ifndef FAST486_NO_FPU
1551 Fast486FpuException(PFAST486_STATE State)
1553 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_NE)
1555 /* Call the #MF handler */
1556 Fast486Exception(State, FAST486_EXCEPTION_MF);
1560 /* Use the external interrupt */
1561 State->FpuCallback(State);
1568 Fast486FpuNormalize(PFAST486_STATE State,
1569 PFAST486_FPU_DATA_REG Data)
1573 if (FPU_IS_NORMALIZED(Data)) return TRUE;
1574 if (FPU_IS_ZERO(Data))
1580 LeadingZeros = CountLeadingZeros64(Data->Mantissa);
1582 if (LeadingZeros < Data->Exponent)
1584 Data->Mantissa <<= LeadingZeros;
1585 Data->Exponent -= LeadingZeros;
1589 /* Raise the underflow exception */
1590 State->FpuStatus.Ue = TRUE;
1592 if (State->FpuControl.Um)
1594 /* Make it denormalized */
1595 Data->Mantissa <<= Data->Exponent - 1;
1600 Fast486FpuException(State);
1611 Fast486FpuGetValueTag(PFAST486_FPU_DATA_REG Data)
1613 if (FPU_IS_ZERO(Data)) return FPU_TAG_ZERO;
1614 else if (FPU_IS_NAN(Data)) return FPU_TAG_SPECIAL;
1615 else return FPU_TAG_VALID;
1621 Fast486FpuPush(PFAST486_STATE State,
1622 PCFAST486_FPU_DATA_REG Data)
1624 State->FpuStatus.Top--;
1626 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1635 /* Raise the stack fault and invalid operation exception */
1636 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
1638 /* Set the C1 condition code bit (stack overflow) */
1639 State->FpuStatus.Code1 = TRUE;
1641 if (!State->FpuControl.Im) Fast486FpuException(State);
1649 Fast486FpuPop(PFAST486_STATE State)
1651 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
1653 FPU_SET_TAG(0, FPU_TAG_EMPTY);
1654 State->FpuStatus.Top++;
1660 /* Raise the stack fault and invalid operation exception */
1661 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
1663 /* Clear the C1 condition code bit (stack underflow) */
1664 State->FpuStatus.Code1 = FALSE;
1666 if (!State->FpuControl.Im) Fast486FpuException(State);