[FAST486]
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34
35 /* PUBLIC VARIABLES ***********************************************************/
36
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
40 Fast486OpcodeGroup0F00,
41 Fast486OpcodeGroup0F01,
42 NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
43 Fast486ExtOpcodeLsl,
44 NULL, // Invalid
45 NULL, // Invalid
46 Fast486ExtOpcodeClts,
47 NULL, // Invalid
48 NULL, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 NULL, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 NULL, // Invalid
51 NULL, // Reserved (UD1)
52 NULL, // Invalid
53 NULL, // Invalid
54 NULL, // Invalid
55 NULL, // Invalid
56 NULL, // Invalid
57 NULL, // Invalid
58 NULL, // Invalid
59 NULL, // Invalid
60 NULL, // Invalid
61 NULL, // Invalid
62 NULL, // Invalid
63 NULL, // Invalid
64 NULL, // Invalid
65 NULL, // Invalid
66 NULL, // Invalid
67 NULL, // Invalid
68 NULL, // Invalid
69 NULL, // Invalid
70 NULL, // Invalid
71 NULL, // Invalid
72 Fast486ExtOpcodeStoreControlReg,
73 Fast486ExtOpcodeStoreDebugReg,
74 Fast486ExtOpcodeLoadControlReg,
75 Fast486ExtOpcodeLoadDebugReg,
76 NULL, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 NULL, // Invalid
78 NULL, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 NULL, // Invalid
80 NULL, // Invalid
81 NULL, // Invalid
82 NULL, // Invalid
83 NULL, // Invalid
84 NULL, // Invalid
85 NULL, // Invalid
86 NULL, // Invalid
87 NULL, // Invalid
88 NULL, // Invalid
89 NULL, // Invalid
90 NULL, // Invalid
91 NULL, // Invalid
92 NULL, // Invalid
93 NULL, // Invalid
94 NULL, // Invalid
95 NULL, // Invalid
96 NULL, // Invalid
97 NULL, // Invalid
98 NULL, // Invalid
99 NULL, // Invalid
100 NULL, // Invalid
101 NULL, // Invalid
102 NULL, // Invalid
103 NULL, // Invalid
104 NULL, // Invalid
105 NULL, // Invalid
106 NULL, // Invalid
107 NULL, // Invalid
108 NULL, // Invalid
109 NULL, // Invalid
110 NULL, // Invalid
111 NULL, // Invalid
112 NULL, // Invalid
113 NULL, // Invalid
114 NULL, // Invalid
115 NULL, // Invalid
116 NULL, // Invalid
117 NULL, // Invalid
118 NULL, // Invalid
119 NULL, // Invalid
120 NULL, // Invalid
121 NULL, // Invalid
122 NULL, // Invalid
123 NULL, // Invalid
124 NULL, // Invalid
125 NULL, // Invalid
126 NULL, // Invalid
127 NULL, // Invalid
128 NULL, // Invalid
129 NULL, // Invalid
130 NULL, // Invalid
131 NULL, // Invalid
132 NULL, // Invalid
133 NULL, // Invalid
134 NULL, // Invalid
135 NULL, // Invalid
136 NULL, // Invalid
137 NULL, // Invalid
138 NULL, // Invalid
139 NULL, // Invalid
140 NULL, // Invalid
141 NULL, // Invalid
142 NULL, // Invalid
143 NULL, // Invalid
144 NULL, // Invalid
145 NULL, // Invalid
146 NULL, // Invalid
147 NULL, // Invalid
148 NULL, // Invalid
149 NULL, // Invalid
150 NULL, // Invalid
151 NULL, // Invalid
152 NULL, // Invalid
153 NULL, // Invalid
154 NULL, // Invalid
155 NULL, // Invalid
156 NULL, // Invalid
157 NULL, // Invalid
158 NULL, // Invalid
159 NULL, // Invalid
160 NULL, // Invalid
161 NULL, // Invalid
162 NULL, // Invalid
163 NULL, // Invalid
164 NULL, // Invalid
165 NULL, // Invalid
166 NULL, // Invalid
167 NULL, // Invalid
168 Fast486ExtOpcodeConditionalJmp,
169 Fast486ExtOpcodeConditionalJmp,
170 Fast486ExtOpcodeConditionalJmp,
171 Fast486ExtOpcodeConditionalJmp,
172 Fast486ExtOpcodeConditionalJmp,
173 Fast486ExtOpcodeConditionalJmp,
174 Fast486ExtOpcodeConditionalJmp,
175 Fast486ExtOpcodeConditionalJmp,
176 Fast486ExtOpcodeConditionalJmp,
177 Fast486ExtOpcodeConditionalJmp,
178 Fast486ExtOpcodeConditionalJmp,
179 Fast486ExtOpcodeConditionalJmp,
180 Fast486ExtOpcodeConditionalJmp,
181 Fast486ExtOpcodeConditionalJmp,
182 Fast486ExtOpcodeConditionalJmp,
183 Fast486ExtOpcodeConditionalJmp,
184 Fast486ExtOpcodeConditionalSet,
185 Fast486ExtOpcodeConditionalSet,
186 Fast486ExtOpcodeConditionalSet,
187 Fast486ExtOpcodeConditionalSet,
188 Fast486ExtOpcodeConditionalSet,
189 Fast486ExtOpcodeConditionalSet,
190 Fast486ExtOpcodeConditionalSet,
191 Fast486ExtOpcodeConditionalSet,
192 Fast486ExtOpcodeConditionalSet,
193 Fast486ExtOpcodeConditionalSet,
194 Fast486ExtOpcodeConditionalSet,
195 Fast486ExtOpcodeConditionalSet,
196 Fast486ExtOpcodeConditionalSet,
197 Fast486ExtOpcodeConditionalSet,
198 Fast486ExtOpcodeConditionalSet,
199 Fast486ExtOpcodeConditionalSet,
200 Fast486ExtOpcodePushFs,
201 Fast486ExtOpcodePopFs,
202 NULL, // Invalid
203 Fast486ExtOpcodeBitTest,
204 Fast486ExtOpcodeShld,
205 Fast486ExtOpcodeShld,
206 NULL, // Invalid
207 NULL, // Invalid
208 Fast486ExtOpcodePushGs,
209 Fast486ExtOpcodePopGs,
210 NULL, // Invalid
211 Fast486ExtOpcodeBts,
212 Fast486ExtOpcodeShrd,
213 Fast486ExtOpcodeShrd,
214 NULL, // Invalid
215 Fast486ExtOpcodeImul,
216 Fast486ExtOpcodeCmpXchgByte,
217 Fast486ExtOpcodeCmpXchg,
218 Fast486ExtOpcodeLss,
219 Fast486ExtOpcodeBtr,
220 Fast486ExtOpcodeLfsLgs,
221 Fast486ExtOpcodeLfsLgs,
222 Fast486ExtOpcodeMovzxByte,
223 Fast486ExtOpcodeMovzxWord,
224 NULL, // Invalid
225 Fast486OpcodeGroup0FB9,
226 Fast486OpcodeGroup0FBA,
227 Fast486ExtOpcodeBtc,
228 Fast486ExtOpcodeBsf,
229 Fast486ExtOpcodeBsr,
230 Fast486ExtOpcodeMovsxByte,
231 Fast486ExtOpcodeMovsxWord,
232 Fast486ExtOpcodeXaddByte,
233 Fast486ExtOpcodeXadd,
234 NULL, // Invalid
235 NULL, // Invalid
236 NULL, // Invalid
237 NULL, // Invalid
238 NULL, // Invalid
239 NULL, // Invalid
240 Fast486ExtOpcodeBswap,
241 Fast486ExtOpcodeBswap,
242 Fast486ExtOpcodeBswap,
243 Fast486ExtOpcodeBswap,
244 Fast486ExtOpcodeBswap,
245 Fast486ExtOpcodeBswap,
246 Fast486ExtOpcodeBswap,
247 Fast486ExtOpcodeBswap,
248 NULL, // Invalid
249 NULL, // Invalid
250 NULL, // Invalid
251 NULL, // Invalid
252 NULL, // Invalid
253 NULL, // Invalid
254 NULL, // Invalid
255 NULL, // Invalid
256 NULL, // Invalid
257 NULL, // Invalid
258 NULL, // Invalid
259 NULL, // Invalid
260 NULL, // Invalid
261 NULL, // Invalid
262 NULL, // Invalid
263 NULL, // Invalid
264 NULL, // Invalid
265 NULL, // Invalid
266 NULL, // Invalid
267 NULL, // Invalid
268 NULL, // Invalid
269 NULL, // Invalid
270 NULL, // Invalid
271 NULL, // Invalid
272 NULL, // Invalid
273 NULL, // Invalid
274 NULL, // Invalid
275 NULL, // Invalid
276 NULL, // Invalid
277 NULL, // Invalid
278 NULL, // Invalid
279 NULL, // Invalid
280 NULL, // Invalid
281 NULL, // Invalid
282 NULL, // Invalid
283 NULL, // Invalid
284 NULL, // Invalid
285 NULL, // Invalid
286 NULL, // Invalid
287 NULL, // Invalid
288 NULL, // Invalid
289 NULL, // Invalid
290 NULL, // Invalid
291 NULL, // Invalid
292 NULL, // Invalid
293 NULL, // Invalid
294 NULL, // Invalid
295 NULL, // Invalid
296 };
297
298 /* PUBLIC FUNCTIONS ***********************************************************/
299
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
301 {
302 BOOLEAN OperandSize, AddressSize;
303 FAST486_MOD_REG_RM ModRegRm;
304 USHORT Selector;
305 ULONG Limit;
306 FAST486_GDT_ENTRY GdtEntry;
307
308 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
309
310 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
311 || State->Flags.Vm)
312 {
313 /* Not recognized */
314 Fast486Exception(State, FAST486_EXCEPTION_UD);
315 return FALSE;
316 }
317
318 NO_LOCK_PREFIX();
319 TOGGLE_OPSIZE(OperandSize);
320 TOGGLE_ADSIZE(AddressSize);
321
322 /* Get the operands */
323 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
324 {
325 /* Exception occurred */
326 return FALSE;
327 }
328
329 if (OperandSize)
330 {
331 ULONG Value;
332
333 /* Read the value */
334 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
335 {
336 /* Exception occurred */
337 return FALSE;
338 }
339
340 Selector = LOWORD(Value);
341 }
342 else
343 {
344 /* Read the value */
345 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
346 {
347 /* Exception occurred */
348 return FALSE;
349 }
350 }
351
352 if (!(Selector & SEGMENT_TABLE_INDICATOR))
353 {
354 /* Check if the GDT contains the entry */
355 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
356 {
357 State->Flags.Zf = FALSE;
358 return TRUE;
359 }
360
361 /* Read the GDT */
362 if (!Fast486ReadLinearMemory(State,
363 State->Gdtr.Address
364 + GET_SEGMENT_INDEX(Selector),
365 &GdtEntry,
366 sizeof(GdtEntry)))
367 {
368 /* Exception occurred */
369 return FALSE;
370 }
371 }
372 else
373 {
374 /* Check if the LDT contains the entry */
375 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
376 {
377 State->Flags.Zf = FALSE;
378 return TRUE;
379 }
380
381 /* Read the LDT */
382 if (!Fast486ReadLinearMemory(State,
383 State->Ldtr.Base
384 + GET_SEGMENT_INDEX(Selector),
385 &GdtEntry,
386 sizeof(GdtEntry)))
387 {
388 /* Exception occurred */
389 return FALSE;
390 }
391 }
392
393 /* Privilege check */
394 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
395 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
396 {
397 State->Flags.Zf = FALSE;
398 return TRUE;
399 }
400
401 /* Calculate the limit */
402 Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
403 if (GdtEntry.Granularity) Limit <<= 12;
404
405 /* Set ZF */
406 State->Flags.Zf = TRUE;
407
408 if (OperandSize)
409 {
410 /* Read the value */
411 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit))
412 {
413 /* Exception occurred */
414 return FALSE;
415 }
416 }
417 else
418 {
419 /* Read the value */
420 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit)))
421 {
422 /* Exception occurred */
423 return FALSE;
424 }
425 }
426
427 return TRUE;
428 }
429
430 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
431 {
432 NO_LOCK_PREFIX();
433
434 /* The current privilege level must be zero */
435 if (Fast486GetCurrentPrivLevel(State) != 0)
436 {
437 Fast486Exception(State, FAST486_EXCEPTION_GP);
438 return FALSE;
439 }
440
441 /* Clear the task switch bit */
442 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
443
444 return TRUE;
445 }
446
447 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
448 {
449 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
450 FAST486_MOD_REG_RM ModRegRm;
451
452 NO_LOCK_PREFIX();
453 TOGGLE_ADSIZE(AddressSize);
454
455 /* Get the operands */
456 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
457 {
458 /* Exception occurred */
459 return FALSE;
460 }
461
462 /* The current privilege level must be zero */
463 if (Fast486GetCurrentPrivLevel(State) != 0)
464 {
465 Fast486Exception(State, FAST486_EXCEPTION_GP);
466 return FALSE;
467 }
468
469 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
470 {
471 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
472 Fast486Exception(State, FAST486_EXCEPTION_UD);
473 return FALSE;
474 }
475
476 if (ModRegRm.Register != 0)
477 {
478 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
479 ModRegRm.Register--;
480 }
481
482 /* Store the value of the control register */
483 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
484
485 /* Return success */
486 return TRUE;
487 }
488
489 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
490 {
491 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
492 FAST486_MOD_REG_RM ModRegRm;
493
494 NO_LOCK_PREFIX();
495 TOGGLE_ADSIZE(AddressSize);
496
497 /* Get the operands */
498 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
499 {
500 /* Exception occurred */
501 return FALSE;
502 }
503
504 /* The current privilege level must be zero */
505 if (Fast486GetCurrentPrivLevel(State) != 0)
506 {
507 Fast486Exception(State, FAST486_EXCEPTION_GP);
508 return FALSE;
509 }
510
511 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
512 {
513 /* DR6 and DR7 are aliases to DR4 and DR5 */
514 ModRegRm.Register -= 2;
515 }
516
517 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
518 {
519 /* Disallow access to debug registers */
520 Fast486Exception(State, FAST486_EXCEPTION_GP);
521 return FALSE;
522 }
523
524 /* Store the value of the debug register */
525 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
526
527 /* Return success */
528 return TRUE;
529 }
530
531 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
532 {
533 ULONG Value;
534 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
535 FAST486_MOD_REG_RM ModRegRm;
536
537 NO_LOCK_PREFIX();
538 TOGGLE_ADSIZE(AddressSize);
539
540 /* Get the operands */
541 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
542 {
543 /* Exception occurred */
544 return FALSE;
545 }
546
547 /* The current privilege level must be zero */
548 if (Fast486GetCurrentPrivLevel(State) != 0)
549 {
550 Fast486Exception(State, FAST486_EXCEPTION_GP);
551 return FALSE;
552 }
553
554 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
555 {
556 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
557 Fast486Exception(State, FAST486_EXCEPTION_UD);
558 return FALSE;
559 }
560
561 if (ModRegRm.Register != 0)
562 {
563 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
564 ModRegRm.Register--;
565 }
566
567 /* Get the value */
568 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
569
570 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
571 {
572 /* CR0 checks */
573
574 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
575 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
576 {
577 /* Invalid value */
578 Fast486Exception(State, FAST486_EXCEPTION_GP);
579 return FALSE;
580 }
581 }
582
583 /* Load a value to the control register */
584 State->ControlRegisters[ModRegRm.Register] = Value;
585
586 /* Return success */
587 return TRUE;
588 }
589
590 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
591 {
592 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
593 FAST486_MOD_REG_RM ModRegRm;
594
595 NO_LOCK_PREFIX();
596 TOGGLE_ADSIZE(AddressSize);
597
598 /* Get the operands */
599 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
600 {
601 /* Exception occurred */
602 return FALSE;
603 }
604
605 /* The current privilege level must be zero */
606 if (Fast486GetCurrentPrivLevel(State) != 0)
607 {
608 Fast486Exception(State, FAST486_EXCEPTION_GP);
609 return FALSE;
610 }
611
612 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
613 {
614 /* DR6 and DR7 are aliases to DR4 and DR5 */
615 ModRegRm.Register -= 2;
616 }
617
618 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
619 {
620 /* Disallow access to debug registers */
621 Fast486Exception(State, FAST486_EXCEPTION_GP);
622 return FALSE;
623 }
624
625 /* Load a value to the debug register */
626 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
627
628 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
629 {
630 /* The reserved bits are 1 */
631 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
632 }
633 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
634 {
635 /* The reserved bits are 0 */
636 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
637 }
638
639 /* Return success */
640 return TRUE;
641 }
642
643 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
644 {
645 /* Call the internal API */
646 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
647 }
648
649 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
650 {
651 ULONG NewSelector;
652
653 if (!Fast486StackPop(State, &NewSelector))
654 {
655 /* Exception occurred */
656 return FALSE;
657 }
658
659 /* Call the internal API */
660 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
661 }
662
663 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
664 {
665 BOOLEAN OperandSize, AddressSize;
666 FAST486_MOD_REG_RM ModRegRm;
667 UINT DataSize;
668 ULONG BitNumber;
669
670 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
671 TOGGLE_OPSIZE(OperandSize);
672 TOGGLE_ADSIZE(AddressSize);
673
674 /* Get the number of bits */
675 if (OperandSize) DataSize = 32;
676 else DataSize = 16;
677
678 /* Get the operands */
679 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
680 {
681 /* Exception occurred */
682 return FALSE;
683 }
684
685 /* Get the bit number */
686 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
687 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
688
689 if (ModRegRm.Memory)
690 {
691 /*
692 * For memory operands, add the bit offset divided by
693 * the data size to the address
694 */
695 ModRegRm.MemoryAddress += BitNumber / DataSize;
696 }
697
698 /* Normalize the bit number */
699 BitNumber %= DataSize;
700
701 if (OperandSize)
702 {
703 ULONG Value;
704
705 /* Read the value */
706 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
707 {
708 /* Exception occurred */
709 return FALSE;
710 }
711
712 /* Set CF to the bit value */
713 State->Flags.Cf = (Value >> BitNumber) & 1;
714 }
715 else
716 {
717 USHORT Value;
718
719 /* Read the value */
720 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
721 {
722 /* Exception occurred */
723 return FALSE;
724 }
725
726 /* Set CF to the bit value */
727 State->Flags.Cf = (Value >> BitNumber) & 1;
728 }
729
730 /* Return success */
731 return TRUE;
732 }
733
734 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
735 {
736 BOOLEAN OperandSize, AddressSize;
737 FAST486_MOD_REG_RM ModRegRm;
738 UCHAR Count;
739
740 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
741 TOGGLE_OPSIZE(OperandSize);
742 TOGGLE_ADSIZE(AddressSize);
743
744 /* Make sure this is the right instruction */
745 ASSERT((Opcode & 0xFE) == 0xA4);
746
747 /* Get the operands */
748 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
749 {
750 /* Exception occurred */
751 return FALSE;
752 }
753
754 if (Opcode == 0xA4)
755 {
756 /* Fetch the count */
757 if (!Fast486FetchByte(State, &Count))
758 {
759 /* Exception occurred */
760 return FALSE;
761 }
762 }
763 else
764 {
765 /* The count is in CL */
766 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
767 }
768
769 /* Normalize the count */
770 Count &= 0x1F;
771
772 /* Do nothing if the count is zero */
773 if (Count == 0) return TRUE;
774
775 if (OperandSize)
776 {
777 ULONG Source, Destination, Result;
778
779 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
780 {
781 /* Exception occurred */
782 return FALSE;
783 }
784
785 /* Calculate the result */
786 Result = (Destination << Count) | (Source >> (32 - Count));
787
788 /* Update flags */
789 State->Flags.Cf = (Destination >> (32 - Count)) & 1;
790 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
791 != (Destination & SIGN_FLAG_LONG);
792 State->Flags.Zf = (Result == 0);
793 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
794 State->Flags.Pf = Fast486CalculateParity(Result);
795
796 /* Write back the result */
797 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
798 }
799 else
800 {
801 USHORT Source, Destination, Result;
802 ULONG DoubleSource;
803
804 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
805 {
806 /* Exception occurred */
807 return FALSE;
808 }
809
810 DoubleSource = Source | (Source << 16);
811
812 /* Calculate the result */
813 Result = (Destination << Count) | (DoubleSource >> (32 - Count));
814
815 /* Update flags */
816 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
817 else State->Flags.Cf = (Source >> (32 - Count)) & 1;
818
819 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
820 != (Destination & SIGN_FLAG_WORD);
821 State->Flags.Zf = (Result == 0);
822 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
823 State->Flags.Pf = Fast486CalculateParity(Result);
824
825 /* Write back the result */
826 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
827 }
828 }
829
830 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
831 {
832 /* Call the internal API */
833 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
834 }
835
836 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
837 {
838 ULONG NewSelector;
839
840 if (!Fast486StackPop(State, &NewSelector))
841 {
842 /* Exception occurred */
843 return FALSE;
844 }
845
846 /* Call the internal API */
847 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
848 }
849
850 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
851 {
852 BOOLEAN OperandSize, AddressSize;
853 FAST486_MOD_REG_RM ModRegRm;
854 UINT DataSize;
855 ULONG BitNumber;
856
857 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
858 TOGGLE_OPSIZE(OperandSize);
859 TOGGLE_ADSIZE(AddressSize);
860
861 /* Get the number of bits */
862 if (OperandSize) DataSize = 32;
863 else DataSize = 16;
864
865 /* Get the operands */
866 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
867 {
868 /* Exception occurred */
869 return FALSE;
870 }
871
872 /* Get the bit number */
873 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
874 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
875
876 if (ModRegRm.Memory)
877 {
878 /*
879 * For memory operands, add the bit offset divided by
880 * the data size to the address
881 */
882 ModRegRm.MemoryAddress += BitNumber / DataSize;
883 }
884
885 /* Normalize the bit number */
886 BitNumber %= DataSize;
887
888 if (OperandSize)
889 {
890 ULONG Value;
891
892 /* Read the value */
893 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
894 {
895 /* Exception occurred */
896 return FALSE;
897 }
898
899 /* Set CF to the bit value */
900 State->Flags.Cf = (Value >> BitNumber) & 1;
901
902 /* Set the bit */
903 Value |= 1 << BitNumber;
904
905 /* Write back the result */
906 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
907 {
908 /* Exception occurred */
909 return FALSE;
910 }
911 }
912 else
913 {
914 USHORT Value;
915
916 /* Read the value */
917 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
918 {
919 /* Exception occurred */
920 return FALSE;
921 }
922
923 /* Set CF to the bit value */
924 State->Flags.Cf = (Value >> BitNumber) & 1;
925
926 /* Set the bit */
927 Value |= 1 << BitNumber;
928
929 /* Write back the result */
930 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
931 {
932 /* Exception occurred */
933 return FALSE;
934 }
935 }
936
937 /* Return success */
938 return TRUE;
939 }
940
941 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
942 {
943 BOOLEAN OperandSize, AddressSize;
944 FAST486_MOD_REG_RM ModRegRm;
945 UCHAR Count;
946
947 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
948 TOGGLE_OPSIZE(OperandSize);
949 TOGGLE_ADSIZE(AddressSize);
950
951 /* Make sure this is the right instruction */
952 ASSERT((Opcode & 0xFE) == 0xAC);
953
954 /* Get the operands */
955 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
956 {
957 /* Exception occurred */
958 return FALSE;
959 }
960
961 if (Opcode == 0xAC)
962 {
963 /* Fetch the count */
964 if (!Fast486FetchByte(State, &Count))
965 {
966 /* Exception occurred */
967 return FALSE;
968 }
969 }
970 else
971 {
972 /* The count is in CL */
973 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
974 }
975
976 /* Normalize the count */
977 Count &= 0x1F;
978
979 /* Do nothing if the count is zero */
980 if (Count == 0) return TRUE;
981
982 if (OperandSize)
983 {
984 ULONG Source, Destination, Result;
985
986 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
987 {
988 /* Exception occurred */
989 return FALSE;
990 }
991
992 /* Calculate the result */
993 Result = (Destination >> Count) | (Source << (32 - Count));
994
995 /* Update flags */
996 State->Flags.Cf = (Destination >> (Count - 1)) & 1;
997 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
998 != (Destination & SIGN_FLAG_LONG);
999 State->Flags.Zf = (Result == 0);
1000 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1001 State->Flags.Pf = Fast486CalculateParity(Result);
1002
1003 /* Write back the result */
1004 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1005 }
1006 else
1007 {
1008 USHORT Source, Destination, Result;
1009
1010 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1011 {
1012 /* Exception occurred */
1013 return FALSE;
1014 }
1015
1016 /* Calculate the result */
1017 Result = (Destination >> Count) | (Source << (16 - Count));
1018
1019 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
1020
1021 /* Update flags */
1022 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1023 else State->Flags.Cf = (Source >> (Count - 17)) & 1;
1024
1025 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
1026 != (Destination & SIGN_FLAG_WORD);
1027 State->Flags.Zf = (Result == 0);
1028 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1029 State->Flags.Pf = Fast486CalculateParity(Result);
1030
1031 /* Write back the result */
1032 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
1033 }
1034 }
1035
1036 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
1037 {
1038 BOOLEAN OperandSize, AddressSize;
1039 FAST486_MOD_REG_RM ModRegRm;
1040
1041 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1042
1043 TOGGLE_OPSIZE(OperandSize);
1044 TOGGLE_ADSIZE(AddressSize);
1045
1046 /* Get the operands */
1047 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1048 {
1049 /* Exception occurred */
1050 return FALSE;
1051 }
1052
1053 if (OperandSize)
1054 {
1055 LONG Source, Destination;
1056 LONGLONG Result;
1057
1058 /* Read the operands */
1059 if (!Fast486ReadModrmDwordOperands(State,
1060 &ModRegRm,
1061 (PULONG)&Destination,
1062 (PULONG)&Source))
1063 {
1064 /* Exception occurred */
1065 return FALSE;
1066 }
1067
1068 /* Calculate the result */
1069 Result = (LONGLONG)Source * (LONGLONG)Destination;
1070
1071 /* Update the flags */
1072 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1073
1074 /* Write back the result */
1075 return Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
1076 }
1077 else
1078 {
1079 SHORT Source, Destination;
1080 LONG Result;
1081
1082 /* Read the operands */
1083 if (!Fast486ReadModrmWordOperands(State,
1084 &ModRegRm,
1085 (PUSHORT)&Destination,
1086 (PUSHORT)&Source))
1087 {
1088 /* Exception occurred */
1089 return FALSE;
1090 }
1091
1092 /* Calculate the result */
1093 Result = (LONG)Source * (LONG)Destination;
1094
1095 /* Update the flags */
1096 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1097
1098 /* Write back the result */
1099 return Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
1100 }
1101 }
1102
1103 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
1104 {
1105 FAST486_MOD_REG_RM ModRegRm;
1106 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1107 UCHAR Source, Destination, Result;
1108 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1109
1110 TOGGLE_ADSIZE(AddressSize);
1111
1112 /* Get the operands */
1113 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1114 {
1115 /* Exception occurred */
1116 return FALSE;
1117 }
1118
1119 /* Read the operands */
1120 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
1121 {
1122 /* Exception occurred */
1123 return FALSE;
1124 }
1125
1126 /* Compare AL with the destination */
1127 Result = Accumulator - Destination;
1128
1129 /* Update the flags */
1130 State->Flags.Cf = (Accumulator < Destination);
1131 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
1132 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1133 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1134 State->Flags.Zf = (Result == 0);
1135 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1136 State->Flags.Pf = Fast486CalculateParity(Result);
1137
1138 if (State->Flags.Zf)
1139 {
1140 /* Load the source operand into the destination */
1141 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1142 }
1143 else
1144 {
1145 /* Load the destination into AL */
1146 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1147 }
1148
1149 /* Return success */
1150 return TRUE;
1151 }
1152
1153 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1154 {
1155 FAST486_MOD_REG_RM ModRegRm;
1156 BOOLEAN OperandSize, AddressSize;
1157
1158 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1159
1160 TOGGLE_OPSIZE(OperandSize);
1161 TOGGLE_ADSIZE(AddressSize);
1162
1163 /* Get the operands */
1164 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1165 {
1166 /* Exception occurred */
1167 return FALSE;
1168 }
1169
1170 if (OperandSize)
1171 {
1172 ULONG Source, Destination, Result;
1173 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1174
1175 /* Read the operands */
1176 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1177 {
1178 /* Exception occurred */
1179 return FALSE;
1180 }
1181
1182 /* Compare EAX with the destination */
1183 Result = Accumulator - Destination;
1184
1185 /* Update the flags */
1186 State->Flags.Cf = (Accumulator < Destination);
1187 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1188 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1189 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1190 State->Flags.Zf = (Result == 0);
1191 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1192 State->Flags.Pf = Fast486CalculateParity(Result);
1193
1194 if (State->Flags.Zf)
1195 {
1196 /* Load the source operand into the destination */
1197 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1198 }
1199 else
1200 {
1201 /* Load the destination into EAX */
1202 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1203 }
1204 }
1205 else
1206 {
1207 USHORT Source, Destination, Result;
1208 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1209
1210 /* Read the operands */
1211 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1212 {
1213 /* Exception occurred */
1214 return FALSE;
1215 }
1216
1217 /* Compare AX with the destination */
1218 Result = Accumulator - Destination;
1219
1220 /* Update the flags */
1221 State->Flags.Cf = (Accumulator < Destination);
1222 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1223 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1224 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1225 State->Flags.Zf = (Result == 0);
1226 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1227 State->Flags.Pf = Fast486CalculateParity(Result);
1228
1229 if (State->Flags.Zf)
1230 {
1231 /* Load the source operand into the destination */
1232 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1233 }
1234 else
1235 {
1236 /* Load the destination into AX */
1237 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1238 }
1239 }
1240
1241 /* Return success */
1242 return TRUE;
1243 }
1244
1245 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1246 {
1247 UCHAR FarPointer[6];
1248 BOOLEAN OperandSize, AddressSize;
1249 FAST486_MOD_REG_RM ModRegRm;
1250
1251 /* Make sure this is the right instruction */
1252 ASSERT(Opcode == 0xB2);
1253
1254 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1255
1256 TOGGLE_OPSIZE(OperandSize);
1257 TOGGLE_ADSIZE(AddressSize);
1258
1259 /* Get the operands */
1260 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1261 {
1262 /* Exception occurred */
1263 return FALSE;
1264 }
1265
1266 if (!ModRegRm.Memory)
1267 {
1268 /* Invalid */
1269 Fast486Exception(State, FAST486_EXCEPTION_UD);
1270 return FALSE;
1271 }
1272
1273 if (!Fast486ReadMemory(State,
1274 (State->PrefixFlags & FAST486_PREFIX_SEG)
1275 ? State->SegmentOverride : FAST486_REG_DS,
1276 ModRegRm.MemoryAddress,
1277 FALSE,
1278 FarPointer,
1279 OperandSize ? 6 : 4))
1280 {
1281 /* Exception occurred */
1282 return FALSE;
1283 }
1284
1285 if (OperandSize)
1286 {
1287 ULONG Offset = *((PULONG)FarPointer);
1288 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1289
1290 /* Set the register to the offset */
1291 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1292
1293 /* Load the segment */
1294 return Fast486LoadSegment(State,
1295 FAST486_REG_SS,
1296 Segment);
1297 }
1298 else
1299 {
1300 USHORT Offset = *((PUSHORT)FarPointer);
1301 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1302
1303 /* Set the register to the offset */
1304 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1305
1306 /* Load the segment */
1307 return Fast486LoadSegment(State,
1308 FAST486_REG_SS,
1309 Segment);
1310 }
1311 }
1312
1313 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1314 {
1315 BOOLEAN OperandSize, AddressSize;
1316 FAST486_MOD_REG_RM ModRegRm;
1317 UINT DataSize;
1318 ULONG BitNumber;
1319
1320 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1321 TOGGLE_OPSIZE(OperandSize);
1322 TOGGLE_ADSIZE(AddressSize);
1323
1324 /* Get the number of bits */
1325 if (OperandSize) DataSize = 32;
1326 else DataSize = 16;
1327
1328 /* Get the operands */
1329 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1330 {
1331 /* Exception occurred */
1332 return FALSE;
1333 }
1334
1335 /* Get the bit number */
1336 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1337 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1338
1339 if (ModRegRm.Memory)
1340 {
1341 /*
1342 * For memory operands, add the bit offset divided by
1343 * the data size to the address
1344 */
1345 ModRegRm.MemoryAddress += BitNumber / DataSize;
1346 }
1347
1348 /* Normalize the bit number */
1349 BitNumber %= DataSize;
1350
1351 if (OperandSize)
1352 {
1353 ULONG Value;
1354
1355 /* Read the value */
1356 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1357 {
1358 /* Exception occurred */
1359 return FALSE;
1360 }
1361
1362 /* Set CF to the bit value */
1363 State->Flags.Cf = (Value >> BitNumber) & 1;
1364
1365 /* Clear the bit */
1366 Value &= ~(1 << BitNumber);
1367
1368 /* Write back the result */
1369 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1370 {
1371 /* Exception occurred */
1372 return FALSE;
1373 }
1374 }
1375 else
1376 {
1377 USHORT Value;
1378
1379 /* Read the value */
1380 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1381 {
1382 /* Exception occurred */
1383 return FALSE;
1384 }
1385
1386 /* Set CF to the bit value */
1387 State->Flags.Cf = (Value >> BitNumber) & 1;
1388
1389 /* Clear the bit */
1390 Value &= ~(1 << BitNumber);
1391
1392 /* Write back the result */
1393 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1394 {
1395 /* Exception occurred */
1396 return FALSE;
1397 }
1398 }
1399
1400 /* Return success */
1401 return TRUE;
1402 }
1403
1404 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1405 {
1406 UCHAR FarPointer[6];
1407 BOOLEAN OperandSize, AddressSize;
1408 FAST486_MOD_REG_RM ModRegRm;
1409
1410 /* Make sure this is the right instruction */
1411 ASSERT((Opcode & 0xFE) == 0xB4);
1412
1413 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1414
1415 TOGGLE_OPSIZE(OperandSize);
1416 TOGGLE_ADSIZE(AddressSize);
1417
1418 /* Get the operands */
1419 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1420 {
1421 /* Exception occurred */
1422 return FALSE;
1423 }
1424
1425 if (!ModRegRm.Memory)
1426 {
1427 /* Invalid */
1428 Fast486Exception(State, FAST486_EXCEPTION_UD);
1429 return FALSE;
1430 }
1431
1432 if (!Fast486ReadMemory(State,
1433 (State->PrefixFlags & FAST486_PREFIX_SEG)
1434 ? State->SegmentOverride : FAST486_REG_DS,
1435 ModRegRm.MemoryAddress,
1436 FALSE,
1437 FarPointer,
1438 OperandSize ? 6 : 4))
1439 {
1440 /* Exception occurred */
1441 return FALSE;
1442 }
1443
1444 if (OperandSize)
1445 {
1446 ULONG Offset = *((PULONG)FarPointer);
1447 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1448
1449 /* Set the register to the offset */
1450 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1451
1452 /* Load the segment */
1453 return Fast486LoadSegment(State,
1454 (Opcode == 0xB4)
1455 ? FAST486_REG_FS : FAST486_REG_GS,
1456 Segment);
1457 }
1458 else
1459 {
1460 USHORT Offset = *((PUSHORT)FarPointer);
1461 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1462
1463 /* Set the register to the offset */
1464 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1465
1466 /* Load the segment */
1467 return Fast486LoadSegment(State,
1468 (Opcode == 0xB4)
1469 ? FAST486_REG_FS : FAST486_REG_GS,
1470 Segment);
1471 }
1472 }
1473
1474 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1475 {
1476 UCHAR Value;
1477 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1478 FAST486_MOD_REG_RM ModRegRm;
1479
1480 TOGGLE_ADSIZE(AddressSize);
1481
1482 /* Make sure this is the right instruction */
1483 ASSERT(Opcode == 0xB6);
1484
1485 /* Get the operands */
1486 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1487 {
1488 /* Exception occurred */
1489 return FALSE;
1490 }
1491
1492 /* Read the operands */
1493 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1494 {
1495 /* Exception occurred */
1496 return FALSE;
1497 }
1498
1499 /* Write back the zero-extended value */
1500 return Fast486WriteModrmDwordOperands(State,
1501 &ModRegRm,
1502 TRUE,
1503 (ULONG)Value);
1504 }
1505
1506 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1507 {
1508 USHORT Value;
1509 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1510 FAST486_MOD_REG_RM ModRegRm;
1511
1512 TOGGLE_ADSIZE(AddressSize);
1513
1514 /* Make sure this is the right instruction */
1515 ASSERT(Opcode == 0xB7);
1516
1517 /* Get the operands */
1518 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1519 {
1520 /* Exception occurred */
1521 return FALSE;
1522 }
1523
1524 /* Read the operands */
1525 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1526 {
1527 /* Exception occurred */
1528 return FALSE;
1529 }
1530
1531 /* Write back the zero-extended value */
1532 return Fast486WriteModrmDwordOperands(State,
1533 &ModRegRm,
1534 TRUE,
1535 (ULONG)Value);
1536 }
1537
1538 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1539 {
1540 BOOLEAN OperandSize, AddressSize;
1541 FAST486_MOD_REG_RM ModRegRm;
1542 UINT DataSize;
1543 ULONG BitNumber;
1544
1545 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1546 TOGGLE_OPSIZE(OperandSize);
1547 TOGGLE_ADSIZE(AddressSize);
1548
1549 /* Get the number of bits */
1550 if (OperandSize) DataSize = 32;
1551 else DataSize = 16;
1552
1553 /* Get the operands */
1554 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1555 {
1556 /* Exception occurred */
1557 return FALSE;
1558 }
1559
1560 /* Get the bit number */
1561 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1562 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1563
1564 if (ModRegRm.Memory)
1565 {
1566 /*
1567 * For memory operands, add the bit offset divided by
1568 * the data size to the address
1569 */
1570 ModRegRm.MemoryAddress += BitNumber / DataSize;
1571 }
1572
1573 /* Normalize the bit number */
1574 BitNumber %= DataSize;
1575
1576 if (OperandSize)
1577 {
1578 ULONG Value;
1579
1580 /* Read the value */
1581 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1582 {
1583 /* Exception occurred */
1584 return FALSE;
1585 }
1586
1587 /* Set CF to the bit value */
1588 State->Flags.Cf = (Value >> BitNumber) & 1;
1589
1590 /* Toggle the bit */
1591 Value ^= 1 << BitNumber;
1592
1593 /* Write back the result */
1594 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1595 {
1596 /* Exception occurred */
1597 return FALSE;
1598 }
1599 }
1600 else
1601 {
1602 USHORT Value;
1603
1604 /* Read the value */
1605 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1606 {
1607 /* Exception occurred */
1608 return FALSE;
1609 }
1610
1611 /* Set CF to the bit value */
1612 State->Flags.Cf = (Value >> BitNumber) & 1;
1613
1614 /* Toggle the bit */
1615 Value ^= 1 << BitNumber;
1616
1617 /* Write back the result */
1618 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1619 {
1620 /* Exception occurred */
1621 return FALSE;
1622 }
1623 }
1624
1625 /* Return success */
1626 return TRUE;
1627 }
1628
1629 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1630 {
1631 INT i;
1632 ULONG Value = 0;
1633 BOOLEAN OperandSize, AddressSize;
1634 FAST486_MOD_REG_RM ModRegRm;
1635 ULONG BitNumber;
1636 UINT DataSize;
1637
1638 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1639 TOGGLE_OPSIZE(OperandSize);
1640 TOGGLE_ADSIZE(AddressSize);
1641
1642 /* Make sure this is the right instruction */
1643 ASSERT(Opcode == 0xBC);
1644
1645 /* Get the number of bits */
1646 if (OperandSize) DataSize = 32;
1647 else DataSize = 16;
1648
1649 /* Get the operands */
1650 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1651 {
1652 /* Exception occurred */
1653 return FALSE;
1654 }
1655
1656 /* Read the value */
1657 if (OperandSize)
1658 {
1659 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1660 {
1661 /* Exception occurred */
1662 return FALSE;
1663 }
1664 }
1665 else
1666 {
1667 if (!Fast486ReadModrmWordOperands(State,
1668 &ModRegRm,
1669 (PUSHORT)NULL,
1670 (PUSHORT)&Value))
1671 {
1672 /* Exception occurred */
1673 return FALSE;
1674 }
1675 }
1676
1677 /* Set ZF */
1678 State->Flags.Zf = (Value == 0);
1679 if (State->Flags.Zf) return TRUE;
1680
1681 for (i = 0; i < DataSize; i++)
1682 {
1683 if(Value & (1 << i))
1684 {
1685 /* Save the bit number */
1686 BitNumber = i;
1687
1688 /* Exit the loop */
1689 break;
1690 }
1691 }
1692
1693 /* Write back the result */
1694 if (OperandSize)
1695 {
1696 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1697 {
1698 /* Exception occurred */
1699 return FALSE;
1700 }
1701 }
1702 else
1703 {
1704 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1705 {
1706 /* Exception occurred */
1707 return FALSE;
1708 }
1709 }
1710
1711 return TRUE;
1712 }
1713
1714 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1715 {
1716 INT i;
1717 ULONG Value = 0;
1718 BOOLEAN OperandSize, AddressSize;
1719 FAST486_MOD_REG_RM ModRegRm;
1720 ULONG BitNumber;
1721 UINT DataSize;
1722
1723 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1724 TOGGLE_OPSIZE(OperandSize);
1725 TOGGLE_ADSIZE(AddressSize);
1726
1727 /* Make sure this is the right instruction */
1728 ASSERT(Opcode == 0xBD);
1729
1730 /* Get the number of bits */
1731 if (OperandSize) DataSize = 32;
1732 else DataSize = 16;
1733
1734 /* Get the operands */
1735 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1736 {
1737 /* Exception occurred */
1738 return FALSE;
1739 }
1740
1741 /* Read the value */
1742 if (OperandSize)
1743 {
1744 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1745 {
1746 /* Exception occurred */
1747 return FALSE;
1748 }
1749 }
1750 else
1751 {
1752 if (!Fast486ReadModrmWordOperands(State,
1753 &ModRegRm,
1754 (PUSHORT)NULL,
1755 (PUSHORT)&Value))
1756 {
1757 /* Exception occurred */
1758 return FALSE;
1759 }
1760 }
1761
1762 /* Set ZF according to the value */
1763 State->Flags.Zf = (Value == 0);
1764 if (State->Flags.Zf) return TRUE;
1765
1766 for (i = DataSize - 1; i >= 0; i--)
1767 {
1768 if(Value & (1 << i))
1769 {
1770 /* Save the bit number */
1771 BitNumber = i;
1772
1773 /* Exit the loop */
1774 break;
1775 }
1776 }
1777
1778 /* Write back the result */
1779 if (OperandSize)
1780 {
1781 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1782 {
1783 /* Exception occurred */
1784 return FALSE;
1785 }
1786 }
1787 else
1788 {
1789 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1790 {
1791 /* Exception occurred */
1792 return FALSE;
1793 }
1794 }
1795
1796 return TRUE;
1797 }
1798
1799 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1800 {
1801 CHAR Value;
1802 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1803 FAST486_MOD_REG_RM ModRegRm;
1804
1805 TOGGLE_ADSIZE(AddressSize);
1806
1807 /* Make sure this is the right instruction */
1808 ASSERT(Opcode == 0xBE);
1809
1810 /* Get the operands */
1811 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1812 {
1813 /* Exception occurred */
1814 return FALSE;
1815 }
1816
1817 /* Read the operands */
1818 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1819 {
1820 /* Exception occurred */
1821 return FALSE;
1822 }
1823
1824 /* Write back the sign-extended value */
1825 return Fast486WriteModrmDwordOperands(State,
1826 &ModRegRm,
1827 TRUE,
1828 (ULONG)((LONG)Value));
1829 }
1830
1831 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1832 {
1833 SHORT Value;
1834 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1835 FAST486_MOD_REG_RM ModRegRm;
1836
1837 TOGGLE_ADSIZE(AddressSize);
1838
1839 /* Make sure this is the right instruction */
1840 ASSERT(Opcode == 0xBF);
1841
1842 /* Get the operands */
1843 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1844 {
1845 /* Exception occurred */
1846 return FALSE;
1847 }
1848
1849 /* Read the operands */
1850 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1851 {
1852 /* Exception occurred */
1853 return FALSE;
1854 }
1855
1856 /* Write back the sign-extended value */
1857 return Fast486WriteModrmDwordOperands(State,
1858 &ModRegRm,
1859 TRUE,
1860 (ULONG)((LONG)Value));
1861 }
1862
1863 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1864 {
1865 BOOLEAN Jump = FALSE;
1866 LONG Offset = 0;
1867 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1868
1869 TOGGLE_OPSIZE(Size);
1870 NO_LOCK_PREFIX();
1871
1872 /* Make sure this is the right instruction */
1873 ASSERT((Opcode & 0xF0) == 0x80);
1874
1875 /* Fetch the offset */
1876 if (Size)
1877 {
1878 if (!Fast486FetchDword(State, (PULONG)&Offset))
1879 {
1880 /* Exception occurred */
1881 return FALSE;
1882 }
1883 }
1884 else
1885 {
1886 SHORT Value;
1887
1888 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1889 {
1890 /* Exception occurred */
1891 return FALSE;
1892 }
1893
1894 /* Sign-extend */
1895 Offset = (LONG)Value;
1896 }
1897
1898 switch ((Opcode & 0x0F) >> 1)
1899 {
1900 /* JO / JNO */
1901 case 0:
1902 {
1903 Jump = State->Flags.Of;
1904 break;
1905 }
1906
1907 /* JC / JNC */
1908 case 1:
1909 {
1910 Jump = State->Flags.Cf;
1911 break;
1912 }
1913
1914 /* JZ / JNZ */
1915 case 2:
1916 {
1917 Jump = State->Flags.Zf;
1918 break;
1919 }
1920
1921 /* JBE / JNBE */
1922 case 3:
1923 {
1924 Jump = State->Flags.Cf || State->Flags.Zf;
1925 break;
1926 }
1927
1928 /* JS / JNS */
1929 case 4:
1930 {
1931 Jump = State->Flags.Sf;
1932 break;
1933 }
1934
1935 /* JP / JNP */
1936 case 5:
1937 {
1938 Jump = State->Flags.Pf;
1939 break;
1940 }
1941
1942 /* JL / JNL */
1943 case 6:
1944 {
1945 Jump = State->Flags.Sf != State->Flags.Of;
1946 break;
1947 }
1948
1949 /* JLE / JNLE */
1950 case 7:
1951 {
1952 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1953 break;
1954 }
1955 }
1956
1957 if (Opcode & 1)
1958 {
1959 /* Invert the result */
1960 Jump = !Jump;
1961 }
1962
1963 if (Jump)
1964 {
1965 /* Move the instruction pointer */
1966 State->InstPtr.Long += Offset;
1967 }
1968
1969 /* Return success */
1970 return TRUE;
1971 }
1972
1973 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1974 {
1975 BOOLEAN Value = FALSE;
1976 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1977 FAST486_MOD_REG_RM ModRegRm;
1978
1979 TOGGLE_ADSIZE(AddressSize);
1980
1981 /* Get the operands */
1982 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1983 {
1984 /* Exception occurred */
1985 return FALSE;
1986 }
1987
1988 /* Make sure this is the right instruction */
1989 ASSERT((Opcode & 0xF0) == 0x90);
1990
1991 switch ((Opcode & 0x0F) >> 1)
1992 {
1993 /* SETO / SETNO */
1994 case 0:
1995 {
1996 Value = State->Flags.Of;
1997 break;
1998 }
1999
2000 /* SETC / SETNC */
2001 case 1:
2002 {
2003 Value = State->Flags.Cf;
2004 break;
2005 }
2006
2007 /* SETZ / SETNZ */
2008 case 2:
2009 {
2010 Value = State->Flags.Zf;
2011 break;
2012 }
2013
2014 /* SETBE / SETNBE */
2015 case 3:
2016 {
2017 Value = State->Flags.Cf || State->Flags.Zf;
2018 break;
2019 }
2020
2021 /* SETS / SETNS */
2022 case 4:
2023 {
2024 Value = State->Flags.Sf;
2025 break;
2026 }
2027
2028 /* SETP / SETNP */
2029 case 5:
2030 {
2031 Value = State->Flags.Pf;
2032 break;
2033 }
2034
2035 /* SETL / SETNL */
2036 case 6:
2037 {
2038 Value = State->Flags.Sf != State->Flags.Of;
2039 break;
2040 }
2041
2042 /* SETLE / SETNLE */
2043 case 7:
2044 {
2045 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2046 break;
2047 }
2048 }
2049
2050 if (Opcode & 1)
2051 {
2052 /* Invert the result */
2053 Value = !Value;
2054 }
2055
2056 /* Write back the result */
2057 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
2058 }
2059
2060 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
2061 {
2062 UCHAR Source, Destination, Result;
2063 FAST486_MOD_REG_RM ModRegRm;
2064 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2065
2066 /* Make sure this is the right instruction */
2067 ASSERT(Opcode == 0xC0);
2068
2069 TOGGLE_ADSIZE(AddressSize);
2070
2071 /* Get the operands */
2072 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2073 {
2074 /* Exception occurred */
2075 return FALSE;
2076 }
2077
2078 if (!Fast486ReadModrmByteOperands(State,
2079 &ModRegRm,
2080 &Source,
2081 &Destination))
2082 {
2083 /* Exception occurred */
2084 return FALSE;
2085 }
2086
2087 /* Calculate the result */
2088 Result = Source + Destination;
2089
2090 /* Update the flags */
2091 State->Flags.Cf = (Result < Source) && (Result < Destination);
2092 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
2093 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2094 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2095 State->Flags.Zf = (Result == 0);
2096 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2097 State->Flags.Pf = Fast486CalculateParity(Result);
2098
2099 /* Write the sum to the destination */
2100 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
2101 {
2102 /* Exception occurred */
2103 return FALSE;
2104 }
2105
2106 /* Write the old value of the destination to the source */
2107 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
2108 {
2109 /* Exception occurred */
2110 return FALSE;
2111 }
2112
2113 return TRUE;
2114 }
2115
2116 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
2117 {
2118 FAST486_MOD_REG_RM ModRegRm;
2119 BOOLEAN OperandSize, AddressSize;
2120
2121 /* Make sure this is the right instruction */
2122 ASSERT(Opcode == 0xC1);
2123
2124 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2125
2126 TOGGLE_ADSIZE(AddressSize);
2127 TOGGLE_OPSIZE(OperandSize);
2128
2129 /* Get the operands */
2130 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2131 {
2132 /* Exception occurred */
2133 return FALSE;
2134 }
2135
2136 /* Check the operand size */
2137 if (OperandSize)
2138 {
2139 ULONG Source, Destination, Result;
2140
2141 if (!Fast486ReadModrmDwordOperands(State,
2142 &ModRegRm,
2143 &Source,
2144 &Destination))
2145 {
2146 /* Exception occurred */
2147 return FALSE;
2148 }
2149
2150 /* Calculate the result */
2151 Result = Source + Destination;
2152
2153 /* Update the flags */
2154 State->Flags.Cf = (Result < Source) && (Result < Destination);
2155 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2156 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2157 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2158 State->Flags.Zf = (Result == 0);
2159 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2160 State->Flags.Pf = Fast486CalculateParity(Result);
2161
2162 /* Write the old value of the destination to the source */
2163 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2164 {
2165 /* Exception occurred */
2166 return FALSE;
2167 }
2168
2169 /* Write the sum to the destination */
2170 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
2171 {
2172 /* Exception occurred */
2173 return FALSE;
2174 }
2175 }
2176 else
2177 {
2178 USHORT Source, Destination, Result;
2179
2180 if (!Fast486ReadModrmWordOperands(State,
2181 &ModRegRm,
2182 &Source,
2183 &Destination))
2184 {
2185 /* Exception occurred */
2186 return FALSE;
2187 }
2188
2189 /* Calculate the result */
2190 Result = Source + Destination;
2191
2192 /* Update the flags */
2193 State->Flags.Cf = (Result < Source) && (Result < Destination);
2194 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2195 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2196 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2197 State->Flags.Zf = (Result == 0);
2198 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2199 State->Flags.Pf = Fast486CalculateParity(Result);
2200
2201 /* Write the old value of the destination to the source */
2202 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2203 {
2204 /* Exception occurred */
2205 return FALSE;
2206 }
2207
2208 /* Write the sum to the destination */
2209 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
2210 {
2211 /* Exception occurred */
2212 return FALSE;
2213 }
2214 }
2215
2216 return TRUE;
2217 }
2218
2219 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2220 {
2221 PUCHAR Pointer;
2222
2223 NO_LOCK_PREFIX();
2224
2225 /* Get a pointer to the value */
2226 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2227
2228 /* Swap the byte order */
2229 SWAP(Pointer[0], Pointer[3]);
2230 SWAP(Pointer[1], Pointer[2]);
2231
2232 /* Return success */
2233 return TRUE;
2234 }
2235
2236 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2237 {
2238 UCHAR SecondOpcode;
2239
2240 /* Fetch the second operation code */
2241 if (!Fast486FetchByte(State, &SecondOpcode))
2242 {
2243 /* Exception occurred */
2244 return FALSE;
2245 }
2246
2247 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
2248 {
2249 /* Call the extended opcode handler */
2250 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2251 }
2252 else
2253 {
2254 /* This is not a valid opcode */
2255 Fast486Exception(State, FAST486_EXCEPTION_UD);
2256 return FALSE;
2257 }
2258 }
2259