394542bae723cfdcce91ce8980f6ef4b759c240c
[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 if (State->MemReadCallback)
190 {
191 State->MemReadCallback(State,
192 State->Gdtr.Address
193 + GET_SEGMENT_INDEX(Selector),
194 &GdtEntry,
195 sizeof(GdtEntry));
196 }
197 else
198 {
199 RtlMoveMemory(&GdtEntry,
200 (PVOID)(State->Gdtr.Address
201 + GET_SEGMENT_INDEX(Selector)),
202 sizeof(GdtEntry));
203 }
204
205 if (Segment == FAST486_REG_SS)
206 {
207 /* Loading the stack segment */
208
209 if (GET_SEGMENT_INDEX(Selector) == 0)
210 {
211 Fast486Exception(State, FAST486_EXCEPTION_GP);
212 return FALSE;
213 }
214
215 if (!GdtEntry.SystemType)
216 {
217 /* This is a special descriptor */
218 Fast486Exception(State, FAST486_EXCEPTION_GP);
219 return FALSE;
220 }
221
222 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
223 {
224 Fast486Exception(State, FAST486_EXCEPTION_GP);
225 return FALSE;
226 }
227
228 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
229 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
230 {
231 Fast486Exception(State, FAST486_EXCEPTION_GP);
232 return FALSE;
233 }
234
235 if (!GdtEntry.Present)
236 {
237 Fast486Exception(State, FAST486_EXCEPTION_SS);
238 return FALSE;
239 }
240 }
241 else if (Segment == FAST486_REG_CS)
242 {
243 /* Loading the code segment */
244 // TODO: NOT IMPLEMENTED
245 }
246 else
247 {
248 /* Loading a data segment */
249
250 if (!GdtEntry.SystemType)
251 {
252 /* This is a special descriptor */
253 Fast486Exception(State, FAST486_EXCEPTION_GP);
254 return FALSE;
255 }
256
257 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
258 && (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
259 {
260 Fast486Exception(State, FAST486_EXCEPTION_GP);
261 return FALSE;
262 }
263
264 if (!GdtEntry.Present)
265 {
266 Fast486Exception(State, FAST486_EXCEPTION_NP);
267 return FALSE;
268 }
269 }
270
271 /* Update the cache entry */
272 CachedDescriptor->Selector = Selector;
273 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseHigh << 24);
274 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
275 CachedDescriptor->Accessed = GdtEntry.Accessed;
276 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
277 CachedDescriptor->DirConf = GdtEntry.DirConf;
278 CachedDescriptor->Executable = GdtEntry.Executable;
279 CachedDescriptor->SystemType = GdtEntry.SystemType;
280 CachedDescriptor->Dpl = GdtEntry.Dpl;
281 CachedDescriptor->Present = GdtEntry.Present;
282 CachedDescriptor->Size = GdtEntry.Size;
283
284 /* Check for page granularity */
285 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
286 }
287 else
288 {
289 /* Update the selector and base */
290 CachedDescriptor->Selector = Selector;
291 CachedDescriptor->Base = Selector << 4;
292 }
293
294 return TRUE;
295 }
296
297 FORCEINLINE
298 BOOLEAN
299 Fast486FetchByte(PFAST486_STATE State,
300 PUCHAR Data)
301 {
302 PFAST486_SEG_REG CachedDescriptor;
303
304 /* Get the cached descriptor of CS */
305 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
306
307 /* Read from memory */
308 if (!Fast486ReadMemory(State,
309 FAST486_REG_CS,
310 (CachedDescriptor->Size) ? State->InstPtr.Long
311 : State->InstPtr.LowWord,
312 TRUE,
313 Data,
314 sizeof(UCHAR)))
315 {
316 /* Exception occurred during instruction fetch */
317 return FALSE;
318 }
319
320 /* Advance the instruction pointer */
321 if (CachedDescriptor->Size) State->InstPtr.Long++;
322 else State->InstPtr.LowWord++;
323
324 return TRUE;
325 }
326
327 FORCEINLINE
328 BOOLEAN
329 Fast486FetchWord(PFAST486_STATE State,
330 PUSHORT Data)
331 {
332 PFAST486_SEG_REG CachedDescriptor;
333
334 /* Get the cached descriptor of CS */
335 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
336
337 /* Read from memory */
338 // FIXME: Fix byte order on big-endian machines
339 if (!Fast486ReadMemory(State,
340 FAST486_REG_CS,
341 (CachedDescriptor->Size) ? State->InstPtr.Long
342 : State->InstPtr.LowWord,
343 TRUE,
344 Data,
345 sizeof(USHORT)))
346 {
347 /* Exception occurred during instruction fetch */
348 return FALSE;
349 }
350
351 /* Advance the instruction pointer */
352 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
353 else State->InstPtr.LowWord += sizeof(USHORT);
354
355 return TRUE;
356 }
357
358 FORCEINLINE
359 BOOLEAN
360 Fast486FetchDword(PFAST486_STATE State,
361 PULONG Data)
362 {
363 PFAST486_SEG_REG CachedDescriptor;
364
365 /* Get the cached descriptor of CS */
366 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
367
368 /* Read from memory */
369 // FIXME: Fix byte order on big-endian machines
370 if (!Fast486ReadMemory(State,
371 FAST486_REG_CS,
372 (CachedDescriptor->Size) ? State->InstPtr.Long
373 : State->InstPtr.LowWord,
374 TRUE,
375 Data,
376 sizeof(ULONG)))
377 {
378 /* Exception occurred during instruction fetch */
379 return FALSE;
380 }
381
382 /* Advance the instruction pointer */
383 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
384 else State->InstPtr.LowWord += sizeof(ULONG);
385
386 return TRUE;
387 }
388
389 FORCEINLINE
390 BOOLEAN
391 Fast486GetIntVector(PFAST486_STATE State,
392 UCHAR Number,
393 PFAST486_IDT_ENTRY IdtEntry)
394 {
395 ULONG FarPointer;
396
397 /* Check for protected mode */
398 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
399 {
400 /* Read from the IDT */
401 // FIXME: This code is only correct when paging is disabled!!!
402 if (State->MemReadCallback)
403 {
404 State->MemReadCallback(State,
405 State->Idtr.Address
406 + Number * sizeof(*IdtEntry),
407 IdtEntry,
408 sizeof(*IdtEntry));
409 }
410 else
411 {
412 RtlMoveMemory(IdtEntry,
413 (PVOID)(State->Idtr.Address
414 + Number * sizeof(*IdtEntry)),
415 sizeof(*IdtEntry));
416 }
417 }
418 else
419 {
420 /* Read from the real-mode IVT */
421
422 /* Paging is always disabled in real mode */
423 if (State->MemReadCallback)
424 {
425 State->MemReadCallback(State,
426 State->Idtr.Address
427 + Number * sizeof(FarPointer),
428 &FarPointer,
429 sizeof(FarPointer));
430 }
431 else
432 {
433 RtlMoveMemory(&FarPointer,
434 (PVOID)(State->Idtr.Address
435 + Number * sizeof(FarPointer)),
436 sizeof(FarPointer));
437 }
438
439 /* Fill a fake IDT entry */
440 IdtEntry->Offset = LOWORD(FarPointer);
441 IdtEntry->Selector = HIWORD(FarPointer);
442 IdtEntry->Zero = 0;
443 IdtEntry->Type = FAST486_IDT_INT_GATE;
444 IdtEntry->Storage = FALSE;
445 IdtEntry->Dpl = 0;
446 IdtEntry->Present = TRUE;
447 IdtEntry->OffsetHigh = 0;
448 }
449
450 /*
451 * Once paging support is implemented this function
452 * will not always return true
453 */
454 return TRUE;
455 }
456
457 FORCEINLINE
458 BOOLEAN
459 Fast486CalculateParity(UCHAR Number)
460 {
461 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
462 }
463
464 FORCEINLINE
465 BOOLEAN
466 Fast486ParseModRegRm(PFAST486_STATE State,
467 BOOLEAN AddressSize,
468 PFAST486_MOD_REG_RM ModRegRm)
469 {
470 UCHAR ModRmByte, Mode, RegMem;
471
472 /* Fetch the MOD REG R/M byte */
473 if (!Fast486FetchByte(State, &ModRmByte))
474 {
475 /* Exception occurred */
476 return FALSE;
477 }
478
479 /* Unpack the mode and R/M */
480 Mode = ModRmByte >> 6;
481 RegMem = ModRmByte & 0x07;
482
483 /* Set the register operand */
484 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
485
486 /* Check the mode */
487 if ((ModRmByte >> 6) == 3)
488 {
489 /* The second operand is also a register */
490 ModRegRm->Memory = FALSE;
491 ModRegRm->SecondRegister = RegMem;
492
493 /* Done parsing */
494 return TRUE;
495 }
496
497 /* The second operand is memory */
498 ModRegRm->Memory = TRUE;
499
500 if (AddressSize)
501 {
502 if (RegMem == FAST486_REG_ESP)
503 {
504 UCHAR SibByte;
505 ULONG Scale, Index, Base;
506
507 /* Fetch the SIB byte */
508 if (!Fast486FetchByte(State, &SibByte))
509 {
510 /* Exception occurred */
511 return FALSE;
512 }
513
514 /* Unpack the scale, index and base */
515 Scale = 1 << (SibByte >> 6);
516 Index = (SibByte >> 3) & 0x07;
517 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
518 else Index = 0;
519 Base = State->GeneralRegs[SibByte & 0x07].Long;
520
521 /* Calculate the address */
522 ModRegRm->MemoryAddress = Base + Index * Scale;
523 }
524 else if (RegMem == FAST486_REG_EBP)
525 {
526 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
527 else ModRegRm->MemoryAddress = 0;
528 }
529 else
530 {
531 /* Get the base from the register */
532 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
533 }
534
535 /* Check if there is no segment override */
536 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
537 {
538 /* Check if the default segment should be SS */
539 if ((RegMem == FAST486_REG_EBP) && Mode)
540 {
541 /* Add a SS: prefix */
542 State->PrefixFlags |= FAST486_PREFIX_SEG;
543 State->SegmentOverride = FAST486_REG_SS;
544 }
545 }
546
547 if (Mode == 1)
548 {
549 CHAR Offset;
550
551 /* Fetch the byte */
552 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
553 {
554 /* Exception occurred */
555 return FALSE;
556 }
557
558 /* Add the signed offset to the address */
559 ModRegRm->MemoryAddress += (LONG)Offset;
560 }
561 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
562 {
563 LONG Offset;
564
565 /* Fetch the dword */
566 if (!Fast486FetchDword(State, (PULONG)&Offset))
567 {
568 /* Exception occurred */
569 return FALSE;
570 }
571
572 /* Add the signed offset to the address */
573 ModRegRm->MemoryAddress += Offset;
574 }
575 }
576 else
577 {
578 /* Check the operand */
579 switch (RegMem)
580 {
581 case 0:
582 case 2:
583 {
584 /* (SS:)[BX + SI] */
585 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
586 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
587
588 break;
589 }
590
591 case 1:
592 case 3:
593 {
594 /* (SS:)[BX + DI] */
595 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
596 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
597
598 break;
599 }
600
601 case 4:
602 {
603 /* [SI] */
604 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
605
606 break;
607 }
608
609 case 5:
610 {
611 /* [DI] */
612 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
613
614 break;
615 }
616
617 case 6:
618 {
619 if (Mode)
620 {
621 /* [BP] */
622 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
623 }
624 else
625 {
626 /* [constant] (added later) */
627 ModRegRm->MemoryAddress = 0;
628 }
629
630 break;
631 }
632
633 case 7:
634 {
635 /* [BX] */
636 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
637
638 break;
639 }
640 }
641
642 /* Check if there is no segment override */
643 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
644 {
645 /* Check if the default segment should be SS */
646 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
647 {
648 /* Add a SS: prefix */
649 State->PrefixFlags |= FAST486_PREFIX_SEG;
650 State->SegmentOverride = FAST486_REG_SS;
651 }
652 }
653
654 if (Mode == 1)
655 {
656 CHAR Offset;
657
658 /* Fetch the byte */
659 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
660 {
661 /* Exception occurred */
662 return FALSE;
663 }
664
665 /* Add the signed offset to the address */
666 ModRegRm->MemoryAddress += (LONG)Offset;
667 }
668 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
669 {
670 SHORT Offset;
671
672 /* Fetch the word */
673 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
674 {
675 /* Exception occurred */
676 return FALSE;
677 }
678
679 /* Add the signed offset to the address */
680 ModRegRm->MemoryAddress += (LONG)Offset;
681 }
682
683 /* Clear the top 16 bits */
684 ModRegRm->MemoryAddress &= 0x0000FFFF;
685 }
686
687 return TRUE;
688 }
689
690 FORCEINLINE
691 BOOLEAN
692 Fast486ReadModrmByteOperands(PFAST486_STATE State,
693 PFAST486_MOD_REG_RM ModRegRm,
694 PUCHAR RegValue,
695 PUCHAR RmValue)
696 {
697 FAST486_SEG_REGS Segment = FAST486_REG_DS;
698
699 /* Get the register value */
700 if (ModRegRm->Register & 0x04)
701 {
702 /* AH, CH, DH, BH */
703 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
704 }
705 else
706 {
707 /* AL, CL, DL, BL */
708 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
709 }
710
711 if (!ModRegRm->Memory)
712 {
713 /* Get the second register value */
714 if (ModRegRm->SecondRegister & 0x04)
715 {
716 /* AH, CH, DH, BH */
717 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
718 }
719 else
720 {
721 /* AL, CL, DL, BL */
722 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
723 }
724 }
725 else
726 {
727 /* Check for the segment override */
728 if (State->PrefixFlags & FAST486_PREFIX_SEG)
729 {
730 /* Use the override segment instead */
731 Segment = State->SegmentOverride;
732 }
733
734 /* Read memory */
735 if (!Fast486ReadMemory(State,
736 Segment,
737 ModRegRm->MemoryAddress,
738 FALSE,
739 RmValue,
740 sizeof(UCHAR)))
741 {
742 /* Exception occurred */
743 return FALSE;
744 }
745 }
746
747 return TRUE;
748 }
749
750 FORCEINLINE
751 BOOLEAN
752 Fast486ReadModrmWordOperands(PFAST486_STATE State,
753 PFAST486_MOD_REG_RM ModRegRm,
754 PUSHORT RegValue,
755 PUSHORT RmValue)
756 {
757 FAST486_SEG_REGS Segment = FAST486_REG_DS;
758
759 /* Get the register value */
760 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
761
762 if (!ModRegRm->Memory)
763 {
764 /* Get the second register value */
765 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
766 }
767 else
768 {
769 /* Check for the segment override */
770 if (State->PrefixFlags & FAST486_PREFIX_SEG)
771 {
772 /* Use the override segment instead */
773 Segment = State->SegmentOverride;
774 }
775
776 /* Read memory */
777 if (!Fast486ReadMemory(State,
778 Segment,
779 ModRegRm->MemoryAddress,
780 FALSE,
781 RmValue,
782 sizeof(USHORT)))
783 {
784 /* Exception occurred */
785 return FALSE;
786 }
787 }
788
789 return TRUE;
790 }
791
792 FORCEINLINE
793 BOOLEAN
794 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
795 PFAST486_MOD_REG_RM ModRegRm,
796 PULONG RegValue,
797 PULONG RmValue)
798 {
799 FAST486_SEG_REGS Segment = FAST486_REG_DS;
800
801 /* Get the register value */
802 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
803
804 if (!ModRegRm->Memory)
805 {
806 /* Get the second register value */
807 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
808 }
809 else
810 {
811 /* Check for the segment override */
812 if (State->PrefixFlags & FAST486_PREFIX_SEG)
813 {
814 /* Use the override segment instead */
815 Segment = State->SegmentOverride;
816 }
817
818 /* Read memory */
819 if (!Fast486ReadMemory(State,
820 Segment,
821 ModRegRm->MemoryAddress,
822 FALSE,
823 RmValue,
824 sizeof(ULONG)))
825 {
826 /* Exception occurred */
827 return FALSE;
828 }
829 }
830
831 return TRUE;
832 }
833
834 FORCEINLINE
835 BOOLEAN
836 Fast486WriteModrmByteOperands(PFAST486_STATE State,
837 PFAST486_MOD_REG_RM ModRegRm,
838 BOOLEAN WriteRegister,
839 UCHAR Value)
840 {
841 FAST486_SEG_REGS Segment = FAST486_REG_DS;
842
843 if (WriteRegister)
844 {
845 /* Store the value in the register */
846 if (ModRegRm->Register & 0x04)
847 {
848 /* AH, CH, DH, BH */
849 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
850 }
851 else
852 {
853 /* AL, CL, DL, BL */
854 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
855 }
856 }
857 else
858 {
859 if (!ModRegRm->Memory)
860 {
861 /* Store the value in the second register */
862 if (ModRegRm->SecondRegister & 0x04)
863 {
864 /* AH, CH, DH, BH */
865 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
866 }
867 else
868 {
869 /* AL, CL, DL, BL */
870 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
871 }
872 }
873 else
874 {
875 /* Check for the segment override */
876 if (State->PrefixFlags & FAST486_PREFIX_SEG)
877 {
878 /* Use the override segment instead */
879 Segment = State->SegmentOverride;
880 }
881
882 /* Write memory */
883 if (!Fast486WriteMemory(State,
884 Segment,
885 ModRegRm->MemoryAddress,
886 &Value,
887 sizeof(UCHAR)))
888 {
889 /* Exception occurred */
890 return FALSE;
891 }
892 }
893 }
894
895 return TRUE;
896 }
897
898 FORCEINLINE
899 BOOLEAN
900 Fast486WriteModrmWordOperands(PFAST486_STATE State,
901 PFAST486_MOD_REG_RM ModRegRm,
902 BOOLEAN WriteRegister,
903 USHORT Value)
904 {
905 FAST486_SEG_REGS Segment = FAST486_REG_DS;
906
907 if (WriteRegister)
908 {
909 /* Store the value in the register */
910 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
911 }
912 else
913 {
914 if (!ModRegRm->Memory)
915 {
916 /* Store the value in the second register */
917 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
918 }
919 else
920 {
921 /* Check for the segment override */
922 if (State->PrefixFlags & FAST486_PREFIX_SEG)
923 {
924 /* Use the override segment instead */
925 Segment = State->SegmentOverride;
926 }
927
928 /* Write memory */
929 if (!Fast486WriteMemory(State,
930 Segment,
931 ModRegRm->MemoryAddress,
932 &Value,
933 sizeof(USHORT)))
934 {
935 /* Exception occurred */
936 return FALSE;
937 }
938 }
939 }
940
941 return TRUE;
942 }
943
944 FORCEINLINE
945 BOOLEAN
946 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
947 PFAST486_MOD_REG_RM ModRegRm,
948 BOOLEAN WriteRegister,
949 ULONG Value)
950 {
951 FAST486_SEG_REGS Segment = FAST486_REG_DS;
952
953 if (WriteRegister)
954 {
955 /* Store the value in the register */
956 State->GeneralRegs[ModRegRm->Register].Long = Value;
957 }
958 else
959 {
960 if (!ModRegRm->Memory)
961 {
962 /* Store the value in the second register */
963 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
964 }
965 else
966 {
967 /* Check for the segment override */
968 if (State->PrefixFlags & FAST486_PREFIX_SEG)
969 {
970 /* Use the override segment instead */
971 Segment = State->SegmentOverride;
972 }
973
974 /* Write memory */
975 if (!Fast486WriteMemory(State,
976 Segment,
977 ModRegRm->MemoryAddress,
978 &Value,
979 sizeof(ULONG)))
980 {
981 /* Exception occurred */
982 return FALSE;
983 }
984 }
985 }
986
987 return TRUE;
988 }
989
990 /* EOF */