[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 #include "common.h"
23
24 /* PUBLIC FUNCTIONS ***********************************************************/
25
26 FORCEINLINE
27 ULONG
28 Fast486GetPageTableEntry(PFAST486_STATE State,
29 ULONG VirtualAddress,
30 BOOLEAN MarkAsDirty)
31 {
32 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
33 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
34 FAST486_PAGE_DIR DirectoryEntry;
35 FAST486_PAGE_TABLE TableEntry;
36 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
37
38 if ((State->Tlb != NULL)
39 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
40 {
41 /* Return the cached entry */
42 return State->Tlb[VirtualAddress >> 12];
43 }
44
45 /* Read the directory entry */
46 State->MemReadCallback(State,
47 PageDirectory + PdeIndex * sizeof(ULONG),
48 &DirectoryEntry.Value,
49 sizeof(DirectoryEntry));
50
51 /* Make sure it is present */
52 if (!DirectoryEntry.Present) return 0;
53
54 /* Was the directory entry accessed before? */
55 if (!DirectoryEntry.Accessed)
56 {
57 /* Well, it is now */
58 DirectoryEntry.Accessed = TRUE;
59
60 /* Write back the directory entry */
61 State->MemWriteCallback(State,
62 PageDirectory + PdeIndex * sizeof(ULONG),
63 &DirectoryEntry.Value,
64 sizeof(DirectoryEntry));
65 }
66
67 /* Read the table entry */
68 State->MemReadCallback(State,
69 (DirectoryEntry.TableAddress << 12)
70 + PteIndex * sizeof(ULONG),
71 &TableEntry.Value,
72 sizeof(TableEntry));
73
74 /* Make sure it is present */
75 if (!TableEntry.Present) return 0;
76
77 if (MarkAsDirty) TableEntry.Dirty = TRUE;
78
79 /* Was the table entry accessed before? */
80 if (!TableEntry.Accessed)
81 {
82 /* Well, it is now */
83 TableEntry.Accessed = TRUE;
84
85 /* Write back the table entry */
86 State->MemWriteCallback(State,
87 (DirectoryEntry.TableAddress << 12)
88 + PteIndex * sizeof(ULONG),
89 &TableEntry.Value,
90 sizeof(TableEntry));
91 }
92
93 /*
94 * The resulting permissions depend on the permissions
95 * in the page directory table too
96 */
97 TableEntry.Writeable &= DirectoryEntry.Writeable;
98 TableEntry.Usermode &= DirectoryEntry.Usermode;
99
100 if (State->Tlb != NULL)
101 {
102 /* Set the TLB entry */
103 State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
104 }
105
106 /* Return the table entry */
107 return TableEntry.Value;
108 }
109
110 FORCEINLINE
111 BOOLEAN
112 Fast486ReadLinearMemory(PFAST486_STATE State,
113 ULONG LinearAddress,
114 PVOID Buffer,
115 ULONG Size)
116 {
117 INT Cpl = Fast486GetCurrentPrivLevel(State);
118
119 /* Check if paging is enabled */
120 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
121 {
122 ULONG Page;
123 FAST486_PAGE_TABLE TableEntry;
124
125 for (Page = PAGE_ALIGN(LinearAddress);
126 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
127 Page += PAGE_SIZE)
128 {
129 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
130
131 /* Get the table entry */
132 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
133
134 if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
135 {
136 /* Exception */
137 Fast486ExceptionWithErrorCode(State,
138 FAST486_EXCEPTION_PF,
139 TableEntry.Value & 0x07);
140 return FALSE;
141 }
142
143 /* Check if this is the first page */
144 if (Page == PAGE_ALIGN(LinearAddress))
145 {
146 /* Start copying from the offset from the beginning of the page */
147 PageOffset = PAGE_OFFSET(LinearAddress);
148 }
149
150 /* Check if this is the last page */
151 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
152 {
153 /* Copy only a part of the page */
154 PageLength = PAGE_OFFSET(LinearAddress + Size);
155 }
156
157 /* Read the memory */
158 State->MemReadCallback(State,
159 (TableEntry.Address << 12) | PageOffset,
160 Buffer,
161 PageLength);
162 }
163 }
164 else
165 {
166 /* Read the memory */
167 State->MemReadCallback(State, LinearAddress, Buffer, Size);
168 }
169
170 return TRUE;
171 }
172
173 FORCEINLINE
174 BOOLEAN
175 Fast486WriteLinearMemory(PFAST486_STATE State,
176 ULONG LinearAddress,
177 PVOID Buffer,
178 ULONG Size)
179 {
180 INT Cpl = Fast486GetCurrentPrivLevel(State);
181
182 /* Check if paging is enabled */
183 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
184 {
185 ULONG Page;
186 FAST486_PAGE_TABLE TableEntry;
187
188 for (Page = PAGE_ALIGN(LinearAddress);
189 Page <= PAGE_ALIGN(LinearAddress + Size - 1);
190 Page += PAGE_SIZE)
191 {
192 ULONG PageOffset = 0, PageLength = PAGE_SIZE;
193
194 /* Get the table entry */
195 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
196
197 if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
198 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
199 && !TableEntry.Writeable))
200 {
201 /* Exception */
202 Fast486ExceptionWithErrorCode(State,
203 FAST486_EXCEPTION_PF,
204 TableEntry.Value & 0x07);
205 return FALSE;
206 }
207
208 /* Check if this is the first page */
209 if (Page == PAGE_ALIGN(LinearAddress))
210 {
211 /* Start copying from the offset from the beginning of the page */
212 PageOffset = PAGE_OFFSET(LinearAddress);
213 }
214
215 /* Check if this is the last page */
216 if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
217 {
218 /* Copy only a part of the page */
219 PageLength = PAGE_OFFSET(LinearAddress + Size);
220 }
221
222 /* Write the memory */
223 State->MemWriteCallback(State,
224 (TableEntry.Address << 12) | PageOffset,
225 Buffer,
226 PageLength);
227 }
228 }
229 else
230 {
231 /* Write the memory */
232 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
233 }
234
235 return TRUE;
236 }
237
238 FORCEINLINE
239 VOID
240 Fast486Exception(PFAST486_STATE State,
241 FAST486_EXCEPTIONS ExceptionCode)
242 {
243 /* Call the internal function */
244 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0);
245 }
246
247 FORCEINLINE
248 BOOLEAN
249 Fast486StackPush(PFAST486_STATE State,
250 ULONG Value)
251 {
252 BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
253
254 /* The OPSIZE prefix toggles the size */
255 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
256
257 if (Size)
258 {
259 /* 32-bit size */
260
261 /* Check if ESP is between 1 and 3 */
262 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1
263 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3)
264 {
265 Fast486Exception(State, FAST486_EXCEPTION_SS);
266 return FALSE;
267 }
268
269 /* Subtract ESP by 4 */
270 State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
271
272 /* Store the value in SS:ESP */
273 return Fast486WriteMemory(State,
274 FAST486_REG_SS,
275 State->GeneralRegs[FAST486_REG_ESP].Long,
276 &Value,
277 sizeof(ULONG));
278 }
279 else
280 {
281 /* 16-bit size */
282 USHORT ShortValue = LOWORD(Value);
283
284 /* Check if SP is 1 */
285 if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
286 {
287 Fast486Exception(State, FAST486_EXCEPTION_SS);
288 return FALSE;
289 }
290
291 /* Subtract SP by 2 */
292 State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
293
294 /* Store the value in SS:SP */
295 return Fast486WriteMemory(State,
296 FAST486_REG_SS,
297 State->GeneralRegs[FAST486_REG_ESP].LowWord,
298 &ShortValue,
299 sizeof(USHORT));
300 }
301 }
302
303 FORCEINLINE
304 BOOLEAN
305 Fast486StackPop(PFAST486_STATE State,
306 PULONG Value)
307 {
308 ULONG LongValue;
309 USHORT ShortValue;
310 BOOLEAN Size = State->SegmentRegs[FAST486_REG_SS].Size;
311
312 /* The OPSIZE prefix toggles the size */
313 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE) Size = !Size;
314
315 if (Size)
316 {
317 /* 32-bit size */
318
319 /* Check if ESP is 0xFFFFFFFF */
320 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
321 {
322 Fast486Exception(State, FAST486_EXCEPTION_SS);
323 return FALSE;
324 }
325
326 /* Read the value from SS:ESP */
327 if (!Fast486ReadMemory(State,
328 FAST486_REG_SS,
329 State->GeneralRegs[FAST486_REG_ESP].Long,
330 FALSE,
331 &LongValue,
332 sizeof(LongValue)))
333 {
334 /* An exception occurred */
335 return FALSE;
336 }
337
338 /* Increment ESP by 4 */
339 State->GeneralRegs[FAST486_REG_ESP].Long += 4;
340
341 /* Store the value in the result */
342 *Value = LongValue;
343 }
344 else
345 {
346 /* 16-bit size */
347
348 /* Check if SP is 0xFFFF */
349 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
350 {
351 Fast486Exception(State, FAST486_EXCEPTION_SS);
352 return FALSE;
353 }
354
355 /* Read the value from SS:SP */
356 if (!Fast486ReadMemory(State,
357 FAST486_REG_SS,
358 State->GeneralRegs[FAST486_REG_ESP].LowWord,
359 FALSE,
360 &ShortValue,
361 sizeof(ShortValue)))
362 {
363 /* An exception occurred */
364 return FALSE;
365 }
366
367 /* Increment SP by 2 */
368 State->GeneralRegs[FAST486_REG_ESP].Long += 2;
369
370 /* Store the value in the result */
371 *Value = ShortValue;
372 }
373
374 return TRUE;
375 }
376
377 FORCEINLINE
378 BOOLEAN
379 Fast486LoadSegment(PFAST486_STATE State,
380 INT Segment,
381 USHORT Selector)
382 {
383 PFAST486_SEG_REG CachedDescriptor;
384 FAST486_GDT_ENTRY GdtEntry;
385
386 ASSERT(Segment < FAST486_NUM_SEG_REGS);
387
388 /* Get the cached descriptor */
389 CachedDescriptor = &State->SegmentRegs[Segment];
390
391 /* Check for protected mode */
392 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
393 {
394 /* Make sure the GDT contains the entry */
395 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
396 {
397 Fast486Exception(State, FAST486_EXCEPTION_GP);
398 return FALSE;
399 }
400
401 /* Read the GDT */
402 if (!Fast486ReadLinearMemory(State,
403 State->Gdtr.Address
404 + GET_SEGMENT_INDEX(Selector),
405 &GdtEntry,
406 sizeof(GdtEntry)))
407 {
408 /* Exception occurred */
409 return FALSE;
410 }
411
412 if (Segment == FAST486_REG_SS)
413 {
414 /* Loading the stack segment */
415
416 if (GET_SEGMENT_INDEX(Selector) == 0)
417 {
418 Fast486Exception(State, FAST486_EXCEPTION_GP);
419 return FALSE;
420 }
421
422 if (!GdtEntry.SystemType)
423 {
424 /* This is a special descriptor */
425 Fast486Exception(State, FAST486_EXCEPTION_GP);
426 return FALSE;
427 }
428
429 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
430 {
431 Fast486Exception(State, FAST486_EXCEPTION_GP);
432 return FALSE;
433 }
434
435 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
436 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
437 {
438 Fast486Exception(State, FAST486_EXCEPTION_GP);
439 return FALSE;
440 }
441
442 if (!GdtEntry.Present)
443 {
444 Fast486Exception(State, FAST486_EXCEPTION_SS);
445 return FALSE;
446 }
447 }
448 else if (Segment == FAST486_REG_CS)
449 {
450 /* Loading the code segment */
451 // TODO: NOT IMPLEMENTED
452 }
453 else
454 {
455 /* Loading a data segment */
456
457 if (!GdtEntry.SystemType)
458 {
459 /* This is a special descriptor */
460 Fast486Exception(State, FAST486_EXCEPTION_GP);
461 return FALSE;
462 }
463
464 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
465 && (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
466 {
467 Fast486Exception(State, FAST486_EXCEPTION_GP);
468 return FALSE;
469 }
470
471 if (!GdtEntry.Present)
472 {
473 Fast486Exception(State, FAST486_EXCEPTION_NP);
474 return FALSE;
475 }
476 }
477
478 /* Update the cache entry */
479 CachedDescriptor->Selector = Selector;
480 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
481 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
482 CachedDescriptor->Accessed = GdtEntry.Accessed;
483 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
484 CachedDescriptor->DirConf = GdtEntry.DirConf;
485 CachedDescriptor->Executable = GdtEntry.Executable;
486 CachedDescriptor->SystemType = GdtEntry.SystemType;
487 CachedDescriptor->Dpl = GdtEntry.Dpl;
488 CachedDescriptor->Present = GdtEntry.Present;
489 CachedDescriptor->Size = GdtEntry.Size;
490
491 /* Check for page granularity */
492 if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
493 }
494 else
495 {
496 /* Update the selector and base */
497 CachedDescriptor->Selector = Selector;
498 CachedDescriptor->Base = Selector << 4;
499 }
500
501 return TRUE;
502 }
503
504 FORCEINLINE
505 BOOLEAN
506 Fast486FetchByte(PFAST486_STATE State,
507 PUCHAR Data)
508 {
509 PFAST486_SEG_REG CachedDescriptor;
510
511 /* Get the cached descriptor of CS */
512 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
513
514 /* Read from memory */
515 if (!Fast486ReadMemory(State,
516 FAST486_REG_CS,
517 (CachedDescriptor->Size) ? State->InstPtr.Long
518 : State->InstPtr.LowWord,
519 TRUE,
520 Data,
521 sizeof(UCHAR)))
522 {
523 /* Exception occurred during instruction fetch */
524 return FALSE;
525 }
526
527 /* Advance the instruction pointer */
528 if (CachedDescriptor->Size) State->InstPtr.Long++;
529 else State->InstPtr.LowWord++;
530
531 return TRUE;
532 }
533
534 FORCEINLINE
535 BOOLEAN
536 Fast486FetchWord(PFAST486_STATE State,
537 PUSHORT Data)
538 {
539 PFAST486_SEG_REG CachedDescriptor;
540
541 /* Get the cached descriptor of CS */
542 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
543
544 /* Read from memory */
545 // FIXME: Fix byte order on big-endian machines
546 if (!Fast486ReadMemory(State,
547 FAST486_REG_CS,
548 (CachedDescriptor->Size) ? State->InstPtr.Long
549 : State->InstPtr.LowWord,
550 TRUE,
551 Data,
552 sizeof(USHORT)))
553 {
554 /* Exception occurred during instruction fetch */
555 return FALSE;
556 }
557
558 /* Advance the instruction pointer */
559 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
560 else State->InstPtr.LowWord += sizeof(USHORT);
561
562 return TRUE;
563 }
564
565 FORCEINLINE
566 BOOLEAN
567 Fast486FetchDword(PFAST486_STATE State,
568 PULONG Data)
569 {
570 PFAST486_SEG_REG CachedDescriptor;
571
572 /* Get the cached descriptor of CS */
573 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
574
575 /* Read from memory */
576 // FIXME: Fix byte order on big-endian machines
577 if (!Fast486ReadMemory(State,
578 FAST486_REG_CS,
579 (CachedDescriptor->Size) ? State->InstPtr.Long
580 : State->InstPtr.LowWord,
581 TRUE,
582 Data,
583 sizeof(ULONG)))
584 {
585 /* Exception occurred during instruction fetch */
586 return FALSE;
587 }
588
589 /* Advance the instruction pointer */
590 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
591 else State->InstPtr.LowWord += sizeof(ULONG);
592
593 return TRUE;
594 }
595
596 FORCEINLINE
597 BOOLEAN
598 Fast486GetIntVector(PFAST486_STATE State,
599 UCHAR Number,
600 PFAST486_IDT_ENTRY IdtEntry)
601 {
602 ULONG FarPointer;
603
604 /* Check for protected mode */
605 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
606 {
607 /* Read from the IDT */
608 if (!Fast486ReadLinearMemory(State,
609 State->Idtr.Address
610 + Number * sizeof(*IdtEntry),
611 IdtEntry,
612 sizeof(*IdtEntry)))
613 {
614 /* Exception occurred */
615 return FALSE;
616 }
617 }
618 else
619 {
620 /* Read from the real-mode IVT */
621
622 /* Paging is always disabled in real mode */
623 State->MemReadCallback(State,
624 State->Idtr.Address
625 + Number * sizeof(FarPointer),
626 &FarPointer,
627 sizeof(FarPointer));
628
629 /* Fill a fake IDT entry */
630 IdtEntry->Offset = LOWORD(FarPointer);
631 IdtEntry->Selector = HIWORD(FarPointer);
632 IdtEntry->Zero = 0;
633 IdtEntry->Type = FAST486_IDT_INT_GATE;
634 IdtEntry->Storage = FALSE;
635 IdtEntry->Dpl = 0;
636 IdtEntry->Present = TRUE;
637 IdtEntry->OffsetHigh = 0;
638 }
639
640 return TRUE;
641 }
642
643 FORCEINLINE
644 BOOLEAN
645 Fast486CalculateParity(UCHAR Number)
646 {
647 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
648 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
649 }
650
651 FORCEINLINE
652 BOOLEAN
653 Fast486ParseModRegRm(PFAST486_STATE State,
654 BOOLEAN AddressSize,
655 PFAST486_MOD_REG_RM ModRegRm)
656 {
657 UCHAR ModRmByte, Mode, RegMem;
658
659 /* Fetch the MOD REG R/M byte */
660 if (!Fast486FetchByte(State, &ModRmByte))
661 {
662 /* Exception occurred */
663 return FALSE;
664 }
665
666 /* Unpack the mode and R/M */
667 Mode = ModRmByte >> 6;
668 RegMem = ModRmByte & 0x07;
669
670 /* Set the register operand */
671 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
672
673 /* Check the mode */
674 if ((ModRmByte >> 6) == 3)
675 {
676 /* The second operand is also a register */
677 ModRegRm->Memory = FALSE;
678 ModRegRm->SecondRegister = RegMem;
679
680 /* Done parsing */
681 return TRUE;
682 }
683
684 /* The second operand is memory */
685 ModRegRm->Memory = TRUE;
686
687 if (AddressSize)
688 {
689 if (RegMem == FAST486_REG_ESP)
690 {
691 UCHAR SibByte;
692 ULONG Scale, Index, Base;
693
694 /* Fetch the SIB byte */
695 if (!Fast486FetchByte(State, &SibByte))
696 {
697 /* Exception occurred */
698 return FALSE;
699 }
700
701 /* Unpack the scale, index and base */
702 Scale = 1 << (SibByte >> 6);
703 Index = (SibByte >> 3) & 0x07;
704 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
705 else Index = 0;
706 Base = State->GeneralRegs[SibByte & 0x07].Long;
707
708 /* Calculate the address */
709 ModRegRm->MemoryAddress = Base + Index * Scale;
710 }
711 else if (RegMem == FAST486_REG_EBP)
712 {
713 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
714 else ModRegRm->MemoryAddress = 0;
715 }
716 else
717 {
718 /* Get the base from the register */
719 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
720 }
721
722 /* Check if there is no segment override */
723 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
724 {
725 /* Check if the default segment should be SS */
726 if ((RegMem == FAST486_REG_EBP) && Mode)
727 {
728 /* Add a SS: prefix */
729 State->PrefixFlags |= FAST486_PREFIX_SEG;
730 State->SegmentOverride = FAST486_REG_SS;
731 }
732 }
733
734 if (Mode == 1)
735 {
736 CHAR Offset;
737
738 /* Fetch the byte */
739 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
740 {
741 /* Exception occurred */
742 return FALSE;
743 }
744
745 /* Add the signed offset to the address */
746 ModRegRm->MemoryAddress += (LONG)Offset;
747 }
748 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
749 {
750 LONG Offset;
751
752 /* Fetch the dword */
753 if (!Fast486FetchDword(State, (PULONG)&Offset))
754 {
755 /* Exception occurred */
756 return FALSE;
757 }
758
759 /* Add the signed offset to the address */
760 ModRegRm->MemoryAddress += Offset;
761 }
762 }
763 else
764 {
765 /* Check the operand */
766 switch (RegMem)
767 {
768 case 0:
769 {
770 /* [BX + SI] */
771 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
772 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
773
774 break;
775 }
776
777 case 1:
778 {
779 /* [BX + DI] */
780 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
781 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
782
783 break;
784 }
785
786 case 2:
787 {
788 /* SS:[BP + SI] */
789 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
790 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
791
792 break;
793 }
794
795 case 3:
796 {
797 /* SS:[BP + DI] */
798 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
799 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
800
801 break;
802 }
803
804 case 4:
805 {
806 /* [SI] */
807 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
808
809 break;
810 }
811
812 case 5:
813 {
814 /* [DI] */
815 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
816
817 break;
818 }
819
820 case 6:
821 {
822 if (Mode)
823 {
824 /* [BP] */
825 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
826 }
827 else
828 {
829 /* [constant] (added later) */
830 ModRegRm->MemoryAddress = 0;
831 }
832
833 break;
834 }
835
836 case 7:
837 {
838 /* [BX] */
839 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
840
841 break;
842 }
843 }
844
845 /* Check if there is no segment override */
846 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
847 {
848 /* Check if the default segment should be SS */
849 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
850 {
851 /* Add a SS: prefix */
852 State->PrefixFlags |= FAST486_PREFIX_SEG;
853 State->SegmentOverride = FAST486_REG_SS;
854 }
855 }
856
857 if (Mode == 1)
858 {
859 CHAR Offset;
860
861 /* Fetch the byte */
862 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
863 {
864 /* Exception occurred */
865 return FALSE;
866 }
867
868 /* Add the signed offset to the address */
869 ModRegRm->MemoryAddress += (LONG)Offset;
870 }
871 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
872 {
873 SHORT Offset;
874
875 /* Fetch the word */
876 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
877 {
878 /* Exception occurred */
879 return FALSE;
880 }
881
882 /* Add the signed offset to the address */
883 ModRegRm->MemoryAddress += (LONG)Offset;
884 }
885
886 /* Clear the top 16 bits */
887 ModRegRm->MemoryAddress &= 0x0000FFFF;
888 }
889
890 return TRUE;
891 }
892
893 FORCEINLINE
894 BOOLEAN
895 Fast486ReadModrmByteOperands(PFAST486_STATE State,
896 PFAST486_MOD_REG_RM ModRegRm,
897 PUCHAR RegValue,
898 PUCHAR RmValue)
899 {
900 FAST486_SEG_REGS Segment = FAST486_REG_DS;
901
902 /* Get the register value */
903 if (ModRegRm->Register & 0x04)
904 {
905 /* AH, CH, DH, BH */
906 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
907 }
908 else
909 {
910 /* AL, CL, DL, BL */
911 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
912 }
913
914 if (!ModRegRm->Memory)
915 {
916 /* Get the second register value */
917 if (ModRegRm->SecondRegister & 0x04)
918 {
919 /* AH, CH, DH, BH */
920 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
921 }
922 else
923 {
924 /* AL, CL, DL, BL */
925 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
926 }
927 }
928 else
929 {
930 /* Check for the segment override */
931 if (State->PrefixFlags & FAST486_PREFIX_SEG)
932 {
933 /* Use the override segment instead */
934 Segment = State->SegmentOverride;
935 }
936
937 /* Read memory */
938 if (!Fast486ReadMemory(State,
939 Segment,
940 ModRegRm->MemoryAddress,
941 FALSE,
942 RmValue,
943 sizeof(UCHAR)))
944 {
945 /* Exception occurred */
946 return FALSE;
947 }
948 }
949
950 return TRUE;
951 }
952
953 FORCEINLINE
954 BOOLEAN
955 Fast486ReadModrmWordOperands(PFAST486_STATE State,
956 PFAST486_MOD_REG_RM ModRegRm,
957 PUSHORT RegValue,
958 PUSHORT RmValue)
959 {
960 FAST486_SEG_REGS Segment = FAST486_REG_DS;
961
962 /* Get the register value */
963 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
964
965 if (!ModRegRm->Memory)
966 {
967 /* Get the second register value */
968 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
969 }
970 else
971 {
972 /* Check for the segment override */
973 if (State->PrefixFlags & FAST486_PREFIX_SEG)
974 {
975 /* Use the override segment instead */
976 Segment = State->SegmentOverride;
977 }
978
979 /* Read memory */
980 if (!Fast486ReadMemory(State,
981 Segment,
982 ModRegRm->MemoryAddress,
983 FALSE,
984 RmValue,
985 sizeof(USHORT)))
986 {
987 /* Exception occurred */
988 return FALSE;
989 }
990 }
991
992 return TRUE;
993 }
994
995 FORCEINLINE
996 BOOLEAN
997 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
998 PFAST486_MOD_REG_RM ModRegRm,
999 PULONG RegValue,
1000 PULONG RmValue)
1001 {
1002 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1003
1004 /* Get the register value */
1005 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1006
1007 if (!ModRegRm->Memory)
1008 {
1009 /* Get the second register value */
1010 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1011 }
1012 else
1013 {
1014 /* Check for the segment override */
1015 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1016 {
1017 /* Use the override segment instead */
1018 Segment = State->SegmentOverride;
1019 }
1020
1021 /* Read memory */
1022 if (!Fast486ReadMemory(State,
1023 Segment,
1024 ModRegRm->MemoryAddress,
1025 FALSE,
1026 RmValue,
1027 sizeof(ULONG)))
1028 {
1029 /* Exception occurred */
1030 return FALSE;
1031 }
1032 }
1033
1034 return TRUE;
1035 }
1036
1037 FORCEINLINE
1038 BOOLEAN
1039 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1040 PFAST486_MOD_REG_RM ModRegRm,
1041 BOOLEAN WriteRegister,
1042 UCHAR Value)
1043 {
1044 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1045
1046 if (WriteRegister)
1047 {
1048 /* Store the value in the register */
1049 if (ModRegRm->Register & 0x04)
1050 {
1051 /* AH, CH, DH, BH */
1052 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1053 }
1054 else
1055 {
1056 /* AL, CL, DL, BL */
1057 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1058 }
1059 }
1060 else
1061 {
1062 if (!ModRegRm->Memory)
1063 {
1064 /* Store the value in the second register */
1065 if (ModRegRm->SecondRegister & 0x04)
1066 {
1067 /* AH, CH, DH, BH */
1068 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1069 }
1070 else
1071 {
1072 /* AL, CL, DL, BL */
1073 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1074 }
1075 }
1076 else
1077 {
1078 /* Check for the segment override */
1079 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1080 {
1081 /* Use the override segment instead */
1082 Segment = State->SegmentOverride;
1083 }
1084
1085 /* Write memory */
1086 if (!Fast486WriteMemory(State,
1087 Segment,
1088 ModRegRm->MemoryAddress,
1089 &Value,
1090 sizeof(UCHAR)))
1091 {
1092 /* Exception occurred */
1093 return FALSE;
1094 }
1095 }
1096 }
1097
1098 return TRUE;
1099 }
1100
1101 FORCEINLINE
1102 BOOLEAN
1103 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1104 PFAST486_MOD_REG_RM ModRegRm,
1105 BOOLEAN WriteRegister,
1106 USHORT Value)
1107 {
1108 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1109
1110 if (WriteRegister)
1111 {
1112 /* Store the value in the register */
1113 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1114 }
1115 else
1116 {
1117 if (!ModRegRm->Memory)
1118 {
1119 /* Store the value in the second register */
1120 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1121 }
1122 else
1123 {
1124 /* Check for the segment override */
1125 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1126 {
1127 /* Use the override segment instead */
1128 Segment = State->SegmentOverride;
1129 }
1130
1131 /* Write memory */
1132 if (!Fast486WriteMemory(State,
1133 Segment,
1134 ModRegRm->MemoryAddress,
1135 &Value,
1136 sizeof(USHORT)))
1137 {
1138 /* Exception occurred */
1139 return FALSE;
1140 }
1141 }
1142 }
1143
1144 return TRUE;
1145 }
1146
1147 FORCEINLINE
1148 BOOLEAN
1149 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1150 PFAST486_MOD_REG_RM ModRegRm,
1151 BOOLEAN WriteRegister,
1152 ULONG Value)
1153 {
1154 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1155
1156 if (WriteRegister)
1157 {
1158 /* Store the value in the register */
1159 State->GeneralRegs[ModRegRm->Register].Long = Value;
1160 }
1161 else
1162 {
1163 if (!ModRegRm->Memory)
1164 {
1165 /* Store the value in the second register */
1166 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1167 }
1168 else
1169 {
1170 /* Check for the segment override */
1171 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1172 {
1173 /* Use the override segment instead */
1174 Segment = State->SegmentOverride;
1175 }
1176
1177 /* Write memory */
1178 if (!Fast486WriteMemory(State,
1179 Segment,
1180 ModRegRm->MemoryAddress,
1181 &Value,
1182 sizeof(ULONG)))
1183 {
1184 /* Exception occurred */
1185 return FALSE;
1186 }
1187 }
1188 }
1189
1190 return TRUE;
1191 }
1192
1193 /* EOF */