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
%= DataSize
;
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
;
674 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
676 /* Exception occurred */
680 DoubleSource
= Source
| (Source
<< 16);
682 /* Calculate the result */
683 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
686 State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
687 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
688 != (Destination
& SIGN_FLAG_WORD
);
689 State
->Flags
.Zf
= (Result
== 0);
690 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
691 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
693 /* Write back the result */
694 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
698 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
700 /* Call the internal API */
701 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
704 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
708 if (!Fast486StackPop(State
, &NewSelector
))
710 /* Exception occurred */
714 /* Call the internal API */
715 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
718 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
720 BOOLEAN OperandSize
, AddressSize
;
721 FAST486_MOD_REG_RM ModRegRm
;
725 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
726 TOGGLE_OPSIZE(OperandSize
);
727 TOGGLE_ADSIZE(AddressSize
);
729 /* Get the number of bits */
730 if (OperandSize
) DataSize
= 32;
733 /* Get the operands */
734 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
736 /* Exception occurred */
740 /* Get the bit number */
741 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
742 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
747 * For memory operands, add the bit offset divided by
748 * the data size to the address
750 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
753 /* Normalize the bit number */
754 BitNumber
%= DataSize
;
761 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
763 /* Exception occurred */
767 /* Set CF to the bit value */
768 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
771 Value
|= 1 << BitNumber
;
773 /* Write back the result */
774 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
776 /* Exception occurred */
785 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
787 /* Exception occurred */
791 /* Set CF to the bit value */
792 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
795 Value
|= 1 << BitNumber
;
797 /* Write back the result */
798 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
800 /* Exception occurred */
809 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
811 BOOLEAN OperandSize
, AddressSize
;
812 FAST486_MOD_REG_RM ModRegRm
;
815 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
816 TOGGLE_OPSIZE(OperandSize
);
817 TOGGLE_ADSIZE(AddressSize
);
819 /* Make sure this is the right instruction */
820 ASSERT((Opcode
& 0xFE) == 0xAC);
822 /* Get the operands */
823 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
825 /* Exception occurred */
831 /* Fetch the count */
832 if (!Fast486FetchByte(State
, &Count
))
834 /* Exception occurred */
840 /* The count is in CL */
841 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
844 /* Normalize the count */
847 /* Do nothing if the count is zero */
848 if (Count
== 0) return TRUE
;
852 ULONG Source
, Destination
, Result
;
854 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
856 /* Exception occurred */
860 /* Calculate the result */
861 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
864 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
865 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
866 != (Destination
& SIGN_FLAG_LONG
);
867 State
->Flags
.Zf
= (Result
== 0);
868 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
869 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
871 /* Write back the result */
872 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
876 USHORT Source
, Destination
, Result
;
878 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
880 /* Exception occurred */
884 /* Calculate the result */
885 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
887 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
890 State
->Flags
.Cf
= (Result
>> (Count
- 1)) & 1;
891 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
892 != (Destination
& SIGN_FLAG_WORD
);
893 State
->Flags
.Zf
= (Result
== 0);
894 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
895 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
897 /* Write back the result */
898 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
902 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
904 BOOLEAN OperandSize
, AddressSize
;
905 FAST486_MOD_REG_RM ModRegRm
;
907 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
909 TOGGLE_OPSIZE(OperandSize
);
910 TOGGLE_ADSIZE(AddressSize
);
912 /* Get the operands */
913 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
915 /* Exception occurred */
921 LONG Source
, Destination
;
924 /* Read the operands */
925 if (!Fast486ReadModrmDwordOperands(State
,
927 (PULONG
)&Destination
,
930 /* Exception occurred */
934 /* Calculate the result */
935 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
937 /* Update the flags */
938 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
940 /* Write back the result */
941 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
945 SHORT Source
, Destination
;
948 /* Read the operands */
949 if (!Fast486ReadModrmWordOperands(State
,
951 (PUSHORT
)&Destination
,
954 /* Exception occurred */
958 /* Calculate the result */
959 Result
= (LONG
)Source
* (LONG
)Destination
;
961 /* Update the flags */
962 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
964 /* Write back the result */
965 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
969 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
971 FAST486_MOD_REG_RM ModRegRm
;
972 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
973 UCHAR Source
, Destination
, Result
;
974 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
976 TOGGLE_ADSIZE(AddressSize
);
978 /* Get the operands */
979 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
981 /* Exception occurred */
985 /* Read the operands */
986 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
988 /* Exception occurred */
992 /* Compare AL with the destination */
993 Result
= Accumulator
- Destination
;
995 /* Update the flags */
996 State
->Flags
.Cf
= (Accumulator
< Destination
);
997 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
998 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
999 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1000 State
->Flags
.Zf
= (Result
== 0);
1001 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1002 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1004 if (State
->Flags
.Zf
)
1006 /* Load the source operand into the destination */
1007 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1011 /* Load the destination into AL */
1012 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1015 /* Return success */
1019 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1021 FAST486_MOD_REG_RM ModRegRm
;
1022 BOOLEAN OperandSize
, AddressSize
;
1024 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1026 TOGGLE_OPSIZE(OperandSize
);
1027 TOGGLE_ADSIZE(AddressSize
);
1029 /* Get the operands */
1030 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1032 /* Exception occurred */
1038 ULONG Source
, Destination
, Result
;
1039 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1041 /* Read the operands */
1042 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1044 /* Exception occurred */
1048 /* Compare EAX with the destination */
1049 Result
= Accumulator
- Destination
;
1051 /* Update the flags */
1052 State
->Flags
.Cf
= (Accumulator
< Destination
);
1053 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1054 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1055 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1056 State
->Flags
.Zf
= (Result
== 0);
1057 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1058 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1060 if (State
->Flags
.Zf
)
1062 /* Load the source operand into the destination */
1063 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1067 /* Load the destination into EAX */
1068 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1073 USHORT Source
, Destination
, Result
;
1074 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1076 /* Read the operands */
1077 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1079 /* Exception occurred */
1083 /* Compare AX with the destination */
1084 Result
= Accumulator
- Destination
;
1086 /* Update the flags */
1087 State
->Flags
.Cf
= (Accumulator
< Destination
);
1088 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1089 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1090 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1091 State
->Flags
.Zf
= (Result
== 0);
1092 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1093 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1095 if (State
->Flags
.Zf
)
1097 /* Load the source operand into the destination */
1098 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1102 /* Load the destination into AX */
1103 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1107 /* Return success */
1111 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1113 UCHAR FarPointer
[6];
1114 BOOLEAN OperandSize
, AddressSize
;
1115 FAST486_MOD_REG_RM ModRegRm
;
1117 /* Make sure this is the right instruction */
1118 ASSERT(Opcode
== 0xB2);
1120 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1122 TOGGLE_OPSIZE(OperandSize
);
1123 TOGGLE_ADSIZE(AddressSize
);
1125 /* Get the operands */
1126 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1128 /* Exception occurred */
1132 if (!ModRegRm
.Memory
)
1135 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1139 if (!Fast486ReadMemory(State
,
1140 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1141 ? State
->SegmentOverride
: FAST486_REG_DS
,
1142 ModRegRm
.MemoryAddress
,
1145 OperandSize
? 6 : 4))
1147 /* Exception occurred */
1153 ULONG Offset
= *((PULONG
)FarPointer
);
1154 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1156 /* Set the register to the offset */
1157 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1159 /* Load the segment */
1160 return Fast486LoadSegment(State
,
1166 USHORT Offset
= *((PUSHORT
)FarPointer
);
1167 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1169 /* Set the register to the offset */
1170 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1172 /* Load the segment */
1173 return Fast486LoadSegment(State
,
1179 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1181 BOOLEAN OperandSize
, AddressSize
;
1182 FAST486_MOD_REG_RM ModRegRm
;
1186 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1187 TOGGLE_OPSIZE(OperandSize
);
1188 TOGGLE_ADSIZE(AddressSize
);
1190 /* Get the number of bits */
1191 if (OperandSize
) DataSize
= 32;
1194 /* Get the operands */
1195 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1197 /* Exception occurred */
1201 /* Get the bit number */
1202 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1203 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1205 if (ModRegRm
.Memory
)
1208 * For memory operands, add the bit offset divided by
1209 * the data size to the address
1211 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1214 /* Normalize the bit number */
1215 BitNumber
%= DataSize
;
1221 /* Read the value */
1222 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1224 /* Exception occurred */
1228 /* Set CF to the bit value */
1229 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1232 Value
&= ~(1 << BitNumber
);
1234 /* Write back the result */
1235 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1237 /* Exception occurred */
1243 USHORT Dummy
, Value
;
1245 /* Read the value */
1246 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1248 /* Exception occurred */
1252 /* Set CF to the bit value */
1253 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1256 Value
&= ~(1 << BitNumber
);
1258 /* Write back the result */
1259 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1261 /* Exception occurred */
1266 /* Return success */
1270 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1272 UCHAR FarPointer
[6];
1273 BOOLEAN OperandSize
, AddressSize
;
1274 FAST486_MOD_REG_RM ModRegRm
;
1276 /* Make sure this is the right instruction */
1277 ASSERT((Opcode
& 0xFE) == 0xB4);
1279 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1281 TOGGLE_OPSIZE(OperandSize
);
1282 TOGGLE_ADSIZE(AddressSize
);
1284 /* Get the operands */
1285 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1287 /* Exception occurred */
1291 if (!ModRegRm
.Memory
)
1294 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1298 if (!Fast486ReadMemory(State
,
1299 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1300 ? State
->SegmentOverride
: FAST486_REG_DS
,
1301 ModRegRm
.MemoryAddress
,
1304 OperandSize
? 6 : 4))
1306 /* Exception occurred */
1312 ULONG Offset
= *((PULONG
)FarPointer
);
1313 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1315 /* Set the register to the offset */
1316 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1318 /* Load the segment */
1319 return Fast486LoadSegment(State
,
1321 ? FAST486_REG_FS
: FAST486_REG_GS
,
1326 USHORT Offset
= *((PUSHORT
)FarPointer
);
1327 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1329 /* Set the register to the offset */
1330 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1332 /* Load the segment */
1333 return Fast486LoadSegment(State
,
1335 ? FAST486_REG_FS
: FAST486_REG_GS
,
1340 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1343 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1344 FAST486_MOD_REG_RM ModRegRm
;
1346 TOGGLE_ADSIZE(AddressSize
);
1348 /* Make sure this is the right instruction */
1349 ASSERT(Opcode
== 0xB6);
1351 /* Get the operands */
1352 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1354 /* Exception occurred */
1358 /* Read the operands */
1359 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1361 /* Exception occurred */
1365 /* Write back the zero-extended value */
1366 return Fast486WriteModrmDwordOperands(State
,
1372 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1374 USHORT Dummy
, Value
;
1375 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1376 FAST486_MOD_REG_RM ModRegRm
;
1378 TOGGLE_ADSIZE(AddressSize
);
1380 /* Make sure this is the right instruction */
1381 ASSERT(Opcode
== 0xB7);
1383 /* Get the operands */
1384 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1386 /* Exception occurred */
1390 /* Read the operands */
1391 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1393 /* Exception occurred */
1397 /* Write back the zero-extended value */
1398 return Fast486WriteModrmDwordOperands(State
,
1404 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1406 BOOLEAN OperandSize
, AddressSize
;
1407 FAST486_MOD_REG_RM ModRegRm
;
1411 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1412 TOGGLE_OPSIZE(OperandSize
);
1413 TOGGLE_ADSIZE(AddressSize
);
1415 /* Get the number of bits */
1416 if (OperandSize
) DataSize
= 32;
1419 /* Get the operands */
1420 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1422 /* Exception occurred */
1426 /* Get the bit number */
1427 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1428 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1430 if (ModRegRm
.Memory
)
1433 * For memory operands, add the bit offset divided by
1434 * the data size to the address
1436 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1439 /* Normalize the bit number */
1440 BitNumber
%= DataSize
;
1446 /* Read the value */
1447 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1449 /* Exception occurred */
1453 /* Set CF to the bit value */
1454 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1456 /* Toggle the bit */
1457 Value
^= 1 << BitNumber
;
1459 /* Write back the result */
1460 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1462 /* Exception occurred */
1468 USHORT Dummy
, Value
;
1470 /* Read the value */
1471 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1473 /* Exception occurred */
1477 /* Set CF to the bit value */
1478 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1480 /* Toggle the bit */
1481 Value
^= 1 << BitNumber
;
1483 /* Write back the result */
1484 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1486 /* Exception occurred */
1491 /* Return success */
1495 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1498 ULONG Dummy
= 0, Value
= 0;
1499 BOOLEAN OperandSize
, AddressSize
;
1500 FAST486_MOD_REG_RM ModRegRm
;
1504 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1505 TOGGLE_OPSIZE(OperandSize
);
1506 TOGGLE_ADSIZE(AddressSize
);
1508 /* Make sure this is the right instruction */
1509 ASSERT(Opcode
== 0xBC);
1511 /* Get the number of bits */
1512 if (OperandSize
) DataSize
= 32;
1515 /* Get the operands */
1516 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1518 /* Exception occurred */
1522 /* Read the value */
1525 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1527 /* Exception occurred */
1533 if (!Fast486ReadModrmWordOperands(State
,
1538 /* Exception occurred */
1544 State
->Flags
.Zf
= (Value
== 0);
1545 if (State
->Flags
.Zf
) return TRUE
;
1547 for (i
= 0; i
< DataSize
; i
++)
1549 if(Value
& (1 << i
))
1551 /* Save the bit number */
1559 /* Write back the result */
1562 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1564 /* Exception occurred */
1570 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1572 /* 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 */
1628 /* Set ZF according to the value */
1629 State
->Flags
.Zf
= (Value
== 0);
1630 if (State
->Flags
.Zf
) return TRUE
;
1632 for (i
= DataSize
- 1; i
>= 0; i
--)
1634 if(Value
& (1 << i
))
1636 /* Save the bit number */
1644 /* Write back the result */
1647 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1649 /* Exception occurred */
1655 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1657 /* Exception occurred */
1665 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1669 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1670 FAST486_MOD_REG_RM ModRegRm
;
1672 TOGGLE_ADSIZE(AddressSize
);
1674 /* Make sure this is the right instruction */
1675 ASSERT(Opcode
== 0xBE);
1677 /* Get the operands */
1678 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1680 /* Exception occurred */
1684 /* Read the operands */
1685 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, (PUCHAR
)&Value
))
1687 /* Exception occurred */
1691 /* Write back the sign-extended value */
1692 return Fast486WriteModrmDwordOperands(State
,
1695 (ULONG
)((LONG
)Value
));
1698 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1702 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1703 FAST486_MOD_REG_RM ModRegRm
;
1705 TOGGLE_ADSIZE(AddressSize
);
1707 /* Make sure this is the right instruction */
1708 ASSERT(Opcode
== 0xBF);
1710 /* Get the operands */
1711 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1713 /* Exception occurred */
1717 /* Read the operands */
1718 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, (PUSHORT
)&Value
))
1720 /* Exception occurred */
1724 /* Write back the sign-extended value */
1725 return Fast486WriteModrmDwordOperands(State
,
1728 (ULONG
)((LONG
)Value
));
1731 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1733 BOOLEAN Jump
= FALSE
;
1735 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1737 TOGGLE_OPSIZE(Size
);
1740 /* Make sure this is the right instruction */
1741 ASSERT((Opcode
& 0xF0) == 0x80);
1743 /* Fetch the offset */
1746 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1748 /* Exception occurred */
1756 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1758 /* Exception occurred */
1763 Offset
= (LONG
)Value
;
1766 switch ((Opcode
& 0x0F) >> 1)
1771 Jump
= State
->Flags
.Of
;
1778 Jump
= State
->Flags
.Cf
;
1785 Jump
= State
->Flags
.Zf
;
1792 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1799 Jump
= State
->Flags
.Sf
;
1806 Jump
= State
->Flags
.Pf
;
1813 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1820 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1827 /* Invert the result */
1833 /* Move the instruction pointer */
1834 State
->InstPtr
.Long
+= Offset
;
1837 /* Return success */
1841 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1843 BOOLEAN Value
= FALSE
;
1844 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1845 FAST486_MOD_REG_RM ModRegRm
;
1847 TOGGLE_ADSIZE(AddressSize
);
1849 /* Get the operands */
1850 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1852 /* Exception occurred */
1856 /* Make sure this is the right instruction */
1857 ASSERT((Opcode
& 0xF0) == 0x90);
1859 switch ((Opcode
& 0x0F) >> 1)
1864 Value
= State
->Flags
.Of
;
1871 Value
= State
->Flags
.Cf
;
1878 Value
= State
->Flags
.Zf
;
1882 /* SETBE / SETNBE */
1885 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1892 Value
= State
->Flags
.Sf
;
1899 Value
= State
->Flags
.Pf
;
1906 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1910 /* SETLE / SETNLE */
1913 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1920 /* Invert the result */
1924 /* Write back the result */
1925 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1928 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
1930 UCHAR Source
, Destination
, Result
;
1931 FAST486_MOD_REG_RM ModRegRm
;
1932 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1934 /* Make sure this is the right instruction */
1935 ASSERT(Opcode
== 0xC0);
1937 TOGGLE_ADSIZE(AddressSize
);
1939 /* Get the operands */
1940 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1942 /* Exception occurred */
1946 if (!Fast486ReadModrmByteOperands(State
,
1951 /* Exception occurred */
1955 /* Calculate the result */
1956 Result
= Source
+ Destination
;
1958 /* Update the flags */
1959 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1960 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
1961 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1962 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1963 State
->Flags
.Zf
= (Result
== 0);
1964 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1965 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1967 /* Write the sum to the destination */
1968 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
1970 /* Exception occurred */
1974 /* Write the old value of the destination to the source */
1975 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
1977 /* Exception occurred */
1984 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
1986 FAST486_MOD_REG_RM ModRegRm
;
1987 BOOLEAN OperandSize
, AddressSize
;
1989 /* Make sure this is the right instruction */
1990 ASSERT(Opcode
== 0xC1);
1992 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1994 TOGGLE_ADSIZE(AddressSize
);
1995 TOGGLE_OPSIZE(OperandSize
);
1997 /* Get the operands */
1998 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2000 /* Exception occurred */
2004 /* Check the operand size */
2007 ULONG Source
, Destination
, Result
;
2009 if (!Fast486ReadModrmDwordOperands(State
,
2014 /* Exception occurred */
2018 /* Calculate the result */
2019 Result
= Source
+ Destination
;
2021 /* Update the flags */
2022 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2023 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2024 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2025 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2026 State
->Flags
.Zf
= (Result
== 0);
2027 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2028 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2030 /* Write the old value of the destination to the source */
2031 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2033 /* Exception occurred */
2037 /* Write the sum to the destination */
2038 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
2040 /* Exception occurred */
2046 USHORT Source
, Destination
, Result
;
2048 if (!Fast486ReadModrmWordOperands(State
,
2053 /* Exception occurred */
2057 /* Calculate the result */
2058 Result
= Source
+ Destination
;
2060 /* Update the flags */
2061 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2062 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2063 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2064 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2065 State
->Flags
.Zf
= (Result
== 0);
2066 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2067 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2069 /* Write the old value of the destination to the source */
2070 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2072 /* Exception occurred */
2076 /* Write the sum to the destination */
2077 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2079 /* Exception occurred */
2087 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2093 /* Get a pointer to the value */
2094 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2096 /* Swap the byte order */
2097 SWAP(Pointer
[0], Pointer
[3]);
2098 SWAP(Pointer
[1], Pointer
[2]);
2100 /* Return success */
2104 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2108 /* Fetch the second operation code */
2109 if (!Fast486FetchByte(State
, &SecondOpcode
))
2111 /* Exception occurred */
2115 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
2117 /* Call the extended opcode handler */
2118 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
2122 /* This is not a valid opcode */
2123 Fast486Exception(State
, FAST486_EXCEPTION_UD
);