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 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
32 /* In protected mode, return the RPL of the CS */
33 return GET_SEGMENT_RPL(State->SegmentRegs[FAST486_REG_CS].Selector);
37 /* Real mode is always in supervisor mode */
44 Fast486GetPageTableEntry(PFAST486_STATE State,
48 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
49 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
50 FAST486_PAGE_DIR DirectoryEntry;
51 FAST486_PAGE_TABLE TableEntry;
52 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
54 if ((State->Tlb != NULL)
55 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
57 /* Return the cached entry */
58 return State->Tlb[VirtualAddress >> 12];
61 /* Read the directory entry */
62 State->MemReadCallback(State,
63 PageDirectory + PdeIndex * sizeof(ULONG),
64 &DirectoryEntry.Value,
65 sizeof(DirectoryEntry));
67 /* Make sure it is present */
68 if (!DirectoryEntry.Present) return 0;
70 /* Was the directory entry accessed before? */
71 if (!DirectoryEntry.Accessed)
74 DirectoryEntry.Accessed = TRUE;
76 /* Write back the directory entry */
77 State->MemWriteCallback(State,
78 PageDirectory + PdeIndex * sizeof(ULONG),
79 &DirectoryEntry.Value,
80 sizeof(DirectoryEntry));
83 /* Read the table entry */
84 State->MemReadCallback(State,
85 (DirectoryEntry.TableAddress << 12)
86 + PteIndex * sizeof(ULONG),
90 /* Make sure it is present */
91 if (!TableEntry.Present) return 0;
93 if (MarkAsDirty) TableEntry.Dirty = TRUE;
95 /* Was the table entry accessed before? */
96 if (!TableEntry.Accessed)
99 TableEntry.Accessed = TRUE;
101 /* Write back the table entry */
102 State->MemWriteCallback(State,
103 (DirectoryEntry.TableAddress << 12)
104 + PteIndex * sizeof(ULONG),
110 * The resulting permissions depend on the permissions
111 * in the page directory table too
113 TableEntry.Writeable &= DirectoryEntry.Writeable;
114 TableEntry.Usermode &= DirectoryEntry.Usermode;
116 if (State->Tlb != NULL)
118 /* Set the TLB entry */
119 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
122 /* Return the table entry */
123 return TableEntry.Value;
128 Fast486ReadLinearMemory(PFAST486_STATE State,
133 INT Cpl = Fast486GetCurrentPrivLevel(State);
135 /* Check if paging is enabled */
136 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
139 FAST486_PAGE_TABLE TableEntry;
141 for (Page = PAGE_ALIGN(LinearAddress);
142 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
145 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
147 /* Get the table entry */
148 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
150 if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
153 Fast486ExceptionWithErrorCode(State,
154 FAST486_EXCEPTION_PF,
155 TableEntry.Value & 0x07);
159 /* Check if this is the first page */
160 if (Page == PAGE_ALIGN(LinearAddress))
162 /* Start copying from the offset from the beginning of the page */
163 PageOffset = PAGE_OFFSET(LinearAddress);
166 /* Check if this is the last page */
167 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
169 /* Copy only a part of the page */
170 PageLength = PAGE_OFFSET(LinearAddress + Size);
173 /* Read the memory */
174 State->MemReadCallback(State,
175 (TableEntry.Address << 12) | PageOffset,
182 /* Read the memory */
183 State->MemReadCallback(State, LinearAddress, Buffer, Size);
191 Fast486WriteLinearMemory(PFAST486_STATE State,
196 INT Cpl = Fast486GetCurrentPrivLevel(State);
198 /* Check if paging is enabled */
199 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
202 FAST486_PAGE_TABLE TableEntry;
204 for (Page = PAGE_ALIGN(LinearAddress);
205 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
208 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
210 /* Get the table entry */
211 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
213 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
214 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
215 && !TableEntry.Writeable))
218 Fast486ExceptionWithErrorCode(State,
219 FAST486_EXCEPTION_PF,
220 TableEntry.Value & 0x07);
224 /* Check if this is the first page */
225 if (Page == PAGE_ALIGN(LinearAddress))
227 /* Start copying from the offset from the beginning of the page */
228 PageOffset = PAGE_OFFSET(LinearAddress);
231 /* Check if this is the last page */
232 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
234 /* Copy only a part of the page */
235 PageLength = PAGE_OFFSET(LinearAddress + Size);
238 /* Write the memory */
239 State->MemWriteCallback(State,
240 (TableEntry.Address << 12) | PageOffset,
247 /* Write the memory */
248 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
256 Fast486Exception(PFAST486_STATE State,
257 FAST486_EXCEPTIONS ExceptionCode)
259 /* Call the internal function */
260 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
265 Fast486StackPush(PFAST486_STATE State,
268 BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
270 /* The OPSIZE prefix toggles the size */
271 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
277 /* Check if ESP is between 1 and 3 */
278 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
279 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
281 Fast486Exception(State, FAST486_EXCEPTION_SS);
285 /* Subtract ESP by 4 */
286 State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
288 /* Store the value in SS:ESP */
289 return Fast486WriteMemory(State,
291 State->GeneralRegs[FAST486_REG_ESP].Long,
298 USHORT ShortValue = LOWORD(Value);
300 /* Check if SP is 1 */
301 if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
303 Fast486Exception(State, FAST486_EXCEPTION_SS);
307 /* Subtract SP by 2 */
308 State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
310 /* Store the value in SS:SP */
311 return Fast486WriteMemory(State,
313 State->GeneralRegs[FAST486_REG_ESP].LowWord,
321 Fast486StackPop(PFAST486_STATE State,
326 BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
328 /* The OPSIZE prefix toggles the size */
329 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
335 /* Check if ESP is 0xFFFFFFFF */
336 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
338 Fast486Exception(State, FAST486_EXCEPTION_SS);
342 /* Read the value from SS:ESP */
343 if (!Fast486ReadMemory(State,
345 State->GeneralRegs[FAST486_REG_ESP].Long,
350 /* An exception occurred */
354 /* Increment ESP by 4 */
355 State->GeneralRegs[FAST486_REG_ESP].Long += 4;
357 /* Store the value in the result */
364 /* Check if SP is 0xFFFF */
365 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
367 Fast486Exception(State, FAST486_EXCEPTION_SS);
371 /* Read the value from SS:SP */
372 if (!Fast486ReadMemory(State,
374 State->GeneralRegs[FAST486_REG_ESP].LowWord,
379 /* An exception occurred */
383 /* Increment SP by 2 */
384 State->GeneralRegs[FAST486_REG_ESP].LowWord += 2;
386 /* Store the value in the result */
395 Fast486LoadSegment(PFAST486_STATE State,
399 PFAST486_SEG_REG CachedDescriptor;
400 FAST486_GDT_ENTRY GdtEntry;
402 ASSERT(Segment < FAST486_NUM_SEG_REGS);
404 /* Get the cached descriptor */
405 CachedDescriptor = &State->SegmentRegs[Segment];
407 /* Check for protected mode */
408 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
410 /* Make sure the GDT contains the entry */
411 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
413 Fast486Exception(State, FAST486_EXCEPTION_GP);
418 if (!Fast486ReadLinearMemory(State,
420 + GET_SEGMENT_INDEX(Selector),
424 /* Exception occurred */
428 if (Segment == FAST486_REG_SS)
430 /* Loading the stack segment */
432 if (GET_SEGMENT_INDEX(Selector) == 0)
434 Fast486Exception(State, FAST486_EXCEPTION_GP);
438 if (!GdtEntry.SystemType)
440 /* This is a special descriptor */
441 Fast486Exception(State, FAST486_EXCEPTION_GP);
445 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
447 Fast486Exception(State, FAST486_EXCEPTION_GP);
451 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
452 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
454 Fast486Exception(State, FAST486_EXCEPTION_GP);
458 if (!GdtEntry.Present)
460 Fast486Exception(State, FAST486_EXCEPTION_SS);
464 else if (Segment == FAST486_REG_CS)
466 /* Loading the code segment */
467 // TODO: NOT IMPLEMENTED
471 /* Loading a data segment */
473 if (!GdtEntry.SystemType)
475 /* This is a special descriptor */
476 Fast486Exception(State, FAST486_EXCEPTION_GP);
480 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
481 && (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
483 Fast486Exception(State, FAST486_EXCEPTION_GP);
487 if (!GdtEntry.Present)
489 Fast486Exception(State, FAST486_EXCEPTION_NP);
494 /* Update the cache entry */
495 CachedDescriptor->Selector = Selector;
496 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
497 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
498 CachedDescriptor->Accessed = GdtEntry.Accessed;
499 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
500 CachedDescriptor->DirConf = GdtEntry.DirConf;
501 CachedDescriptor->Executable = GdtEntry.Executable;
502 CachedDescriptor->SystemType = GdtEntry.SystemType;
503 CachedDescriptor->Dpl = GdtEntry.Dpl;
504 CachedDescriptor->Present = GdtEntry.Present;
505 CachedDescriptor->Size = GdtEntry.Size;
507 /* Check for page granularity */
508 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
512 /* Update the selector and base */
513 CachedDescriptor->Selector = Selector;
514 CachedDescriptor->Base = Selector << 4;
522 Fast486FetchByte(PFAST486_STATE State,
525 PFAST486_SEG_REG CachedDescriptor;
527 /* Get the cached descriptor of CS */
528 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
530 /* Read from memory */
531 if (!Fast486ReadMemory(State,
533 (CachedDescriptor->Size) ? State->InstPtr.Long
534 : State->InstPtr.LowWord,
539 /* Exception occurred during instruction fetch */
543 /* Advance the instruction pointer */
544 if (CachedDescriptor->Size) State->InstPtr.Long++;
545 else State->InstPtr.LowWord++;
552 Fast486FetchWord(PFAST486_STATE State,
555 PFAST486_SEG_REG CachedDescriptor;
557 /* Get the cached descriptor of CS */
558 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
560 /* Read from memory */
561 // FIXME: Fix byte order on big-endian machines
562 if (!Fast486ReadMemory(State,
564 (CachedDescriptor->Size) ? State->InstPtr.Long
565 : State->InstPtr.LowWord,
570 /* Exception occurred during instruction fetch */
574 /* Advance the instruction pointer */
575 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
576 else State->InstPtr.LowWord += sizeof(USHORT);
583 Fast486FetchDword(PFAST486_STATE State,
586 PFAST486_SEG_REG CachedDescriptor;
588 /* Get the cached descriptor of CS */
589 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
591 /* Read from memory */
592 // FIXME: Fix byte order on big-endian machines
593 if (!Fast486ReadMemory(State,
595 (CachedDescriptor->Size) ? State->InstPtr.Long
596 : State->InstPtr.LowWord,
601 /* Exception occurred during instruction fetch */
605 /* Advance the instruction pointer */
606 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
607 else State->InstPtr.LowWord += sizeof(ULONG);
614 Fast486GetIntVector(PFAST486_STATE State,
616 PFAST486_IDT_ENTRY IdtEntry)
620 /* Check for protected mode */
621 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
623 /* Read from the IDT */
624 if (!Fast486ReadLinearMemory(State,
626 + Number * sizeof(*IdtEntry),
630 /* Exception occurred */
636 /* Read from the real-mode IVT */
638 /* Paging is always disabled in real mode */
639 State->MemReadCallback(State,
641 + Number * sizeof(FarPointer),
645 /* Fill a fake IDT entry */
646 IdtEntry->Offset = LOWORD(FarPointer);
647 IdtEntry->Selector = HIWORD(FarPointer);
649 IdtEntry->Type = FAST486_IDT_INT_GATE;
650 IdtEntry->Storage = FALSE;
652 IdtEntry->Present = TRUE;
653 IdtEntry->OffsetHigh = 0;
661 Fast486CalculateParity(UCHAR Number)
663 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
664 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
669 Fast486ParseModRegRm(PFAST486_STATE State,
671 PFAST486_MOD_REG_RM ModRegRm)
673 UCHAR ModRmByte, Mode, RegMem;
675 /* Fetch the MOD REG R/M byte */
676 if (!Fast486FetchByte(State, &ModRmByte))
678 /* Exception occurred */
682 /* Unpack the mode and R/M */
683 Mode = ModRmByte >> 6;
684 RegMem = ModRmByte & 0x07;
686 /* Set the register operand */
687 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
690 if ((ModRmByte >> 6) == 3)
692 /* The second operand is also a register */
693 ModRegRm->Memory = FALSE;
694 ModRegRm->SecondRegister = RegMem;
700 /* The second operand is memory */
701 ModRegRm->Memory = TRUE;
705 if (RegMem == FAST486_REG_ESP)
708 ULONG Scale, Index, Base;
710 /* Fetch the SIB byte */
711 if (!Fast486FetchByte(State, &SibByte))
713 /* Exception occurred */
717 /* Unpack the scale, index and base */
718 Scale = 1 << (SibByte >> 6);
719 Index = (SibByte >> 3) & 0x07;
720 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
723 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
725 /* Use the register a base */
726 Base = State->GeneralRegs[SibByte & 0x07].Long;
731 if (!Fast486FetchDword(State, &Base))
733 /* Exception occurred */
738 /* Calculate the address */
739 ModRegRm->MemoryAddress = Base + Index * Scale;
741 else if (RegMem == FAST486_REG_EBP)
743 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
744 else ModRegRm->MemoryAddress = 0;
748 /* Get the base from the register */
749 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
752 /* Check if there is no segment override */
753 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
755 /* Check if the default segment should be SS */
756 if ((RegMem == FAST486_REG_EBP) && Mode)
758 /* Add a SS: prefix */
759 State->PrefixFlags |= FAST486_PREFIX_SEG;
760 State->SegmentOverride = FAST486_REG_SS;
769 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
771 /* Exception occurred */
775 /* Add the signed offset to the address */
776 ModRegRm->MemoryAddress += (LONG)Offset;
778 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
782 /* Fetch the dword */
783 if (!Fast486FetchDword(State, (PULONG)&Offset))
785 /* Exception occurred */
789 /* Add the signed offset to the address */
790 ModRegRm->MemoryAddress += Offset;
795 /* Check the operand */
801 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
802 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
810 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
811 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
819 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
820 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
828 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
829 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
837 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
845 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
855 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
859 /* [constant] (added later) */
860 ModRegRm->MemoryAddress = 0;
869 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
875 /* Check if there is no segment override */
876 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
878 /* Check if the default segment should be SS */
879 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
881 /* Add a SS: prefix */
882 State->PrefixFlags |= FAST486_PREFIX_SEG;
883 State->SegmentOverride = FAST486_REG_SS;
892 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
894 /* Exception occurred */
898 /* Add the signed offset to the address */
899 ModRegRm->MemoryAddress += (LONG)Offset;
901 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
906 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
908 /* Exception occurred */
912 /* Add the signed offset to the address */
913 ModRegRm->MemoryAddress += (LONG)Offset;
916 /* Clear the top 16 bits */
917 ModRegRm->MemoryAddress &= 0x0000FFFF;
925 Fast486ReadModrmByteOperands(PFAST486_STATE State,
926 PFAST486_MOD_REG_RM ModRegRm,
930 FAST486_SEG_REGS Segment = FAST486_REG_DS;
932 /* Get the register value */
933 if (ModRegRm->Register & 0x04)
936 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
941 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
944 if (!ModRegRm->Memory)
946 /* Get the second register value */
947 if (ModRegRm->SecondRegister & 0x04)
950 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
955 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
960 /* Check for the segment override */
961 if (State->PrefixFlags & FAST486_PREFIX_SEG)
963 /* Use the override segment instead */
964 Segment = State->SegmentOverride;
968 if (!Fast486ReadMemory(State,
970 ModRegRm->MemoryAddress,
975 /* Exception occurred */
985 Fast486ReadModrmWordOperands(PFAST486_STATE State,
986 PFAST486_MOD_REG_RM ModRegRm,
990 FAST486_SEG_REGS Segment = FAST486_REG_DS;
992 /* Get the register value */
993 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
995 if (!ModRegRm->Memory)
997 /* Get the second register value */
998 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1002 /* Check for the segment override */
1003 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1005 /* Use the override segment instead */
1006 Segment = State->SegmentOverride;
1010 if (!Fast486ReadMemory(State,
1012 ModRegRm->MemoryAddress,
1017 /* Exception occurred */
1027 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1028 PFAST486_MOD_REG_RM ModRegRm,
1032 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1034 /* Get the register value */
1035 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1037 if (!ModRegRm->Memory)
1039 /* Get the second register value */
1040 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1044 /* Check for the segment override */
1045 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1047 /* Use the override segment instead */
1048 Segment = State->SegmentOverride;
1052 if (!Fast486ReadMemory(State,
1054 ModRegRm->MemoryAddress,
1059 /* Exception occurred */
1069 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1070 PFAST486_MOD_REG_RM ModRegRm,
1071 BOOLEAN WriteRegister,
1074 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1078 /* Store the value in the register */
1079 if (ModRegRm->Register & 0x04)
1081 /* AH, CH, DH, BH */
1082 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1086 /* AL, CL, DL, BL */
1087 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1092 if (!ModRegRm->Memory)
1094 /* Store the value in the second register */
1095 if (ModRegRm->SecondRegister & 0x04)
1097 /* AH, CH, DH, BH */
1098 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1102 /* AL, CL, DL, BL */
1103 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1108 /* Check for the segment override */
1109 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1111 /* Use the override segment instead */
1112 Segment = State->SegmentOverride;
1116 if (!Fast486WriteMemory(State,
1118 ModRegRm->MemoryAddress,
1122 /* Exception occurred */
1133 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1134 PFAST486_MOD_REG_RM ModRegRm,
1135 BOOLEAN WriteRegister,
1138 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1142 /* Store the value in the register */
1143 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1147 if (!ModRegRm->Memory)
1149 /* Store the value in the second register */
1150 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1154 /* Check for the segment override */
1155 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1157 /* Use the override segment instead */
1158 Segment = State->SegmentOverride;
1162 if (!Fast486WriteMemory(State,
1164 ModRegRm->MemoryAddress,
1168 /* Exception occurred */
1179 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1180 PFAST486_MOD_REG_RM ModRegRm,
1181 BOOLEAN WriteRegister,
1184 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1188 /* Store the value in the register */
1189 State->GeneralRegs[ModRegRm->Register].Long = Value;
1193 if (!ModRegRm->Memory)
1195 /* Store the value in the second register */
1196 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1200 /* Check for the segment override */
1201 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1203 /* Use the override segment instead */
1204 Segment = State->SegmentOverride;
1208 if (!Fast486WriteMemory(State,
1210 ModRegRm->MemoryAddress,
1214 /* Exception occurred */