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 INT Cpl = Fast486GetCurrentPrivLevel(State);
127 /* Check if paging is enabled */
128 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
131 FAST486_PAGE_TABLE TableEntry;
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 copying from the offset from the beginning of the page */
155 PageOffset = PAGE_OFFSET(LinearAddress);
158 /* Check if this is the last page */
159 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
161 /* Copy only a part of the page */
162 PageLength = PAGE_OFFSET(LinearAddress + Size);
165 /* Read the memory */
166 State->MemReadCallback(State,
167 (TableEntry.Address << 12) | PageOffset,
174 /* Read the memory */
175 State->MemReadCallback(State, LinearAddress, Buffer, Size);
183 Fast486WriteLinearMemory(PFAST486_STATE State,
188 INT Cpl = Fast486GetCurrentPrivLevel(State);
190 /* Check if paging is enabled */
191 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
194 FAST486_PAGE_TABLE TableEntry;
196 for (Page = PAGE_ALIGN(LinearAddress);
197 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
200 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
202 /* Get the table entry */
203 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
205 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
206 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
207 && !TableEntry.Writeable))
210 Fast486ExceptionWithErrorCode(State,
211 FAST486_EXCEPTION_PF,
212 TableEntry.Value & 0x07);
216 /* Check if this is the first page */
217 if (Page == PAGE_ALIGN(LinearAddress))
219 /* Start copying from the offset from the beginning of the page */
220 PageOffset = PAGE_OFFSET(LinearAddress);
223 /* Check if this is the last page */
224 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
226 /* Copy only a part of the page */
227 PageLength = PAGE_OFFSET(LinearAddress + Size);
230 /* Write the memory */
231 State->MemWriteCallback(State,
232 (TableEntry.Address << 12) | PageOffset,
239 /* Write the memory */
240 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
248 Fast486Exception(PFAST486_STATE State,
249 FAST486_EXCEPTIONS ExceptionCode)
251 /* Call the internal function */
252 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
257 Fast486StackPush(PFAST486_STATE State,
260 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
262 /* The OPSIZE prefix toggles the size */
263 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
269 /* Check if ESP is between 1 and 3 */
270 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
271 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
273 Fast486Exception(State, FAST486_EXCEPTION_SS);
277 /* Subtract ESP by 4 */
278 State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
280 /* Store the value in SS:ESP */
281 return Fast486WriteMemory(State,
283 State->GeneralRegs[FAST486_REG_ESP].Long,
290 USHORT ShortValue = LOWORD(Value);
292 /* Check if SP is 1 */
293 if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
295 Fast486Exception(State, FAST486_EXCEPTION_SS);
299 /* Subtract SP by 2 */
300 State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
302 /* Store the value in SS:SP */
303 return Fast486WriteMemory(State,
305 State->GeneralRegs[FAST486_REG_ESP].LowWord,
313 Fast486StackPop(PFAST486_STATE State,
318 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
320 /* The OPSIZE prefix toggles the size */
327 /* Check if ESP is 0xFFFFFFFF */
328 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
330 Fast486Exception(State, FAST486_EXCEPTION_SS);
334 /* Read the value from SS:ESP */
335 if (!Fast486ReadMemory(State,
337 State->GeneralRegs[FAST486_REG_ESP].Long,
342 /* An exception occurred */
346 /* Increment ESP by 4 */
347 State->GeneralRegs[FAST486_REG_ESP].Long += 4;
349 /* Store the value in the result */
356 /* Check if SP is 0xFFFF */
357 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
359 Fast486Exception(State, FAST486_EXCEPTION_SS);
363 /* Read the value from SS:SP */
364 if (!Fast486ReadMemory(State,
366 State->GeneralRegs[FAST486_REG_ESP].LowWord,
371 /* An exception occurred */
375 /* Increment SP by 2 */
376 State->GeneralRegs[FAST486_REG_ESP].LowWord += 2;
378 /* Store the value in the result */
387 Fast486LoadSegment(PFAST486_STATE State,
391 PFAST486_SEG_REG CachedDescriptor;
392 FAST486_GDT_ENTRY GdtEntry;
394 ASSERT(Segment < FAST486_NUM_SEG_REGS);
396 /* Get the cached descriptor */
397 CachedDescriptor = &State->SegmentRegs[Segment];
399 /* Check for protected mode */
400 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
402 /* Make sure the GDT contains the entry */
403 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
405 Fast486Exception(State, FAST486_EXCEPTION_GP);
410 if (!Fast486ReadLinearMemory(State,
412 + GET_SEGMENT_INDEX(Selector),
416 /* Exception occurred */
420 if (Segment == FAST486_REG_SS)
422 /* Loading the stack segment */
424 if (GET_SEGMENT_INDEX(Selector) == 0)
426 Fast486Exception(State, FAST486_EXCEPTION_GP);
430 if (!GdtEntry.SystemType)
432 /* This is a special descriptor */
433 Fast486Exception(State, FAST486_EXCEPTION_GP);
437 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
439 Fast486Exception(State, FAST486_EXCEPTION_GP);
443 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
444 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
446 Fast486Exception(State, FAST486_EXCEPTION_GP);
450 if (!GdtEntry.Present)
452 Fast486Exception(State, FAST486_EXCEPTION_SS);
456 else if (Segment == FAST486_REG_CS)
458 /* Loading the code segment */
459 // TODO: Implement security checks, call gates, etc...
462 State->Cpl = GET_SEGMENT_RPL(Selector);
466 /* Loading a data segment */
468 if (!GdtEntry.SystemType)
470 /* This is a special descriptor */
471 Fast486Exception(State, FAST486_EXCEPTION_GP);
475 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
476 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
478 Fast486Exception(State, FAST486_EXCEPTION_GP);
482 if (!GdtEntry.Present)
484 Fast486Exception(State, FAST486_EXCEPTION_NP);
489 /* Update the cache entry */
490 CachedDescriptor->Selector = Selector;
491 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
492 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
493 CachedDescriptor->Accessed = GdtEntry.Accessed;
494 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
495 CachedDescriptor->DirConf = GdtEntry.DirConf;
496 CachedDescriptor->Executable = GdtEntry.Executable;
497 CachedDescriptor->SystemType = GdtEntry.SystemType;
498 CachedDescriptor->Dpl = GdtEntry.Dpl;
499 CachedDescriptor->Present = GdtEntry.Present;
500 CachedDescriptor->Size = GdtEntry.Size;
502 /* Check for page granularity */
503 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
507 /* Update the selector and base */
508 CachedDescriptor->Selector = Selector;
509 CachedDescriptor->Base = Selector << 4;
517 Fast486FetchByte(PFAST486_STATE State,
520 PFAST486_SEG_REG CachedDescriptor;
522 /* Get the cached descriptor of CS */
523 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
525 /* Read from memory */
526 if (!Fast486ReadMemory(State,
528 (CachedDescriptor->Size) ? State->InstPtr.Long
529 : State->InstPtr.LowWord,
534 /* Exception occurred during instruction fetch */
538 /* Advance the instruction pointer */
539 if (CachedDescriptor->Size) State->InstPtr.Long++;
540 else State->InstPtr.LowWord++;
547 Fast486FetchWord(PFAST486_STATE State,
550 PFAST486_SEG_REG CachedDescriptor;
552 /* Get the cached descriptor of CS */
553 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
555 /* Read from memory */
556 // FIXME: Fix byte order on big-endian machines
557 if (!Fast486ReadMemory(State,
559 (CachedDescriptor->Size) ? State->InstPtr.Long
560 : State->InstPtr.LowWord,
565 /* Exception occurred during instruction fetch */
569 /* Advance the instruction pointer */
570 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
571 else State->InstPtr.LowWord += sizeof(USHORT);
578 Fast486FetchDword(PFAST486_STATE State,
581 PFAST486_SEG_REG CachedDescriptor;
583 /* Get the cached descriptor of CS */
584 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
586 /* Read from memory */
587 // FIXME: Fix byte order on big-endian machines
588 if (!Fast486ReadMemory(State,
590 (CachedDescriptor->Size) ? State->InstPtr.Long
591 : State->InstPtr.LowWord,
596 /* Exception occurred during instruction fetch */
600 /* Advance the instruction pointer */
601 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
602 else State->InstPtr.LowWord += sizeof(ULONG);
609 Fast486GetIntVector(PFAST486_STATE State,
611 PFAST486_IDT_ENTRY IdtEntry)
615 /* Check for protected mode */
616 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
618 /* Read from the IDT */
619 if (!Fast486ReadLinearMemory(State,
621 + Number * sizeof(*IdtEntry),
625 /* Exception occurred */
631 /* Read from the real-mode IVT */
633 /* Paging is always disabled in real mode */
634 State->MemReadCallback(State,
636 + Number * sizeof(FarPointer),
640 /* Fill a fake IDT entry */
641 IdtEntry->Offset = LOWORD(FarPointer);
642 IdtEntry->Selector = HIWORD(FarPointer);
644 IdtEntry->Type = FAST486_IDT_INT_GATE;
645 IdtEntry->Storage = FALSE;
647 IdtEntry->Present = TRUE;
648 IdtEntry->OffsetHigh = 0;
656 Fast486CalculateParity(UCHAR Number)
658 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
659 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
664 Fast486ParseModRegRm(PFAST486_STATE State,
666 PFAST486_MOD_REG_RM ModRegRm)
668 UCHAR ModRmByte, Mode, RegMem;
670 /* Fetch the MOD REG R/M byte */
671 if (!Fast486FetchByte(State, &ModRmByte))
673 /* Exception occurred */
677 /* Unpack the mode and R/M */
678 Mode = ModRmByte >> 6;
679 RegMem = ModRmByte & 0x07;
681 /* Set the register operand */
682 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
685 if ((ModRmByte >> 6) == 3)
687 /* The second operand is also a register */
688 ModRegRm->Memory = FALSE;
689 ModRegRm->SecondRegister = RegMem;
695 /* The second operand is memory */
696 ModRegRm->Memory = TRUE;
700 if (RegMem == FAST486_REG_ESP)
703 ULONG Scale, Index, Base;
705 /* Fetch the SIB byte */
706 if (!Fast486FetchByte(State, &SibByte))
708 /* Exception occurred */
712 /* Unpack the scale, index and base */
713 Scale = 1 << (SibByte >> 6);
714 Index = (SibByte >> 3) & 0x07;
715 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
718 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
720 /* Use the register a base */
721 Base = State->GeneralRegs[SibByte & 0x07].Long;
726 if (!Fast486FetchDword(State, &Base))
728 /* Exception occurred */
733 if ((SibByte & 0x07) == FAST486_REG_ESP)
735 /* Check if there is no segment override */
736 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
738 /* Add a SS: prefix */
739 State->PrefixFlags |= FAST486_PREFIX_SEG;
740 State->SegmentOverride = FAST486_REG_SS;
744 /* Calculate the address */
745 ModRegRm->MemoryAddress = Base + Index * Scale;
747 else if (RegMem == FAST486_REG_EBP)
749 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
750 else ModRegRm->MemoryAddress = 0;
754 /* Get the base from the register */
755 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
758 /* Check if there is no segment override */
759 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
761 /* Check if the default segment should be SS */
762 if ((RegMem == FAST486_REG_EBP) && Mode)
764 /* Add a SS: prefix */
765 State->PrefixFlags |= FAST486_PREFIX_SEG;
766 State->SegmentOverride = FAST486_REG_SS;
775 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
777 /* Exception occurred */
781 /* Add the signed offset to the address */
782 ModRegRm->MemoryAddress += (LONG)Offset;
784 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
788 /* Fetch the dword */
789 if (!Fast486FetchDword(State, (PULONG)&Offset))
791 /* Exception occurred */
795 /* Add the signed offset to the address */
796 ModRegRm->MemoryAddress += Offset;
801 /* Check the operand */
807 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
808 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
816 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
817 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
825 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
826 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
834 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
835 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
843 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
851 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
861 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
865 /* [constant] (added later) */
866 ModRegRm->MemoryAddress = 0;
875 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
881 /* Check if there is no segment override */
882 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
884 /* Check if the default segment should be SS */
885 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
887 /* Add a SS: prefix */
888 State->PrefixFlags |= FAST486_PREFIX_SEG;
889 State->SegmentOverride = FAST486_REG_SS;
898 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
900 /* Exception occurred */
904 /* Add the signed offset to the address */
905 ModRegRm->MemoryAddress += (LONG)Offset;
907 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
912 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
914 /* Exception occurred */
918 /* Add the signed offset to the address */
919 ModRegRm->MemoryAddress += (LONG)Offset;
922 /* Clear the top 16 bits */
923 ModRegRm->MemoryAddress &= 0x0000FFFF;
931 Fast486ReadModrmByteOperands(PFAST486_STATE State,
932 PFAST486_MOD_REG_RM ModRegRm,
936 FAST486_SEG_REGS Segment = FAST486_REG_DS;
940 /* Get the register value */
941 if (ModRegRm->Register & 0x04)
944 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
949 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
955 if (!ModRegRm->Memory)
957 /* Get the second register value */
958 if (ModRegRm->SecondRegister & 0x04)
961 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
966 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
971 /* Check for the segment override */
972 if (State->PrefixFlags & FAST486_PREFIX_SEG)
974 /* Use the override segment instead */
975 Segment = State->SegmentOverride;
979 if (!Fast486ReadMemory(State,
981 ModRegRm->MemoryAddress,
986 /* Exception occurred */
997 Fast486ReadModrmWordOperands(PFAST486_STATE State,
998 PFAST486_MOD_REG_RM ModRegRm,
1002 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1006 /* Get the register value */
1007 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1012 if (!ModRegRm->Memory)
1014 /* Get the second register value */
1015 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1019 /* Check for the segment override */
1020 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1022 /* Use the override segment instead */
1023 Segment = State->SegmentOverride;
1027 if (!Fast486ReadMemory(State,
1029 ModRegRm->MemoryAddress,
1034 /* Exception occurred */
1045 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1046 PFAST486_MOD_REG_RM ModRegRm,
1050 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1054 /* Get the register value */
1055 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1060 if (!ModRegRm->Memory)
1062 /* Get the second register value */
1063 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1067 /* Check for the segment override */
1068 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1070 /* Use the override segment instead */
1071 Segment = State->SegmentOverride;
1075 if (!Fast486ReadMemory(State,
1077 ModRegRm->MemoryAddress,
1082 /* Exception occurred */
1093 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1094 PFAST486_MOD_REG_RM ModRegRm,
1095 BOOLEAN WriteRegister,
1098 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1102 /* Store the value in the register */
1103 if (ModRegRm->Register & 0x04)
1105 /* AH, CH, DH, BH */
1106 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1110 /* AL, CL, DL, BL */
1111 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1116 if (!ModRegRm->Memory)
1118 /* Store the value in the second register */
1119 if (ModRegRm->SecondRegister & 0x04)
1121 /* AH, CH, DH, BH */
1122 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1126 /* AL, CL, DL, BL */
1127 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1132 /* Check for the segment override */
1133 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1135 /* Use the override segment instead */
1136 Segment = State->SegmentOverride;
1140 if (!Fast486WriteMemory(State,
1142 ModRegRm->MemoryAddress,
1146 /* Exception occurred */
1157 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1158 PFAST486_MOD_REG_RM ModRegRm,
1159 BOOLEAN WriteRegister,
1162 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1166 /* Store the value in the register */
1167 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1171 if (!ModRegRm->Memory)
1173 /* Store the value in the second register */
1174 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1178 /* Check for the segment override */
1179 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1181 /* Use the override segment instead */
1182 Segment = State->SegmentOverride;
1186 if (!Fast486WriteMemory(State,
1188 ModRegRm->MemoryAddress,
1192 /* Exception occurred */
1203 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1204 PFAST486_MOD_REG_RM ModRegRm,
1205 BOOLEAN WriteRegister,
1208 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1212 /* Store the value in the register */
1213 State->GeneralRegs[ModRegRm->Register].Long = Value;
1217 if (!ModRegRm->Memory)
1219 /* Store the value in the second register */
1220 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1224 /* Check for the segment override */
1225 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1227 /* Use the override segment instead */
1228 Segment = State->SegmentOverride;
1232 if (!Fast486WriteMemory(State,
1234 ModRegRm->MemoryAddress,
1238 /* Exception occurred */