[FAST486]
[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->SegmentRegs[FAST486_REG_SS].Size
412 ? State->GeneralRegs[FAST486_REG_ESP].Long
413 : State->GeneralRegs[FAST486_REG_ESP].LowWord,
414 FALSE,
415 &LongValue,
416 sizeof(LongValue)))
417 {
418 /* An exception occurred */
419 return FALSE;
420 }
421
422 if (State->SegmentRegs[FAST486_REG_SS].Size)
423 {
424 /* Increment ESP by 4 */
425 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
426 }
427 else
428 {
429 /* Increment SP by 4 */
430 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(ULONG);
431 }
432
433 /* Store the value in the result */
434 *Value = LongValue;
435 }
436 else
437 {
438 /* 16-bit size */
439 USHORT ShortValue;
440
441 /* Check if SP is 0xFFFF */
442 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
443 {
444 Fast486Exception(State, FAST486_EXCEPTION_SS);
445 return FALSE;
446 }
447
448 /* Read the value from SS:SP */
449 if (!Fast486ReadMemory(State,
450 FAST486_REG_SS,
451 State->SegmentRegs[FAST486_REG_SS].Size
452 ? State->GeneralRegs[FAST486_REG_ESP].Long
453 : State->GeneralRegs[FAST486_REG_ESP].LowWord,
454 FALSE,
455 &ShortValue,
456 sizeof(ShortValue)))
457 {
458 /* An exception occurred */
459 return FALSE;
460 }
461
462 if (State->SegmentRegs[FAST486_REG_SS].Size)
463 {
464 /* Increment ESP by 2 */
465 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(USHORT);
466 }
467 else
468 {
469 /* Increment SP by 2 */
470 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
471 }
472
473 /* Store the value in the result */
474 *Value = ShortValue;
475 }
476
477 return TRUE;
478 }
479
480 FORCEINLINE
481 BOOLEAN
482 FASTCALL
483 Fast486ReadDescriptorEntry(PFAST486_STATE State,
484 USHORT Selector,
485 PBOOLEAN EntryValid,
486 PFAST486_GDT_ENTRY Entry)
487 {
488 if (!(Selector & SEGMENT_TABLE_INDICATOR))
489 {
490 /* Make sure the GDT contains the entry */
491 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
492 {
493 *EntryValid = FALSE;
494 return TRUE;
495 }
496
497 /* Read the GDT */
498 if (!Fast486ReadLinearMemory(State,
499 State->Gdtr.Address
500 + GET_SEGMENT_INDEX(Selector),
501 Entry,
502 sizeof(*Entry)))
503 {
504 /* Exception occurred */
505 *EntryValid = FALSE;
506 return FALSE;
507 }
508 }
509 else
510 {
511 /* Make sure the LDT contains the entry */
512 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1u))
513 {
514 *EntryValid = FALSE;
515 return TRUE;
516 }
517
518 /* Read the LDT */
519 if (!Fast486ReadLinearMemory(State,
520 State->Ldtr.Base
521 + GET_SEGMENT_INDEX(Selector),
522 Entry,
523 sizeof(*Entry)))
524 {
525 /* Exception occurred */
526 *EntryValid = FALSE;
527 return FALSE;
528 }
529 }
530
531 *EntryValid = TRUE;
532 return TRUE;
533 }
534
535 FORCEINLINE
536 BOOLEAN
537 FASTCALL
538 Fast486LoadSegmentInternal(PFAST486_STATE State,
539 FAST486_SEG_REGS Segment,
540 USHORT Selector,
541 FAST486_EXCEPTIONS Exception)
542 {
543 PFAST486_SEG_REG CachedDescriptor;
544 BOOLEAN Valid;
545 FAST486_GDT_ENTRY GdtEntry;
546
547 ASSERT(Segment < FAST486_NUM_SEG_REGS);
548
549 /* Get the cached descriptor */
550 CachedDescriptor = &State->SegmentRegs[Segment];
551
552 /* Check for protected mode */
553 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
554 {
555 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
556 {
557 /* Exception occurred */
558 return FALSE;
559 }
560
561 if (!Valid)
562 {
563 /* Invalid selector */
564 Fast486ExceptionWithErrorCode(State, Exception, Selector);
565 return FALSE;
566 }
567
568 if (Segment == FAST486_REG_SS)
569 {
570 /* Loading the stack segment */
571
572 if (GET_SEGMENT_INDEX(Selector) == 0)
573 {
574 Fast486Exception(State, Exception);
575 return FALSE;
576 }
577
578 if (!GdtEntry.SystemType)
579 {
580 /* This is a special descriptor */
581 Fast486ExceptionWithErrorCode(State, Exception, Selector);
582 return FALSE;
583 }
584
585 if (GdtEntry.Executable || !GdtEntry.ReadWrite)
586 {
587 Fast486ExceptionWithErrorCode(State, Exception, Selector);
588 return FALSE;
589 }
590
591 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
592 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
593 {
594 Fast486ExceptionWithErrorCode(State, Exception, Selector);
595 return FALSE;
596 }
597
598 if (!GdtEntry.Present)
599 {
600 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
601 return FALSE;
602 }
603 }
604 else if (Segment == FAST486_REG_CS)
605 {
606 /* Loading the code segment */
607
608 #ifndef FAST486_NO_PREFETCH
609 /* Invalidate the prefetch */
610 State->PrefetchValid = FALSE;
611 #endif
612
613 if (GET_SEGMENT_INDEX(Selector) == 0)
614 {
615 Fast486Exception(State, Exception);
616 return FALSE;
617 }
618
619 if (!GdtEntry.SystemType)
620 {
621 /* Must be a segment descriptor */
622 Fast486ExceptionWithErrorCode(State, Exception, Selector);
623 return FALSE;
624 }
625
626 if (!GdtEntry.Present)
627 {
628 Fast486ExceptionWithErrorCode(State, Exception, Selector);
629 return FALSE;
630 }
631
632 if (!GdtEntry.Executable)
633 {
634 Fast486ExceptionWithErrorCode(State, Exception, Selector);
635 return FALSE;
636 }
637
638 if (GdtEntry.DirConf)
639 {
640 /* Conforming Code Segment */
641
642 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
643 {
644 /* Must be accessed from lower-privileged code */
645 Fast486ExceptionWithErrorCode(State, Exception, Selector);
646 return FALSE;
647 }
648 }
649 else
650 {
651 /* Regular code segment */
652
653 if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State)))
654 {
655 Fast486ExceptionWithErrorCode(State, Exception, Selector);
656 return FALSE;
657 }
658 }
659 }
660 else
661 {
662 /* Loading a data segment */
663
664 if (GET_SEGMENT_INDEX(Selector) != 0)
665 {
666 if (!GdtEntry.SystemType)
667 {
668 /* This is a special descriptor */
669 Fast486ExceptionWithErrorCode(State, Exception, Selector);
670 return FALSE;
671 }
672
673 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
674 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
675 {
676 Fast486ExceptionWithErrorCode(State, Exception, Selector);
677 return FALSE;
678 }
679
680 if (!GdtEntry.Present)
681 {
682 Fast486ExceptionWithErrorCode(State, Exception, Selector);
683 return FALSE;
684 }
685 }
686 else
687 {
688 /* This is a NULL selector */
689 RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
690 }
691 }
692
693 /* Update the cache entry */
694 CachedDescriptor->Selector = Selector;
695 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
696 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
697 CachedDescriptor->Accessed = GdtEntry.Accessed;
698 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite;
699 CachedDescriptor->DirConf = GdtEntry.DirConf;
700 CachedDescriptor->Executable = GdtEntry.Executable;
701 CachedDescriptor->SystemType = GdtEntry.SystemType;
702 CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
703 CachedDescriptor->Dpl = GdtEntry.Dpl;
704 CachedDescriptor->Present = GdtEntry.Present;
705 CachedDescriptor->Size = GdtEntry.Size;
706
707 /* Check for page granularity */
708 if (GdtEntry.Granularity)
709 {
710 CachedDescriptor->Limit <<= 12;
711 CachedDescriptor->Limit |= 0x00000FFF;
712 }
713 }
714 else
715 {
716 /* Update the selector and base */
717 CachedDescriptor->Selector = Selector;
718 CachedDescriptor->Base = Selector << 4;
719 }
720
721 return TRUE;
722 }
723
724 FORCEINLINE
725 BOOLEAN
726 FASTCALL
727 Fast486LoadSegment(PFAST486_STATE State,
728 FAST486_SEG_REGS Segment,
729 USHORT Selector)
730 {
731 return Fast486LoadSegmentInternal(State,
732 Segment,
733 Selector,
734 FAST486_EXCEPTION_GP);
735 }
736
737 FORCEINLINE
738 BOOLEAN
739 FASTCALL
740 Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call)
741 {
742 BOOLEAN Valid;
743 FAST486_SYSTEM_DESCRIPTOR Descriptor;
744
745 if (!Fast486ReadDescriptorEntry(State,
746 Selector,
747 &Valid,
748 (PFAST486_GDT_ENTRY)&Descriptor))
749 {
750 /* Exception occurred */
751 return FALSE;
752 }
753
754 if (!Valid)
755 {
756 /* Invalid selector */
757 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
758 return FALSE;
759 }
760
761 switch (Descriptor.Signature)
762 {
763 case FAST486_TASK_GATE_SIGNATURE:
764 {
765 Fast486TaskSwitch(State,
766 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
767 ((PFAST486_IDT_ENTRY)&Descriptor)->Selector);
768
769 return FALSE;
770 }
771
772 case FAST486_TSS_SIGNATURE:
773 {
774 Fast486TaskSwitch(State,
775 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP,
776 Selector);
777
778 return FALSE;
779 }
780
781 case FAST486_CALL_GATE_SIGNATURE:
782 {
783 // TODO: NOT IMPLEMENTED
784 UNIMPLEMENTED;
785 }
786
787 default:
788 {
789 /* Security check for jumps and calls only */
790 if (State->Cpl != Descriptor.Dpl)
791 {
792 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
793 return FALSE;
794 }
795
796 return TRUE;
797 }
798 }
799 }
800
801 FORCEINLINE
802 BOOLEAN
803 FASTCALL
804 Fast486FetchByte(PFAST486_STATE State,
805 PUCHAR Data)
806 {
807 PFAST486_SEG_REG CachedDescriptor;
808 ULONG Offset;
809 #ifndef FAST486_NO_PREFETCH
810 ULONG LinearAddress;
811 #endif
812
813 /* Get the cached descriptor of CS */
814 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
815
816 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
817 : State->InstPtr.LowWord;
818 #ifndef FAST486_NO_PREFETCH
819 LinearAddress = CachedDescriptor->Base + Offset;
820
821 if (State->PrefetchValid
822 && (LinearAddress >= State->PrefetchAddress)
823 && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
824 {
825 *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
826 }
827 else
828 #endif
829 {
830 /* Read from memory */
831 if (!Fast486ReadMemory(State,
832 FAST486_REG_CS,
833 Offset,
834 TRUE,
835 Data,
836 sizeof(UCHAR)))
837 {
838 /* Exception occurred during instruction fetch */
839 return FALSE;
840 }
841 }
842
843 /* Advance the instruction pointer */
844 if (CachedDescriptor->Size) State->InstPtr.Long++;
845 else State->InstPtr.LowWord++;
846
847 return TRUE;
848 }
849
850 FORCEINLINE
851 BOOLEAN
852 FASTCALL
853 Fast486FetchWord(PFAST486_STATE State,
854 PUSHORT Data)
855 {
856 PFAST486_SEG_REG CachedDescriptor;
857 ULONG Offset;
858 #ifndef FAST486_NO_PREFETCH
859 ULONG LinearAddress;
860 #endif
861
862 /* Get the cached descriptor of CS */
863 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
864
865 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
866 : State->InstPtr.LowWord;
867
868 #ifndef FAST486_NO_PREFETCH
869 LinearAddress = CachedDescriptor->Base + Offset;
870
871 if (State->PrefetchValid
872 && (LinearAddress >= State->PrefetchAddress)
873 && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
874 {
875 *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
876 }
877 else
878 #endif
879 {
880 /* Read from memory */
881 // FIXME: Fix byte order on big-endian machines
882 if (!Fast486ReadMemory(State,
883 FAST486_REG_CS,
884 Offset,
885 TRUE,
886 Data,
887 sizeof(USHORT)))
888 {
889 /* Exception occurred during instruction fetch */
890 return FALSE;
891 }
892 }
893
894 /* Advance the instruction pointer */
895 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT);
896 else State->InstPtr.LowWord += sizeof(USHORT);
897
898 return TRUE;
899 }
900
901 FORCEINLINE
902 BOOLEAN
903 FASTCALL
904 Fast486FetchDword(PFAST486_STATE State,
905 PULONG Data)
906 {
907 PFAST486_SEG_REG CachedDescriptor;
908 ULONG Offset;
909 #ifndef FAST486_NO_PREFETCH
910 ULONG LinearAddress;
911 #endif
912
913 /* Get the cached descriptor of CS */
914 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS];
915
916 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long
917 : State->InstPtr.LowWord;
918
919 #ifndef FAST486_NO_PREFETCH
920 LinearAddress = CachedDescriptor->Base + Offset;
921
922 if (State->PrefetchValid
923 && (LinearAddress >= State->PrefetchAddress)
924 && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
925 {
926 *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress];
927 }
928 else
929 #endif
930 {
931 /* Read from memory */
932 // FIXME: Fix byte order on big-endian machines
933 if (!Fast486ReadMemory(State,
934 FAST486_REG_CS,
935 Offset,
936 TRUE,
937 Data,
938 sizeof(ULONG)))
939 {
940 /* Exception occurred during instruction fetch */
941 return FALSE;
942 }
943 }
944
945 /* Advance the instruction pointer */
946 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG);
947 else State->InstPtr.LowWord += sizeof(ULONG);
948
949 return TRUE;
950 }
951
952 FORCEINLINE
953 BOOLEAN
954 FASTCALL
955 Fast486CalculateParity(UCHAR Number)
956 {
957 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too...
958 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1;
959 }
960
961 FORCEINLINE
962 BOOLEAN
963 FASTCALL
964 Fast486ParseModRegRm(PFAST486_STATE State,
965 BOOLEAN AddressSize,
966 PFAST486_MOD_REG_RM ModRegRm)
967 {
968 UCHAR ModRmByte, Mode, RegMem;
969
970 /* Fetch the MOD REG R/M byte */
971 if (!Fast486FetchByte(State, &ModRmByte))
972 {
973 /* Exception occurred */
974 return FALSE;
975 }
976
977 /* Unpack the mode and R/M */
978 Mode = ModRmByte >> 6;
979 RegMem = ModRmByte & 0x07;
980
981 /* Set the register operand */
982 ModRegRm->Register = (ModRmByte >> 3) & 0x07;
983
984 /* Check the mode */
985 if (Mode == 3)
986 {
987 /* The second operand is also a register */
988 ModRegRm->Memory = FALSE;
989 ModRegRm->SecondRegister = RegMem;
990
991 /* Done parsing */
992 return TRUE;
993 }
994
995 /* The second operand is memory */
996 ModRegRm->Memory = TRUE;
997
998 if (AddressSize)
999 {
1000 if (RegMem == FAST486_REG_ESP)
1001 {
1002 UCHAR SibByte;
1003 ULONG Scale, Index, Base;
1004
1005 /* Fetch the SIB byte */
1006 if (!Fast486FetchByte(State, &SibByte))
1007 {
1008 /* Exception occurred */
1009 return FALSE;
1010 }
1011
1012 /* Unpack the scale, index and base */
1013 Scale = 1 << (SibByte >> 6);
1014 Index = (SibByte >> 3) & 0x07;
1015 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long;
1016 else Index = 0;
1017
1018 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0))
1019 {
1020 /* Use the register a base */
1021 Base = State->GeneralRegs[SibByte & 0x07].Long;
1022 }
1023 else
1024 {
1025 /* Fetch the base */
1026 if (!Fast486FetchDword(State, &Base))
1027 {
1028 /* Exception occurred */
1029 return FALSE;
1030 }
1031 }
1032
1033 if ((SibByte & 0x07) == FAST486_REG_ESP)
1034 {
1035 /* Check if there is no segment override */
1036 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1037 {
1038 /* Add a SS: prefix */
1039 State->PrefixFlags |= FAST486_PREFIX_SEG;
1040 State->SegmentOverride = FAST486_REG_SS;
1041 }
1042 }
1043
1044 /* Calculate the address */
1045 ModRegRm->MemoryAddress = Base + Index * Scale;
1046 }
1047 else if (RegMem == FAST486_REG_EBP)
1048 {
1049 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long;
1050 else ModRegRm->MemoryAddress = 0;
1051 }
1052 else
1053 {
1054 /* Get the base from the register */
1055 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long;
1056 }
1057
1058 /* Check if there is no segment override */
1059 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1060 {
1061 /* Check if the default segment should be SS */
1062 if ((RegMem == FAST486_REG_EBP) && Mode)
1063 {
1064 /* Add a SS: prefix */
1065 State->PrefixFlags |= FAST486_PREFIX_SEG;
1066 State->SegmentOverride = FAST486_REG_SS;
1067 }
1068 }
1069
1070 if (Mode == 1)
1071 {
1072 CHAR Offset;
1073
1074 /* Fetch the byte */
1075 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1076 {
1077 /* Exception occurred */
1078 return FALSE;
1079 }
1080
1081 /* Add the signed offset to the address */
1082 ModRegRm->MemoryAddress += (LONG)Offset;
1083 }
1084 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP)))
1085 {
1086 LONG Offset;
1087
1088 /* Fetch the dword */
1089 if (!Fast486FetchDword(State, (PULONG)&Offset))
1090 {
1091 /* Exception occurred */
1092 return FALSE;
1093 }
1094
1095 /* Add the signed offset to the address */
1096 ModRegRm->MemoryAddress += Offset;
1097 }
1098 }
1099 else
1100 {
1101 /* Check the operand */
1102 switch (RegMem)
1103 {
1104 case 0:
1105 {
1106 /* [BX + SI] */
1107 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1108 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1109 break;
1110 }
1111
1112 case 1:
1113 {
1114 /* [BX + DI] */
1115 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord
1116 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1117 break;
1118 }
1119
1120 case 2:
1121 {
1122 /* SS:[BP + SI] */
1123 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1124 + State->GeneralRegs[FAST486_REG_ESI].LowWord;
1125 break;
1126 }
1127
1128 case 3:
1129 {
1130 /* SS:[BP + DI] */
1131 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord
1132 + State->GeneralRegs[FAST486_REG_EDI].LowWord;
1133 break;
1134 }
1135
1136 case 4:
1137 {
1138 /* [SI] */
1139 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord;
1140 break;
1141 }
1142
1143 case 5:
1144 {
1145 /* [DI] */
1146 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord;
1147 break;
1148 }
1149
1150 case 6:
1151 {
1152 if (Mode)
1153 {
1154 /* [BP] */
1155 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord;
1156 }
1157 else
1158 {
1159 /* [constant] (added later) */
1160 ModRegRm->MemoryAddress = 0;
1161 }
1162
1163 break;
1164 }
1165
1166 case 7:
1167 {
1168 /* [BX] */
1169 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord;
1170 break;
1171 }
1172 }
1173
1174 /* Check if there is no segment override */
1175 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
1176 {
1177 /* Check if the default segment should be SS */
1178 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode))
1179 {
1180 /* Add a SS: prefix */
1181 State->PrefixFlags |= FAST486_PREFIX_SEG;
1182 State->SegmentOverride = FAST486_REG_SS;
1183 }
1184 }
1185
1186 if (Mode == 1)
1187 {
1188 CHAR Offset;
1189
1190 /* Fetch the byte */
1191 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1192 {
1193 /* Exception occurred */
1194 return FALSE;
1195 }
1196
1197 /* Add the signed offset to the address */
1198 ModRegRm->MemoryAddress += (LONG)Offset;
1199 }
1200 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6)))
1201 {
1202 SHORT Offset;
1203
1204 /* Fetch the word */
1205 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
1206 {
1207 /* Exception occurred */
1208 return FALSE;
1209 }
1210
1211 /* Add the signed offset to the address */
1212 ModRegRm->MemoryAddress += (LONG)Offset;
1213 }
1214
1215 /* Clear the top 16 bits */
1216 ModRegRm->MemoryAddress &= 0x0000FFFF;
1217 }
1218
1219 return TRUE;
1220 }
1221
1222 FORCEINLINE
1223 BOOLEAN
1224 FASTCALL
1225 Fast486ReadModrmByteOperands(PFAST486_STATE State,
1226 PFAST486_MOD_REG_RM ModRegRm,
1227 PUCHAR RegValue,
1228 PUCHAR RmValue)
1229 {
1230 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1231
1232 if (RegValue)
1233 {
1234 /* Get the register value */
1235 if (ModRegRm->Register & 0x04)
1236 {
1237 /* AH, CH, DH, BH */
1238 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte;
1239 }
1240 else
1241 {
1242 /* AL, CL, DL, BL */
1243 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte;
1244 }
1245 }
1246
1247 if (RmValue)
1248 {
1249 if (!ModRegRm->Memory)
1250 {
1251 /* Get the second register value */
1252 if (ModRegRm->SecondRegister & 0x04)
1253 {
1254 /* AH, CH, DH, BH */
1255 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte;
1256 }
1257 else
1258 {
1259 /* AL, CL, DL, BL */
1260 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte;
1261 }
1262 }
1263 else
1264 {
1265 /* Check for the segment override */
1266 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1267 {
1268 /* Use the override segment instead */
1269 Segment = State->SegmentOverride;
1270 }
1271
1272 /* Read memory */
1273 if (!Fast486ReadMemory(State,
1274 Segment,
1275 ModRegRm->MemoryAddress,
1276 FALSE,
1277 RmValue,
1278 sizeof(UCHAR)))
1279 {
1280 /* Exception occurred */
1281 return FALSE;
1282 }
1283 }
1284 }
1285
1286 return TRUE;
1287 }
1288
1289 FORCEINLINE
1290 BOOLEAN
1291 FASTCALL
1292 Fast486ReadModrmWordOperands(PFAST486_STATE State,
1293 PFAST486_MOD_REG_RM ModRegRm,
1294 PUSHORT RegValue,
1295 PUSHORT RmValue)
1296 {
1297 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1298
1299 if (RegValue)
1300 {
1301 /* Get the register value */
1302 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord;
1303 }
1304
1305 if (RmValue)
1306 {
1307 if (!ModRegRm->Memory)
1308 {
1309 /* Get the second register value */
1310 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord;
1311 }
1312 else
1313 {
1314 /* Check for the segment override */
1315 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1316 {
1317 /* Use the override segment instead */
1318 Segment = State->SegmentOverride;
1319 }
1320
1321 /* Read memory */
1322 if (!Fast486ReadMemory(State,
1323 Segment,
1324 ModRegRm->MemoryAddress,
1325 FALSE,
1326 RmValue,
1327 sizeof(USHORT)))
1328 {
1329 /* Exception occurred */
1330 return FALSE;
1331 }
1332 }
1333 }
1334
1335 return TRUE;
1336 }
1337
1338 FORCEINLINE
1339 BOOLEAN
1340 FASTCALL
1341 Fast486ReadModrmDwordOperands(PFAST486_STATE State,
1342 PFAST486_MOD_REG_RM ModRegRm,
1343 PULONG RegValue,
1344 PULONG RmValue)
1345 {
1346 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1347
1348 if (RegValue)
1349 {
1350 /* Get the register value */
1351 *RegValue = State->GeneralRegs[ModRegRm->Register].Long;
1352 }
1353
1354 if (RmValue)
1355 {
1356 if (!ModRegRm->Memory)
1357 {
1358 /* Get the second register value */
1359 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long;
1360 }
1361 else
1362 {
1363 /* Check for the segment override */
1364 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1365 {
1366 /* Use the override segment instead */
1367 Segment = State->SegmentOverride;
1368 }
1369
1370 /* Read memory */
1371 if (!Fast486ReadMemory(State,
1372 Segment,
1373 ModRegRm->MemoryAddress,
1374 FALSE,
1375 RmValue,
1376 sizeof(ULONG)))
1377 {
1378 /* Exception occurred */
1379 return FALSE;
1380 }
1381 }
1382 }
1383
1384 return TRUE;
1385 }
1386
1387 FORCEINLINE
1388 BOOLEAN
1389 FASTCALL
1390 Fast486WriteModrmByteOperands(PFAST486_STATE State,
1391 PFAST486_MOD_REG_RM ModRegRm,
1392 BOOLEAN WriteRegister,
1393 UCHAR Value)
1394 {
1395 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1396
1397 if (WriteRegister)
1398 {
1399 /* Store the value in the register */
1400 if (ModRegRm->Register & 0x04)
1401 {
1402 /* AH, CH, DH, BH */
1403 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value;
1404 }
1405 else
1406 {
1407 /* AL, CL, DL, BL */
1408 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value;
1409 }
1410 }
1411 else
1412 {
1413 if (!ModRegRm->Memory)
1414 {
1415 /* Store the value in the second register */
1416 if (ModRegRm->SecondRegister & 0x04)
1417 {
1418 /* AH, CH, DH, BH */
1419 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value;
1420 }
1421 else
1422 {
1423 /* AL, CL, DL, BL */
1424 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value;
1425 }
1426 }
1427 else
1428 {
1429 /* Check for the segment override */
1430 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1431 {
1432 /* Use the override segment instead */
1433 Segment = State->SegmentOverride;
1434 }
1435
1436 /* Write memory */
1437 if (!Fast486WriteMemory(State,
1438 Segment,
1439 ModRegRm->MemoryAddress,
1440 &Value,
1441 sizeof(UCHAR)))
1442 {
1443 /* Exception occurred */
1444 return FALSE;
1445 }
1446 }
1447 }
1448
1449 return TRUE;
1450 }
1451
1452 FORCEINLINE
1453 BOOLEAN
1454 FASTCALL
1455 Fast486WriteModrmWordOperands(PFAST486_STATE State,
1456 PFAST486_MOD_REG_RM ModRegRm,
1457 BOOLEAN WriteRegister,
1458 USHORT Value)
1459 {
1460 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1461
1462 if (WriteRegister)
1463 {
1464 /* Store the value in the register */
1465 State->GeneralRegs[ModRegRm->Register].LowWord = Value;
1466 }
1467 else
1468 {
1469 if (!ModRegRm->Memory)
1470 {
1471 /* Store the value in the second register */
1472 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value;
1473 }
1474 else
1475 {
1476 /* Check for the segment override */
1477 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1478 {
1479 /* Use the override segment instead */
1480 Segment = State->SegmentOverride;
1481 }
1482
1483 /* Write memory */
1484 if (!Fast486WriteMemory(State,
1485 Segment,
1486 ModRegRm->MemoryAddress,
1487 &Value,
1488 sizeof(USHORT)))
1489 {
1490 /* Exception occurred */
1491 return FALSE;
1492 }
1493 }
1494 }
1495
1496 return TRUE;
1497 }
1498
1499 FORCEINLINE
1500 BOOLEAN
1501 FASTCALL
1502 Fast486WriteModrmDwordOperands(PFAST486_STATE State,
1503 PFAST486_MOD_REG_RM ModRegRm,
1504 BOOLEAN WriteRegister,
1505 ULONG Value)
1506 {
1507 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1508
1509 if (WriteRegister)
1510 {
1511 /* Store the value in the register */
1512 State->GeneralRegs[ModRegRm->Register].Long = Value;
1513 }
1514 else
1515 {
1516 if (!ModRegRm->Memory)
1517 {
1518 /* Store the value in the second register */
1519 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value;
1520 }
1521 else
1522 {
1523 /* Check for the segment override */
1524 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1525 {
1526 /* Use the override segment instead */
1527 Segment = State->SegmentOverride;
1528 }
1529
1530 /* Write memory */
1531 if (!Fast486WriteMemory(State,
1532 Segment,
1533 ModRegRm->MemoryAddress,
1534 &Value,
1535 sizeof(ULONG)))
1536 {
1537 /* Exception occurred */
1538 return FALSE;
1539 }
1540 }
1541 }
1542
1543 return TRUE;
1544 }
1545
1546 #ifndef FAST486_NO_FPU
1547
1548 FORCEINLINE
1549 VOID
1550 FASTCALL
1551 Fast486FpuException(PFAST486_STATE State)
1552 {
1553 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_NE)
1554 {
1555 /* Call the #MF handler */
1556 Fast486Exception(State, FAST486_EXCEPTION_MF);
1557 }
1558 else
1559 {
1560 /* Use the external interrupt */
1561 State->FpuCallback(State);
1562 }
1563 }
1564
1565 FORCEINLINE
1566 BOOLEAN
1567 FASTCALL
1568 Fast486FpuNormalize(PFAST486_STATE State,
1569 PFAST486_FPU_DATA_REG Data)
1570 {
1571 UINT LeadingZeros;
1572
1573 if (FPU_IS_NORMALIZED(Data)) return TRUE;
1574 if (FPU_IS_ZERO(Data))
1575 {
1576 Data->Exponent = 0;
1577 return TRUE;
1578 }
1579
1580 LeadingZeros = CountLeadingZeros64(Data->Mantissa);
1581
1582 if (LeadingZeros < Data->Exponent)
1583 {
1584 Data->Mantissa <<= LeadingZeros;
1585 Data->Exponent -= LeadingZeros;
1586 }
1587 else
1588 {
1589 /* Raise the underflow exception */
1590 State->FpuStatus.Ue = TRUE;
1591
1592 if (State->FpuControl.Um)
1593 {
1594 /* Make it denormalized */
1595 Data->Mantissa <<= Data->Exponent - 1;
1596 Data->Exponent = 1;
1597 }
1598 else
1599 {
1600 Fast486FpuException(State);
1601 return FALSE;
1602 }
1603 }
1604
1605 return TRUE;
1606 }
1607
1608 FORCEINLINE
1609 USHORT
1610 FASTCALL
1611 Fast486FpuGetValueTag(PFAST486_FPU_DATA_REG Data)
1612 {
1613 if (FPU_IS_ZERO(Data)) return FPU_TAG_ZERO;
1614 else if (FPU_IS_NAN(Data)) return FPU_TAG_SPECIAL;
1615 else return FPU_TAG_VALID;
1616 }
1617
1618 FORCEINLINE
1619 BOOLEAN
1620 FASTCALL
1621 Fast486FpuPush(PFAST486_STATE State,
1622 PCFAST486_FPU_DATA_REG Data)
1623 {
1624 State->FpuStatus.Top--;
1625
1626 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY)
1627 {
1628 FPU_ST(0) = *Data;
1629 FPU_UPDATE_TAG(0);
1630
1631 return TRUE;
1632 }
1633 else
1634 {
1635 /* Raise the stack fault and invalid operation exception */
1636 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
1637
1638 /* Set the C1 condition code bit (stack overflow) */
1639 State->FpuStatus.Code1 = TRUE;
1640
1641 if (!State->FpuControl.Im) Fast486FpuException(State);
1642 return FALSE;
1643 }
1644 }
1645
1646 FORCEINLINE
1647 BOOLEAN
1648 FASTCALL
1649 Fast486FpuPop(PFAST486_STATE State)
1650 {
1651 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY)
1652 {
1653 FPU_SET_TAG(0, FPU_TAG_EMPTY);
1654 State->FpuStatus.Top++;
1655
1656 return TRUE;
1657 }
1658 else
1659 {
1660 /* Raise the stack fault and invalid operation exception */
1661 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE;
1662
1663 /* Clear the C1 condition code bit (stack underflow) */
1664 State->FpuStatus.Code1 = FALSE;
1665
1666 if (!State->FpuControl.Im) Fast486FpuException(State);
1667 return FALSE;
1668 }
1669 }
1670
1671 #endif
1672
1673 /* EOF */