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