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