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 */
642 /* Do nothing if the count is zero */
643 if (Count
== 0) return TRUE
;
647 ULONG Source
, Destination
, Result
;
649 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
651 /* Exception occurred */
655 /* Calculate the result */
656 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
659 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
660 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
661 != (Destination
& SIGN_FLAG_LONG
);
662 State
->Flags
.Zf
= (Result
== 0);
663 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
664 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
666 /* Write back the result */
667 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
671 USHORT Source
, Destination
, Result
;
673 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
675 /* Exception occurred */
679 /* Calculate the result */
680 Result
= (Destination
<< Count
) | (Source
>> (16 - Count
));
683 State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
684 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
685 != (Destination
& SIGN_FLAG_WORD
);
686 State
->Flags
.Zf
= (Result
== 0);
687 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
688 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
690 /* Write back the result */
691 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
695 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
697 /* Call the internal API */
698 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
701 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
705 if (!Fast486StackPop(State
, &NewSelector
))
707 /* Exception occurred */
711 /* Call the internal API */
712 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
715 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
717 BOOLEAN OperandSize
, AddressSize
;
718 FAST486_MOD_REG_RM ModRegRm
;
722 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
723 TOGGLE_OPSIZE(OperandSize
);
724 TOGGLE_ADSIZE(AddressSize
);
726 /* Get the number of bits */
727 if (OperandSize
) DataSize
= 32;
730 /* Get the operands */
731 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
733 /* Exception occurred */
737 /* Get the bit number */
738 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
739 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
744 * For memory operands, add the bit offset divided by
745 * the data size to the address
747 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
750 /* Normalize the bit number */
751 BitNumber
&= (1 << DataSize
) - 1;
758 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
760 /* Exception occurred */
764 /* Set CF to the bit value */
765 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
768 Value
|= 1 << BitNumber
;
770 /* Write back the result */
771 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
773 /* Exception occurred */
782 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
784 /* Exception occurred */
788 /* Set CF to the bit value */
789 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
792 Value
|= 1 << BitNumber
;
794 /* Write back the result */
795 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
797 /* Exception occurred */
806 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
808 BOOLEAN OperandSize
, AddressSize
;
809 FAST486_MOD_REG_RM ModRegRm
;
812 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
813 TOGGLE_OPSIZE(OperandSize
);
814 TOGGLE_ADSIZE(AddressSize
);
816 /* Make sure this is the right instruction */
817 ASSERT((Opcode
& 0xFE) == 0xAC);
819 /* Get the operands */
820 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
822 /* Exception occurred */
828 /* Fetch the count */
829 if (!Fast486FetchByte(State
, &Count
))
831 /* Exception occurred */
837 /* The count is in CL */
838 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
841 /* Normalize the count */
844 /* Do nothing if the count is zero */
845 if (Count
== 0) return TRUE
;
849 ULONG Source
, Destination
, Result
;
851 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
853 /* Exception occurred */
857 /* Calculate the result */
858 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
861 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
862 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
863 != (Destination
& SIGN_FLAG_LONG
);
864 State
->Flags
.Zf
= (Result
== 0);
865 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
866 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
868 /* Write back the result */
869 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
873 USHORT Source
, Destination
, Result
;
875 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
877 /* Exception occurred */
881 /* Calculate the result */
882 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
885 State
->Flags
.Cf
= (Result
>> (Count
- 1)) & 1;
886 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
887 != (Destination
& SIGN_FLAG_WORD
);
888 State
->Flags
.Zf
= (Result
== 0);
889 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
890 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
892 /* Write back the result */
893 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
897 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
899 BOOLEAN OperandSize
, AddressSize
;
900 FAST486_MOD_REG_RM ModRegRm
;
902 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
904 TOGGLE_OPSIZE(OperandSize
);
905 TOGGLE_ADSIZE(AddressSize
);
907 /* Get the operands */
908 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
910 /* Exception occurred */
916 LONG Source
, Destination
;
919 /* Read the operands */
920 if (!Fast486ReadModrmDwordOperands(State
,
922 (PULONG
)&Destination
,
925 /* Exception occurred */
929 /* Calculate the result */
930 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
932 /* Update the flags */
933 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
935 /* Write back the result */
936 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
940 SHORT Source
, Destination
;
943 /* Read the operands */
944 if (!Fast486ReadModrmWordOperands(State
,
946 (PUSHORT
)&Destination
,
949 /* Exception occurred */
953 /* Calculate the result */
954 Result
= (LONG
)Source
* (LONG
)Destination
;
956 /* Update the flags */
957 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
959 /* Write back the result */
960 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
964 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
966 FAST486_MOD_REG_RM ModRegRm
;
967 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
968 UCHAR Source
, Destination
, Result
;
969 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
971 TOGGLE_ADSIZE(AddressSize
);
973 /* Get the operands */
974 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
976 /* Exception occurred */
980 /* Read the operands */
981 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
983 /* Exception occurred */
987 /* Compare AL with the destination */
988 Result
= Accumulator
- Destination
;
990 /* Update the flags */
991 State
->Flags
.Cf
= (Accumulator
< Destination
);
992 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
993 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
994 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
995 State
->Flags
.Zf
= (Result
== 0);
996 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
997 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1001 /* Load the source operand into the destination */
1002 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1006 /* Load the destination into AL */
1007 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1010 /* Return success */
1014 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1016 FAST486_MOD_REG_RM ModRegRm
;
1017 BOOLEAN OperandSize
, AddressSize
;
1019 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1021 TOGGLE_OPSIZE(OperandSize
);
1022 TOGGLE_ADSIZE(AddressSize
);
1024 /* Get the operands */
1025 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1027 /* Exception occurred */
1033 ULONG Source
, Destination
, Result
;
1034 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1036 /* Read the operands */
1037 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1039 /* Exception occurred */
1043 /* Compare EAX with the destination */
1044 Result
= Accumulator
- Destination
;
1046 /* Update the flags */
1047 State
->Flags
.Cf
= (Accumulator
< Destination
);
1048 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1049 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1050 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1051 State
->Flags
.Zf
= (Result
== 0);
1052 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1053 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1055 if (State
->Flags
.Zf
)
1057 /* Load the source operand into the destination */
1058 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1062 /* Load the destination into EAX */
1063 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1068 USHORT Source
, Destination
, Result
;
1069 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1071 /* Read the operands */
1072 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1074 /* Exception occurred */
1078 /* Compare AX with the destination */
1079 Result
= Accumulator
- Destination
;
1081 /* Update the flags */
1082 State
->Flags
.Cf
= (Accumulator
< Destination
);
1083 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1084 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1085 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1086 State
->Flags
.Zf
= (Result
== 0);
1087 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1088 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1090 if (State
->Flags
.Zf
)
1092 /* Load the source operand into the destination */
1093 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1097 /* Load the destination into AX */
1098 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1102 /* Return success */
1106 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1108 UCHAR FarPointer
[6];
1109 BOOLEAN OperandSize
, AddressSize
;
1110 FAST486_MOD_REG_RM ModRegRm
;
1112 /* Make sure this is the right instruction */
1113 ASSERT(Opcode
== 0xB2);
1115 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1117 TOGGLE_OPSIZE(OperandSize
);
1118 TOGGLE_ADSIZE(AddressSize
);
1120 /* Get the operands */
1121 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1123 /* Exception occurred */
1127 if (!ModRegRm
.Memory
)
1130 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1134 if (!Fast486ReadMemory(State
,
1135 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1136 ? State
->SegmentOverride
: FAST486_REG_DS
,
1137 ModRegRm
.MemoryAddress
,
1140 OperandSize
? 6 : 4))
1142 /* Exception occurred */
1148 ULONG Offset
= *((PULONG
)FarPointer
);
1149 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1151 /* Set the register to the offset */
1152 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1154 /* Load the segment */
1155 return Fast486LoadSegment(State
,
1161 USHORT Offset
= *((PUSHORT
)FarPointer
);
1162 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1164 /* Set the register to the offset */
1165 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1167 /* Load the segment */
1168 return Fast486LoadSegment(State
,
1174 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1176 BOOLEAN OperandSize
, AddressSize
;
1177 FAST486_MOD_REG_RM ModRegRm
;
1181 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1182 TOGGLE_OPSIZE(OperandSize
);
1183 TOGGLE_ADSIZE(AddressSize
);
1185 /* Get the number of bits */
1186 if (OperandSize
) DataSize
= 32;
1189 /* Get the operands */
1190 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1192 /* Exception occurred */
1196 /* Get the bit number */
1197 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1198 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1200 if (ModRegRm
.Memory
)
1203 * For memory operands, add the bit offset divided by
1204 * the data size to the address
1206 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1209 /* Normalize the bit number */
1210 BitNumber
&= (1 << DataSize
) - 1;
1216 /* Read the value */
1217 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1219 /* Exception occurred */
1223 /* Set CF to the bit value */
1224 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1227 Value
&= ~(1 << BitNumber
);
1229 /* Write back the result */
1230 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1232 /* Exception occurred */
1238 USHORT Dummy
, Value
;
1240 /* Read the value */
1241 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1243 /* Exception occurred */
1247 /* Set CF to the bit value */
1248 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1251 Value
&= ~(1 << BitNumber
);
1253 /* Write back the result */
1254 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1256 /* Exception occurred */
1261 /* Return success */
1265 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1267 UCHAR FarPointer
[6];
1268 BOOLEAN OperandSize
, AddressSize
;
1269 FAST486_MOD_REG_RM ModRegRm
;
1271 /* Make sure this is the right instruction */
1272 ASSERT((Opcode
& 0xFE) == 0xB4);
1274 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1276 TOGGLE_OPSIZE(OperandSize
);
1277 TOGGLE_ADSIZE(AddressSize
);
1279 /* Get the operands */
1280 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1282 /* Exception occurred */
1286 if (!ModRegRm
.Memory
)
1289 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1293 if (!Fast486ReadMemory(State
,
1294 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1295 ? State
->SegmentOverride
: FAST486_REG_DS
,
1296 ModRegRm
.MemoryAddress
,
1299 OperandSize
? 6 : 4))
1301 /* Exception occurred */
1307 ULONG Offset
= *((PULONG
)FarPointer
);
1308 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1310 /* Set the register to the offset */
1311 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1313 /* Load the segment */
1314 return Fast486LoadSegment(State
,
1316 ? FAST486_REG_FS
: FAST486_REG_GS
,
1321 USHORT Offset
= *((PUSHORT
)FarPointer
);
1322 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1324 /* Set the register to the offset */
1325 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1327 /* Load the segment */
1328 return Fast486LoadSegment(State
,
1330 ? FAST486_REG_FS
: FAST486_REG_GS
,
1335 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1338 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1339 FAST486_MOD_REG_RM ModRegRm
;
1341 TOGGLE_ADSIZE(AddressSize
);
1343 /* Make sure this is the right instruction */
1344 ASSERT(Opcode
== 0xB6);
1346 /* Get the operands */
1347 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1349 /* Exception occurred */
1353 /* Read the operands */
1354 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1356 /* Exception occurred */
1360 /* Write back the zero-extended value */
1361 return Fast486WriteModrmDwordOperands(State
,
1367 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1369 USHORT Dummy
, Value
;
1370 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1371 FAST486_MOD_REG_RM ModRegRm
;
1373 TOGGLE_ADSIZE(AddressSize
);
1375 /* Make sure this is the right instruction */
1376 ASSERT(Opcode
== 0xB7);
1378 /* Get the operands */
1379 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1381 /* Exception occurred */
1385 /* Read the operands */
1386 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1388 /* Exception occurred */
1392 /* Write back the zero-extended value */
1393 return Fast486WriteModrmDwordOperands(State
,
1399 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1401 BOOLEAN OperandSize
, AddressSize
;
1402 FAST486_MOD_REG_RM ModRegRm
;
1406 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1407 TOGGLE_OPSIZE(OperandSize
);
1408 TOGGLE_ADSIZE(AddressSize
);
1410 /* Get the number of bits */
1411 if (OperandSize
) DataSize
= 32;
1414 /* Get the operands */
1415 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1417 /* Exception occurred */
1421 /* Get the bit number */
1422 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1423 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1425 if (ModRegRm
.Memory
)
1428 * For memory operands, add the bit offset divided by
1429 * the data size to the address
1431 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1434 /* Normalize the bit number */
1435 BitNumber
&= (1 << DataSize
) - 1;
1441 /* Read the value */
1442 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1444 /* Exception occurred */
1448 /* Set CF to the bit value */
1449 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1451 /* Toggle the bit */
1452 Value
^= 1 << BitNumber
;
1454 /* Write back the result */
1455 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1457 /* Exception occurred */
1463 USHORT Dummy
, Value
;
1465 /* Read the value */
1466 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1468 /* Exception occurred */
1472 /* Set CF to the bit value */
1473 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1475 /* Toggle the bit */
1476 Value
^= 1 << BitNumber
;
1478 /* Write back the result */
1479 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1481 /* Exception occurred */
1486 /* Return success */
1490 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1493 ULONG Dummy
= 0, Value
= 0;
1494 BOOLEAN OperandSize
, AddressSize
;
1495 FAST486_MOD_REG_RM ModRegRm
;
1499 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1500 TOGGLE_OPSIZE(OperandSize
);
1501 TOGGLE_ADSIZE(AddressSize
);
1503 /* Make sure this is the right instruction */
1504 ASSERT(Opcode
== 0xBC);
1506 /* Get the number of bits */
1507 if (OperandSize
) DataSize
= 32;
1510 /* Get the operands */
1511 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1513 /* Exception occurred */
1517 /* Read the value */
1520 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1522 /* Exception occurred */
1528 if (!Fast486ReadModrmWordOperands(State
,
1533 /* Exception occurred */
1539 State
->Flags
.Zf
= FALSE
;
1541 for (i
= 0; i
< DataSize
; i
++)
1543 if(Value
& (1 << i
))
1546 State
->Flags
.Zf
= TRUE
;
1548 /* Save the bit number */
1556 if (State
->Flags
.Zf
)
1558 /* Write back the result */
1561 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1563 /* Exception occurred */
1569 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1571 /* Exception occurred */
1580 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1583 ULONG Dummy
= 0, Value
= 0;
1584 BOOLEAN OperandSize
, AddressSize
;
1585 FAST486_MOD_REG_RM ModRegRm
;
1589 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1590 TOGGLE_OPSIZE(OperandSize
);
1591 TOGGLE_ADSIZE(AddressSize
);
1593 /* Make sure this is the right instruction */
1594 ASSERT(Opcode
== 0xBD);
1596 /* Get the number of bits */
1597 if (OperandSize
) DataSize
= 32;
1600 /* Get the operands */
1601 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1603 /* Exception occurred */
1607 /* Read the value */
1610 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1612 /* Exception occurred */
1618 if (!Fast486ReadModrmWordOperands(State
,
1623 /* Exception occurred */
1629 State
->Flags
.Zf
= FALSE
;
1631 for (i
= DataSize
- 1; i
>= 0; i
--)
1633 if(Value
& (1 << i
))
1636 State
->Flags
.Zf
= TRUE
;
1638 /* Save the bit number */
1646 if (State
->Flags
.Zf
)
1648 /* Write back the result */
1651 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1653 /* Exception occurred */
1659 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1661 /* Exception occurred */
1670 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1674 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1675 FAST486_MOD_REG_RM ModRegRm
;
1677 TOGGLE_ADSIZE(AddressSize
);
1679 /* Make sure this is the right instruction */
1680 ASSERT(Opcode
== 0xBE);
1682 /* Get the operands */
1683 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1685 /* Exception occurred */
1689 /* Read the operands */
1690 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, (PUCHAR
)&Value
))
1692 /* Exception occurred */
1696 /* Write back the sign-extended value */
1697 return Fast486WriteModrmDwordOperands(State
,
1700 (ULONG
)((LONG
)Value
));
1703 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1707 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1708 FAST486_MOD_REG_RM ModRegRm
;
1710 TOGGLE_ADSIZE(AddressSize
);
1712 /* Make sure this is the right instruction */
1713 ASSERT(Opcode
== 0xBF);
1715 /* Get the operands */
1716 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1718 /* Exception occurred */
1722 /* Read the operands */
1723 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, (PUSHORT
)&Value
))
1725 /* Exception occurred */
1729 /* Write back the sign-extended value */
1730 return Fast486WriteModrmDwordOperands(State
,
1733 (ULONG
)((LONG
)Value
));
1736 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1738 BOOLEAN Jump
= FALSE
;
1740 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1742 TOGGLE_OPSIZE(Size
);
1745 /* Make sure this is the right instruction */
1746 ASSERT((Opcode
& 0xF0) == 0x80);
1748 /* Fetch the offset */
1751 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1753 /* Exception occurred */
1761 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1763 /* Exception occurred */
1768 Offset
= (LONG
)Value
;
1771 switch ((Opcode
& 0x0F) >> 1)
1776 Jump
= State
->Flags
.Of
;
1783 Jump
= State
->Flags
.Cf
;
1790 Jump
= State
->Flags
.Zf
;
1797 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1804 Jump
= State
->Flags
.Sf
;
1811 Jump
= State
->Flags
.Pf
;
1818 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1825 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1832 /* Invert the result */
1838 /* Move the instruction pointer */
1839 State
->InstPtr
.Long
+= Offset
;
1842 /* Return success */
1846 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1848 BOOLEAN Value
= FALSE
;
1849 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1850 FAST486_MOD_REG_RM ModRegRm
;
1852 TOGGLE_ADSIZE(AddressSize
);
1854 /* Get the operands */
1855 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1857 /* Exception occurred */
1861 /* Make sure this is the right instruction */
1862 ASSERT((Opcode
& 0xF0) == 0x90);
1864 switch ((Opcode
& 0x0F) >> 1)
1869 Value
= State
->Flags
.Of
;
1876 Value
= State
->Flags
.Cf
;
1883 Value
= State
->Flags
.Zf
;
1887 /* SETBE / SETNBE */
1890 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1897 Value
= State
->Flags
.Sf
;
1904 Value
= State
->Flags
.Pf
;
1911 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1915 /* SETLE / SETNLE */
1918 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1925 /* Invert the result */
1929 /* Write back the result */
1930 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1933 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
1935 UCHAR Source
, Destination
, Result
;
1936 FAST486_MOD_REG_RM ModRegRm
;
1937 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1939 /* Make sure this is the right instruction */
1940 ASSERT(Opcode
== 0xC0);
1942 TOGGLE_ADSIZE(AddressSize
);
1944 /* Get the operands */
1945 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1947 /* Exception occurred */
1951 if (!Fast486ReadModrmByteOperands(State
,
1956 /* Exception occurred */
1960 /* Calculate the result */
1961 Result
= Source
+ Destination
;
1963 /* Update the flags */
1964 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1965 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
1966 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1967 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1968 State
->Flags
.Zf
= (Result
== 0);
1969 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1970 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1972 /* Write the sum to the destination */
1973 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
1975 /* Exception occurred */
1979 /* Write the old value of the destination to the source */
1980 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
1982 /* Exception occurred */
1989 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
1991 FAST486_MOD_REG_RM ModRegRm
;
1992 BOOLEAN OperandSize
, AddressSize
;
1994 /* Make sure this is the right instruction */
1995 ASSERT(Opcode
== 0xC1);
1997 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1999 TOGGLE_ADSIZE(AddressSize
);
2000 TOGGLE_OPSIZE(OperandSize
);
2002 /* Get the operands */
2003 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2005 /* Exception occurred */
2009 /* Check the operand size */
2012 ULONG Source
, Destination
, Result
;
2014 if (!Fast486ReadModrmDwordOperands(State
,
2019 /* Exception occurred */
2023 /* Calculate the result */
2024 Result
= Source
+ Destination
;
2026 /* Update the flags */
2027 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2028 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2029 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2030 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2031 State
->Flags
.Zf
= (Result
== 0);
2032 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2033 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2035 /* Write the sum to the destination */
2036 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
2038 /* Exception occurred */
2042 /* Write the old value of the destination to the source */
2043 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2045 /* Exception occurred */
2051 USHORT Source
, Destination
, Result
;
2053 if (!Fast486ReadModrmWordOperands(State
,
2058 /* Exception occurred */
2062 /* Calculate the result */
2063 Result
= Source
+ Destination
;
2065 /* Update the flags */
2066 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2067 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2068 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2069 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2070 State
->Flags
.Zf
= (Result
== 0);
2071 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2072 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2074 /* Write the sum to the destination */
2075 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2077 /* Exception occurred */
2081 /* Write the old value of the destination to the source */
2082 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2084 /* Exception occurred */
2092 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2098 /* Get a pointer to the value */
2099 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2101 /* Swap the byte order */
2102 SWAP(Pointer
[0], Pointer
[3]);
2103 SWAP(Pointer
[1], Pointer
[2]);
2105 /* Return success */
2109 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2113 /* Fetch the second operation code */
2114 if (!Fast486FetchByte(State
, &SecondOpcode
))
2116 /* Exception occurred */
2120 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
2122 /* Call the extended opcode handler */
2123 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
2127 /* This is not a valid opcode */
2128 Fast486Exception(State
, FAST486_EXCEPTION_UD
);