Sync up to trunk head before merging.
[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 Fast486ExtOpcodeLar,
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(Fast486ExtOpcodeLar)
301 {
302 BOOLEAN OperandSize, AddressSize;
303 FAST486_MOD_REG_RM ModRegRm;
304 USHORT Selector;
305 FAST486_GDT_ENTRY GdtEntry;
306 DWORD AccessRights;
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 /* Set ZF */
402 State->Flags.Zf = TRUE;
403
404 /* Get the access rights */
405 AccessRights = ((PDWORD)&GdtEntry)[1] & 0x00F0FF00;
406
407 /* Return the access rights */
408 if (OperandSize)
409 {
410 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, AccessRights))
411 {
412 /* Exception occurred */
413 return FALSE;
414 }
415 }
416 else
417 {
418 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(AccessRights)))
419 {
420 /* Exception occurred */
421 return FALSE;
422 }
423 }
424
425 return TRUE;
426 }
427
428 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
429 {
430 BOOLEAN OperandSize, AddressSize;
431 FAST486_MOD_REG_RM ModRegRm;
432 USHORT Selector;
433 ULONG Limit;
434 FAST486_GDT_ENTRY GdtEntry;
435
436 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
437
438 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
439 || State->Flags.Vm)
440 {
441 /* Not recognized */
442 Fast486Exception(State, FAST486_EXCEPTION_UD);
443 return FALSE;
444 }
445
446 NO_LOCK_PREFIX();
447 TOGGLE_OPSIZE(OperandSize);
448 TOGGLE_ADSIZE(AddressSize);
449
450 /* Get the operands */
451 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
452 {
453 /* Exception occurred */
454 return FALSE;
455 }
456
457 if (OperandSize)
458 {
459 ULONG Value;
460
461 /* Read the value */
462 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
463 {
464 /* Exception occurred */
465 return FALSE;
466 }
467
468 Selector = LOWORD(Value);
469 }
470 else
471 {
472 /* Read the value */
473 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
474 {
475 /* Exception occurred */
476 return FALSE;
477 }
478 }
479
480 if (!(Selector & SEGMENT_TABLE_INDICATOR))
481 {
482 /* Check if the GDT contains the entry */
483 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
484 {
485 State->Flags.Zf = FALSE;
486 return TRUE;
487 }
488
489 /* Read the GDT */
490 if (!Fast486ReadLinearMemory(State,
491 State->Gdtr.Address
492 + GET_SEGMENT_INDEX(Selector),
493 &GdtEntry,
494 sizeof(GdtEntry)))
495 {
496 /* Exception occurred */
497 return FALSE;
498 }
499 }
500 else
501 {
502 /* Check if the LDT contains the entry */
503 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
504 {
505 State->Flags.Zf = FALSE;
506 return TRUE;
507 }
508
509 /* Read the LDT */
510 if (!Fast486ReadLinearMemory(State,
511 State->Ldtr.Base
512 + GET_SEGMENT_INDEX(Selector),
513 &GdtEntry,
514 sizeof(GdtEntry)))
515 {
516 /* Exception occurred */
517 return FALSE;
518 }
519 }
520
521 /* Privilege check */
522 if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
523 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
524 {
525 State->Flags.Zf = FALSE;
526 return TRUE;
527 }
528
529 /* Calculate the limit */
530 Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
531 if (GdtEntry.Granularity) Limit <<= 12;
532
533 /* Set ZF */
534 State->Flags.Zf = TRUE;
535
536 if (OperandSize)
537 {
538 /* Return the limit */
539 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit))
540 {
541 /* Exception occurred */
542 return FALSE;
543 }
544 }
545 else
546 {
547 /* Return the limit */
548 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit)))
549 {
550 /* Exception occurred */
551 return FALSE;
552 }
553 }
554
555 return TRUE;
556 }
557
558 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
559 {
560 NO_LOCK_PREFIX();
561
562 /* The current privilege level must be zero */
563 if (Fast486GetCurrentPrivLevel(State) != 0)
564 {
565 Fast486Exception(State, FAST486_EXCEPTION_GP);
566 return FALSE;
567 }
568
569 /* Clear the task switch bit */
570 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
571
572 return TRUE;
573 }
574
575 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
576 {
577 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
578 FAST486_MOD_REG_RM ModRegRm;
579
580 NO_LOCK_PREFIX();
581 TOGGLE_ADSIZE(AddressSize);
582
583 /* Get the operands */
584 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
585 {
586 /* Exception occurred */
587 return FALSE;
588 }
589
590 /* The current privilege level must be zero */
591 if (Fast486GetCurrentPrivLevel(State) != 0)
592 {
593 Fast486Exception(State, FAST486_EXCEPTION_GP);
594 return FALSE;
595 }
596
597 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
598 {
599 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
600 Fast486Exception(State, FAST486_EXCEPTION_UD);
601 return FALSE;
602 }
603
604 if (ModRegRm.Register != 0)
605 {
606 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
607 ModRegRm.Register--;
608 }
609
610 /* Store the value of the control register */
611 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
612
613 /* Return success */
614 return TRUE;
615 }
616
617 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
618 {
619 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
620 FAST486_MOD_REG_RM ModRegRm;
621
622 NO_LOCK_PREFIX();
623 TOGGLE_ADSIZE(AddressSize);
624
625 /* Get the operands */
626 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
627 {
628 /* Exception occurred */
629 return FALSE;
630 }
631
632 /* The current privilege level must be zero */
633 if (Fast486GetCurrentPrivLevel(State) != 0)
634 {
635 Fast486Exception(State, FAST486_EXCEPTION_GP);
636 return FALSE;
637 }
638
639 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
640 {
641 /* DR6 and DR7 are aliases to DR4 and DR5 */
642 ModRegRm.Register -= 2;
643 }
644
645 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
646 {
647 /* Disallow access to debug registers */
648 Fast486Exception(State, FAST486_EXCEPTION_GP);
649 return FALSE;
650 }
651
652 /* Store the value of the debug register */
653 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
654
655 /* Return success */
656 return TRUE;
657 }
658
659 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
660 {
661 ULONG Value;
662 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
663 FAST486_MOD_REG_RM ModRegRm;
664
665 NO_LOCK_PREFIX();
666 TOGGLE_ADSIZE(AddressSize);
667
668 /* Get the operands */
669 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
670 {
671 /* Exception occurred */
672 return FALSE;
673 }
674
675 /* The current privilege level must be zero */
676 if (Fast486GetCurrentPrivLevel(State) != 0)
677 {
678 Fast486Exception(State, FAST486_EXCEPTION_GP);
679 return FALSE;
680 }
681
682 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
683 {
684 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
685 Fast486Exception(State, FAST486_EXCEPTION_UD);
686 return FALSE;
687 }
688
689 if (ModRegRm.Register != 0)
690 {
691 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
692 ModRegRm.Register--;
693 }
694
695 /* Get the value */
696 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
697
698 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
699 {
700 /* CR0 checks */
701
702 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
703 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
704 {
705 /* Invalid value */
706 Fast486Exception(State, FAST486_EXCEPTION_GP);
707 return FALSE;
708 }
709 }
710
711 /* Load a value to the control register */
712 State->ControlRegisters[ModRegRm.Register] = Value;
713
714 /* Return success */
715 return TRUE;
716 }
717
718 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
719 {
720 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
721 FAST486_MOD_REG_RM ModRegRm;
722
723 NO_LOCK_PREFIX();
724 TOGGLE_ADSIZE(AddressSize);
725
726 /* Get the operands */
727 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
728 {
729 /* Exception occurred */
730 return FALSE;
731 }
732
733 /* The current privilege level must be zero */
734 if (Fast486GetCurrentPrivLevel(State) != 0)
735 {
736 Fast486Exception(State, FAST486_EXCEPTION_GP);
737 return FALSE;
738 }
739
740 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
741 {
742 /* DR6 and DR7 are aliases to DR4 and DR5 */
743 ModRegRm.Register -= 2;
744 }
745
746 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
747 {
748 /* Disallow access to debug registers */
749 Fast486Exception(State, FAST486_EXCEPTION_GP);
750 return FALSE;
751 }
752
753 /* Load a value to the debug register */
754 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
755
756 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
757 {
758 /* The reserved bits are 1 */
759 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
760 }
761 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
762 {
763 /* The reserved bits are 0 */
764 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
765 }
766
767 /* Return success */
768 return TRUE;
769 }
770
771 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
772 {
773 /* Call the internal API */
774 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
775 }
776
777 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
778 {
779 ULONG NewSelector;
780
781 if (!Fast486StackPop(State, &NewSelector))
782 {
783 /* Exception occurred */
784 return FALSE;
785 }
786
787 /* Call the internal API */
788 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
789 }
790
791 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
792 {
793 BOOLEAN OperandSize, AddressSize;
794 FAST486_MOD_REG_RM ModRegRm;
795 UINT DataSize;
796 ULONG BitNumber;
797
798 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
799 TOGGLE_OPSIZE(OperandSize);
800 TOGGLE_ADSIZE(AddressSize);
801
802 /* Get the number of bits */
803 if (OperandSize) DataSize = 32;
804 else DataSize = 16;
805
806 /* Get the operands */
807 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
808 {
809 /* Exception occurred */
810 return FALSE;
811 }
812
813 /* Get the bit number */
814 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
815 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
816
817 if (ModRegRm.Memory)
818 {
819 /*
820 * For memory operands, add the bit offset divided by
821 * the data size to the address
822 */
823 ModRegRm.MemoryAddress += BitNumber / DataSize;
824 }
825
826 /* Normalize the bit number */
827 BitNumber %= DataSize;
828
829 if (OperandSize)
830 {
831 ULONG Value;
832
833 /* Read the value */
834 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
835 {
836 /* Exception occurred */
837 return FALSE;
838 }
839
840 /* Set CF to the bit value */
841 State->Flags.Cf = (Value >> BitNumber) & 1;
842 }
843 else
844 {
845 USHORT Value;
846
847 /* Read the value */
848 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
849 {
850 /* Exception occurred */
851 return FALSE;
852 }
853
854 /* Set CF to the bit value */
855 State->Flags.Cf = (Value >> BitNumber) & 1;
856 }
857
858 /* Return success */
859 return TRUE;
860 }
861
862 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
863 {
864 BOOLEAN OperandSize, AddressSize;
865 FAST486_MOD_REG_RM ModRegRm;
866 UCHAR Count;
867
868 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
869 TOGGLE_OPSIZE(OperandSize);
870 TOGGLE_ADSIZE(AddressSize);
871
872 /* Make sure this is the right instruction */
873 ASSERT((Opcode & 0xFE) == 0xA4);
874
875 /* Get the operands */
876 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
877 {
878 /* Exception occurred */
879 return FALSE;
880 }
881
882 if (Opcode == 0xA4)
883 {
884 /* Fetch the count */
885 if (!Fast486FetchByte(State, &Count))
886 {
887 /* Exception occurred */
888 return FALSE;
889 }
890 }
891 else
892 {
893 /* The count is in CL */
894 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
895 }
896
897 /* Normalize the count */
898 Count &= 0x1F;
899
900 /* Do nothing if the count is zero */
901 if (Count == 0) return TRUE;
902
903 if (OperandSize)
904 {
905 ULONG Source, Destination, Result;
906
907 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
908 {
909 /* Exception occurred */
910 return FALSE;
911 }
912
913 /* Calculate the result */
914 Result = (Destination << Count) | (Source >> (32 - Count));
915
916 /* Update flags */
917 State->Flags.Cf = (Destination >> (32 - Count)) & 1;
918 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
919 != (Destination & SIGN_FLAG_LONG);
920 State->Flags.Zf = (Result == 0);
921 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
922 State->Flags.Pf = Fast486CalculateParity(Result);
923
924 /* Write back the result */
925 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
926 }
927 else
928 {
929 USHORT Source, Destination, Result;
930 ULONG DoubleSource;
931
932 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
933 {
934 /* Exception occurred */
935 return FALSE;
936 }
937
938 DoubleSource = Source | (Source << 16);
939
940 /* Calculate the result */
941 Result = (Destination << Count) | (DoubleSource >> (32 - Count));
942
943 /* Update flags */
944 if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
945 else State->Flags.Cf = (Source >> (32 - Count)) & 1;
946
947 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
948 != (Destination & SIGN_FLAG_WORD);
949 State->Flags.Zf = (Result == 0);
950 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
951 State->Flags.Pf = Fast486CalculateParity(Result);
952
953 /* Write back the result */
954 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
955 }
956 }
957
958 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
959 {
960 /* Call the internal API */
961 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
962 }
963
964 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
965 {
966 ULONG NewSelector;
967
968 if (!Fast486StackPop(State, &NewSelector))
969 {
970 /* Exception occurred */
971 return FALSE;
972 }
973
974 /* Call the internal API */
975 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
976 }
977
978 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
979 {
980 BOOLEAN OperandSize, AddressSize;
981 FAST486_MOD_REG_RM ModRegRm;
982 UINT DataSize;
983 ULONG BitNumber;
984
985 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
986 TOGGLE_OPSIZE(OperandSize);
987 TOGGLE_ADSIZE(AddressSize);
988
989 /* Get the number of bits */
990 if (OperandSize) DataSize = 32;
991 else DataSize = 16;
992
993 /* Get the operands */
994 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
995 {
996 /* Exception occurred */
997 return FALSE;
998 }
999
1000 /* Get the bit number */
1001 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1002 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1003
1004 if (ModRegRm.Memory)
1005 {
1006 /*
1007 * For memory operands, add the bit offset divided by
1008 * the data size to the address
1009 */
1010 ModRegRm.MemoryAddress += BitNumber / DataSize;
1011 }
1012
1013 /* Normalize the bit number */
1014 BitNumber %= DataSize;
1015
1016 if (OperandSize)
1017 {
1018 ULONG Value;
1019
1020 /* Read the value */
1021 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1022 {
1023 /* Exception occurred */
1024 return FALSE;
1025 }
1026
1027 /* Set CF to the bit value */
1028 State->Flags.Cf = (Value >> BitNumber) & 1;
1029
1030 /* Set the bit */
1031 Value |= 1 << BitNumber;
1032
1033 /* Write back the result */
1034 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1035 {
1036 /* Exception occurred */
1037 return FALSE;
1038 }
1039 }
1040 else
1041 {
1042 USHORT Value;
1043
1044 /* Read the value */
1045 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1046 {
1047 /* Exception occurred */
1048 return FALSE;
1049 }
1050
1051 /* Set CF to the bit value */
1052 State->Flags.Cf = (Value >> BitNumber) & 1;
1053
1054 /* Set the bit */
1055 Value |= 1 << BitNumber;
1056
1057 /* Write back the result */
1058 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1059 {
1060 /* Exception occurred */
1061 return FALSE;
1062 }
1063 }
1064
1065 /* Return success */
1066 return TRUE;
1067 }
1068
1069 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
1070 {
1071 BOOLEAN OperandSize, AddressSize;
1072 FAST486_MOD_REG_RM ModRegRm;
1073 UCHAR Count;
1074
1075 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1076 TOGGLE_OPSIZE(OperandSize);
1077 TOGGLE_ADSIZE(AddressSize);
1078
1079 /* Make sure this is the right instruction */
1080 ASSERT((Opcode & 0xFE) == 0xAC);
1081
1082 /* Get the operands */
1083 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1084 {
1085 /* Exception occurred */
1086 return FALSE;
1087 }
1088
1089 if (Opcode == 0xAC)
1090 {
1091 /* Fetch the count */
1092 if (!Fast486FetchByte(State, &Count))
1093 {
1094 /* Exception occurred */
1095 return FALSE;
1096 }
1097 }
1098 else
1099 {
1100 /* The count is in CL */
1101 Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
1102 }
1103
1104 /* Normalize the count */
1105 Count &= 0x1F;
1106
1107 /* Do nothing if the count is zero */
1108 if (Count == 0) return TRUE;
1109
1110 if (OperandSize)
1111 {
1112 ULONG Source, Destination, Result;
1113
1114 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1115 {
1116 /* Exception occurred */
1117 return FALSE;
1118 }
1119
1120 /* Calculate the result */
1121 Result = (Destination >> Count) | (Source << (32 - Count));
1122
1123 /* Update flags */
1124 State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1125 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
1126 != (Destination & SIGN_FLAG_LONG);
1127 State->Flags.Zf = (Result == 0);
1128 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1129 State->Flags.Pf = Fast486CalculateParity(Result);
1130
1131 /* Write back the result */
1132 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1133 }
1134 else
1135 {
1136 USHORT Source, Destination, Result;
1137
1138 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1139 {
1140 /* Exception occurred */
1141 return FALSE;
1142 }
1143
1144 /* Calculate the result */
1145 Result = (Destination >> Count) | (Source << (16 - Count));
1146
1147 if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
1148
1149 /* Update flags */
1150 if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1151 else State->Flags.Cf = (Source >> (Count - 17)) & 1;
1152
1153 if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
1154 != (Destination & SIGN_FLAG_WORD);
1155 State->Flags.Zf = (Result == 0);
1156 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1157 State->Flags.Pf = Fast486CalculateParity(Result);
1158
1159 /* Write back the result */
1160 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
1161 }
1162 }
1163
1164 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
1165 {
1166 BOOLEAN OperandSize, AddressSize;
1167 FAST486_MOD_REG_RM ModRegRm;
1168
1169 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1170
1171 TOGGLE_OPSIZE(OperandSize);
1172 TOGGLE_ADSIZE(AddressSize);
1173
1174 /* Get the operands */
1175 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1176 {
1177 /* Exception occurred */
1178 return FALSE;
1179 }
1180
1181 if (OperandSize)
1182 {
1183 LONG Source, Destination;
1184 LONGLONG Result;
1185
1186 /* Read the operands */
1187 if (!Fast486ReadModrmDwordOperands(State,
1188 &ModRegRm,
1189 (PULONG)&Destination,
1190 (PULONG)&Source))
1191 {
1192 /* Exception occurred */
1193 return FALSE;
1194 }
1195
1196 /* Calculate the result */
1197 Result = (LONGLONG)Source * (LONGLONG)Destination;
1198
1199 /* Update the flags */
1200 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1201
1202 /* Write back the result */
1203 return Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
1204 }
1205 else
1206 {
1207 SHORT Source, Destination;
1208 LONG Result;
1209
1210 /* Read the operands */
1211 if (!Fast486ReadModrmWordOperands(State,
1212 &ModRegRm,
1213 (PUSHORT)&Destination,
1214 (PUSHORT)&Source))
1215 {
1216 /* Exception occurred */
1217 return FALSE;
1218 }
1219
1220 /* Calculate the result */
1221 Result = (LONG)Source * (LONG)Destination;
1222
1223 /* Update the flags */
1224 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1225
1226 /* Write back the result */
1227 return Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
1228 }
1229 }
1230
1231 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
1232 {
1233 FAST486_MOD_REG_RM ModRegRm;
1234 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1235 UCHAR Source, Destination, Result;
1236 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1237
1238 TOGGLE_ADSIZE(AddressSize);
1239
1240 /* Get the operands */
1241 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1242 {
1243 /* Exception occurred */
1244 return FALSE;
1245 }
1246
1247 /* Read the operands */
1248 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
1249 {
1250 /* Exception occurred */
1251 return FALSE;
1252 }
1253
1254 /* Compare AL with the destination */
1255 Result = Accumulator - Destination;
1256
1257 /* Update the flags */
1258 State->Flags.Cf = (Accumulator < Destination);
1259 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
1260 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1261 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1262 State->Flags.Zf = (Result == 0);
1263 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1264 State->Flags.Pf = Fast486CalculateParity(Result);
1265
1266 if (State->Flags.Zf)
1267 {
1268 /* Load the source operand into the destination */
1269 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1270 }
1271 else
1272 {
1273 /* Load the destination into AL */
1274 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1275 }
1276
1277 /* Return success */
1278 return TRUE;
1279 }
1280
1281 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1282 {
1283 FAST486_MOD_REG_RM ModRegRm;
1284 BOOLEAN OperandSize, AddressSize;
1285
1286 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1287
1288 TOGGLE_OPSIZE(OperandSize);
1289 TOGGLE_ADSIZE(AddressSize);
1290
1291 /* Get the operands */
1292 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1293 {
1294 /* Exception occurred */
1295 return FALSE;
1296 }
1297
1298 if (OperandSize)
1299 {
1300 ULONG Source, Destination, Result;
1301 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1302
1303 /* Read the operands */
1304 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1305 {
1306 /* Exception occurred */
1307 return FALSE;
1308 }
1309
1310 /* Compare EAX with the destination */
1311 Result = Accumulator - Destination;
1312
1313 /* Update the flags */
1314 State->Flags.Cf = (Accumulator < Destination);
1315 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1316 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1317 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1318 State->Flags.Zf = (Result == 0);
1319 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1320 State->Flags.Pf = Fast486CalculateParity(Result);
1321
1322 if (State->Flags.Zf)
1323 {
1324 /* Load the source operand into the destination */
1325 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1326 }
1327 else
1328 {
1329 /* Load the destination into EAX */
1330 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1331 }
1332 }
1333 else
1334 {
1335 USHORT Source, Destination, Result;
1336 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1337
1338 /* Read the operands */
1339 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1340 {
1341 /* Exception occurred */
1342 return FALSE;
1343 }
1344
1345 /* Compare AX with the destination */
1346 Result = Accumulator - Destination;
1347
1348 /* Update the flags */
1349 State->Flags.Cf = (Accumulator < Destination);
1350 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1351 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1352 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1353 State->Flags.Zf = (Result == 0);
1354 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1355 State->Flags.Pf = Fast486CalculateParity(Result);
1356
1357 if (State->Flags.Zf)
1358 {
1359 /* Load the source operand into the destination */
1360 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1361 }
1362 else
1363 {
1364 /* Load the destination into AX */
1365 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1366 }
1367 }
1368
1369 /* Return success */
1370 return TRUE;
1371 }
1372
1373 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1374 {
1375 UCHAR FarPointer[6];
1376 BOOLEAN OperandSize, AddressSize;
1377 FAST486_MOD_REG_RM ModRegRm;
1378
1379 /* Make sure this is the right instruction */
1380 ASSERT(Opcode == 0xB2);
1381
1382 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1383
1384 TOGGLE_OPSIZE(OperandSize);
1385 TOGGLE_ADSIZE(AddressSize);
1386
1387 /* Get the operands */
1388 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1389 {
1390 /* Exception occurred */
1391 return FALSE;
1392 }
1393
1394 if (!ModRegRm.Memory)
1395 {
1396 /* Invalid */
1397 Fast486Exception(State, FAST486_EXCEPTION_UD);
1398 return FALSE;
1399 }
1400
1401 if (!Fast486ReadMemory(State,
1402 (State->PrefixFlags & FAST486_PREFIX_SEG)
1403 ? State->SegmentOverride : FAST486_REG_DS,
1404 ModRegRm.MemoryAddress,
1405 FALSE,
1406 FarPointer,
1407 OperandSize ? 6 : 4))
1408 {
1409 /* Exception occurred */
1410 return FALSE;
1411 }
1412
1413 if (OperandSize)
1414 {
1415 ULONG Offset = *((PULONG)FarPointer);
1416 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1417
1418 /* Set the register to the offset */
1419 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1420
1421 /* Load the segment */
1422 return Fast486LoadSegment(State,
1423 FAST486_REG_SS,
1424 Segment);
1425 }
1426 else
1427 {
1428 USHORT Offset = *((PUSHORT)FarPointer);
1429 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1430
1431 /* Set the register to the offset */
1432 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1433
1434 /* Load the segment */
1435 return Fast486LoadSegment(State,
1436 FAST486_REG_SS,
1437 Segment);
1438 }
1439 }
1440
1441 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1442 {
1443 BOOLEAN OperandSize, AddressSize;
1444 FAST486_MOD_REG_RM ModRegRm;
1445 UINT DataSize;
1446 ULONG BitNumber;
1447
1448 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1449 TOGGLE_OPSIZE(OperandSize);
1450 TOGGLE_ADSIZE(AddressSize);
1451
1452 /* Get the number of bits */
1453 if (OperandSize) DataSize = 32;
1454 else DataSize = 16;
1455
1456 /* Get the operands */
1457 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1458 {
1459 /* Exception occurred */
1460 return FALSE;
1461 }
1462
1463 /* Get the bit number */
1464 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1465 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1466
1467 if (ModRegRm.Memory)
1468 {
1469 /*
1470 * For memory operands, add the bit offset divided by
1471 * the data size to the address
1472 */
1473 ModRegRm.MemoryAddress += BitNumber / DataSize;
1474 }
1475
1476 /* Normalize the bit number */
1477 BitNumber %= DataSize;
1478
1479 if (OperandSize)
1480 {
1481 ULONG Value;
1482
1483 /* Read the value */
1484 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1485 {
1486 /* Exception occurred */
1487 return FALSE;
1488 }
1489
1490 /* Set CF to the bit value */
1491 State->Flags.Cf = (Value >> BitNumber) & 1;
1492
1493 /* Clear the bit */
1494 Value &= ~(1 << BitNumber);
1495
1496 /* Write back the result */
1497 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1498 {
1499 /* Exception occurred */
1500 return FALSE;
1501 }
1502 }
1503 else
1504 {
1505 USHORT Value;
1506
1507 /* Read the value */
1508 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1509 {
1510 /* Exception occurred */
1511 return FALSE;
1512 }
1513
1514 /* Set CF to the bit value */
1515 State->Flags.Cf = (Value >> BitNumber) & 1;
1516
1517 /* Clear the bit */
1518 Value &= ~(1 << BitNumber);
1519
1520 /* Write back the result */
1521 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1522 {
1523 /* Exception occurred */
1524 return FALSE;
1525 }
1526 }
1527
1528 /* Return success */
1529 return TRUE;
1530 }
1531
1532 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1533 {
1534 UCHAR FarPointer[6];
1535 BOOLEAN OperandSize, AddressSize;
1536 FAST486_MOD_REG_RM ModRegRm;
1537
1538 /* Make sure this is the right instruction */
1539 ASSERT((Opcode & 0xFE) == 0xB4);
1540
1541 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1542
1543 TOGGLE_OPSIZE(OperandSize);
1544 TOGGLE_ADSIZE(AddressSize);
1545
1546 /* Get the operands */
1547 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1548 {
1549 /* Exception occurred */
1550 return FALSE;
1551 }
1552
1553 if (!ModRegRm.Memory)
1554 {
1555 /* Invalid */
1556 Fast486Exception(State, FAST486_EXCEPTION_UD);
1557 return FALSE;
1558 }
1559
1560 if (!Fast486ReadMemory(State,
1561 (State->PrefixFlags & FAST486_PREFIX_SEG)
1562 ? State->SegmentOverride : FAST486_REG_DS,
1563 ModRegRm.MemoryAddress,
1564 FALSE,
1565 FarPointer,
1566 OperandSize ? 6 : 4))
1567 {
1568 /* Exception occurred */
1569 return FALSE;
1570 }
1571
1572 if (OperandSize)
1573 {
1574 ULONG Offset = *((PULONG)FarPointer);
1575 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1576
1577 /* Set the register to the offset */
1578 State->GeneralRegs[ModRegRm.Register].Long = Offset;
1579
1580 /* Load the segment */
1581 return Fast486LoadSegment(State,
1582 (Opcode == 0xB4)
1583 ? FAST486_REG_FS : FAST486_REG_GS,
1584 Segment);
1585 }
1586 else
1587 {
1588 USHORT Offset = *((PUSHORT)FarPointer);
1589 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1590
1591 /* Set the register to the offset */
1592 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1593
1594 /* Load the segment */
1595 return Fast486LoadSegment(State,
1596 (Opcode == 0xB4)
1597 ? FAST486_REG_FS : FAST486_REG_GS,
1598 Segment);
1599 }
1600 }
1601
1602 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1603 {
1604 UCHAR Value;
1605 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1606 FAST486_MOD_REG_RM ModRegRm;
1607
1608 TOGGLE_ADSIZE(AddressSize);
1609
1610 /* Make sure this is the right instruction */
1611 ASSERT(Opcode == 0xB6);
1612
1613 /* Get the operands */
1614 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1615 {
1616 /* Exception occurred */
1617 return FALSE;
1618 }
1619
1620 /* Read the operands */
1621 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1622 {
1623 /* Exception occurred */
1624 return FALSE;
1625 }
1626
1627 /* Write back the zero-extended value */
1628 return Fast486WriteModrmDwordOperands(State,
1629 &ModRegRm,
1630 TRUE,
1631 (ULONG)Value);
1632 }
1633
1634 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1635 {
1636 USHORT Value;
1637 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1638 FAST486_MOD_REG_RM ModRegRm;
1639
1640 TOGGLE_ADSIZE(AddressSize);
1641
1642 /* Make sure this is the right instruction */
1643 ASSERT(Opcode == 0xB7);
1644
1645 /* Get the operands */
1646 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1647 {
1648 /* Exception occurred */
1649 return FALSE;
1650 }
1651
1652 /* Read the operands */
1653 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1654 {
1655 /* Exception occurred */
1656 return FALSE;
1657 }
1658
1659 /* Write back the zero-extended value */
1660 return Fast486WriteModrmDwordOperands(State,
1661 &ModRegRm,
1662 TRUE,
1663 (ULONG)Value);
1664 }
1665
1666 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1667 {
1668 BOOLEAN OperandSize, AddressSize;
1669 FAST486_MOD_REG_RM ModRegRm;
1670 UINT DataSize;
1671 ULONG BitNumber;
1672
1673 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1674 TOGGLE_OPSIZE(OperandSize);
1675 TOGGLE_ADSIZE(AddressSize);
1676
1677 /* Get the number of bits */
1678 if (OperandSize) DataSize = 32;
1679 else DataSize = 16;
1680
1681 /* Get the operands */
1682 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1683 {
1684 /* Exception occurred */
1685 return FALSE;
1686 }
1687
1688 /* Get the bit number */
1689 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1690 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1691
1692 if (ModRegRm.Memory)
1693 {
1694 /*
1695 * For memory operands, add the bit offset divided by
1696 * the data size to the address
1697 */
1698 ModRegRm.MemoryAddress += BitNumber / DataSize;
1699 }
1700
1701 /* Normalize the bit number */
1702 BitNumber %= DataSize;
1703
1704 if (OperandSize)
1705 {
1706 ULONG Value;
1707
1708 /* Read the value */
1709 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1710 {
1711 /* Exception occurred */
1712 return FALSE;
1713 }
1714
1715 /* Set CF to the bit value */
1716 State->Flags.Cf = (Value >> BitNumber) & 1;
1717
1718 /* Toggle the bit */
1719 Value ^= 1 << BitNumber;
1720
1721 /* Write back the result */
1722 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1723 {
1724 /* Exception occurred */
1725 return FALSE;
1726 }
1727 }
1728 else
1729 {
1730 USHORT Value;
1731
1732 /* Read the value */
1733 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1734 {
1735 /* Exception occurred */
1736 return FALSE;
1737 }
1738
1739 /* Set CF to the bit value */
1740 State->Flags.Cf = (Value >> BitNumber) & 1;
1741
1742 /* Toggle the bit */
1743 Value ^= 1 << BitNumber;
1744
1745 /* Write back the result */
1746 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1747 {
1748 /* Exception occurred */
1749 return FALSE;
1750 }
1751 }
1752
1753 /* Return success */
1754 return TRUE;
1755 }
1756
1757 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1758 {
1759 INT i;
1760 ULONG Value = 0;
1761 BOOLEAN OperandSize, AddressSize;
1762 FAST486_MOD_REG_RM ModRegRm;
1763 ULONG BitNumber;
1764 UINT DataSize;
1765
1766 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1767 TOGGLE_OPSIZE(OperandSize);
1768 TOGGLE_ADSIZE(AddressSize);
1769
1770 /* Make sure this is the right instruction */
1771 ASSERT(Opcode == 0xBC);
1772
1773 /* Get the number of bits */
1774 if (OperandSize) DataSize = 32;
1775 else DataSize = 16;
1776
1777 /* Get the operands */
1778 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1779 {
1780 /* Exception occurred */
1781 return FALSE;
1782 }
1783
1784 /* Read the value */
1785 if (OperandSize)
1786 {
1787 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1788 {
1789 /* Exception occurred */
1790 return FALSE;
1791 }
1792 }
1793 else
1794 {
1795 if (!Fast486ReadModrmWordOperands(State,
1796 &ModRegRm,
1797 (PUSHORT)NULL,
1798 (PUSHORT)&Value))
1799 {
1800 /* Exception occurred */
1801 return FALSE;
1802 }
1803 }
1804
1805 /* Set ZF */
1806 State->Flags.Zf = (Value == 0);
1807 if (State->Flags.Zf) return TRUE;
1808
1809 for (i = 0; i < DataSize; i++)
1810 {
1811 if(Value & (1 << i))
1812 {
1813 /* Save the bit number */
1814 BitNumber = i;
1815
1816 /* Exit the loop */
1817 break;
1818 }
1819 }
1820
1821 /* Write back the result */
1822 if (OperandSize)
1823 {
1824 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1825 {
1826 /* Exception occurred */
1827 return FALSE;
1828 }
1829 }
1830 else
1831 {
1832 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1833 {
1834 /* Exception occurred */
1835 return FALSE;
1836 }
1837 }
1838
1839 return TRUE;
1840 }
1841
1842 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1843 {
1844 INT i;
1845 ULONG Value = 0;
1846 BOOLEAN OperandSize, AddressSize;
1847 FAST486_MOD_REG_RM ModRegRm;
1848 ULONG BitNumber;
1849 UINT DataSize;
1850
1851 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1852 TOGGLE_OPSIZE(OperandSize);
1853 TOGGLE_ADSIZE(AddressSize);
1854
1855 /* Make sure this is the right instruction */
1856 ASSERT(Opcode == 0xBD);
1857
1858 /* Get the number of bits */
1859 if (OperandSize) DataSize = 32;
1860 else DataSize = 16;
1861
1862 /* Get the operands */
1863 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1864 {
1865 /* Exception occurred */
1866 return FALSE;
1867 }
1868
1869 /* Read the value */
1870 if (OperandSize)
1871 {
1872 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1873 {
1874 /* Exception occurred */
1875 return FALSE;
1876 }
1877 }
1878 else
1879 {
1880 if (!Fast486ReadModrmWordOperands(State,
1881 &ModRegRm,
1882 (PUSHORT)NULL,
1883 (PUSHORT)&Value))
1884 {
1885 /* Exception occurred */
1886 return FALSE;
1887 }
1888 }
1889
1890 /* Set ZF according to the value */
1891 State->Flags.Zf = (Value == 0);
1892 if (State->Flags.Zf) return TRUE;
1893
1894 for (i = DataSize - 1; i >= 0; i--)
1895 {
1896 if(Value & (1 << i))
1897 {
1898 /* Save the bit number */
1899 BitNumber = i;
1900
1901 /* Exit the loop */
1902 break;
1903 }
1904 }
1905
1906 /* Write back the result */
1907 if (OperandSize)
1908 {
1909 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1910 {
1911 /* Exception occurred */
1912 return FALSE;
1913 }
1914 }
1915 else
1916 {
1917 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1918 {
1919 /* Exception occurred */
1920 return FALSE;
1921 }
1922 }
1923
1924 return TRUE;
1925 }
1926
1927 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1928 {
1929 CHAR Value;
1930 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1931 FAST486_MOD_REG_RM ModRegRm;
1932
1933 TOGGLE_ADSIZE(AddressSize);
1934
1935 /* Make sure this is the right instruction */
1936 ASSERT(Opcode == 0xBE);
1937
1938 /* Get the operands */
1939 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1940 {
1941 /* Exception occurred */
1942 return FALSE;
1943 }
1944
1945 /* Read the operands */
1946 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1947 {
1948 /* Exception occurred */
1949 return FALSE;
1950 }
1951
1952 /* Write back the sign-extended value */
1953 return Fast486WriteModrmDwordOperands(State,
1954 &ModRegRm,
1955 TRUE,
1956 (ULONG)((LONG)Value));
1957 }
1958
1959 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1960 {
1961 SHORT Value;
1962 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1963 FAST486_MOD_REG_RM ModRegRm;
1964
1965 TOGGLE_ADSIZE(AddressSize);
1966
1967 /* Make sure this is the right instruction */
1968 ASSERT(Opcode == 0xBF);
1969
1970 /* Get the operands */
1971 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1972 {
1973 /* Exception occurred */
1974 return FALSE;
1975 }
1976
1977 /* Read the operands */
1978 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1979 {
1980 /* Exception occurred */
1981 return FALSE;
1982 }
1983
1984 /* Write back the sign-extended value */
1985 return Fast486WriteModrmDwordOperands(State,
1986 &ModRegRm,
1987 TRUE,
1988 (ULONG)((LONG)Value));
1989 }
1990
1991 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1992 {
1993 BOOLEAN Jump = FALSE;
1994 LONG Offset = 0;
1995 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1996
1997 TOGGLE_OPSIZE(Size);
1998 NO_LOCK_PREFIX();
1999
2000 /* Make sure this is the right instruction */
2001 ASSERT((Opcode & 0xF0) == 0x80);
2002
2003 /* Fetch the offset */
2004 if (Size)
2005 {
2006 if (!Fast486FetchDword(State, (PULONG)&Offset))
2007 {
2008 /* Exception occurred */
2009 return FALSE;
2010 }
2011 }
2012 else
2013 {
2014 SHORT Value;
2015
2016 if (!Fast486FetchWord(State, (PUSHORT)&Value))
2017 {
2018 /* Exception occurred */
2019 return FALSE;
2020 }
2021
2022 /* Sign-extend */
2023 Offset = (LONG)Value;
2024 }
2025
2026 switch ((Opcode & 0x0F) >> 1)
2027 {
2028 /* JO / JNO */
2029 case 0:
2030 {
2031 Jump = State->Flags.Of;
2032 break;
2033 }
2034
2035 /* JC / JNC */
2036 case 1:
2037 {
2038 Jump = State->Flags.Cf;
2039 break;
2040 }
2041
2042 /* JZ / JNZ */
2043 case 2:
2044 {
2045 Jump = State->Flags.Zf;
2046 break;
2047 }
2048
2049 /* JBE / JNBE */
2050 case 3:
2051 {
2052 Jump = State->Flags.Cf || State->Flags.Zf;
2053 break;
2054 }
2055
2056 /* JS / JNS */
2057 case 4:
2058 {
2059 Jump = State->Flags.Sf;
2060 break;
2061 }
2062
2063 /* JP / JNP */
2064 case 5:
2065 {
2066 Jump = State->Flags.Pf;
2067 break;
2068 }
2069
2070 /* JL / JNL */
2071 case 6:
2072 {
2073 Jump = State->Flags.Sf != State->Flags.Of;
2074 break;
2075 }
2076
2077 /* JLE / JNLE */
2078 case 7:
2079 {
2080 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2081 break;
2082 }
2083 }
2084
2085 if (Opcode & 1)
2086 {
2087 /* Invert the result */
2088 Jump = !Jump;
2089 }
2090
2091 if (Jump)
2092 {
2093 /* Move the instruction pointer */
2094 State->InstPtr.Long += Offset;
2095 }
2096
2097 /* Return success */
2098 return TRUE;
2099 }
2100
2101 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
2102 {
2103 BOOLEAN Value = FALSE;
2104 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2105 FAST486_MOD_REG_RM ModRegRm;
2106
2107 TOGGLE_ADSIZE(AddressSize);
2108
2109 /* Get the operands */
2110 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2111 {
2112 /* Exception occurred */
2113 return FALSE;
2114 }
2115
2116 /* Make sure this is the right instruction */
2117 ASSERT((Opcode & 0xF0) == 0x90);
2118
2119 switch ((Opcode & 0x0F) >> 1)
2120 {
2121 /* SETO / SETNO */
2122 case 0:
2123 {
2124 Value = State->Flags.Of;
2125 break;
2126 }
2127
2128 /* SETC / SETNC */
2129 case 1:
2130 {
2131 Value = State->Flags.Cf;
2132 break;
2133 }
2134
2135 /* SETZ / SETNZ */
2136 case 2:
2137 {
2138 Value = State->Flags.Zf;
2139 break;
2140 }
2141
2142 /* SETBE / SETNBE */
2143 case 3:
2144 {
2145 Value = State->Flags.Cf || State->Flags.Zf;
2146 break;
2147 }
2148
2149 /* SETS / SETNS */
2150 case 4:
2151 {
2152 Value = State->Flags.Sf;
2153 break;
2154 }
2155
2156 /* SETP / SETNP */
2157 case 5:
2158 {
2159 Value = State->Flags.Pf;
2160 break;
2161 }
2162
2163 /* SETL / SETNL */
2164 case 6:
2165 {
2166 Value = State->Flags.Sf != State->Flags.Of;
2167 break;
2168 }
2169
2170 /* SETLE / SETNLE */
2171 case 7:
2172 {
2173 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2174 break;
2175 }
2176 }
2177
2178 if (Opcode & 1)
2179 {
2180 /* Invert the result */
2181 Value = !Value;
2182 }
2183
2184 /* Write back the result */
2185 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
2186 }
2187
2188 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
2189 {
2190 UCHAR Source, Destination, Result;
2191 FAST486_MOD_REG_RM ModRegRm;
2192 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2193
2194 /* Make sure this is the right instruction */
2195 ASSERT(Opcode == 0xC0);
2196
2197 TOGGLE_ADSIZE(AddressSize);
2198
2199 /* Get the operands */
2200 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2201 {
2202 /* Exception occurred */
2203 return FALSE;
2204 }
2205
2206 if (!Fast486ReadModrmByteOperands(State,
2207 &ModRegRm,
2208 &Source,
2209 &Destination))
2210 {
2211 /* Exception occurred */
2212 return FALSE;
2213 }
2214
2215 /* Calculate the result */
2216 Result = Source + Destination;
2217
2218 /* Update the flags */
2219 State->Flags.Cf = (Result < Source) && (Result < Destination);
2220 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
2221 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2222 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2223 State->Flags.Zf = (Result == 0);
2224 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2225 State->Flags.Pf = Fast486CalculateParity(Result);
2226
2227 /* Write the sum to the destination */
2228 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
2229 {
2230 /* Exception occurred */
2231 return FALSE;
2232 }
2233
2234 /* Write the old value of the destination to the source */
2235 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
2236 {
2237 /* Exception occurred */
2238 return FALSE;
2239 }
2240
2241 return TRUE;
2242 }
2243
2244 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
2245 {
2246 FAST486_MOD_REG_RM ModRegRm;
2247 BOOLEAN OperandSize, AddressSize;
2248
2249 /* Make sure this is the right instruction */
2250 ASSERT(Opcode == 0xC1);
2251
2252 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2253
2254 TOGGLE_ADSIZE(AddressSize);
2255 TOGGLE_OPSIZE(OperandSize);
2256
2257 /* Get the operands */
2258 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2259 {
2260 /* Exception occurred */
2261 return FALSE;
2262 }
2263
2264 /* Check the operand size */
2265 if (OperandSize)
2266 {
2267 ULONG Source, Destination, Result;
2268
2269 if (!Fast486ReadModrmDwordOperands(State,
2270 &ModRegRm,
2271 &Source,
2272 &Destination))
2273 {
2274 /* Exception occurred */
2275 return FALSE;
2276 }
2277
2278 /* Calculate the result */
2279 Result = Source + Destination;
2280
2281 /* Update the flags */
2282 State->Flags.Cf = (Result < Source) && (Result < Destination);
2283 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2284 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2285 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2286 State->Flags.Zf = (Result == 0);
2287 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2288 State->Flags.Pf = Fast486CalculateParity(Result);
2289
2290 /* Write the old value of the destination to the source */
2291 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2292 {
2293 /* Exception occurred */
2294 return FALSE;
2295 }
2296
2297 /* Write the sum to the destination */
2298 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
2299 {
2300 /* Exception occurred */
2301 return FALSE;
2302 }
2303 }
2304 else
2305 {
2306 USHORT Source, Destination, Result;
2307
2308 if (!Fast486ReadModrmWordOperands(State,
2309 &ModRegRm,
2310 &Source,
2311 &Destination))
2312 {
2313 /* Exception occurred */
2314 return FALSE;
2315 }
2316
2317 /* Calculate the result */
2318 Result = Source + Destination;
2319
2320 /* Update the flags */
2321 State->Flags.Cf = (Result < Source) && (Result < Destination);
2322 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2323 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2324 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2325 State->Flags.Zf = (Result == 0);
2326 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2327 State->Flags.Pf = Fast486CalculateParity(Result);
2328
2329 /* Write the old value of the destination to the source */
2330 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2331 {
2332 /* Exception occurred */
2333 return FALSE;
2334 }
2335
2336 /* Write the sum to the destination */
2337 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
2338 {
2339 /* Exception occurred */
2340 return FALSE;
2341 }
2342 }
2343
2344 return TRUE;
2345 }
2346
2347 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2348 {
2349 PUCHAR Pointer;
2350
2351 NO_LOCK_PREFIX();
2352
2353 /* Get a pointer to the value */
2354 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2355
2356 /* Swap the byte order */
2357 SWAP(Pointer[0], Pointer[3]);
2358 SWAP(Pointer[1], Pointer[2]);
2359
2360 /* Return success */
2361 return TRUE;
2362 }
2363
2364 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2365 {
2366 UCHAR SecondOpcode;
2367
2368 /* Fetch the second operation code */
2369 if (!Fast486FetchByte(State, &SecondOpcode))
2370 {
2371 /* Exception occurred */
2372 return FALSE;
2373 }
2374
2375 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
2376 {
2377 /* Call the extended opcode handler */
2378 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2379 }
2380 else
2381 {
2382 /* This is not a valid opcode */
2383 Fast486Exception(State, FAST486_EXCEPTION_UD);
2384 return FALSE;
2385 }
2386 }
2387