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 /* Get the operands */
907 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
909 /* Exception occurred */
915 LONG Source
, Destination
;
918 /* Read the operands */
919 if (!Fast486ReadModrmDwordOperands(State
,
921 (PULONG
)&Destination
,
924 /* Exception occurred */
928 /* Calculate the result */
929 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
931 /* Update the flags */
932 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
934 /* Write back the result */
935 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
939 SHORT Source
, Destination
;
942 /* Read the operands */
943 if (!Fast486ReadModrmWordOperands(State
,
945 (PUSHORT
)&Destination
,
948 /* Exception occurred */
952 /* Calculate the result */
953 Result
= (LONG
)Source
* (LONG
)Destination
;
955 /* Update the flags */
956 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
958 /* Write back the result */
959 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
963 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
965 FAST486_MOD_REG_RM ModRegRm
;
966 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
967 UCHAR Source
, Destination
, Result
;
968 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
970 TOGGLE_ADSIZE(AddressSize
);
972 /* Get the operands */
973 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
975 /* Exception occurred */
979 /* Read the operands */
980 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
982 /* Exception occurred */
986 /* Compare AL with the destination */
987 Result
= Accumulator
- Destination
;
989 /* Update the flags */
990 State
->Flags
.Cf
= (Accumulator
< Destination
);
991 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
992 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
993 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
994 State
->Flags
.Zf
= (Result
== 0);
995 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
996 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1000 /* Load the source operand into the destination */
1001 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1005 /* Load the destination into AL */
1006 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1009 /* Return success */
1013 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1015 FAST486_MOD_REG_RM ModRegRm
;
1016 BOOLEAN OperandSize
, AddressSize
;
1018 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1020 TOGGLE_OPSIZE(OperandSize
);
1021 TOGGLE_ADSIZE(AddressSize
);
1023 /* Get the operands */
1024 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1026 /* Exception occurred */
1032 ULONG Source
, Destination
, Result
;
1033 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1035 /* Read the operands */
1036 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1038 /* Exception occurred */
1042 /* Compare EAX with the destination */
1043 Result
= Accumulator
- Destination
;
1045 /* Update the flags */
1046 State
->Flags
.Cf
= (Accumulator
< Destination
);
1047 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1048 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1049 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1050 State
->Flags
.Zf
= (Result
== 0);
1051 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1052 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1054 if (State
->Flags
.Zf
)
1056 /* Load the source operand into the destination */
1057 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1061 /* Load the destination into EAX */
1062 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1067 USHORT Source
, Destination
, Result
;
1068 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1070 /* Read the operands */
1071 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1073 /* Exception occurred */
1077 /* Compare AX with the destination */
1078 Result
= Accumulator
- Destination
;
1080 /* Update the flags */
1081 State
->Flags
.Cf
= (Accumulator
< Destination
);
1082 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1083 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1084 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1085 State
->Flags
.Zf
= (Result
== 0);
1086 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1087 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1089 if (State
->Flags
.Zf
)
1091 /* Load the source operand into the destination */
1092 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1096 /* Load the destination into AX */
1097 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1101 /* Return success */
1105 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1107 UCHAR FarPointer
[6];
1108 BOOLEAN OperandSize
, AddressSize
;
1109 FAST486_MOD_REG_RM ModRegRm
;
1111 /* Make sure this is the right instruction */
1112 ASSERT(Opcode
== 0xB2);
1114 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1116 TOGGLE_OPSIZE(OperandSize
);
1117 TOGGLE_ADSIZE(AddressSize
);
1119 /* Get the operands */
1120 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1122 /* Exception occurred */
1126 if (!ModRegRm
.Memory
)
1129 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1133 if (!Fast486ReadMemory(State
,
1134 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1135 ? State
->SegmentOverride
: FAST486_REG_DS
,
1136 ModRegRm
.MemoryAddress
,
1139 OperandSize
? 6 : 4))
1141 /* Exception occurred */
1147 ULONG Offset
= *((PULONG
)FarPointer
);
1148 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1150 /* Set the register to the offset */
1151 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1153 /* Load the segment */
1154 return Fast486LoadSegment(State
,
1160 USHORT Offset
= *((PUSHORT
)FarPointer
);
1161 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1163 /* Set the register to the offset */
1164 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1166 /* Load the segment */
1167 return Fast486LoadSegment(State
,
1173 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1175 BOOLEAN OperandSize
, AddressSize
;
1176 FAST486_MOD_REG_RM ModRegRm
;
1180 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1181 TOGGLE_OPSIZE(OperandSize
);
1182 TOGGLE_ADSIZE(AddressSize
);
1184 /* Get the number of bits */
1185 if (OperandSize
) DataSize
= 32;
1188 /* Get the operands */
1189 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1191 /* Exception occurred */
1195 /* Get the bit number */
1196 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1197 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1199 if (ModRegRm
.Memory
)
1202 * For memory operands, add the bit offset divided by
1203 * the data size to the address
1205 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1208 /* Normalize the bit number */
1209 BitNumber
&= (1 << DataSize
) - 1;
1215 /* Read the value */
1216 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1218 /* Exception occurred */
1222 /* Set CF to the bit value */
1223 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1226 Value
&= ~(1 << BitNumber
);
1228 /* Write back the result */
1229 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1231 /* Exception occurred */
1237 USHORT Dummy
, Value
;
1239 /* Read the value */
1240 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1242 /* Exception occurred */
1246 /* Set CF to the bit value */
1247 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1250 Value
&= ~(1 << BitNumber
);
1252 /* Write back the result */
1253 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1255 /* Exception occurred */
1260 /* Return success */
1264 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1266 UCHAR FarPointer
[6];
1267 BOOLEAN OperandSize
, AddressSize
;
1268 FAST486_MOD_REG_RM ModRegRm
;
1270 /* Make sure this is the right instruction */
1271 ASSERT((Opcode
& 0xFE) == 0xB4);
1273 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1275 TOGGLE_OPSIZE(OperandSize
);
1276 TOGGLE_ADSIZE(AddressSize
);
1278 /* Get the operands */
1279 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1281 /* Exception occurred */
1285 if (!ModRegRm
.Memory
)
1288 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1292 if (!Fast486ReadMemory(State
,
1293 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1294 ? State
->SegmentOverride
: FAST486_REG_DS
,
1295 ModRegRm
.MemoryAddress
,
1298 OperandSize
? 6 : 4))
1300 /* Exception occurred */
1306 ULONG Offset
= *((PULONG
)FarPointer
);
1307 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1309 /* Set the register to the offset */
1310 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1312 /* Load the segment */
1313 return Fast486LoadSegment(State
,
1315 ? FAST486_REG_FS
: FAST486_REG_GS
,
1320 USHORT Offset
= *((PUSHORT
)FarPointer
);
1321 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1323 /* Set the register to the offset */
1324 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1326 /* Load the segment */
1327 return Fast486LoadSegment(State
,
1329 ? FAST486_REG_FS
: FAST486_REG_GS
,
1334 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1337 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1338 FAST486_MOD_REG_RM ModRegRm
;
1340 TOGGLE_ADSIZE(AddressSize
);
1342 /* Make sure this is the right instruction */
1343 ASSERT(Opcode
== 0xB6);
1345 /* Get the operands */
1346 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1348 /* Exception occurred */
1352 /* Read the operands */
1353 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1355 /* Exception occurred */
1359 /* Write back the zero-extended value */
1360 return Fast486WriteModrmDwordOperands(State
,
1366 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1368 USHORT Dummy
, Value
;
1369 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1370 FAST486_MOD_REG_RM ModRegRm
;
1372 TOGGLE_ADSIZE(AddressSize
);
1374 /* Make sure this is the right instruction */
1375 ASSERT(Opcode
== 0xB7);
1377 /* Get the operands */
1378 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1380 /* Exception occurred */
1384 /* Read the operands */
1385 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1387 /* Exception occurred */
1391 /* Write back the zero-extended value */
1392 return Fast486WriteModrmDwordOperands(State
,
1398 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1400 BOOLEAN OperandSize
, AddressSize
;
1401 FAST486_MOD_REG_RM ModRegRm
;
1405 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1406 TOGGLE_OPSIZE(OperandSize
);
1407 TOGGLE_ADSIZE(AddressSize
);
1409 /* Get the number of bits */
1410 if (OperandSize
) DataSize
= 32;
1413 /* Get the operands */
1414 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1416 /* Exception occurred */
1420 /* Get the bit number */
1421 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1422 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1424 if (ModRegRm
.Memory
)
1427 * For memory operands, add the bit offset divided by
1428 * the data size to the address
1430 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1433 /* Normalize the bit number */
1434 BitNumber
&= (1 << DataSize
) - 1;
1440 /* Read the value */
1441 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1443 /* Exception occurred */
1447 /* Set CF to the bit value */
1448 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1450 /* Toggle the bit */
1451 Value
^= 1 << BitNumber
;
1453 /* Write back the result */
1454 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1456 /* Exception occurred */
1462 USHORT Dummy
, Value
;
1464 /* Read the value */
1465 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1467 /* Exception occurred */
1471 /* Set CF to the bit value */
1472 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1474 /* Toggle the bit */
1475 Value
^= 1 << BitNumber
;
1477 /* Write back the result */
1478 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1480 /* Exception occurred */
1485 /* Return success */
1489 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1492 ULONG Dummy
= 0, Value
= 0;
1493 BOOLEAN OperandSize
, AddressSize
;
1494 FAST486_MOD_REG_RM ModRegRm
;
1498 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1499 TOGGLE_OPSIZE(OperandSize
);
1500 TOGGLE_ADSIZE(AddressSize
);
1502 /* Make sure this is the right instruction */
1503 ASSERT(Opcode
== 0xBC);
1505 /* Get the number of bits */
1506 if (OperandSize
) DataSize
= 32;
1509 /* Get the operands */
1510 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1512 /* Exception occurred */
1516 /* Read the value */
1519 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1521 /* Exception occurred */
1527 if (!Fast486ReadModrmWordOperands(State
,
1532 /* Exception occurred */
1538 State
->Flags
.Zf
= FALSE
;
1540 for (i
= 0; i
< DataSize
; i
++)
1542 if(Value
& (1 << i
))
1545 State
->Flags
.Zf
= TRUE
;
1547 /* Save the bit number */
1555 if (State
->Flags
.Zf
)
1557 /* Write back the result */
1560 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1562 /* Exception occurred */
1568 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1570 /* Exception occurred */
1579 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1582 ULONG Dummy
= 0, Value
= 0;
1583 BOOLEAN OperandSize
, AddressSize
;
1584 FAST486_MOD_REG_RM ModRegRm
;
1588 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1589 TOGGLE_OPSIZE(OperandSize
);
1590 TOGGLE_ADSIZE(AddressSize
);
1592 /* Make sure this is the right instruction */
1593 ASSERT(Opcode
== 0xBD);
1595 /* Get the number of bits */
1596 if (OperandSize
) DataSize
= 32;
1599 /* Get the operands */
1600 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1602 /* Exception occurred */
1606 /* Read the value */
1609 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1611 /* Exception occurred */
1617 if (!Fast486ReadModrmWordOperands(State
,
1622 /* Exception occurred */
1628 State
->Flags
.Zf
= FALSE
;
1630 for (i
= DataSize
- 1; i
>= 0; i
--)
1632 if(Value
& (1 << i
))
1635 State
->Flags
.Zf
= TRUE
;
1637 /* Save the bit number */
1645 if (State
->Flags
.Zf
)
1647 /* Write back the result */
1650 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1652 /* Exception occurred */
1658 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1660 /* Exception occurred */
1669 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1673 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1674 FAST486_MOD_REG_RM ModRegRm
;
1676 TOGGLE_ADSIZE(AddressSize
);
1678 /* Make sure this is the right instruction */
1679 ASSERT(Opcode
== 0xBE);
1681 /* Get the operands */
1682 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1684 /* Exception occurred */
1688 /* Read the operands */
1689 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, (PUCHAR
)&Value
))
1691 /* Exception occurred */
1695 /* Write back the sign-extended value */
1696 return Fast486WriteModrmDwordOperands(State
,
1699 (ULONG
)((LONG
)Value
));
1702 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1706 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1707 FAST486_MOD_REG_RM ModRegRm
;
1709 TOGGLE_ADSIZE(AddressSize
);
1711 /* Make sure this is the right instruction */
1712 ASSERT(Opcode
== 0xBF);
1714 /* Get the operands */
1715 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1717 /* Exception occurred */
1721 /* Read the operands */
1722 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, (PUSHORT
)&Value
))
1724 /* Exception occurred */
1728 /* Write back the sign-extended value */
1729 return Fast486WriteModrmDwordOperands(State
,
1732 (ULONG
)((LONG
)Value
));
1735 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1737 BOOLEAN Jump
= FALSE
;
1739 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1741 TOGGLE_OPSIZE(Size
);
1744 /* Make sure this is the right instruction */
1745 ASSERT((Opcode
& 0xF0) == 0x80);
1747 /* Fetch the offset */
1750 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1752 /* Exception occurred */
1760 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1762 /* Exception occurred */
1767 Offset
= (LONG
)Value
;
1770 switch ((Opcode
& 0x0F) >> 1)
1775 Jump
= State
->Flags
.Of
;
1782 Jump
= State
->Flags
.Cf
;
1789 Jump
= State
->Flags
.Zf
;
1796 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1803 Jump
= State
->Flags
.Sf
;
1810 Jump
= State
->Flags
.Pf
;
1817 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1824 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1831 /* Invert the result */
1837 /* Move the instruction pointer */
1838 State
->InstPtr
.Long
+= Offset
;
1841 /* Return success */
1845 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1847 BOOLEAN Value
= FALSE
;
1848 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1849 FAST486_MOD_REG_RM ModRegRm
;
1851 TOGGLE_ADSIZE(AddressSize
);
1853 /* Get the operands */
1854 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1856 /* Exception occurred */
1860 /* Make sure this is the right instruction */
1861 ASSERT((Opcode
& 0xF0) == 0x90);
1863 switch ((Opcode
& 0x0F) >> 1)
1868 Value
= State
->Flags
.Of
;
1875 Value
= State
->Flags
.Cf
;
1882 Value
= State
->Flags
.Zf
;
1886 /* SETBE / SETNBE */
1889 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1896 Value
= State
->Flags
.Sf
;
1903 Value
= State
->Flags
.Pf
;
1910 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1914 /* SETLE / SETNLE */
1917 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1924 /* Invert the result */
1928 /* Write back the result */
1929 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1932 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
1934 UCHAR Source
, Destination
, Result
;
1935 FAST486_MOD_REG_RM ModRegRm
;
1936 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1938 /* Make sure this is the right instruction */
1939 ASSERT(Opcode
== 0xC0);
1941 TOGGLE_ADSIZE(AddressSize
);
1943 /* Get the operands */
1944 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1946 /* Exception occurred */
1950 if (!Fast486ReadModrmByteOperands(State
,
1955 /* Exception occurred */
1959 /* Calculate the result */
1960 Result
= Source
+ Destination
;
1962 /* Update the flags */
1963 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1964 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
1965 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1966 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1967 State
->Flags
.Zf
= (Result
== 0);
1968 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1969 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1971 /* Write the sum to the destination */
1972 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
1974 /* Exception occurred */
1978 /* Write the old value of the destination to the source */
1979 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
1981 /* Exception occurred */
1988 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
1990 FAST486_MOD_REG_RM ModRegRm
;
1991 BOOLEAN OperandSize
, AddressSize
;
1993 /* Make sure this is the right instruction */
1994 ASSERT(Opcode
== 0xC1);
1996 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1998 TOGGLE_ADSIZE(AddressSize
);
1999 TOGGLE_OPSIZE(OperandSize
);
2001 /* Get the operands */
2002 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2004 /* Exception occurred */
2008 /* Check the operand size */
2011 ULONG Source
, Destination
, Result
;
2013 if (!Fast486ReadModrmDwordOperands(State
,
2018 /* Exception occurred */
2022 /* Calculate the result */
2023 Result
= Source
+ Destination
;
2025 /* Update the flags */
2026 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2027 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2028 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2029 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2030 State
->Flags
.Zf
= (Result
== 0);
2031 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2032 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2034 /* Write the sum to the destination */
2035 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
2037 /* Exception occurred */
2041 /* Write the old value of the destination to the source */
2042 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2044 /* Exception occurred */
2050 USHORT Source
, Destination
, Result
;
2052 if (!Fast486ReadModrmWordOperands(State
,
2057 /* Exception occurred */
2061 /* Calculate the result */
2062 Result
= Source
+ Destination
;
2064 /* Update the flags */
2065 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2066 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2067 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2068 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2069 State
->Flags
.Zf
= (Result
== 0);
2070 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2071 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2073 /* Write the sum to the destination */
2074 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2076 /* Exception occurred */
2080 /* Write the old value of the destination to the source */
2081 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2083 /* Exception occurred */
2091 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2097 /* Get a pointer to the value */
2098 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2100 /* Swap the byte order */
2101 SWAP(Pointer
[0], Pointer
[3]);
2102 SWAP(Pointer
[1], Pointer
[2]);
2104 /* Return success */
2108 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2112 /* Fetch the second operation code */
2113 if (!Fast486FetchByte(State
, &SecondOpcode
))
2115 /* Exception occurred */
2119 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
2121 /* Call the extended opcode handler */
2122 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
2126 /* This is not a valid opcode */
2127 Fast486Exception(State
, FAST486_EXCEPTION_UD
);