2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 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.
24 /* PUBLIC FUNCTIONS ***********************************************************/
28 Fast486GetCurrentPrivLevel(PFAST486_STATE State)
30 /* Return the CPL, or 3 if we're in virtual 8086 mode */
31 return (!State->Flags.Vm) ? State->Cpl : 3;
36 Fast486GetPageTableEntry(PFAST486_STATE State,
40 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
41 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
42 FAST486_PAGE_DIR DirectoryEntry;
43 FAST486_PAGE_TABLE TableEntry;
44 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
46 if ((State->Tlb != NULL)
47 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
49 /* Return the cached entry */
50 return State->Tlb[VirtualAddress >> 12];
53 /* Read the directory entry */
54 State->MemReadCallback(State,
55 PageDirectory + PdeIndex * sizeof(ULONG),
56 &DirectoryEntry.Value,
57 sizeof(DirectoryEntry));
59 /* Make sure it is present */
60 if (!DirectoryEntry.Present) return 0;
62 /* Was the directory entry accessed before? */
63 if (!DirectoryEntry.Accessed)
66 DirectoryEntry.Accessed = TRUE;
68 /* Write back the directory entry */
69 State->MemWriteCallback(State,
70 PageDirectory + PdeIndex * sizeof(ULONG),
71 &DirectoryEntry.Value,
72 sizeof(DirectoryEntry));
75 /* Read the table entry */
76 State->MemReadCallback(State,
77 (DirectoryEntry.TableAddress << 12)
78 + PteIndex * sizeof(ULONG),
82 /* Make sure it is present */
83 if (!TableEntry.Present) return 0;
85 if (MarkAsDirty) TableEntry.Dirty = TRUE;
87 /* Was the table entry accessed before? */
88 if (!TableEntry.Accessed)
91 TableEntry.Accessed = TRUE;
93 /* Write back the table entry */
94 State->MemWriteCallback(State,
95 (DirectoryEntry.TableAddress << 12)
96 + PteIndex * sizeof(ULONG),
102 * The resulting permissions depend on the permissions
103 * in the page directory table too
105 TableEntry.Writeable &= DirectoryEntry.Writeable;
106 TableEntry.Usermode &= DirectoryEntry.Usermode;
108 if (State->Tlb != NULL)
110 /* Set the TLB entry */
111 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
114 /* Return the table entry */
115 return TableEntry.Value;
120 Fast486ReadLinearMemory(PFAST486_STATE State,
125 /* Check if paging is enabled */
126 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
129 FAST486_PAGE_TABLE TableEntry;
130 INT Cpl = Fast486GetCurrentPrivLevel(State);
131 ULONG BufferOffset = 0;
133 for (Page = PAGE_ALIGN(LinearAddress);
134 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
137 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
139 /* Get the table entry */
140 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
142 if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
145 Fast486ExceptionWithErrorCode(State,
146 FAST486_EXCEPTION_PF,
147 TableEntry.Value & 0x07);
151 /* Check if this is the first page */
152 if (Page == PAGE_ALIGN(LinearAddress))
154 /* Start reading from the offset from the beginning of the page */
155 PageOffset = PAGE_OFFSET(LinearAddress);
156 PageLength -= PageOffset;
159 /* Check if this is the last page */
160 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
162 /* Read only a part of the page */
163 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
166 /* Read the memory */
167 State->MemReadCallback(State,
168 (TableEntry.Address << 12) | PageOffset,
169 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
172 BufferOffset += PageLength;
177 /* Read the memory */
178 State->MemReadCallback(State, LinearAddress, Buffer, Size);
186 Fast486WriteLinearMemory(PFAST486_STATE State,
191 /* Check if paging is enabled */
192 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
195 FAST486_PAGE_TABLE TableEntry;
196 INT Cpl = Fast486GetCurrentPrivLevel(State);
197 ULONG BufferOffset = 0;
199 for (Page = PAGE_ALIGN(LinearAddress);
200 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
203 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
205 /* Get the table entry */
206 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
208 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
209 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
210 && !TableEntry.Writeable))
213 Fast486ExceptionWithErrorCode(State,
214 FAST486_EXCEPTION_PF,
215 TableEntry.Value & 0x07);
219 /* Check if this is the first page */
220 if (Page == PAGE_ALIGN(LinearAddress))
222 /* Start writing from the offset from the beginning of the page */
223 PageOffset = PAGE_OFFSET(LinearAddress);
224 PageLength -= PageOffset;
227 /* Check if this is the last page */
228 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
230 /* Write only a part of the page */
231 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
234 /* Write the memory */
235 State->MemWriteCallback(State,
236 (TableEntry.Address << 12) | PageOffset,
237 (PVOID)((ULONG_PTR)Buffer + BufferOffset),
240 BufferOffset += PageLength;
245 /* Write the memory */
246 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
254 Fast486Exception(PFAST486_STATE State,
255 FAST486_EXCEPTIONS ExceptionCode)
257 /* Call the internal function */
258 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
263 Fast486StackPush(PFAST486_STATE State,
266 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
268 /* The OPSIZE prefix toggles the size */
269 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
275 /* Check if ESP is between 1 and 3 */
276 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
277 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
279 Fast486Exception(State, FAST486_EXCEPTION_SS);
283 /* Subtract ESP by 4 */
284 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
286 /* Store the value in SS:ESP */
287 return Fast486WriteMemory(State,
289 State->GeneralRegs[FAST486_REG_ESP].Long,
296 USHORT ShortValue = LOWORD(Value);
298 /* Check if SP is 1 */
299 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
301 Fast486Exception(State, FAST486_EXCEPTION_SS);
305 /* Subtract SP by 2 */
306 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
308 /* Store the value in SS:SP */
309 return Fast486WriteMemory(State,
311 State->GeneralRegs[FAST486_REG_ESP].LowWord,
319 Fast486StackPop(PFAST486_STATE State,
322 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
324 /* The OPSIZE prefix toggles the size */
332 /* Check if ESP is 0xFFFFFFFF */
333 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
335 Fast486Exception(State, FAST486_EXCEPTION_SS);
339 /* Read the value from SS:ESP */
340 if (!Fast486ReadMemory(State,
342 State->GeneralRegs[FAST486_REG_ESP].Long,
347 /* An exception occurred */
351 /* Increment ESP by 4 */
352 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
354 /* Store the value in the result */
362 /* Check if SP is 0xFFFF */
363 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
365 Fast486Exception(State, FAST486_EXCEPTION_SS);
369 /* Read the value from SS:SP */
370 if (!Fast486ReadMemory(State,
372 State->GeneralRegs[FAST486_REG_ESP].LowWord,
377 /* An exception occurred */
381 /* Increment SP by 2 */
382 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
384 /* Store the value in the result */
393 Fast486LoadSegment(PFAST486_STATE State,
394 FAST486_SEG_REGS Segment,
397 PFAST486_SEG_REG CachedDescriptor;
398 FAST486_GDT_ENTRY GdtEntry;
400 ASSERT(Segment < FAST486_NUM_SEG_REGS);
402 /* Get the cached descriptor */
403 CachedDescriptor = &State->SegmentRegs[Segment];
405 /* Check for protected mode */
406 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
408 if (!(Selector & SEGMENT_TABLE_INDICATOR))
410 /* Make sure the GDT contains the entry */
411 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
413 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
418 if (!Fast486ReadLinearMemory(State,
420 + GET_SEGMENT_INDEX(Selector),
424 /* Exception occurred */
430 /* Make sure the LDT contains the entry */
431 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
433 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
438 if (!Fast486ReadLinearMemory(State,
440 + GET_SEGMENT_INDEX(Selector),
444 /* Exception occurred */
449 if (Segment == FAST486_REG_SS)
451 /* Loading the stack segment */
453 if (GET_SEGMENT_INDEX(Selector) == 0)
455 Fast486Exception(State, FAST486_EXCEPTION_GP);
459 if (!GdtEntry.SystemType)
461 /* This is a special descriptor */
462 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
466 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
468 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
472 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
473 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
475 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
479 if (!GdtEntry.Present)
481 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
485 else if (Segment == FAST486_REG_CS)
487 /* Loading the code segment */
489 if (GET_SEGMENT_INDEX(Selector) == 0)
491 Fast486Exception(State, FAST486_EXCEPTION_GP);
495 if (!GdtEntry.SystemType)
497 // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
502 if (!GdtEntry.Present)
504 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
508 if (!GdtEntry.Executable)
510 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
514 if (GdtEntry.DirConf)
516 /* Conforming Code Segment */
518 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
520 /* Must be accessed from lower-privileged code */
521 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
527 /* Regular code segment */
529 if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
530 || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
532 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
538 State->Cpl = GET_SEGMENT_RPL(Selector);
543 /* Loading a data segment */
545 if (!GdtEntry.SystemType)
547 /* This is a special descriptor */
548 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
552 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
553 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
555 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
559 if (!GdtEntry.Present)
561 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
566 /* Update the cache entry */
567 CachedDescriptor->Selector = Selector;
568 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
569 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
570 CachedDescriptor->Accessed = GdtEntry.Accessed;
571 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
572 CachedDescriptor->DirConf = GdtEntry.DirConf;
573 CachedDescriptor->Executable = GdtEntry.Executable;
574 CachedDescriptor->SystemType = GdtEntry.SystemType;
575 CachedDescriptor->Dpl = GdtEntry.Dpl;
576 CachedDescriptor->Present = GdtEntry.Present;
577 CachedDescriptor->Size = GdtEntry.Size;
579 /* Check for page granularity */
580 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
584 /* Update the selector and base */
585 CachedDescriptor->Selector = Selector;
586 CachedDescriptor->Base = Selector << 4;
594 Fast486FetchByte(PFAST486_STATE State,
597 PFAST486_SEG_REG CachedDescriptor;
599 /* Get the cached descriptor of CS */
600 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
602 /* Read from memory */
603 if (!Fast486ReadMemory(State,
605 (CachedDescriptor->Size) ? State->InstPtr.Long
606 : State->InstPtr.LowWord,
611 /* Exception occurred during instruction fetch */
615 /* Advance the instruction pointer */
616 if (CachedDescriptor->Size) State->InstPtr.Long++;
617 else State->InstPtr.LowWord++;
624 Fast486FetchWord(PFAST486_STATE State,
627 PFAST486_SEG_REG CachedDescriptor;
629 /* Get the cached descriptor of CS */
630 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
632 /* Read from memory */
633 // FIXME: Fix byte order on big-endian machines
634 if (!Fast486ReadMemory(State,
636 (CachedDescriptor->Size) ? State->InstPtr.Long
637 : State->InstPtr.LowWord,
642 /* Exception occurred during instruction fetch */
646 /* Advance the instruction pointer */
647 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
648 else State->InstPtr.LowWord += sizeof(USHORT);
655 Fast486FetchDword(PFAST486_STATE State,
658 PFAST486_SEG_REG CachedDescriptor;
660 /* Get the cached descriptor of CS */
661 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
663 /* Read from memory */
664 // FIXME: Fix byte order on big-endian machines
665 if (!Fast486ReadMemory(State,
667 (CachedDescriptor->Size) ? State->InstPtr.Long
668 : State->InstPtr.LowWord,
673 /* Exception occurred during instruction fetch */
677 /* Advance the instruction pointer */
678 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
679 else State->InstPtr.LowWord += sizeof(ULONG);
686 Fast486GetIntVector(PFAST486_STATE State,
688 PFAST486_IDT_ENTRY IdtEntry)
692 /* Check for protected mode */
693 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
695 /* Read from the IDT */
696 if (!Fast486ReadLinearMemory(State,
698 + Number * sizeof(*IdtEntry),
702 /* Exception occurred */
708 /* Read from the real-mode IVT */
710 /* Paging is always disabled in real mode */
711 State->MemReadCallback(State,
713 + Number * sizeof(FarPointer),
717 /* Fill a fake IDT entry */
718 IdtEntry->Offset = LOWORD(FarPointer);
719 IdtEntry->Selector = HIWORD(FarPointer);
721 IdtEntry->Type = FAST486_IDT_INT_GATE;
722 IdtEntry->Storage = FALSE;
724 IdtEntry->Present = TRUE;
725 IdtEntry->OffsetHigh = 0;
733 Fast486CalculateParity(UCHAR Number)
735 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
736 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
741 Fast486ParseModRegRm(PFAST486_STATE State,
743 PFAST486_MOD_REG_RM ModRegRm)
745 UCHAR ModRmByte, Mode, RegMem;
747 /* Fetch the MOD REG R/M byte */
748 if (!Fast486FetchByte(State, &ModRmByte))
750 /* Exception occurred */
754 /* Unpack the mode and R/M */
755 Mode = ModRmByte >> 6;
756 RegMem = ModRmByte & 0x07;
758 /* Set the register operand */
759 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
762 if ((ModRmByte >> 6) == 3)
764 /* The second operand is also a register */
765 ModRegRm->Memory = FALSE;
766 ModRegRm->SecondRegister = RegMem;
772 /* The second operand is memory */
773 ModRegRm->Memory = TRUE;
777 if (RegMem == FAST486_REG_ESP)
780 ULONG Scale, Index, Base;
782 /* Fetch the SIB byte */
783 if (!Fast486FetchByte(State, &SibByte))
785 /* Exception occurred */
789 /* Unpack the scale, index and base */
790 Scale = 1 << (SibByte >> 6);
791 Index = (SibByte >> 3) & 0x07;
792 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
795 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
797 /* Use the register a base */
798 Base = State->GeneralRegs[SibByte & 0x07].Long;
803 if (!Fast486FetchDword(State, &Base))
805 /* Exception occurred */
810 if ((SibByte & 0x07) == FAST486_REG_ESP)
812 /* Check if there is no segment override */
813 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
815 /* Add a SS: prefix */
816 State->PrefixFlags |= FAST486_PREFIX_SEG;
817 State->SegmentOverride = FAST486_REG_SS;
821 /* Calculate the address */
822 ModRegRm->MemoryAddress = Base + Index * Scale;
824 else if (RegMem == FAST486_REG_EBP)
826 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
827 else ModRegRm->MemoryAddress = 0;
831 /* Get the base from the register */
832 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
835 /* Check if there is no segment override */
836 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
838 /* Check if the default segment should be SS */
839 if ((RegMem == FAST486_REG_EBP) && Mode)
841 /* Add a SS: prefix */
842 State->PrefixFlags |= FAST486_PREFIX_SEG;
843 State->SegmentOverride = FAST486_REG_SS;
852 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
854 /* Exception occurred */
858 /* Add the signed offset to the address */
859 ModRegRm->MemoryAddress += (LONG)Offset;
861 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
865 /* Fetch the dword */
866 if (!Fast486FetchDword(State, (PULONG)&Offset))
868 /* Exception occurred */
872 /* Add the signed offset to the address */
873 ModRegRm->MemoryAddress += Offset;
878 /* Check the operand */
884 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
885 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
893 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
894 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
902 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
903 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
911 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
912 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
920 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
928 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
938 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
942 /* [constant] (added later) */
943 ModRegRm->MemoryAddress = 0;
952 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
958 /* Check if there is no segment override */
959 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
961 /* Check if the default segment should be SS */
962 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
964 /* Add a SS: prefix */
965 State->PrefixFlags |= FAST486_PREFIX_SEG;
966 State->SegmentOverride = FAST486_REG_SS;
975 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
977 /* Exception occurred */
981 /* Add the signed offset to the address */
982 ModRegRm->MemoryAddress += (LONG)Offset;
984 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
989 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
991 /* Exception occurred */
995 /* Add the signed offset to the address */
996 ModRegRm->MemoryAddress += (LONG)Offset;
999 /* Clear the top 16 bits */
1000 ModRegRm->MemoryAddress &= 0x0000FFFF;
1008 Fast486ReadModrmByteOperands(PFAST486_STATE State,
1009 PFAST486_MOD_REG_RM ModRegRm,
1013 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1017 /* Get the register value */
1018 if (ModRegRm->Register & 0x04)
1020 /* AH, CH, DH, BH */
1021 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
1025 /* AL, CL, DL, BL */
1026 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
1032 if (!ModRegRm->Memory)
1034 /* Get the second register value */
1035 if (ModRegRm->SecondRegister & 0x04)
1037 /* AH, CH, DH, BH */
1038 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1042 /* AL, CL, DL, BL */
1043 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1048 /* Check for the segment override */
1049 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1051 /* Use the override segment instead */
1052 Segment = State->SegmentOverride;
1056 if (!Fast486ReadMemory(State,
1058 ModRegRm->MemoryAddress,
1063 /* Exception occurred */
1074 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1075 PFAST486_MOD_REG_RM ModRegRm,
1079 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1083 /* Get the register value */
1084 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1089 if (!ModRegRm->Memory)
1091 /* Get the second register value */
1092 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1096 /* Check for the segment override */
1097 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1099 /* Use the override segment instead */
1100 Segment = State->SegmentOverride;
1104 if (!Fast486ReadMemory(State,
1106 ModRegRm->MemoryAddress,
1111 /* Exception occurred */
1122 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1123 PFAST486_MOD_REG_RM ModRegRm,
1127 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1131 /* Get the register value */
1132 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1137 if (!ModRegRm->Memory)
1139 /* Get the second register value */
1140 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1144 /* Check for the segment override */
1145 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1147 /* Use the override segment instead */
1148 Segment = State->SegmentOverride;
1152 if (!Fast486ReadMemory(State,
1154 ModRegRm->MemoryAddress,
1159 /* Exception occurred */
1170 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1171 PFAST486_MOD_REG_RM ModRegRm,
1172 BOOLEAN WriteRegister,
1175 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1179 /* Store the value in the register */
1180 if (ModRegRm->Register & 0x04)
1182 /* AH, CH, DH, BH */
1183 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1187 /* AL, CL, DL, BL */
1188 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1193 if (!ModRegRm->Memory)
1195 /* Store the value in the second register */
1196 if (ModRegRm->SecondRegister & 0x04)
1198 /* AH, CH, DH, BH */
1199 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1203 /* AL, CL, DL, BL */
1204 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1209 /* Check for the segment override */
1210 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1212 /* Use the override segment instead */
1213 Segment = State->SegmentOverride;
1217 if (!Fast486WriteMemory(State,
1219 ModRegRm->MemoryAddress,
1223 /* Exception occurred */
1234 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1235 PFAST486_MOD_REG_RM ModRegRm,
1236 BOOLEAN WriteRegister,
1239 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1243 /* Store the value in the register */
1244 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1248 if (!ModRegRm->Memory)
1250 /* Store the value in the second register */
1251 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1255 /* Check for the segment override */
1256 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1258 /* Use the override segment instead */
1259 Segment = State->SegmentOverride;
1263 if (!Fast486WriteMemory(State,
1265 ModRegRm->MemoryAddress,
1269 /* Exception occurred */
1280 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1281 PFAST486_MOD_REG_RM ModRegRm,
1282 BOOLEAN WriteRegister,
1285 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1289 /* Store the value in the register */
1290 State->GeneralRegs[ModRegRm->Register].Long = Value;
1294 if (!ModRegRm->Memory)
1296 /* Store the value in the second register */
1297 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1301 /* Check for the segment override */
1302 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1304 /* Use the override segment instead */
1305 Segment = State->SegmentOverride;
1309 if (!Fast486WriteMemory(State,
1311 ModRegRm->MemoryAddress,
1315 /* Exception occurred */