2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
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.
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.
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.
22 /* INCLUDES *******************************************************************/
35 /* PUBLIC VARIABLES ***********************************************************/
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
40 NULL
, // TODO: OPCODE 0x00 NOT IMPLEMENTED
41 Fast486OpcodeGroup0F01
,
42 NULL
, // TODO: OPCODE 0x02 NOT IMPLEMENTED
43 NULL
, // TODO: OPCODE 0x03 NOT IMPLEMENTED
44 NULL
, // TODO: OPCODE 0x04 NOT IMPLEMENTED
45 NULL
, // TODO: OPCODE 0x05 NOT IMPLEMENTED
47 NULL
, // TODO: OPCODE 0x07 NOT IMPLEMENTED
48 NULL
, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 NULL
, // TODO: OPCODE 0x09 NOT IMPLEMENTED
51 NULL
, // Reserved (UD1)
72 Fast486ExtOpcodeStoreControlReg
,
73 Fast486ExtOpcodeStoreDebugReg
,
74 Fast486ExtOpcodeLoadControlReg
,
75 Fast486ExtOpcodeLoadDebugReg
,
76 NULL
, // TODO: OPCODE 0x24 NOT IMPLEMENTED
78 NULL
, // TODO: OPCODE 0x26 NOT IMPLEMENTED
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
,
203 Fast486ExtOpcodeBitTest
,
204 Fast486ExtOpcodeShld
,
205 Fast486ExtOpcodeShld
,
208 Fast486ExtOpcodePushGs
,
209 Fast486ExtOpcodePopGs
,
212 Fast486ExtOpcodeShrd
,
213 Fast486ExtOpcodeShrd
,
214 NULL
, // TODO: OPCODE 0xAE NOT IMPLEMENTED
215 Fast486ExtOpcodeImul
,
216 Fast486ExtOpcodeCmpXchgByte
,
217 Fast486ExtOpcodeCmpXchg
,
220 Fast486ExtOpcodeLfsLgs
,
221 Fast486ExtOpcodeLfsLgs
,
222 Fast486ExtOpcodeMovzxByte
,
223 Fast486ExtOpcodeMovzxWord
,
225 Fast486OpcodeGroup0FB9
,
226 Fast486OpcodeGroup0FBA
,
230 Fast486ExtOpcodeMovsxByte
,
231 Fast486ExtOpcodeMovsxWord
,
232 Fast486ExtOpcodeXaddByte
,
233 Fast486ExtOpcodeXadd
,
240 Fast486ExtOpcodeBswap
,
241 Fast486ExtOpcodeBswap
,
242 Fast486ExtOpcodeBswap
,
243 Fast486ExtOpcodeBswap
,
244 Fast486ExtOpcodeBswap
,
245 Fast486ExtOpcodeBswap
,
246 Fast486ExtOpcodeBswap
,
247 Fast486ExtOpcodeBswap
,
298 /* PUBLIC FUNCTIONS ***********************************************************/
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
304 /* The current privilege level must be zero */
305 if (Fast486GetCurrentPrivLevel(State
) != 0)
307 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
311 /* Clear the task switch bit */
312 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
317 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
319 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
320 FAST486_MOD_REG_RM ModRegRm
;
323 TOGGLE_ADSIZE(AddressSize
);
325 /* Get the operands */
326 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
328 /* Exception occurred */
332 /* The current privilege level must be zero */
333 if (Fast486GetCurrentPrivLevel(State
) != 0)
335 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
339 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
341 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
342 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
346 if (ModRegRm
.Register
!= 0)
348 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
352 /* Store the value of the control register */
353 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
359 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
361 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
362 FAST486_MOD_REG_RM ModRegRm
;
365 TOGGLE_ADSIZE(AddressSize
);
367 /* Get the operands */
368 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
370 /* Exception occurred */
374 /* The current privilege level must be zero */
375 if (Fast486GetCurrentPrivLevel(State
) != 0)
377 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
381 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
383 /* DR6 and DR7 are aliases to DR4 and DR5 */
384 ModRegRm
.Register
-= 2;
387 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
389 /* Disallow access to debug registers */
390 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
394 /* Store the value of the debug register */
395 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
401 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
404 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
405 FAST486_MOD_REG_RM ModRegRm
;
408 TOGGLE_ADSIZE(AddressSize
);
410 /* Get the operands */
411 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
413 /* Exception occurred */
417 /* The current privilege level must be zero */
418 if (Fast486GetCurrentPrivLevel(State
) != 0)
420 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
424 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
426 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
427 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
431 if (ModRegRm
.Register
!= 0)
433 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
438 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
440 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
444 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
445 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
448 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
453 /* Load a value to the control register */
454 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
460 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
462 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
463 FAST486_MOD_REG_RM ModRegRm
;
466 TOGGLE_ADSIZE(AddressSize
);
468 /* Get the operands */
469 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
471 /* Exception occurred */
475 /* The current privilege level must be zero */
476 if (Fast486GetCurrentPrivLevel(State
) != 0)
478 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
482 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
484 /* DR6 and DR7 are aliases to DR4 and DR5 */
485 ModRegRm
.Register
-= 2;
488 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
490 /* Disallow access to debug registers */
491 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
495 /* Load a value to the debug register */
496 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
498 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
500 /* The reserved bits are 1 */
501 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
503 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
505 /* The reserved bits are 0 */
506 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
513 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
515 /* Call the internal API */
516 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
519 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
523 if (!Fast486StackPop(State
, &NewSelector
))
525 /* Exception occurred */
529 /* Call the internal API */
530 return Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
533 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
535 BOOLEAN OperandSize
, AddressSize
;
536 FAST486_MOD_REG_RM ModRegRm
;
540 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
541 TOGGLE_OPSIZE(OperandSize
);
542 TOGGLE_ADSIZE(AddressSize
);
544 /* Get the number of bits */
545 if (OperandSize
) DataSize
= 32;
548 /* Get the operands */
549 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
551 /* Exception occurred */
555 /* Get the bit number */
556 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
557 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
562 * For memory operands, add the bit offset divided by
563 * the data size to the address
565 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
568 /* Normalize the bit number */
569 BitNumber
&= (1 << DataSize
) - 1;
576 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
578 /* Exception occurred */
582 /* Set CF to the bit value */
583 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
590 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
592 /* Exception occurred */
596 /* Set CF to the bit value */
597 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
604 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
606 BOOLEAN OperandSize
, AddressSize
;
607 FAST486_MOD_REG_RM ModRegRm
;
610 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
611 TOGGLE_OPSIZE(OperandSize
);
612 TOGGLE_ADSIZE(AddressSize
);
614 /* Make sure this is the right instruction */
615 ASSERT((Opcode
& 0xFE) == 0xA4);
617 /* Get the operands */
618 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
620 /* Exception occurred */
626 /* Fetch the count */
627 if (!Fast486FetchByte(State
, &Count
))
629 /* Exception occurred */
635 /* The count is in CL */
636 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
639 /* Normalize the count */
640 if (OperandSize
) Count
&= 0x1F;
643 /* Do nothing if the count is zero */
644 if (Count
== 0) return TRUE
;
648 ULONG Source
, Destination
, Result
;
650 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
652 /* Exception occurred */
656 /* Calculate the result */
657 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
660 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
661 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
662 != (Destination
& SIGN_FLAG_LONG
);
663 State
->Flags
.Zf
= (Result
== 0);
664 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
665 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
667 /* Write back the result */
668 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
672 USHORT Source
, Destination
, Result
;
674 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
676 /* Exception occurred */
680 /* Calculate the result */
681 Result
= (Destination
<< Count
) | (Source
>> (16 - Count
));
684 State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
685 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
686 != (Destination
& SIGN_FLAG_WORD
);
687 State
->Flags
.Zf
= (Result
== 0);
688 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
689 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
691 /* Write back the result */
692 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
696 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
698 /* Call the internal API */
699 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
702 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
706 if (!Fast486StackPop(State
, &NewSelector
))
708 /* Exception occurred */
712 /* Call the internal API */
713 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
716 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
718 BOOLEAN OperandSize
, AddressSize
;
719 FAST486_MOD_REG_RM ModRegRm
;
723 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
724 TOGGLE_OPSIZE(OperandSize
);
725 TOGGLE_ADSIZE(AddressSize
);
727 /* Get the number of bits */
728 if (OperandSize
) DataSize
= 32;
731 /* Get the operands */
732 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
734 /* Exception occurred */
738 /* Get the bit number */
739 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
740 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
745 * For memory operands, add the bit offset divided by
746 * the data size to the address
748 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
751 /* Normalize the bit number */
752 BitNumber
&= (1 << DataSize
) - 1;
759 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
761 /* Exception occurred */
765 /* Set CF to the bit value */
766 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
769 Value
|= 1 << BitNumber
;
771 /* Write back the result */
772 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
774 /* Exception occurred */
783 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
785 /* Exception occurred */
789 /* Set CF to the bit value */
790 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
793 Value
|= 1 << BitNumber
;
795 /* Write back the result */
796 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
798 /* Exception occurred */
807 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
809 BOOLEAN OperandSize
, AddressSize
;
810 FAST486_MOD_REG_RM ModRegRm
;
813 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
814 TOGGLE_OPSIZE(OperandSize
);
815 TOGGLE_ADSIZE(AddressSize
);
817 /* Make sure this is the right instruction */
818 ASSERT((Opcode
& 0xFE) == 0xAC);
820 /* Get the operands */
821 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
823 /* Exception occurred */
829 /* Fetch the count */
830 if (!Fast486FetchByte(State
, &Count
))
832 /* Exception occurred */
838 /* The count is in CL */
839 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
842 /* Normalize the count */
843 if (OperandSize
) Count
&= 0x1F;
846 /* Do nothing if the count is zero */
847 if (Count
== 0) return TRUE
;
851 ULONG Source
, Destination
, Result
;
853 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
855 /* Exception occurred */
859 /* Calculate the result */
860 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
863 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
864 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
865 != (Destination
& SIGN_FLAG_LONG
);
866 State
->Flags
.Zf
= (Result
== 0);
867 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
868 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
870 /* Write back the result */
871 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
875 USHORT Source
, Destination
, Result
;
877 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
879 /* Exception occurred */
883 /* Calculate the result */
884 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
887 State
->Flags
.Cf
= (Result
>> (Count
- 1)) & 1;
888 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
889 != (Destination
& SIGN_FLAG_WORD
);
890 State
->Flags
.Zf
= (Result
== 0);
891 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
892 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
894 /* Write back the result */
895 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
899 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
901 BOOLEAN OperandSize
, AddressSize
;
902 FAST486_MOD_REG_RM ModRegRm
;
904 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
906 TOGGLE_OPSIZE(OperandSize
);
907 TOGGLE_ADSIZE(AddressSize
);
909 /* Get the operands */
910 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
912 /* Exception occurred */
918 LONG Source
, Destination
;
921 /* Read the operands */
922 if (!Fast486ReadModrmDwordOperands(State
,
924 (PULONG
)&Destination
,
927 /* Exception occurred */
931 /* Calculate the result */
932 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
934 /* Update the flags */
935 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
937 /* Write back the result */
938 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
942 SHORT Source
, Destination
;
945 /* Read the operands */
946 if (!Fast486ReadModrmWordOperands(State
,
948 (PUSHORT
)&Destination
,
951 /* Exception occurred */
955 /* Calculate the result */
956 Result
= (LONG
)Source
* (LONG
)Destination
;
958 /* Update the flags */
959 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
961 /* Write back the result */
962 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
966 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
968 FAST486_MOD_REG_RM ModRegRm
;
969 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
970 UCHAR Source
, Destination
, Result
;
971 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
973 TOGGLE_ADSIZE(AddressSize
);
975 /* Get the operands */
976 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
978 /* Exception occurred */
982 /* Read the operands */
983 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
985 /* Exception occurred */
989 /* Compare AL with the destination */
990 Result
= Accumulator
- Destination
;
992 /* Update the flags */
993 State
->Flags
.Cf
= (Accumulator
< Destination
);
994 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
995 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
996 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
997 State
->Flags
.Zf
= (Result
== 0);
998 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
999 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1001 if (State
->Flags
.Zf
)
1003 /* Load the source operand into the destination */
1004 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1008 /* Load the destination into AL */
1009 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1012 /* Return success */
1016 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1018 FAST486_MOD_REG_RM ModRegRm
;
1019 BOOLEAN OperandSize
, AddressSize
;
1021 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1023 TOGGLE_OPSIZE(OperandSize
);
1024 TOGGLE_ADSIZE(AddressSize
);
1026 /* Get the operands */
1027 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1029 /* Exception occurred */
1035 ULONG Source
, Destination
, Result
;
1036 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1038 /* Read the operands */
1039 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1041 /* Exception occurred */
1045 /* Compare EAX with the destination */
1046 Result
= Accumulator
- Destination
;
1048 /* Update the flags */
1049 State
->Flags
.Cf
= (Accumulator
< Destination
);
1050 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1051 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1052 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1053 State
->Flags
.Zf
= (Result
== 0);
1054 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1055 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1057 if (State
->Flags
.Zf
)
1059 /* Load the source operand into the destination */
1060 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1064 /* Load the destination into EAX */
1065 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1070 USHORT Source
, Destination
, Result
;
1071 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1073 /* Read the operands */
1074 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1076 /* Exception occurred */
1080 /* Compare AX with the destination */
1081 Result
= Accumulator
- Destination
;
1083 /* Update the flags */
1084 State
->Flags
.Cf
= (Accumulator
< Destination
);
1085 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1086 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1087 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1088 State
->Flags
.Zf
= (Result
== 0);
1089 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1090 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1092 if (State
->Flags
.Zf
)
1094 /* Load the source operand into the destination */
1095 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1099 /* Load the destination into AX */
1100 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1104 /* Return success */
1108 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1110 UCHAR FarPointer
[6];
1111 BOOLEAN OperandSize
, AddressSize
;
1112 FAST486_MOD_REG_RM ModRegRm
;
1114 /* Make sure this is the right instruction */
1115 ASSERT(Opcode
== 0xB2);
1117 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1119 TOGGLE_OPSIZE(OperandSize
);
1120 TOGGLE_ADSIZE(AddressSize
);
1122 /* Get the operands */
1123 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1125 /* Exception occurred */
1129 if (!ModRegRm
.Memory
)
1132 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1136 if (!Fast486ReadMemory(State
,
1137 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1138 ? State
->SegmentOverride
: FAST486_REG_DS
,
1139 ModRegRm
.MemoryAddress
,
1142 OperandSize
? 6 : 4))
1144 /* Exception occurred */
1150 ULONG Offset
= *((PULONG
)FarPointer
);
1151 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1153 /* Set the register to the offset */
1154 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1156 /* Load the segment */
1157 return Fast486LoadSegment(State
,
1163 USHORT Offset
= *((PUSHORT
)FarPointer
);
1164 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1166 /* Set the register to the offset */
1167 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1169 /* Load the segment */
1170 return Fast486LoadSegment(State
,
1176 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1178 BOOLEAN OperandSize
, AddressSize
;
1179 FAST486_MOD_REG_RM ModRegRm
;
1183 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1184 TOGGLE_OPSIZE(OperandSize
);
1185 TOGGLE_ADSIZE(AddressSize
);
1187 /* Get the number of bits */
1188 if (OperandSize
) DataSize
= 32;
1191 /* Get the operands */
1192 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1194 /* Exception occurred */
1198 /* Get the bit number */
1199 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1200 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1202 if (ModRegRm
.Memory
)
1205 * For memory operands, add the bit offset divided by
1206 * the data size to the address
1208 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1211 /* Normalize the bit number */
1212 BitNumber
&= (1 << DataSize
) - 1;
1218 /* Read the value */
1219 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1221 /* Exception occurred */
1225 /* Set CF to the bit value */
1226 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1229 Value
&= ~(1 << BitNumber
);
1231 /* Write back the result */
1232 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1234 /* Exception occurred */
1240 USHORT Dummy
, Value
;
1242 /* Read the value */
1243 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1245 /* Exception occurred */
1249 /* Set CF to the bit value */
1250 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1253 Value
&= ~(1 << BitNumber
);
1255 /* Write back the result */
1256 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1258 /* Exception occurred */
1263 /* Return success */
1267 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1269 UCHAR FarPointer
[6];
1270 BOOLEAN OperandSize
, AddressSize
;
1271 FAST486_MOD_REG_RM ModRegRm
;
1273 /* Make sure this is the right instruction */
1274 ASSERT((Opcode
& 0xFE) == 0xB4);
1276 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1278 TOGGLE_OPSIZE(OperandSize
);
1279 TOGGLE_ADSIZE(AddressSize
);
1281 /* Get the operands */
1282 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1284 /* Exception occurred */
1288 if (!ModRegRm
.Memory
)
1291 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1295 if (!Fast486ReadMemory(State
,
1296 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1297 ? State
->SegmentOverride
: FAST486_REG_DS
,
1298 ModRegRm
.MemoryAddress
,
1301 OperandSize
? 6 : 4))
1303 /* Exception occurred */
1309 ULONG Offset
= *((PULONG
)FarPointer
);
1310 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1312 /* Set the register to the offset */
1313 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1315 /* Load the segment */
1316 return Fast486LoadSegment(State
,
1318 ? FAST486_REG_FS
: FAST486_REG_GS
,
1323 USHORT Offset
= *((PUSHORT
)FarPointer
);
1324 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1326 /* Set the register to the offset */
1327 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1329 /* Load the segment */
1330 return Fast486LoadSegment(State
,
1332 ? FAST486_REG_FS
: FAST486_REG_GS
,
1337 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1340 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1341 FAST486_MOD_REG_RM ModRegRm
;
1343 TOGGLE_ADSIZE(AddressSize
);
1345 /* Make sure this is the right instruction */
1346 ASSERT(Opcode
== 0xB6);
1348 /* Get the operands */
1349 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1351 /* Exception occurred */
1355 /* Read the operands */
1356 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1358 /* Exception occurred */
1362 /* Write back the zero-extended value */
1363 return Fast486WriteModrmDwordOperands(State
,
1369 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1371 USHORT Dummy
, Value
;
1372 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1373 FAST486_MOD_REG_RM ModRegRm
;
1375 TOGGLE_ADSIZE(AddressSize
);
1377 /* Make sure this is the right instruction */
1378 ASSERT(Opcode
== 0xB7);
1380 /* Get the operands */
1381 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1383 /* Exception occurred */
1387 /* Read the operands */
1388 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1390 /* Exception occurred */
1394 /* Write back the zero-extended value */
1395 return Fast486WriteModrmDwordOperands(State
,
1401 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1403 BOOLEAN OperandSize
, AddressSize
;
1404 FAST486_MOD_REG_RM ModRegRm
;
1408 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1409 TOGGLE_OPSIZE(OperandSize
);
1410 TOGGLE_ADSIZE(AddressSize
);
1412 /* Get the number of bits */
1413 if (OperandSize
) DataSize
= 32;
1416 /* Get the operands */
1417 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1419 /* Exception occurred */
1423 /* Get the bit number */
1424 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1425 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1427 if (ModRegRm
.Memory
)
1430 * For memory operands, add the bit offset divided by
1431 * the data size to the address
1433 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1436 /* Normalize the bit number */
1437 BitNumber
&= (1 << DataSize
) - 1;
1443 /* Read the value */
1444 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1446 /* Exception occurred */
1450 /* Set CF to the bit value */
1451 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1453 /* Toggle the bit */
1454 Value
^= 1 << BitNumber
;
1456 /* Write back the result */
1457 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1459 /* Exception occurred */
1465 USHORT Dummy
, Value
;
1467 /* Read the value */
1468 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1470 /* Exception occurred */
1474 /* Set CF to the bit value */
1475 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1477 /* Toggle the bit */
1478 Value
^= 1 << BitNumber
;
1480 /* Write back the result */
1481 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1483 /* Exception occurred */
1488 /* Return success */
1492 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1495 ULONG Dummy
= 0, Value
= 0;
1496 BOOLEAN OperandSize
, AddressSize
;
1497 FAST486_MOD_REG_RM ModRegRm
;
1501 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1502 TOGGLE_OPSIZE(OperandSize
);
1503 TOGGLE_ADSIZE(AddressSize
);
1505 /* Make sure this is the right instruction */
1506 ASSERT(Opcode
== 0xBC);
1508 /* Get the number of bits */
1509 if (OperandSize
) DataSize
= 32;
1512 /* Get the operands */
1513 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1515 /* Exception occurred */
1519 /* Read the value */
1522 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1524 /* Exception occurred */
1530 if (!Fast486ReadModrmWordOperands(State
,
1535 /* Exception occurred */
1541 State
->Flags
.Zf
= FALSE
;
1543 for (i
= 0; i
< DataSize
; i
++)
1545 if(Value
& (1 << i
))
1548 State
->Flags
.Zf
= TRUE
;
1550 /* Save the bit number */
1558 if (State
->Flags
.Zf
)
1560 /* Write back the result */
1563 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1565 /* Exception occurred */
1571 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1573 /* Exception occurred */
1582 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1585 ULONG Dummy
= 0, Value
= 0;
1586 BOOLEAN OperandSize
, AddressSize
;
1587 FAST486_MOD_REG_RM ModRegRm
;
1591 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1592 TOGGLE_OPSIZE(OperandSize
);
1593 TOGGLE_ADSIZE(AddressSize
);
1595 /* Make sure this is the right instruction */
1596 ASSERT(Opcode
== 0xBD);
1598 /* Get the number of bits */
1599 if (OperandSize
) DataSize
= 32;
1602 /* Get the operands */
1603 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1605 /* Exception occurred */
1609 /* Read the value */
1612 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1614 /* Exception occurred */
1620 if (!Fast486ReadModrmWordOperands(State
,
1625 /* Exception occurred */
1631 State
->Flags
.Zf
= FALSE
;
1633 for (i
= DataSize
- 1; i
>= 0; i
--)
1635 if(Value
& (1 << i
))
1638 State
->Flags
.Zf
= TRUE
;
1640 /* Save the bit number */
1648 if (State
->Flags
.Zf
)
1650 /* Write back the result */
1653 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1655 /* Exception occurred */
1661 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1663 /* Exception occurred */
1672 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1676 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1677 FAST486_MOD_REG_RM ModRegRm
;
1679 TOGGLE_ADSIZE(AddressSize
);
1681 /* Make sure this is the right instruction */
1682 ASSERT(Opcode
== 0xBE);
1684 /* Get the operands */
1685 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1687 /* Exception occurred */
1691 /* Read the operands */
1692 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, (PUCHAR
)&Value
))
1694 /* Exception occurred */
1698 /* Write back the sign-extended value */
1699 return Fast486WriteModrmDwordOperands(State
,
1702 (ULONG
)((LONG
)Value
));
1705 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1709 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1710 FAST486_MOD_REG_RM ModRegRm
;
1712 TOGGLE_ADSIZE(AddressSize
);
1714 /* Make sure this is the right instruction */
1715 ASSERT(Opcode
== 0xBF);
1717 /* Get the operands */
1718 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1720 /* Exception occurred */
1724 /* Read the operands */
1725 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, (PUSHORT
)&Value
))
1727 /* Exception occurred */
1731 /* Write back the sign-extended value */
1732 return Fast486WriteModrmDwordOperands(State
,
1735 (ULONG
)((LONG
)Value
));
1738 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1740 BOOLEAN Jump
= FALSE
;
1742 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1744 TOGGLE_OPSIZE(Size
);
1747 /* Make sure this is the right instruction */
1748 ASSERT((Opcode
& 0xF0) == 0x80);
1750 /* Fetch the offset */
1753 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1755 /* Exception occurred */
1763 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1765 /* Exception occurred */
1770 Offset
= (LONG
)Value
;
1773 switch ((Opcode
& 0x0F) >> 1)
1778 Jump
= State
->Flags
.Of
;
1785 Jump
= State
->Flags
.Cf
;
1792 Jump
= State
->Flags
.Zf
;
1799 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1806 Jump
= State
->Flags
.Sf
;
1813 Jump
= State
->Flags
.Pf
;
1820 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1827 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1834 /* Invert the result */
1840 /* Move the instruction pointer */
1841 State
->InstPtr
.Long
+= Offset
;
1844 /* Return success */
1848 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1850 BOOLEAN Value
= FALSE
;
1851 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1852 FAST486_MOD_REG_RM ModRegRm
;
1854 TOGGLE_ADSIZE(AddressSize
);
1856 /* Get the operands */
1857 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1859 /* Exception occurred */
1863 /* Make sure this is the right instruction */
1864 ASSERT((Opcode
& 0xF0) == 0x90);
1866 switch ((Opcode
& 0x0F) >> 1)
1871 Value
= State
->Flags
.Of
;
1878 Value
= State
->Flags
.Cf
;
1885 Value
= State
->Flags
.Zf
;
1889 /* SETBE / SETNBE */
1892 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1899 Value
= State
->Flags
.Sf
;
1906 Value
= State
->Flags
.Pf
;
1913 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1917 /* SETLE / SETNLE */
1920 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1927 /* Invert the result */
1931 /* Write back the result */
1932 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1935 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
1937 UCHAR Source
, Destination
, Result
;
1938 FAST486_MOD_REG_RM ModRegRm
;
1939 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1941 /* Make sure this is the right instruction */
1942 ASSERT(Opcode
== 0xC0);
1944 TOGGLE_ADSIZE(AddressSize
);
1946 /* Get the operands */
1947 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1949 /* Exception occurred */
1953 if (!Fast486ReadModrmByteOperands(State
,
1958 /* Exception occurred */
1962 /* Calculate the result */
1963 Result
= Source
+ Destination
;
1965 /* Update the flags */
1966 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1967 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
1968 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1969 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1970 State
->Flags
.Zf
= (Result
== 0);
1971 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1972 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1974 /* Write the sum to the destination */
1975 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
1977 /* Exception occurred */
1981 /* Write the old value of the destination to the source */
1982 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
1984 /* Exception occurred */
1991 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
1993 FAST486_MOD_REG_RM ModRegRm
;
1994 BOOLEAN OperandSize
, AddressSize
;
1996 /* Make sure this is the right instruction */
1997 ASSERT(Opcode
== 0xC1);
1999 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2001 TOGGLE_ADSIZE(AddressSize
);
2002 TOGGLE_OPSIZE(OperandSize
);
2004 /* Get the operands */
2005 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2007 /* Exception occurred */
2011 /* Check the operand size */
2014 ULONG Source
, Destination
, Result
;
2016 if (!Fast486ReadModrmDwordOperands(State
,
2021 /* Exception occurred */
2025 /* Calculate the result */
2026 Result
= Source
+ Destination
;
2028 /* Update the flags */
2029 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2030 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2031 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2032 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2033 State
->Flags
.Zf
= (Result
== 0);
2034 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2035 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2037 /* Write the sum to the destination */
2038 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
2040 /* Exception occurred */
2044 /* Write the old value of the destination to the source */
2045 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2047 /* Exception occurred */
2053 USHORT Source
, Destination
, Result
;
2055 if (!Fast486ReadModrmWordOperands(State
,
2060 /* Exception occurred */
2064 /* Calculate the result */
2065 Result
= Source
+ Destination
;
2067 /* Update the flags */
2068 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2069 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2070 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2071 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2072 State
->Flags
.Zf
= (Result
== 0);
2073 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2074 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2076 /* Write the sum to the destination */
2077 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2079 /* Exception occurred */
2083 /* Write the old value of the destination to the source */
2084 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2086 /* Exception occurred */
2094 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2100 /* Get a pointer to the value */
2101 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2103 /* Swap the byte order */
2104 SWAP(Pointer
[0], Pointer
[3]);
2105 SWAP(Pointer
[1], Pointer
[2]);
2107 /* Return success */
2111 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2115 /* Fetch the second operation code */
2116 if (!Fast486FetchByte(State
, &SecondOpcode
))
2118 /* Exception occurred */
2122 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
2124 /* Call the extended opcode handler */
2125 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
2129 /* This is not a valid opcode */
2130 Fast486Exception(State
, FAST486_EXCEPTION_UD
);