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
,
218 NULL
, // TODO: OPCODE 0xB2 NOT IMPLEMENTED
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(Fast486ExtOpcodeBtr
)
1107 BOOLEAN OperandSize
, AddressSize
;
1108 FAST486_MOD_REG_RM ModRegRm
;
1112 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1113 TOGGLE_OPSIZE(OperandSize
);
1114 TOGGLE_ADSIZE(AddressSize
);
1116 /* Get the number of bits */
1117 if (OperandSize
) DataSize
= 32;
1120 /* Get the operands */
1121 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1123 /* Exception occurred */
1127 /* Get the bit number */
1128 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1129 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1131 if (ModRegRm
.Memory
)
1134 * For memory operands, add the bit offset divided by
1135 * the data size to the address
1137 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1140 /* Normalize the bit number */
1141 BitNumber
&= (1 << DataSize
) - 1;
1147 /* Read the value */
1148 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1150 /* Exception occurred */
1154 /* Set CF to the bit value */
1155 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1158 Value
&= ~(1 << BitNumber
);
1160 /* Write back the result */
1161 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1163 /* Exception occurred */
1169 USHORT Dummy
, Value
;
1171 /* Read the value */
1172 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1174 /* Exception occurred */
1178 /* Set CF to the bit value */
1179 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1182 Value
&= ~(1 << BitNumber
);
1184 /* Write back the result */
1185 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1187 /* Exception occurred */
1192 /* Return success */
1196 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1198 UCHAR FarPointer
[6];
1199 BOOLEAN OperandSize
, AddressSize
;
1200 FAST486_MOD_REG_RM ModRegRm
;
1202 /* Make sure this is the right instruction */
1203 ASSERT((Opcode
& 0xFE) == 0xB4);
1205 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1207 TOGGLE_ADSIZE(AddressSize
);
1209 /* Get the operands */
1210 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1212 /* Exception occurred */
1216 if (!ModRegRm
.Memory
)
1219 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1223 if (!Fast486ReadMemory(State
,
1224 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1225 ? State
->SegmentOverride
: FAST486_REG_DS
,
1226 ModRegRm
.MemoryAddress
,
1229 OperandSize
? 6 : 4))
1231 /* Exception occurred */
1237 ULONG Offset
= *((PULONG
)FarPointer
);
1238 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1240 /* Set the register to the offset */
1241 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1243 /* Load the segment */
1244 return Fast486LoadSegment(State
,
1246 ? FAST486_REG_FS
: FAST486_REG_GS
,
1251 USHORT Offset
= *((PUSHORT
)FarPointer
);
1252 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1254 /* Set the register to the offset */
1255 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1257 /* Load the segment */
1258 return Fast486LoadSegment(State
,
1260 ? FAST486_REG_FS
: FAST486_REG_GS
,
1265 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1268 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1269 FAST486_MOD_REG_RM ModRegRm
;
1271 TOGGLE_ADSIZE(AddressSize
);
1273 /* Make sure this is the right instruction */
1274 ASSERT(Opcode
== 0xB6);
1276 /* Get the operands */
1277 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1279 /* Exception occurred */
1283 /* Read the operands */
1284 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1286 /* Exception occurred */
1290 /* Write back the zero-extended value */
1291 return Fast486WriteModrmDwordOperands(State
,
1297 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
1299 USHORT Dummy
, Value
;
1300 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1301 FAST486_MOD_REG_RM ModRegRm
;
1303 TOGGLE_ADSIZE(AddressSize
);
1305 /* Make sure this is the right instruction */
1306 ASSERT(Opcode
== 0xB7);
1308 /* Get the operands */
1309 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1311 /* Exception occurred */
1315 /* Read the operands */
1316 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1318 /* Exception occurred */
1322 /* Write back the zero-extended value */
1323 return Fast486WriteModrmDwordOperands(State
,
1329 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1331 BOOLEAN OperandSize
, AddressSize
;
1332 FAST486_MOD_REG_RM ModRegRm
;
1336 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1337 TOGGLE_OPSIZE(OperandSize
);
1338 TOGGLE_ADSIZE(AddressSize
);
1340 /* Get the number of bits */
1341 if (OperandSize
) DataSize
= 32;
1344 /* Get the operands */
1345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1347 /* Exception occurred */
1351 /* Get the bit number */
1352 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1353 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1355 if (ModRegRm
.Memory
)
1358 * For memory operands, add the bit offset divided by
1359 * the data size to the address
1361 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1364 /* Normalize the bit number */
1365 BitNumber
&= (1 << DataSize
) - 1;
1371 /* Read the value */
1372 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1374 /* Exception occurred */
1378 /* Set CF to the bit value */
1379 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1381 /* Toggle the bit */
1382 Value
^= 1 << BitNumber
;
1384 /* Write back the result */
1385 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1387 /* Exception occurred */
1393 USHORT Dummy
, Value
;
1395 /* Read the value */
1396 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1398 /* Exception occurred */
1402 /* Set CF to the bit value */
1403 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1405 /* Toggle the bit */
1406 Value
^= 1 << BitNumber
;
1408 /* Write back the result */
1409 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1411 /* Exception occurred */
1416 /* Return success */
1420 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1423 ULONG Dummy
= 0, Value
= 0;
1424 BOOLEAN OperandSize
, AddressSize
;
1425 FAST486_MOD_REG_RM ModRegRm
;
1429 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1430 TOGGLE_OPSIZE(OperandSize
);
1431 TOGGLE_ADSIZE(AddressSize
);
1433 /* Make sure this is the right instruction */
1434 ASSERT(Opcode
== 0xBC);
1436 /* Get the number of bits */
1437 if (OperandSize
) DataSize
= 32;
1440 /* Get the operands */
1441 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1443 /* Exception occurred */
1447 /* Read the value */
1450 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1452 /* Exception occurred */
1458 if (!Fast486ReadModrmWordOperands(State
,
1463 /* Exception occurred */
1469 State
->Flags
.Zf
= FALSE
;
1471 for (i
= 0; i
< DataSize
; i
++)
1473 if(Value
& (1 << i
))
1476 State
->Flags
.Zf
= TRUE
;
1478 /* Save the bit number */
1486 if (State
->Flags
.Zf
)
1488 /* Write back the result */
1491 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1493 /* Exception occurred */
1499 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1501 /* Exception occurred */
1510 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1513 ULONG Dummy
= 0, Value
= 0;
1514 BOOLEAN OperandSize
, AddressSize
;
1515 FAST486_MOD_REG_RM ModRegRm
;
1519 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1520 TOGGLE_OPSIZE(OperandSize
);
1521 TOGGLE_ADSIZE(AddressSize
);
1523 /* Make sure this is the right instruction */
1524 ASSERT(Opcode
== 0xBD);
1526 /* Get the number of bits */
1527 if (OperandSize
) DataSize
= 32;
1530 /* Get the operands */
1531 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1533 /* Exception occurred */
1537 /* Read the value */
1540 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1542 /* Exception occurred */
1548 if (!Fast486ReadModrmWordOperands(State
,
1553 /* Exception occurred */
1559 State
->Flags
.Zf
= FALSE
;
1561 for (i
= DataSize
- 1; i
>= 0; i
--)
1563 if(Value
& (1 << i
))
1566 State
->Flags
.Zf
= TRUE
;
1568 /* Save the bit number */
1576 if (State
->Flags
.Zf
)
1578 /* Write back the result */
1581 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1583 /* Exception occurred */
1589 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1591 /* Exception occurred */
1600 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1604 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1605 FAST486_MOD_REG_RM ModRegRm
;
1607 TOGGLE_ADSIZE(AddressSize
);
1609 /* Make sure this is the right instruction */
1610 ASSERT(Opcode
== 0xBE);
1612 /* Get the operands */
1613 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1615 /* Exception occurred */
1619 /* Read the operands */
1620 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, (PUCHAR
)&Value
))
1622 /* Exception occurred */
1626 /* Write back the sign-extended value */
1627 return Fast486WriteModrmDwordOperands(State
,
1630 (ULONG
)((LONG
)Value
));
1633 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1637 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1638 FAST486_MOD_REG_RM ModRegRm
;
1640 TOGGLE_ADSIZE(AddressSize
);
1642 /* Make sure this is the right instruction */
1643 ASSERT(Opcode
== 0xBF);
1645 /* Get the operands */
1646 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1648 /* Exception occurred */
1652 /* Read the operands */
1653 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, (PUSHORT
)&Value
))
1655 /* Exception occurred */
1659 /* Write back the sign-extended value */
1660 return Fast486WriteModrmDwordOperands(State
,
1663 (ULONG
)((LONG
)Value
));
1666 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1668 BOOLEAN Jump
= FALSE
;
1670 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1672 TOGGLE_OPSIZE(Size
);
1675 /* Make sure this is the right instruction */
1676 ASSERT((Opcode
& 0xF0) == 0x80);
1678 /* Fetch the offset */
1681 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
1683 /* Exception occurred */
1691 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
1693 /* Exception occurred */
1698 Offset
= (LONG
)Value
;
1701 switch ((Opcode
& 0x0F) >> 1)
1706 Jump
= State
->Flags
.Of
;
1713 Jump
= State
->Flags
.Cf
;
1720 Jump
= State
->Flags
.Zf
;
1727 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1734 Jump
= State
->Flags
.Sf
;
1741 Jump
= State
->Flags
.Pf
;
1748 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1755 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1762 /* Invert the result */
1768 /* Move the instruction pointer */
1769 State
->InstPtr
.Long
+= Offset
;
1772 /* Return success */
1776 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
1778 BOOLEAN Value
= FALSE
;
1779 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1780 FAST486_MOD_REG_RM ModRegRm
;
1782 TOGGLE_ADSIZE(AddressSize
);
1784 /* Get the operands */
1785 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1787 /* Exception occurred */
1791 /* Make sure this is the right instruction */
1792 ASSERT((Opcode
& 0xF0) == 0x90);
1794 switch ((Opcode
& 0x0F) >> 1)
1799 Value
= State
->Flags
.Of
;
1806 Value
= State
->Flags
.Cf
;
1813 Value
= State
->Flags
.Zf
;
1817 /* SETBE / SETNBE */
1820 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
1827 Value
= State
->Flags
.Sf
;
1834 Value
= State
->Flags
.Pf
;
1841 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
1845 /* SETLE / SETNLE */
1848 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
1855 /* Invert the result */
1859 /* Write back the result */
1860 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1863 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
1865 UCHAR Source
, Destination
, Result
;
1866 FAST486_MOD_REG_RM ModRegRm
;
1867 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1869 /* Make sure this is the right instruction */
1870 ASSERT(Opcode
== 0xC0);
1872 TOGGLE_ADSIZE(AddressSize
);
1874 /* Get the operands */
1875 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1877 /* Exception occurred */
1881 if (!Fast486ReadModrmByteOperands(State
,
1886 /* Exception occurred */
1890 /* Calculate the result */
1891 Result
= Source
+ Destination
;
1893 /* Update the flags */
1894 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1895 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
1896 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1897 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1898 State
->Flags
.Zf
= (Result
== 0);
1899 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1900 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1902 /* Write the sum to the destination */
1903 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
1905 /* Exception occurred */
1909 /* Write the old value of the destination to the source */
1910 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
1912 /* Exception occurred */
1919 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
1921 FAST486_MOD_REG_RM ModRegRm
;
1922 BOOLEAN OperandSize
, AddressSize
;
1924 /* Make sure this is the right instruction */
1925 ASSERT(Opcode
== 0xC1);
1927 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1929 TOGGLE_ADSIZE(AddressSize
);
1930 TOGGLE_OPSIZE(OperandSize
);
1932 /* Get the operands */
1933 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1935 /* Exception occurred */
1939 /* Check the operand size */
1942 ULONG Source
, Destination
, Result
;
1944 if (!Fast486ReadModrmDwordOperands(State
,
1949 /* Exception occurred */
1953 /* Calculate the result */
1954 Result
= Source
+ Destination
;
1956 /* Update the flags */
1957 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1958 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
1959 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1960 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
1961 State
->Flags
.Zf
= (Result
== 0);
1962 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1963 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1965 /* Write the sum to the destination */
1966 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
1968 /* Exception occurred */
1972 /* Write the old value of the destination to the source */
1973 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
1975 /* Exception occurred */
1981 USHORT Source
, Destination
, Result
;
1983 if (!Fast486ReadModrmWordOperands(State
,
1988 /* Exception occurred */
1992 /* Calculate the result */
1993 Result
= Source
+ Destination
;
1995 /* Update the flags */
1996 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
1997 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
1998 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1999 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2000 State
->Flags
.Zf
= (Result
== 0);
2001 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2002 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2004 /* Write the sum to the destination */
2005 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2007 /* Exception occurred */
2011 /* Write the old value of the destination to the source */
2012 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2014 /* Exception occurred */
2022 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2028 /* Get a pointer to the value */
2029 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2031 /* Swap the byte order */
2032 SWAP(Pointer
[0], Pointer
[3]);
2033 SWAP(Pointer
[1], Pointer
[2]);
2035 /* Return success */
2039 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2043 /* Fetch the second operation code */
2044 if (!Fast486FetchByte(State
, &SecondOpcode
))
2046 /* Exception occurred */
2050 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
2052 /* Call the extended opcode handler */
2053 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
2057 /* This is not a valid opcode */
2058 Fast486Exception(State
, FAST486_EXCEPTION_UD
);