632460597398451f13902d0ec0190113edcce923
[reactos.git] / lib / fast486 / common.inl
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * common.inl
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
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.
11 *
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.
16 *
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.
20 */
21
22 /* PUBLIC FUNCTIONS ***********************************************************/
23
24 FORCEINLINE
25 VOID
26 Fast486Exception(PFAST486_STATE State,
27 FAST486_EXCEPTIONS ExceptionCode)
28 {
29 /* Call the internal function */
30 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
31 }
32
33 FORCEINLINE
34 BOOLEAN
35 Fast486StackPush(PFAST486_STATE State,
36 ULONG Value)
37 {
38 BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
39
40 /* The OPSIZE prefix toggles the size */
41 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
42
43 if (Size)
44 {
45 /* 32-bit size */
46
47 /* Check if ESP is between 1 and 3 */
48 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
49 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
50 {
51 Fast486Exception(State, FAST486_EXCEPTION_SS);
52 return FALSE;
53 }
54
55 /* Subtract ESP by 4 */
56 State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
57
58 /* Store the value in SS:ESP */
59 return Fast486WriteMemory(State,
60 FAST486_REG_SS,
61 State->GeneralRegs[FAST486_REG_ESP].Long,
62 &Value,
63 sizeof(ULONG));
64 }
65 else
66 {
67 /* 16-bit size */
68 USHORT ShortValue = LOWORD(Value);
69
70 /* Check if SP is 1 */
71 if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
72 {
73 Fast486Exception(State, FAST486_EXCEPTION_SS);
74 return FALSE;
75 }
76
77 /* Subtract SP by 2 */
78 State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
79
80 /* Store the value in SS:SP */
81 return Fast486WriteMemory(State,
82 FAST486_REG_SS,
83 State->GeneralRegs[FAST486_REG_ESP].LowWord,
84 &ShortValue,
85 sizeof(USHORT));
86 }
87 }
88
89 FORCEINLINE
90 BOOLEAN
91 Fast486StackPop(PFAST486_STATE State,
92 PULONG Value)
93 {
94 ULONG LongValue;
95 USHORT ShortValue;
96 BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
97
98 /* The OPSIZE prefix toggles the size */
99 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
100
101 if (Size)
102 {
103 /* 32-bit size */
104
105 /* Check if ESP is 0xFFFFFFFF */
106 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
107 {
108 Fast486Exception(State, FAST486_EXCEPTION_SS);
109 return FALSE;
110 }
111
112 /* Read the value from SS:ESP */
113 if (!Fast486ReadMemory(State,
114 FAST486_REG_SS,
115 State->GeneralRegs[FAST486_REG_ESP].Long,
116 FALSE,
117 &LongValue,
118 sizeof(LongValue)))
119 {
120 /* An exception occurred */
121 return FALSE;
122 }
123
124 /* Increment ESP by 4 */
125 State->GeneralRegs[FAST486_REG_ESP].Long += 4;
126
127 /* Store the value in the result */
128 *Value = LongValue;
129 }
130 else
131 {
132 /* 16-bit size */
133
134 /* Check if SP is 0xFFFF */
135 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
136 {
137 Fast486Exception(State, FAST486_EXCEPTION_SS);
138 return FALSE;
139 }
140
141 /* Read the value from SS:SP */
142 if (!Fast486ReadMemory(State,
143 FAST486_REG_SS,
144 State->GeneralRegs[FAST486_REG_ESP].LowWord,
145 FALSE,
146 &ShortValue,
147 sizeof(ShortValue)))
148 {
149 /* An exception occurred */
150 return FALSE;
151 }
152
153 /* Increment SP by 2 */
154 State->GeneralRegs[FAST486_REG_ESP].Long += 2;
155
156 /* Store the value in the result */
157 *Value = ShortValue;
158 }
159
160 return TRUE;
161 }
162
163 FORCEINLINE
164 BOOLEAN
165 Fast486LoadSegment(PFAST486_STATE State,
166 INT Segment,
167 USHORT Selector)
168 {
169 PFAST486_SEG_REG CachedDescriptor;
170 FAST486_GDT_ENTRY GdtEntry;
171
172 ASSERT(Segment < FAST486_NUM_SEG_REGS);
173
174 /* Get the cached descriptor */
175 CachedDescriptor = &State->SegmentRegs[Segment];
176
177 /* Check for protected mode */
178 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
179 {
180 /* Make sure the GDT contains the entry */
181 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
182 {
183 Fast486Exception(State, FAST486_EXCEPTION_GP);
184 return FALSE;
185 }
186
187 /* Read the GDT */
188 // FIXME: This code is only correct when paging is disabled!!!
189 State->MemReadCallback(State,
190 State->Gdtr.Address
191 + GET_SEGMENT_INDEX(Selector),
192 &GdtEntry,
193 sizeof(GdtEntry));
194
195 if (Segment == FAST486_REG_SS)
196 {
197 /* Loading the stack segment */
198
199 if (GET_SEGMENT_INDEX(Selector) == 0)
200 {
201 Fast486Exception(State, FAST486_EXCEPTION_GP);
202 return FALSE;
203 }
204
205 if (!GdtEntry.SystemType)
206 {
207 /* This is a special descriptor */
208 Fast486Exception(State, FAST486_EXCEPTION_GP);
209 return FALSE;
210 }
211
212 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
213 {
214 Fast486Exception(State, FAST486_EXCEPTION_GP);
215 return FALSE;
216 }
217
218 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
219 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
220 {
221 Fast486Exception(State, FAST486_EXCEPTION_GP);
222 return FALSE;
223 }
224
225 if (!GdtEntry.Present)
226 {
227 Fast486Exception(State, FAST486_EXCEPTION_SS);
228 return FALSE;
229 }
230 }
231 else if (Segment == FAST486_REG_CS)
232 {
233 /* Loading the code segment */
234 // TODO: NOT IMPLEMENTED
235 }
236 else
237 {
238 /* Loading a data segment */
239
240 if (!GdtEntry.SystemType)
241 {
242 /* This is a special descriptor */
243 Fast486Exception(State, FAST486_EXCEPTION_GP);
244 return FALSE;
245 }
246
247 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
248 && (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
249 {
250 Fast486Exception(State, FAST486_EXCEPTION_GP);
251 return FALSE;
252 }
253
254 if (!GdtEntry.Present)
255 {
256 Fast486Exception(State, FAST486_EXCEPTION_NP);
257 return FALSE;
258 }
259 }
260
261 /* Update the cache entry */
262 CachedDescriptor->Selector = Selector;
263 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
264 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
265 CachedDescriptor->Accessed = GdtEntry.Accessed;
266 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
267 CachedDescriptor->DirConf = GdtEntry.DirConf;
268 CachedDescriptor->Executable = GdtEntry.Executable;
269 CachedDescriptor->SystemType = GdtEntry.SystemType;
270 CachedDescriptor->Dpl = GdtEntry.Dpl;
271 CachedDescriptor->Present = GdtEntry.Present;
272 CachedDescriptor->Size = GdtEntry.Size;
273
274 /* Check for page granularity */
275 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
276 }
277 else
278 {
279 /* Update the selector and base */
280 CachedDescriptor->Selector = Selector;
281 CachedDescriptor->Base = Selector << 4;
282 }
283
284 return TRUE;
285 }
286
287 FORCEINLINE
288 BOOLEAN
289 Fast486FetchByte(PFAST486_STATE State,
290 PUCHAR Data)
291 {
292 PFAST486_SEG_REG CachedDescriptor;
293
294 /* Get the cached descriptor of CS */
295 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
296
297 /* Read from memory */
298 if (!Fast486ReadMemory(State,
299 FAST486_REG_CS,
300 (CachedDescriptor->Size) ? State->InstPtr.Long
301 : State->InstPtr.LowWord,
302 TRUE,
303 Data,
304 sizeof(UCHAR)))
305 {
306 /* Exception occurred during instruction fetch */
307 return FALSE;
308 }
309
310 /* Advance the instruction pointer */
311 if (CachedDescriptor->Size) State->InstPtr.Long++;
312 else State->InstPtr.LowWord++;
313
314 return TRUE;
315 }
316
317 FORCEINLINE
318 BOOLEAN
319 Fast486FetchWord(PFAST486_STATE State,
320 PUSHORT Data)
321 {
322 PFAST486_SEG_REG CachedDescriptor;
323
324 /* Get the cached descriptor of CS */
325 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
326
327 /* Read from memory */
328 // FIXME: Fix byte order on big-endian machines
329 if (!Fast486ReadMemory(State,
330 FAST486_REG_CS,
331 (CachedDescriptor->Size) ? State->InstPtr.Long
332 : State->InstPtr.LowWord,
333 TRUE,
334 Data,
335 sizeof(USHORT)))
336 {
337 /* Exception occurred during instruction fetch */
338 return FALSE;
339 }
340
341 /* Advance the instruction pointer */
342 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
343 else State->InstPtr.LowWord += sizeof(USHORT);
344
345 return TRUE;
346 }
347
348 FORCEINLINE
349 BOOLEAN
350 Fast486FetchDword(PFAST486_STATE State,
351 PULONG Data)
352 {
353 PFAST486_SEG_REG CachedDescriptor;
354
355 /* Get the cached descriptor of CS */
356 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
357
358 /* Read from memory */
359 // FIXME: Fix byte order on big-endian machines
360 if (!Fast486ReadMemory(State,
361 FAST486_REG_CS,
362 (CachedDescriptor->Size) ? State->InstPtr.Long
363 : State->InstPtr.LowWord,
364 TRUE,
365 Data,
366 sizeof(ULONG)))
367 {
368 /* Exception occurred during instruction fetch */
369 return FALSE;
370 }
371
372 /* Advance the instruction pointer */
373 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
374 else State->InstPtr.LowWord += sizeof(ULONG);
375
376 return TRUE;
377 }
378
379 FORCEINLINE
380 BOOLEAN
381 Fast486GetIntVector(PFAST486_STATE State,
382 UCHAR Number,
383 PFAST486_IDT_ENTRY IdtEntry)
384 {
385 ULONG FarPointer;
386
387 /* Check for protected mode */
388 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
389 {
390 /* Read from the IDT */
391 // FIXME: This code is only correct when paging is disabled!!!
392 State->MemReadCallback(State,
393 State->Idtr.Address
394 + Number * sizeof(*IdtEntry),
395 IdtEntry,
396 sizeof(*IdtEntry));
397 }
398 else
399 {
400 /* Read from the real-mode IVT */
401
402 /* Paging is always disabled in real mode */
403 State->MemReadCallback(State,
404 State->Idtr.Address
405 + Number * sizeof(FarPointer),
406 &FarPointer,
407 sizeof(FarPointer));
408
409 /* Fill a fake IDT entry */
410 IdtEntry->Offset = LOWORD(FarPointer);
411 IdtEntry->Selector = HIWORD(FarPointer);
412 IdtEntry->Zero = 0;
413 IdtEntry->Type = FAST486_IDT_INT_GATE;
414 IdtEntry->Storage = FALSE;
415 IdtEntry->Dpl = 0;
416 IdtEntry->Present = TRUE;
417 IdtEntry->OffsetHigh = 0;
418 }
419
420 /*
421 * Once paging support is implemented this function
422 * will not always return true
423 */
424 return TRUE;
425 }
426
427 FORCEINLINE
428 BOOLEAN
429 Fast486CalculateParity(UCHAR Number)
430 {
431 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
432 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
433 }
434
435 FORCEINLINE
436 BOOLEAN
437 Fast486ParseModRegRm(PFAST486_STATE State,
438 BOOLEAN AddressSize,
439 PFAST486_MOD_REG_RM ModRegRm)
440 {
441 UCHAR ModRmByte, Mode, RegMem;
442
443 /* Fetch the MOD REG R/M byte */
444 if (!Fast486FetchByte(State, &ModRmByte))
445 {
446 /* Exception occurred */
447 return FALSE;
448 }
449
450 /* Unpack the mode and R/M */
451 Mode = ModRmByte >> 6;
452 RegMem = ModRmByte & 0x07;
453
454 /* Set the register operand */
455 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
456
457 /* Check the mode */
458 if ((ModRmByte >> 6) == 3)
459 {
460 /* The second operand is also a register */
461 ModRegRm->Memory = FALSE;
462 ModRegRm->SecondRegister = RegMem;
463
464 /* Done parsing */
465 return TRUE;
466 }
467
468 /* The second operand is memory */
469 ModRegRm->Memory = TRUE;
470
471 if (AddressSize)
472 {
473 if (RegMem == FAST486_REG_ESP)
474 {
475 UCHAR SibByte;
476 ULONG Scale, Index, Base;
477
478 /* Fetch the SIB byte */
479 if (!Fast486FetchByte(State, &SibByte))
480 {
481 /* Exception occurred */
482 return FALSE;
483 }
484
485 /* Unpack the scale, index and base */
486 Scale = 1 << (SibByte >> 6);
487 Index = (SibByte >> 3) & 0x07;
488 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
489 else Index = 0;
490 Base = State->GeneralRegs[SibByte & 0x07].Long;
491
492 /* Calculate the address */
493 ModRegRm->MemoryAddress = Base + Index * Scale;
494 }
495 else if (RegMem == FAST486_REG_EBP)
496 {
497 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
498 else ModRegRm->MemoryAddress = 0;
499 }
500 else
501 {
502 /* Get the base from the register */
503 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
504 }
505
506 /* Check if there is no segment override */
507 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
508 {
509 /* Check if the default segment should be SS */
510 if ((RegMem == FAST486_REG_EBP) && Mode)
511 {
512 /* Add a SS: prefix */
513 State->PrefixFlags |= FAST486_PREFIX_SEG;
514 State->SegmentOverride = FAST486_REG_SS;
515 }
516 }
517
518 if (Mode == 1)
519 {
520 CHAR Offset;
521
522 /* Fetch the byte */
523 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
524 {
525 /* Exception occurred */
526 return FALSE;
527 }
528
529 /* Add the signed offset to the address */
530 ModRegRm->MemoryAddress += (LONG)Offset;
531 }
532 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
533 {
534 LONG Offset;
535
536 /* Fetch the dword */
537 if (!Fast486FetchDword(State, (PULONG)&Offset))
538 {
539 /* Exception occurred */
540 return FALSE;
541 }
542
543 /* Add the signed offset to the address */
544 ModRegRm->MemoryAddress += Offset;
545 }
546 }
547 else
548 {
549 /* Check the operand */
550 switch (RegMem)
551 {
552 case 0:
553 case 2:
554 {
555 /* (SS:)[BX + SI] */
556 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
557 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
558
559 break;
560 }
561
562 case 1:
563 case 3:
564 {
565 /* (SS:)[BX + DI] */
566 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
567 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
568
569 break;
570 }
571
572 case 4:
573 {
574 /* [SI] */
575 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
576
577 break;
578 }
579
580 case 5:
581 {
582 /* [DI] */
583 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
584
585 break;
586 }
587
588 case 6:
589 {
590 if (Mode)
591 {
592 /* [BP] */
593 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
594 }
595 else
596 {
597 /* [constant] (added later) */
598 ModRegRm->MemoryAddress = 0;
599 }
600
601 break;
602 }
603
604 case 7:
605 {
606 /* [BX] */
607 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
608
609 break;
610 }
611 }
612
613 /* Check if there is no segment override */
614 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
615 {
616 /* Check if the default segment should be SS */
617 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
618 {
619 /* Add a SS: prefix */
620 State->PrefixFlags |= FAST486_PREFIX_SEG;
621 State->SegmentOverride = FAST486_REG_SS;
622 }
623 }
624
625 if (Mode == 1)
626 {
627 CHAR Offset;
628
629 /* Fetch the byte */
630 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
631 {
632 /* Exception occurred */
633 return FALSE;
634 }
635
636 /* Add the signed offset to the address */
637 ModRegRm->MemoryAddress += (LONG)Offset;
638 }
639 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
640 {
641 SHORT Offset;
642
643 /* Fetch the word */
644 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
645 {
646 /* Exception occurred */
647 return FALSE;
648 }
649
650 /* Add the signed offset to the address */
651 ModRegRm->MemoryAddress += (LONG)Offset;
652 }
653
654 /* Clear the top 16 bits */
655 ModRegRm->MemoryAddress &= 0x0000FFFF;
656 }
657
658 return TRUE;
659 }
660
661 FORCEINLINE
662 BOOLEAN
663 Fast486ReadModrmByteOperands(PFAST486_STATE State,
664 PFAST486_MOD_REG_RM ModRegRm,
665 PUCHAR RegValue,
666 PUCHAR RmValue)
667 {
668 FAST486_SEG_REGS Segment = FAST486_REG_DS;
669
670 /* Get the register value */
671 if (ModRegRm->Register & 0x04)
672 {
673 /* AH, CH, DH, BH */
674 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
675 }
676 else
677 {
678 /* AL, CL, DL, BL */
679 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
680 }
681
682 if (!ModRegRm->Memory)
683 {
684 /* Get the second register value */
685 if (ModRegRm->SecondRegister & 0x04)
686 {
687 /* AH, CH, DH, BH */
688 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
689 }
690 else
691 {
692 /* AL, CL, DL, BL */
693 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
694 }
695 }
696 else
697 {
698 /* Check for the segment override */
699 if (State->PrefixFlags & FAST486_PREFIX_SEG)
700 {
701 /* Use the override segment instead */
702 Segment = State->SegmentOverride;
703 }
704
705 /* Read memory */
706 if (!Fast486ReadMemory(State,
707 Segment,
708 ModRegRm->MemoryAddress,
709 FALSE,
710 RmValue,
711 sizeof(UCHAR)))
712 {
713 /* Exception occurred */
714 return FALSE;
715 }
716 }
717
718 return TRUE;
719 }
720
721 FORCEINLINE
722 BOOLEAN
723 Fast486ReadModrmWordOperands(PFAST486_STATE State,
724 PFAST486_MOD_REG_RM ModRegRm,
725 PUSHORT RegValue,
726 PUSHORT RmValue)
727 {
728 FAST486_SEG_REGS Segment = FAST486_REG_DS;
729
730 /* Get the register value */
731 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
732
733 if (!ModRegRm->Memory)
734 {
735 /* Get the second register value */
736 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
737 }
738 else
739 {
740 /* Check for the segment override */
741 if (State->PrefixFlags & FAST486_PREFIX_SEG)
742 {
743 /* Use the override segment instead */
744 Segment = State->SegmentOverride;
745 }
746
747 /* Read memory */
748 if (!Fast486ReadMemory(State,
749 Segment,
750 ModRegRm->MemoryAddress,
751 FALSE,
752 RmValue,
753 sizeof(USHORT)))
754 {
755 /* Exception occurred */
756 return FALSE;
757 }
758 }
759
760 return TRUE;
761 }
762
763 FORCEINLINE
764 BOOLEAN
765 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
766 PFAST486_MOD_REG_RM ModRegRm,
767 PULONG RegValue,
768 PULONG RmValue)
769 {
770 FAST486_SEG_REGS Segment = FAST486_REG_DS;
771
772 /* Get the register value */
773 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
774
775 if (!ModRegRm->Memory)
776 {
777 /* Get the second register value */
778 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
779 }
780 else
781 {
782 /* Check for the segment override */
783 if (State->PrefixFlags & FAST486_PREFIX_SEG)
784 {
785 /* Use the override segment instead */
786 Segment = State->SegmentOverride;
787 }
788
789 /* Read memory */
790 if (!Fast486ReadMemory(State,
791 Segment,
792 ModRegRm->MemoryAddress,
793 FALSE,
794 RmValue,
795 sizeof(ULONG)))
796 {
797 /* Exception occurred */
798 return FALSE;
799 }
800 }
801
802 return TRUE;
803 }
804
805 FORCEINLINE
806 BOOLEAN
807 Fast486WriteModrmByteOperands(PFAST486_STATE State,
808 PFAST486_MOD_REG_RM ModRegRm,
809 BOOLEAN WriteRegister,
810 UCHAR Value)
811 {
812 FAST486_SEG_REGS Segment = FAST486_REG_DS;
813
814 if (WriteRegister)
815 {
816 /* Store the value in the register */
817 if (ModRegRm->Register & 0x04)
818 {
819 /* AH, CH, DH, BH */
820 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
821 }
822 else
823 {
824 /* AL, CL, DL, BL */
825 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
826 }
827 }
828 else
829 {
830 if (!ModRegRm->Memory)
831 {
832 /* Store the value in the second register */
833 if (ModRegRm->SecondRegister & 0x04)
834 {
835 /* AH, CH, DH, BH */
836 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
837 }
838 else
839 {
840 /* AL, CL, DL, BL */
841 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
842 }
843 }
844 else
845 {
846 /* Check for the segment override */
847 if (State->PrefixFlags & FAST486_PREFIX_SEG)
848 {
849 /* Use the override segment instead */
850 Segment = State->SegmentOverride;
851 }
852
853 /* Write memory */
854 if (!Fast486WriteMemory(State,
855 Segment,
856 ModRegRm->MemoryAddress,
857 &Value,
858 sizeof(UCHAR)))
859 {
860 /* Exception occurred */
861 return FALSE;
862 }
863 }
864 }
865
866 return TRUE;
867 }
868
869 FORCEINLINE
870 BOOLEAN
871 Fast486WriteModrmWordOperands(PFAST486_STATE State,
872 PFAST486_MOD_REG_RM ModRegRm,
873 BOOLEAN WriteRegister,
874 USHORT Value)
875 {
876 FAST486_SEG_REGS Segment = FAST486_REG_DS;
877
878 if (WriteRegister)
879 {
880 /* Store the value in the register */
881 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
882 }
883 else
884 {
885 if (!ModRegRm->Memory)
886 {
887 /* Store the value in the second register */
888 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
889 }
890 else
891 {
892 /* Check for the segment override */
893 if (State->PrefixFlags & FAST486_PREFIX_SEG)
894 {
895 /* Use the override segment instead */
896 Segment = State->SegmentOverride;
897 }
898
899 /* Write memory */
900 if (!Fast486WriteMemory(State,
901 Segment,
902 ModRegRm->MemoryAddress,
903 &Value,
904 sizeof(USHORT)))
905 {
906 /* Exception occurred */
907 return FALSE;
908 }
909 }
910 }
911
912 return TRUE;
913 }
914
915 FORCEINLINE
916 BOOLEAN
917 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
918 PFAST486_MOD_REG_RM ModRegRm,
919 BOOLEAN WriteRegister,
920 ULONG Value)
921 {
922 FAST486_SEG_REGS Segment = FAST486_REG_DS;
923
924 if (WriteRegister)
925 {
926 /* Store the value in the register */
927 State->GeneralRegs[ModRegRm->Register].Long = Value;
928 }
929 else
930 {
931 if (!ModRegRm->Memory)
932 {
933 /* Store the value in the second register */
934 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
935 }
936 else
937 {
938 /* Check for the segment override */
939 if (State->PrefixFlags & FAST486_PREFIX_SEG)
940 {
941 /* Use the override segment instead */
942 Segment = State->SegmentOverride;
943 }
944
945 /* Write memory */
946 if (!Fast486WriteMemory(State,
947 Segment,
948 ModRegRm->MemoryAddress,
949 &Value,
950 sizeof(ULONG)))
951 {
952 /* Exception occurred */
953 return FALSE;
954 }
955 }
956 }
957
958 return TRUE;
959 }
960
961 /* EOF */