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 if (MarkAsDirty) TableEntry.Dirty = TRUE;
117 /* Was the table entry accessed before? */
118 if (!TableEntry.Accessed)
120 /* Well, it is now */
121 TableEntry.Accessed = TRUE;
123 /* Write back the table entry */
124 State->MemWriteCallback(State,
125 (DirectoryEntry.TableAddress << 12)
126 + PteIndex * sizeof(ULONG),
132 * The resulting permissions depend on the permissions
133 * in the page directory table too
135 TableEntry.Writeable &= DirectoryEntry.Writeable;
136 TableEntry.Usermode &= DirectoryEntry.Usermode;
138 if (State->Tlb != NULL)
140 /* Set the TLB entry */
141 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
144 /* Return the table entry */
145 return TableEntry.Value;
151 Fast486ReadLinearMemory(PFAST486_STATE State,
156 /* Check if paging is enabled */
157 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
160 FAST486_PAGE_TABLE TableEntry;
161 INT Cpl = Fast486GetCurrentPrivLevel(State);
162 ULONG BufferOffset = 0;
164 for (Page = PAGE_ALIGN(LinearAddress);
165 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
166 Page += FAST486_PAGE_SIZE)
168 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
170 /* Get the table entry */
171 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
173 if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
176 Fast486ExceptionWithErrorCode(State,
177 FAST486_EXCEPTION_PF,
178 TableEntry.Present | (State->Cpl ? 0x04 : 0));
182 /* Check if this is the first page */
183 if (Page == PAGE_ALIGN(LinearAddress))
185 /* Start reading from the offset from the beginning of the page */
186 PageOffset = PAGE_OFFSET(LinearAddress);
187 PageLength -= PageOffset;
190 /* Check if this is the last page */
191 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
193 /* Read only a part of the page */
194 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
197 /* Read the memory */
198 State->MemReadCallback(State,
199 (TableEntry.Address << 12) | PageOffset,
200 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
203 BufferOffset += PageLength;
208 /* Read the memory */
209 State->MemReadCallback(State, LinearAddress, Buffer, Size);
218 Fast486WriteLinearMemory(PFAST486_STATE State,
223 /* Check if paging is enabled */
224 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
227 FAST486_PAGE_TABLE TableEntry;
228 INT Cpl = Fast486GetCurrentPrivLevel(State);
229 ULONG BufferOffset = 0;
231 for (Page = PAGE_ALIGN(LinearAddress);
232 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
233 Page += FAST486_PAGE_SIZE)
235 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE;
237 /* Get the table entry */
238 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
240 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
241 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
242 && !TableEntry.Writeable))
245 Fast486ExceptionWithErrorCode(State,
246 FAST486_EXCEPTION_PF,
247 TableEntry.Present | 0x02 | (State->Cpl ? 0x04 : 0));
251 /* Check if this is the first page */
252 if (Page == PAGE_ALIGN(LinearAddress))
254 /* Start writing from the offset from the beginning of the page */
255 PageOffset = PAGE_OFFSET(LinearAddress);
256 PageLength -= PageOffset;
259 /* Check if this is the last page */
260 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
262 /* Write only a part of the page */
263 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
266 /* Write the memory */
267 State->MemWriteCallback(State,
268 (TableEntry.Address << 12) | PageOffset,
269 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
272 BufferOffset += PageLength;
277 /* Write the memory */
278 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
287 Fast486Exception(PFAST486_STATE State,
288 FAST486_EXCEPTIONS ExceptionCode)
290 /* Call the internal function */
291 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
297 Fast486StackPush(PFAST486_STATE State,
300 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
302 /* The OPSIZE prefix toggles the size */
303 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
309 /* Check if ESP is between 1 and 3 */
310 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
311 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
313 Fast486Exception(State, FAST486_EXCEPTION_SS);
317 /* Subtract ESP by 4 */
318 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
320 /* Store the value in SS:ESP */
321 return Fast486WriteMemory(State,
323 State->GeneralRegs[FAST486_REG_ESP].Long,
330 USHORT ShortValue = LOWORD(Value);
332 /* Check if SP is 1 */
333 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
335 Fast486Exception(State, FAST486_EXCEPTION_SS);
339 /* Subtract SP by 2 */
340 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
342 /* Store the value in SS:SP */
343 return Fast486WriteMemory(State,
345 State->GeneralRegs[FAST486_REG_ESP].LowWord,
354 Fast486StackPop(PFAST486_STATE State,
357 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
359 /* The OPSIZE prefix toggles the size */
367 /* Check if ESP is 0xFFFFFFFF */
368 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
370 Fast486Exception(State, FAST486_EXCEPTION_SS);
374 /* Read the value from SS:ESP */
375 if (!Fast486ReadMemory(State,
377 State->GeneralRegs[FAST486_REG_ESP].Long,
382 /* An exception occurred */
386 /* Increment ESP by 4 */
387 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
389 /* Store the value in the result */
397 /* Check if SP is 0xFFFF */
398 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
400 Fast486Exception(State, FAST486_EXCEPTION_SS);
404 /* Read the value from SS:SP */
405 if (!Fast486ReadMemory(State,
407 State->GeneralRegs[FAST486_REG_ESP].LowWord,
412 /* An exception occurred */
416 /* Increment SP by 2 */
417 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
419 /* Store the value in the result */
429 Fast486ReadDescriptorEntry(PFAST486_STATE State,
432 PFAST486_GDT_ENTRY Entry)
434 if (!(Selector & SEGMENT_TABLE_INDICATOR))
436 /* Make sure the GDT contains the entry */
437 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
444 if (!Fast486ReadLinearMemory(State,
446 + GET_SEGMENT_INDEX(Selector),
450 /* Exception occurred */
457 /* Make sure the LDT contains the entry */
458 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
465 if (!Fast486ReadLinearMemory(State,
467 + GET_SEGMENT_INDEX(Selector),
471 /* Exception occurred */
484 Fast486LoadSegmentInternal(PFAST486_STATE State,
485 FAST486_SEG_REGS Segment,
487 FAST486_EXCEPTIONS Exception)
489 PFAST486_SEG_REG CachedDescriptor;
491 FAST486_GDT_ENTRY GdtEntry;
493 ASSERT(Segment < FAST486_NUM_SEG_REGS);
495 /* Get the cached descriptor */
496 CachedDescriptor = &State->SegmentRegs[Segment];
498 /* Check for protected mode */
499 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
501 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
503 /* Exception occurred */
509 /* Invalid selector */
510 Fast486ExceptionWithErrorCode(State, Exception, Selector);
513 if (Segment == FAST486_REG_SS)
515 /* Loading the stack segment */
517 if (GET_SEGMENT_INDEX(Selector) == 0)
519 Fast486Exception(State, Exception);
523 if (!GdtEntry.SystemType)
525 /* This is a special descriptor */
526 Fast486ExceptionWithErrorCode(State, Exception, Selector);
530 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
532 Fast486ExceptionWithErrorCode(State, Exception, Selector);
536 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
537 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
539 Fast486ExceptionWithErrorCode(State, Exception, Selector);
543 if (!GdtEntry.Present)
545 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
549 else if (Segment == FAST486_REG_CS)
551 /* Loading the code segment */
553 #ifndef FAST486_NO_PREFETCH
554 /* Invalidate the prefetch */
555 State->PrefetchValid = FALSE;
558 if (GET_SEGMENT_INDEX(Selector) == 0)
560 Fast486Exception(State, Exception);
564 if (!GdtEntry.SystemType)
566 /* Must be a segment descriptor */
567 Fast486ExceptionWithErrorCode(State, Exception, Selector);
570 if (!GdtEntry.Present)
572 Fast486ExceptionWithErrorCode(State, Exception, Selector);
576 if (!GdtEntry.Executable)
578 Fast486ExceptionWithErrorCode(State, Exception, Selector);
582 if (GdtEntry.DirConf)
584 /* Conforming Code Segment */
586 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
588 /* Must be accessed from lower-privileged code */
589 Fast486ExceptionWithErrorCode(State, Exception, Selector);
595 /* Regular code segment */
597 if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
598 || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
600 Fast486ExceptionWithErrorCode(State, Exception, Selector);
606 State->Cpl = GET_SEGMENT_RPL(Selector);
610 /* Loading a data segment */
612 if (GET_SEGMENT_INDEX(Selector) != 0)
614 if (!GdtEntry.SystemType)
616 /* This is a special descriptor */
617 Fast486ExceptionWithErrorCode(State, Exception, Selector);
621 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
622 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
624 Fast486ExceptionWithErrorCode(State, Exception, Selector);
628 if (!GdtEntry.Present)
630 Fast486ExceptionWithErrorCode(State, Exception, Selector);
636 /* This is a NULL selector */
637 RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
641 /* Update the cache entry */
642 CachedDescriptor->Selector = Selector;
643 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
644 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
645 CachedDescriptor->Accessed = GdtEntry.Accessed;
646 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
647 CachedDescriptor->DirConf = GdtEntry.DirConf;
648 CachedDescriptor->Executable = GdtEntry.Executable;
649 CachedDescriptor->SystemType = GdtEntry.SystemType;
650 CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
651 CachedDescriptor->Dpl = GdtEntry.Dpl;
652 CachedDescriptor->Present = GdtEntry.Present;
653 CachedDescriptor->Size = GdtEntry.Size;
655 /* Check for page granularity */
656 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
660 /* Update the selector and base */
661 CachedDescriptor->Selector = Selector;
662 CachedDescriptor->Base = Selector << 4;
671 Fast486LoadSegment(PFAST486_STATE State,
672 FAST486_SEG_REGS Segment,
675 return Fast486LoadSegmentInternal(State,
678 FAST486_EXCEPTION_GP);
684 Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call)
687 FAST486_SYSTEM_DESCRIPTOR Descriptor;
689 if (!Fast486ReadDescriptorEntry(State,
692 (PFAST486_GDT_ENTRY)&Descriptor))
694 /* Exception occurred */
700 /* Invalid selector */
701 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
705 switch (Descriptor.Signature)
707 case FAST486_TASK_GATE_SIGNATURE:
709 Fast486TaskSwitch(State,
710 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
711 ((PFAST486_IDT_ENTRY)&Descriptor)->Selector);
716 case FAST486_TSS_SIGNATURE:
718 Fast486TaskSwitch(State,
719 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
725 case FAST486_CALL_GATE_SIGNATURE:
727 // TODO: NOT IMPLEMENTED
741 Fast486FetchByte(PFAST486_STATE State,
744 PFAST486_SEG_REG CachedDescriptor;
746 #ifndef FAST486_NO_PREFETCH
750 /* Get the cached descriptor of CS */
751 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
753 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
754 : State->InstPtr.LowWord;
755 #ifndef FAST486_NO_PREFETCH
756 LinearAddress = CachedDescriptor->Base + Offset;
758 if (State->PrefetchValid
759 && (LinearAddress >= State->PrefetchAddress)
760 && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
762 *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
767 /* Read from memory */
768 if (!Fast486ReadMemory(State,
775 /* Exception occurred during instruction fetch */
780 /* Advance the instruction pointer */
781 if (CachedDescriptor->Size) State->InstPtr.Long++;
782 else State->InstPtr.LowWord++;
790 Fast486FetchWord(PFAST486_STATE State,
793 PFAST486_SEG_REG CachedDescriptor;
795 #ifndef FAST486_NO_PREFETCH
799 /* Get the cached descriptor of CS */
800 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
802 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
803 : State->InstPtr.LowWord;
805 #ifndef FAST486_NO_PREFETCH
806 LinearAddress = CachedDescriptor->Base + Offset;
808 if (State->PrefetchValid
809 && (LinearAddress >= State->PrefetchAddress)
810 && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
812 *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
817 /* Read from memory */
818 // FIXME: Fix byte order on big-endian machines
819 if (!Fast486ReadMemory(State,
826 /* Exception occurred during instruction fetch */
831 /* Advance the instruction pointer */
832 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
833 else State->InstPtr.LowWord += sizeof(USHORT);
841 Fast486FetchDword(PFAST486_STATE State,
844 PFAST486_SEG_REG CachedDescriptor;
846 #ifndef FAST486_NO_PREFETCH
850 /* Get the cached descriptor of CS */
851 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
853 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
854 : State->InstPtr.LowWord;
856 #ifndef FAST486_NO_PREFETCH
857 LinearAddress = CachedDescriptor->Base + Offset;
859 if (State->PrefetchValid
860 && (LinearAddress >= State->PrefetchAddress)
861 && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
863 *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
868 /* Read from memory */
869 // FIXME: Fix byte order on big-endian machines
870 if (!Fast486ReadMemory(State,
877 /* Exception occurred during instruction fetch */
882 /* Advance the instruction pointer */
883 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
884 else State->InstPtr.LowWord += sizeof(ULONG);
892 Fast486CalculateParity(UCHAR Number)
894 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
895 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
901 Fast486ParseModRegRm(PFAST486_STATE State,
903 PFAST486_MOD_REG_RM ModRegRm)
905 UCHAR ModRmByte, Mode, RegMem;
907 /* Fetch the MOD REG R/M byte */
908 if (!Fast486FetchByte(State, &ModRmByte))
910 /* Exception occurred */
914 /* Unpack the mode and R/M */
915 Mode = ModRmByte >> 6;
916 RegMem = ModRmByte & 0x07;
918 /* Set the register operand */
919 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
924 /* The second operand is also a register */
925 ModRegRm->Memory = FALSE;
926 ModRegRm->SecondRegister = RegMem;
932 /* The second operand is memory */
933 ModRegRm->Memory = TRUE;
937 if (RegMem == FAST486_REG_ESP)
940 ULONG Scale, Index, Base;
942 /* Fetch the SIB byte */
943 if (!Fast486FetchByte(State, &SibByte))
945 /* Exception occurred */
949 /* Unpack the scale, index and base */
950 Scale = 1 << (SibByte >> 6);
951 Index = (SibByte >> 3) & 0x07;
952 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
955 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
957 /* Use the register a base */
958 Base = State->GeneralRegs[SibByte & 0x07].Long;
963 if (!Fast486FetchDword(State, &Base))
965 /* Exception occurred */
970 if ((SibByte & 0x07) == FAST486_REG_ESP)
972 /* Check if there is no segment override */
973 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
975 /* Add a SS: prefix */
976 State->PrefixFlags |= FAST486_PREFIX_SEG;
977 State->SegmentOverride = FAST486_REG_SS;
981 /* Calculate the address */
982 ModRegRm->MemoryAddress = Base + Index * Scale;
984 else if (RegMem == FAST486_REG_EBP)
986 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
987 else ModRegRm->MemoryAddress = 0;
991 /* Get the base from the register */
992 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
995 /* Check if there is no segment override */
996 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
998 /* Check if the default segment should be SS */
999 if ((RegMem == FAST486_REG_EBP) && Mode)
1001 /* Add a SS: prefix */
1002 State->PrefixFlags |= FAST486_PREFIX_SEG;
1003 State->SegmentOverride = FAST486_REG_SS;
1011 /* Fetch the byte */
1012 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1014 /* Exception occurred */
1018 /* Add the signed offset to the address */
1019 ModRegRm->MemoryAddress += (LONG)Offset;
1021 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
1025 /* Fetch the dword */
1026 if (!Fast486FetchDword(State, (PULONG)&Offset))
1028 /* Exception occurred */
1032 /* Add the signed offset to the address */
1033 ModRegRm->MemoryAddress += Offset;
1038 /* Check the operand */
1044 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1045 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1052 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1053 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1060 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1061 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1068 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1069 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1076 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
1083 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
1092 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
1096 /* [constant] (added later) */
1097 ModRegRm->MemoryAddress = 0;
1106 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
1111 /* Check if there is no segment override */
1112 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1114 /* Check if the default segment should be SS */
1115 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
1117 /* Add a SS: prefix */
1118 State->PrefixFlags |= FAST486_PREFIX_SEG;
1119 State->SegmentOverride = FAST486_REG_SS;
1127 /* Fetch the byte */
1128 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1130 /* Exception occurred */
1134 /* Add the signed offset to the address */
1135 ModRegRm->MemoryAddress += (LONG)Offset;
1137 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
1141 /* Fetch the word */
1142 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
1144 /* Exception occurred */
1148 /* Add the signed offset to the address */
1149 ModRegRm->MemoryAddress += (LONG)Offset;
1152 /* Clear the top 16 bits */
1153 ModRegRm->MemoryAddress &= 0x0000FFFF;
1162 Fast486ReadModrmByteOperands(PFAST486_STATE State,
1163 PFAST486_MOD_REG_RM ModRegRm,
1167 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1171 /* Get the register value */
1172 if (ModRegRm->Register & 0x04)
1174 /* AH, CH, DH, BH */
1175 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
1179 /* AL, CL, DL, BL */
1180 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
1186 if (!ModRegRm->Memory)
1188 /* Get the second register value */
1189 if (ModRegRm->SecondRegister & 0x04)
1191 /* AH, CH, DH, BH */
1192 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1196 /* AL, CL, DL, BL */
1197 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1202 /* Check for the segment override */
1203 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1205 /* Use the override segment instead */
1206 Segment = State->SegmentOverride;
1210 if (!Fast486ReadMemory(State,
1212 ModRegRm->MemoryAddress,
1217 /* Exception occurred */
1229 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1230 PFAST486_MOD_REG_RM ModRegRm,
1234 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1238 /* Get the register value */
1239 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1244 if (!ModRegRm->Memory)
1246 /* Get the second register value */
1247 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1251 /* Check for the segment override */
1252 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1254 /* Use the override segment instead */
1255 Segment = State->SegmentOverride;
1259 if (!Fast486ReadMemory(State,
1261 ModRegRm->MemoryAddress,
1266 /* Exception occurred */
1278 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1279 PFAST486_MOD_REG_RM ModRegRm,
1283 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1287 /* Get the register value */
1288 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1293 if (!ModRegRm->Memory)
1295 /* Get the second register value */
1296 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1300 /* Check for the segment override */
1301 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1303 /* Use the override segment instead */
1304 Segment = State->SegmentOverride;
1308 if (!Fast486ReadMemory(State,
1310 ModRegRm->MemoryAddress,
1315 /* Exception occurred */
1327 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1328 PFAST486_MOD_REG_RM ModRegRm,
1329 BOOLEAN WriteRegister,
1332 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1336 /* Store the value in the register */
1337 if (ModRegRm->Register & 0x04)
1339 /* AH, CH, DH, BH */
1340 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1344 /* AL, CL, DL, BL */
1345 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1350 if (!ModRegRm->Memory)
1352 /* Store the value in the second register */
1353 if (ModRegRm->SecondRegister & 0x04)
1355 /* AH, CH, DH, BH */
1356 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1360 /* AL, CL, DL, BL */
1361 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1366 /* Check for the segment override */
1367 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1369 /* Use the override segment instead */
1370 Segment = State->SegmentOverride;
1374 if (!Fast486WriteMemory(State,
1376 ModRegRm->MemoryAddress,
1380 /* Exception occurred */
1392 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1393 PFAST486_MOD_REG_RM ModRegRm,
1394 BOOLEAN WriteRegister,
1397 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1401 /* Store the value in the register */
1402 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1406 if (!ModRegRm->Memory)
1408 /* Store the value in the second register */
1409 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1413 /* Check for the segment override */
1414 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1416 /* Use the override segment instead */
1417 Segment = State->SegmentOverride;
1421 if (!Fast486WriteMemory(State,
1423 ModRegRm->MemoryAddress,
1427 /* Exception occurred */
1439 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1440 PFAST486_MOD_REG_RM ModRegRm,
1441 BOOLEAN WriteRegister,
1444 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1448 /* Store the value in the register */
1449 State->GeneralRegs[ModRegRm->Register].Long = Value;
1453 if (!ModRegRm->Memory)
1455 /* Store the value in the second register */
1456 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1460 /* Check for the segment override */
1461 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1463 /* Use the override segment instead */
1464 Segment = State->SegmentOverride;
1468 if (!Fast486WriteMemory(State,
1470 ModRegRm->MemoryAddress,
1474 /* Exception occurred */
1483 #ifndef FAST486_NO_FPU
1488 Fast486FpuNormalize(PFAST486_STATE State,
1489 PFAST486_FPU_DATA_REG Data)
1493 if (FPU_IS_NORMALIZED(Data)) return;
1494 if (FPU_IS_ZERO(Data))
1500 LeadingZeros = CountLeadingZeros64(Data->Mantissa);
1502 if (LeadingZeros < Data->Exponent)
1504 Data->Mantissa <<= LeadingZeros;
1505 Data->Exponent -= LeadingZeros;
1509 /* Make it denormalized */
1510 Data->Mantissa <<= Data->Exponent - 1;
1514 State->FpuStatus.Ue = TRUE;
1521 Fast486GetValueTag(PFAST486_FPU_DATA_REG Data)
1523 if (FPU_IS_ZERO(Data)) return FPU_TAG_ZERO;
1524 else if (FPU_IS_NAN(Data)) return FPU_TAG_SPECIAL;
1525 else return FPU_TAG_VALID;
1531 Fast486FpuPush(PFAST486_STATE State,
1532 PFAST486_FPU_DATA_REG Data)
1534 State->FpuStatus.Top--;
1536 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1539 FPU_SET_TAG(0, Fast486GetValueTag(Data));
1541 else State->FpuStatus.Ie = TRUE;
1547 Fast486FpuPop(PFAST486_STATE State)
1549 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
1551 FPU_SET_TAG(0, FPU_TAG_EMPTY);
1552 State->FpuStatus.Top++;
1554 else State->FpuStatus.Ie = TRUE;