[FAST486]
[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.BaseMid << 16) | (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 {
554 /* [BX + SI] */
555 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
556 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
557
558 break;
559 }
560
561 case 1:
562 {
563 /* [BX + DI] */
564 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
565 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
566
567 break;
568 }
569
570 case 2:
571 {
572 /* SS:[BP + SI] */
573 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
574 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
575
576 break;
577 }
578
579 case 3:
580 {
581 /* SS:[BP + DI] */
582 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
583 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
584
585 break;
586 }
587
588 case 4:
589 {
590 /* [SI] */
591 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
592
593 break;
594 }
595
596 case 5:
597 {
598 /* [DI] */
599 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
600
601 break;
602 }
603
604 case 6:
605 {
606 if (Mode)
607 {
608 /* [BP] */
609 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
610 }
611 else
612 {
613 /* [constant] (added later) */
614 ModRegRm->MemoryAddress = 0;
615 }
616
617 break;
618 }
619
620 case 7:
621 {
622 /* [BX] */
623 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
624
625 break;
626 }
627 }
628
629 /* Check if there is no segment override */
630 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
631 {
632 /* Check if the default segment should be SS */
633 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
634 {
635 /* Add a SS: prefix */
636 State->PrefixFlags |= FAST486_PREFIX_SEG;
637 State->SegmentOverride = FAST486_REG_SS;
638 }
639 }
640
641 if (Mode == 1)
642 {
643 CHAR Offset;
644
645 /* Fetch the byte */
646 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
647 {
648 /* Exception occurred */
649 return FALSE;
650 }
651
652 /* Add the signed offset to the address */
653 ModRegRm->MemoryAddress += (LONG)Offset;
654 }
655 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
656 {
657 SHORT Offset;
658
659 /* Fetch the word */
660 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
661 {
662 /* Exception occurred */
663 return FALSE;
664 }
665
666 /* Add the signed offset to the address */
667 ModRegRm->MemoryAddress += (LONG)Offset;
668 }
669
670 /* Clear the top 16 bits */
671 ModRegRm->MemoryAddress &= 0x0000FFFF;
672 }
673
674 return TRUE;
675 }
676
677 FORCEINLINE
678 BOOLEAN
679 Fast486ReadModrmByteOperands(PFAST486_STATE State,
680 PFAST486_MOD_REG_RM ModRegRm,
681 PUCHAR RegValue,
682 PUCHAR RmValue)
683 {
684 FAST486_SEG_REGS Segment = FAST486_REG_DS;
685
686 /* Get the register value */
687 if (ModRegRm->Register & 0x04)
688 {
689 /* AH, CH, DH, BH */
690 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
691 }
692 else
693 {
694 /* AL, CL, DL, BL */
695 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
696 }
697
698 if (!ModRegRm->Memory)
699 {
700 /* Get the second register value */
701 if (ModRegRm->SecondRegister & 0x04)
702 {
703 /* AH, CH, DH, BH */
704 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
705 }
706 else
707 {
708 /* AL, CL, DL, BL */
709 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
710 }
711 }
712 else
713 {
714 /* Check for the segment override */
715 if (State->PrefixFlags & FAST486_PREFIX_SEG)
716 {
717 /* Use the override segment instead */
718 Segment = State->SegmentOverride;
719 }
720
721 /* Read memory */
722 if (!Fast486ReadMemory(State,
723 Segment,
724 ModRegRm->MemoryAddress,
725 FALSE,
726 RmValue,
727 sizeof(UCHAR)))
728 {
729 /* Exception occurred */
730 return FALSE;
731 }
732 }
733
734 return TRUE;
735 }
736
737 FORCEINLINE
738 BOOLEAN
739 Fast486ReadModrmWordOperands(PFAST486_STATE State,
740 PFAST486_MOD_REG_RM ModRegRm,
741 PUSHORT RegValue,
742 PUSHORT RmValue)
743 {
744 FAST486_SEG_REGS Segment = FAST486_REG_DS;
745
746 /* Get the register value */
747 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
748
749 if (!ModRegRm->Memory)
750 {
751 /* Get the second register value */
752 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
753 }
754 else
755 {
756 /* Check for the segment override */
757 if (State->PrefixFlags & FAST486_PREFIX_SEG)
758 {
759 /* Use the override segment instead */
760 Segment = State->SegmentOverride;
761 }
762
763 /* Read memory */
764 if (!Fast486ReadMemory(State,
765 Segment,
766 ModRegRm->MemoryAddress,
767 FALSE,
768 RmValue,
769 sizeof(USHORT)))
770 {
771 /* Exception occurred */
772 return FALSE;
773 }
774 }
775
776 return TRUE;
777 }
778
779 FORCEINLINE
780 BOOLEAN
781 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
782 PFAST486_MOD_REG_RM ModRegRm,
783 PULONG RegValue,
784 PULONG RmValue)
785 {
786 FAST486_SEG_REGS Segment = FAST486_REG_DS;
787
788 /* Get the register value */
789 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
790
791 if (!ModRegRm->Memory)
792 {
793 /* Get the second register value */
794 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
795 }
796 else
797 {
798 /* Check for the segment override */
799 if (State->PrefixFlags & FAST486_PREFIX_SEG)
800 {
801 /* Use the override segment instead */
802 Segment = State->SegmentOverride;
803 }
804
805 /* Read memory */
806 if (!Fast486ReadMemory(State,
807 Segment,
808 ModRegRm->MemoryAddress,
809 FALSE,
810 RmValue,
811 sizeof(ULONG)))
812 {
813 /* Exception occurred */
814 return FALSE;
815 }
816 }
817
818 return TRUE;
819 }
820
821 FORCEINLINE
822 BOOLEAN
823 Fast486WriteModrmByteOperands(PFAST486_STATE State,
824 PFAST486_MOD_REG_RM ModRegRm,
825 BOOLEAN WriteRegister,
826 UCHAR Value)
827 {
828 FAST486_SEG_REGS Segment = FAST486_REG_DS;
829
830 if (WriteRegister)
831 {
832 /* Store the value in the register */
833 if (ModRegRm->Register & 0x04)
834 {
835 /* AH, CH, DH, BH */
836 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
837 }
838 else
839 {
840 /* AL, CL, DL, BL */
841 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
842 }
843 }
844 else
845 {
846 if (!ModRegRm->Memory)
847 {
848 /* Store the value in the second register */
849 if (ModRegRm->SecondRegister & 0x04)
850 {
851 /* AH, CH, DH, BH */
852 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
853 }
854 else
855 {
856 /* AL, CL, DL, BL */
857 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
858 }
859 }
860 else
861 {
862 /* Check for the segment override */
863 if (State->PrefixFlags & FAST486_PREFIX_SEG)
864 {
865 /* Use the override segment instead */
866 Segment = State->SegmentOverride;
867 }
868
869 /* Write memory */
870 if (!Fast486WriteMemory(State,
871 Segment,
872 ModRegRm->MemoryAddress,
873 &Value,
874 sizeof(UCHAR)))
875 {
876 /* Exception occurred */
877 return FALSE;
878 }
879 }
880 }
881
882 return TRUE;
883 }
884
885 FORCEINLINE
886 BOOLEAN
887 Fast486WriteModrmWordOperands(PFAST486_STATE State,
888 PFAST486_MOD_REG_RM ModRegRm,
889 BOOLEAN WriteRegister,
890 USHORT Value)
891 {
892 FAST486_SEG_REGS Segment = FAST486_REG_DS;
893
894 if (WriteRegister)
895 {
896 /* Store the value in the register */
897 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
898 }
899 else
900 {
901 if (!ModRegRm->Memory)
902 {
903 /* Store the value in the second register */
904 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
905 }
906 else
907 {
908 /* Check for the segment override */
909 if (State->PrefixFlags & FAST486_PREFIX_SEG)
910 {
911 /* Use the override segment instead */
912 Segment = State->SegmentOverride;
913 }
914
915 /* Write memory */
916 if (!Fast486WriteMemory(State,
917 Segment,
918 ModRegRm->MemoryAddress,
919 &Value,
920 sizeof(USHORT)))
921 {
922 /* Exception occurred */
923 return FALSE;
924 }
925 }
926 }
927
928 return TRUE;
929 }
930
931 FORCEINLINE
932 BOOLEAN
933 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
934 PFAST486_MOD_REG_RM ModRegRm,
935 BOOLEAN WriteRegister,
936 ULONG Value)
937 {
938 FAST486_SEG_REGS Segment = FAST486_REG_DS;
939
940 if (WriteRegister)
941 {
942 /* Store the value in the register */
943 State->GeneralRegs[ModRegRm->Register].Long = Value;
944 }
945 else
946 {
947 if (!ModRegRm->Memory)
948 {
949 /* Store the value in the second register */
950 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
951 }
952 else
953 {
954 /* Check for the segment override */
955 if (State->PrefixFlags & FAST486_PREFIX_SEG)
956 {
957 /* Use the override segment instead */
958 Segment = State->SegmentOverride;
959 }
960
961 /* Write memory */
962 if (!Fast486WriteMemory(State,
963 Segment,
964 ModRegRm->MemoryAddress,
965 &Value,
966 sizeof(ULONG)))
967 {
968 /* Exception occurred */
969 return FALSE;
970 }
971 }
972 }
973
974 return TRUE;
975 }
976
977 /* EOF */