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 Fast486OpcodeGroup0F00
,
41 Fast486OpcodeGroup0F01
,
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
,
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(Fast486ExtOpcodeLar
)
302 BOOLEAN OperandSize
, AddressSize
;
303 FAST486_MOD_REG_RM ModRegRm
;
305 FAST486_GDT_ENTRY GdtEntry
;
308 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
310 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
314 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
319 TOGGLE_OPSIZE(OperandSize
);
320 TOGGLE_ADSIZE(AddressSize
);
322 /* Get the operands */
323 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
325 /* Exception occurred */
334 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
336 /* Exception occurred */
340 Selector
= LOWORD(Value
);
345 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
347 /* Exception occurred */
352 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
354 /* Check if the GDT contains the entry */
355 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
357 State
->Flags
.Zf
= FALSE
;
362 if (!Fast486ReadLinearMemory(State
,
364 + GET_SEGMENT_INDEX(Selector
),
368 /* Exception occurred */
374 /* Check if the LDT contains the entry */
375 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
377 State
->Flags
.Zf
= FALSE
;
382 if (!Fast486ReadLinearMemory(State
,
384 + GET_SEGMENT_INDEX(Selector
),
388 /* Exception occurred */
393 /* Privilege check */
394 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
395 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
397 State
->Flags
.Zf
= FALSE
;
402 State
->Flags
.Zf
= TRUE
;
404 /* Get the access rights */
405 AccessRights
= ((PDWORD
)&GdtEntry
)[1] & 0x00F0FF00;
407 /* Return the access rights */
410 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, AccessRights
))
412 /* Exception occurred */
418 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(AccessRights
)))
420 /* Exception occurred */
428 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl
)
430 BOOLEAN OperandSize
, AddressSize
;
431 FAST486_MOD_REG_RM ModRegRm
;
434 FAST486_GDT_ENTRY GdtEntry
;
436 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
438 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
442 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
447 TOGGLE_OPSIZE(OperandSize
);
448 TOGGLE_ADSIZE(AddressSize
);
450 /* Get the operands */
451 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
453 /* Exception occurred */
462 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
464 /* Exception occurred */
468 Selector
= LOWORD(Value
);
473 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
475 /* Exception occurred */
480 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
482 /* Check if the GDT contains the entry */
483 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
485 State
->Flags
.Zf
= FALSE
;
490 if (!Fast486ReadLinearMemory(State
,
492 + GET_SEGMENT_INDEX(Selector
),
496 /* Exception occurred */
502 /* Check if the LDT contains the entry */
503 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
505 State
->Flags
.Zf
= FALSE
;
510 if (!Fast486ReadLinearMemory(State
,
512 + GET_SEGMENT_INDEX(Selector
),
516 /* Exception occurred */
521 /* Privilege check */
522 if (((GET_SEGMENT_RPL(Selector
) > GdtEntry
.Dpl
))
523 || (Fast486GetCurrentPrivLevel(State
) > GdtEntry
.Dpl
))
525 State
->Flags
.Zf
= FALSE
;
529 /* Calculate the limit */
530 Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
531 if (GdtEntry
.Granularity
) Limit
<<= 12;
534 State
->Flags
.Zf
= TRUE
;
538 /* Return the limit */
539 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Limit
))
541 /* Exception occurred */
547 /* Return the limit */
548 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(Limit
)))
550 /* Exception occurred */
558 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts
)
562 /* The current privilege level must be zero */
563 if (Fast486GetCurrentPrivLevel(State
) != 0)
565 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
569 /* Clear the task switch bit */
570 State
->ControlRegisters
[FAST486_REG_CR0
] &= ~FAST486_CR0_TS
;
575 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg
)
577 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
578 FAST486_MOD_REG_RM ModRegRm
;
581 TOGGLE_ADSIZE(AddressSize
);
583 /* Get the operands */
584 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
586 /* Exception occurred */
590 /* The current privilege level must be zero */
591 if (Fast486GetCurrentPrivLevel(State
) != 0)
593 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
597 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
599 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
600 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
604 if (ModRegRm
.Register
!= 0)
606 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
610 /* Store the value of the control register */
611 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->ControlRegisters
[ModRegRm
.Register
];
617 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg
)
619 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
620 FAST486_MOD_REG_RM ModRegRm
;
623 TOGGLE_ADSIZE(AddressSize
);
625 /* Get the operands */
626 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
628 /* Exception occurred */
632 /* The current privilege level must be zero */
633 if (Fast486GetCurrentPrivLevel(State
) != 0)
635 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
639 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
641 /* DR6 and DR7 are aliases to DR4 and DR5 */
642 ModRegRm
.Register
-= 2;
645 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
647 /* Disallow access to debug registers */
648 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
652 /* Store the value of the debug register */
653 State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
= State
->DebugRegisters
[ModRegRm
.Register
];
659 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg
)
662 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
663 FAST486_MOD_REG_RM ModRegRm
;
666 TOGGLE_ADSIZE(AddressSize
);
668 /* Get the operands */
669 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
671 /* Exception occurred */
675 /* The current privilege level must be zero */
676 if (Fast486GetCurrentPrivLevel(State
) != 0)
678 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
682 if ((ModRegRm
.Register
== 1) || (ModRegRm
.Register
> 3))
684 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
685 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
689 if (ModRegRm
.Register
!= 0)
691 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
696 Value
= State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
698 if (ModRegRm
.Register
== (INT
)FAST486_REG_CR0
)
702 if (((Value
& (FAST486_CR0_PG
| FAST486_CR0_PE
)) == FAST486_CR0_PG
)
703 || ((Value
& (FAST486_CR0_CD
| FAST486_CR0_NW
)) == FAST486_CR0_NW
))
706 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
711 /* Load a value to the control register */
712 State
->ControlRegisters
[ModRegRm
.Register
] = Value
;
718 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg
)
720 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
721 FAST486_MOD_REG_RM ModRegRm
;
724 TOGGLE_ADSIZE(AddressSize
);
726 /* Get the operands */
727 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
729 /* Exception occurred */
733 /* The current privilege level must be zero */
734 if (Fast486GetCurrentPrivLevel(State
) != 0)
736 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
740 if ((ModRegRm
.Register
== 6) || (ModRegRm
.Register
== 7))
742 /* DR6 and DR7 are aliases to DR4 and DR5 */
743 ModRegRm
.Register
-= 2;
746 if (State
->DebugRegisters
[FAST486_REG_DR5
] & FAST486_DR5_GD
)
748 /* Disallow access to debug registers */
749 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
753 /* Load a value to the debug register */
754 State
->DebugRegisters
[ModRegRm
.Register
] = State
->GeneralRegs
[ModRegRm
.SecondRegister
].Long
;
756 if (ModRegRm
.Register
== (INT
)FAST486_REG_DR4
)
758 /* The reserved bits are 1 */
759 State
->DebugRegisters
[ModRegRm
.Register
] |= FAST486_DR4_RESERVED
;
761 else if (ModRegRm
.Register
== (INT
)FAST486_REG_DR5
)
763 /* The reserved bits are 0 */
764 State
->DebugRegisters
[ModRegRm
.Register
] &= ~FAST486_DR5_RESERVED
;
771 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs
)
773 /* Call the internal API */
774 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
);
777 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs
)
781 if (!Fast486StackPop(State
, &NewSelector
))
783 /* Exception occurred */
787 /* Call the internal API */
788 return Fast486LoadSegment(State
, FAST486_REG_FS
, LOWORD(NewSelector
));
791 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest
)
793 BOOLEAN OperandSize
, AddressSize
;
794 FAST486_MOD_REG_RM ModRegRm
;
798 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
799 TOGGLE_OPSIZE(OperandSize
);
800 TOGGLE_ADSIZE(AddressSize
);
802 /* Get the number of bits */
803 if (OperandSize
) DataSize
= 32;
806 /* Get the operands */
807 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
809 /* Exception occurred */
813 /* Get the bit number */
814 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
815 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
820 * For memory operands, add the bit offset divided by
821 * the data size to the address
823 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
826 /* Normalize the bit number */
827 BitNumber
%= DataSize
;
834 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
836 /* Exception occurred */
840 /* Set CF to the bit value */
841 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
848 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
850 /* Exception occurred */
854 /* Set CF to the bit value */
855 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
862 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld
)
864 BOOLEAN OperandSize
, AddressSize
;
865 FAST486_MOD_REG_RM ModRegRm
;
868 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
869 TOGGLE_OPSIZE(OperandSize
);
870 TOGGLE_ADSIZE(AddressSize
);
872 /* Make sure this is the right instruction */
873 ASSERT((Opcode
& 0xFE) == 0xA4);
875 /* Get the operands */
876 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
878 /* Exception occurred */
884 /* Fetch the count */
885 if (!Fast486FetchByte(State
, &Count
))
887 /* Exception occurred */
893 /* The count is in CL */
894 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
897 /* Normalize the count */
900 /* Do nothing if the count is zero */
901 if (Count
== 0) return TRUE
;
905 ULONG Source
, Destination
, Result
;
907 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
909 /* Exception occurred */
913 /* Calculate the result */
914 Result
= (Destination
<< Count
) | (Source
>> (32 - Count
));
917 State
->Flags
.Cf
= (Destination
>> (32 - Count
)) & 1;
918 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
919 != (Destination
& SIGN_FLAG_LONG
);
920 State
->Flags
.Zf
= (Result
== 0);
921 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
922 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
924 /* Write back the result */
925 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
929 USHORT Source
, Destination
, Result
;
932 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
934 /* Exception occurred */
938 DoubleSource
= Source
| (Source
<< 16);
940 /* Calculate the result */
941 Result
= (Destination
<< Count
) | (DoubleSource
>> (32 - Count
));
944 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (16 - Count
)) & 1;
945 else State
->Flags
.Cf
= (Source
>> (32 - Count
)) & 1;
947 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
948 != (Destination
& SIGN_FLAG_WORD
);
949 State
->Flags
.Zf
= (Result
== 0);
950 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
951 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
953 /* Write back the result */
954 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
958 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs
)
960 /* Call the internal API */
961 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
);
964 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs
)
968 if (!Fast486StackPop(State
, &NewSelector
))
970 /* Exception occurred */
974 /* Call the internal API */
975 return Fast486LoadSegment(State
, FAST486_REG_GS
, LOWORD(NewSelector
));
978 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts
)
980 BOOLEAN OperandSize
, AddressSize
;
981 FAST486_MOD_REG_RM ModRegRm
;
985 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
986 TOGGLE_OPSIZE(OperandSize
);
987 TOGGLE_ADSIZE(AddressSize
);
989 /* Get the number of bits */
990 if (OperandSize
) DataSize
= 32;
993 /* Get the operands */
994 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
996 /* Exception occurred */
1000 /* Get the bit number */
1001 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1002 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1004 if (ModRegRm
.Memory
)
1007 * For memory operands, add the bit offset divided by
1008 * the data size to the address
1010 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1013 /* Normalize the bit number */
1014 BitNumber
%= DataSize
;
1020 /* Read the value */
1021 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1023 /* Exception occurred */
1027 /* Set CF to the bit value */
1028 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1031 Value
|= 1 << BitNumber
;
1033 /* Write back the result */
1034 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1036 /* Exception occurred */
1044 /* Read the value */
1045 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1047 /* Exception occurred */
1051 /* Set CF to the bit value */
1052 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1055 Value
|= 1 << BitNumber
;
1057 /* Write back the result */
1058 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1060 /* Exception occurred */
1065 /* Return success */
1069 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd
)
1071 BOOLEAN OperandSize
, AddressSize
;
1072 FAST486_MOD_REG_RM ModRegRm
;
1075 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1076 TOGGLE_OPSIZE(OperandSize
);
1077 TOGGLE_ADSIZE(AddressSize
);
1079 /* Make sure this is the right instruction */
1080 ASSERT((Opcode
& 0xFE) == 0xAC);
1082 /* Get the operands */
1083 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1085 /* Exception occurred */
1091 /* Fetch the count */
1092 if (!Fast486FetchByte(State
, &Count
))
1094 /* Exception occurred */
1100 /* The count is in CL */
1101 Count
= State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
;
1104 /* Normalize the count */
1107 /* Do nothing if the count is zero */
1108 if (Count
== 0) return TRUE
;
1112 ULONG Source
, Destination
, Result
;
1114 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1116 /* Exception occurred */
1120 /* Calculate the result */
1121 Result
= (Destination
>> Count
) | (Source
<< (32 - Count
));
1124 State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1125 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_LONG
)
1126 != (Destination
& SIGN_FLAG_LONG
);
1127 State
->Flags
.Zf
= (Result
== 0);
1128 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1129 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1131 /* Write back the result */
1132 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1136 USHORT Source
, Destination
, Result
;
1138 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1140 /* Exception occurred */
1144 /* Calculate the result */
1145 Result
= (Destination
>> Count
) | (Source
<< (16 - Count
));
1147 if (Count
>= 16) Result
|= (ULONG
)(Source
| (Source
<< 16)) >> (Count
- 16);
1150 if (Count
<= 16) State
->Flags
.Cf
= (Destination
>> (Count
- 1)) & 1;
1151 else State
->Flags
.Cf
= (Source
>> (Count
- 17)) & 1;
1153 if (Count
== 1) State
->Flags
.Of
= (Result
& SIGN_FLAG_WORD
)
1154 != (Destination
& SIGN_FLAG_WORD
);
1155 State
->Flags
.Zf
= (Result
== 0);
1156 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1157 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1159 /* Write back the result */
1160 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
);
1164 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul
)
1166 BOOLEAN OperandSize
, AddressSize
;
1167 FAST486_MOD_REG_RM ModRegRm
;
1169 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1171 TOGGLE_OPSIZE(OperandSize
);
1172 TOGGLE_ADSIZE(AddressSize
);
1174 /* Get the operands */
1175 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1177 /* Exception occurred */
1183 LONG Source
, Destination
;
1186 /* Read the operands */
1187 if (!Fast486ReadModrmDwordOperands(State
,
1189 (PULONG
)&Destination
,
1192 /* Exception occurred */
1196 /* Calculate the result */
1197 Result
= (LONGLONG
)Source
* (LONGLONG
)Destination
;
1199 /* Update the flags */
1200 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1202 /* Write back the result */
1203 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, (ULONG
)((LONG
)Result
));
1207 SHORT Source
, Destination
;
1210 /* Read the operands */
1211 if (!Fast486ReadModrmWordOperands(State
,
1213 (PUSHORT
)&Destination
,
1216 /* Exception occurred */
1220 /* Calculate the result */
1221 Result
= (LONG
)Source
* (LONG
)Destination
;
1223 /* Update the flags */
1224 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1226 /* Write back the result */
1227 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, (USHORT
)((SHORT
)Result
));
1231 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte
)
1233 FAST486_MOD_REG_RM ModRegRm
;
1234 UCHAR Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1235 UCHAR Source
, Destination
, Result
;
1236 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1238 TOGGLE_ADSIZE(AddressSize
);
1240 /* Get the operands */
1241 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1243 /* Exception occurred */
1247 /* Read the operands */
1248 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Source
, &Destination
))
1250 /* Exception occurred */
1254 /* Compare AL with the destination */
1255 Result
= Accumulator
- Destination
;
1257 /* Update the flags */
1258 State
->Flags
.Cf
= (Accumulator
< Destination
);
1259 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_BYTE
) != (Destination
& SIGN_FLAG_BYTE
))
1260 && ((Accumulator
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1261 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1262 State
->Flags
.Zf
= (Result
== 0);
1263 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1264 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1266 if (State
->Flags
.Zf
)
1268 /* Load the source operand into the destination */
1269 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Source
);
1273 /* Load the destination into AL */
1274 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Destination
;
1277 /* Return success */
1281 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg
)
1283 FAST486_MOD_REG_RM ModRegRm
;
1284 BOOLEAN OperandSize
, AddressSize
;
1286 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1288 TOGGLE_OPSIZE(OperandSize
);
1289 TOGGLE_ADSIZE(AddressSize
);
1291 /* Get the operands */
1292 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1294 /* Exception occurred */
1300 ULONG Source
, Destination
, Result
;
1301 ULONG Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1303 /* Read the operands */
1304 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1306 /* Exception occurred */
1310 /* Compare EAX with the destination */
1311 Result
= Accumulator
- Destination
;
1313 /* Update the flags */
1314 State
->Flags
.Cf
= (Accumulator
< Destination
);
1315 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_LONG
) != (Destination
& SIGN_FLAG_LONG
))
1316 && ((Accumulator
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1317 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1318 State
->Flags
.Zf
= (Result
== 0);
1319 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1320 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1322 if (State
->Flags
.Zf
)
1324 /* Load the source operand into the destination */
1325 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Source
);
1329 /* Load the destination into EAX */
1330 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Destination
;
1335 USHORT Source
, Destination
, Result
;
1336 USHORT Accumulator
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1338 /* Read the operands */
1339 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Source
, &Destination
))
1341 /* Exception occurred */
1345 /* Compare AX with the destination */
1346 Result
= Accumulator
- Destination
;
1348 /* Update the flags */
1349 State
->Flags
.Cf
= (Accumulator
< Destination
);
1350 State
->Flags
.Of
= ((Accumulator
& SIGN_FLAG_WORD
) != (Destination
& SIGN_FLAG_WORD
))
1351 && ((Accumulator
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1352 State
->Flags
.Af
= (Accumulator
& 0x0F) < (Destination
& 0x0F);
1353 State
->Flags
.Zf
= (Result
== 0);
1354 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1355 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1357 if (State
->Flags
.Zf
)
1359 /* Load the source operand into the destination */
1360 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Source
);
1364 /* Load the destination into AX */
1365 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Destination
;
1369 /* Return success */
1373 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss
)
1375 UCHAR FarPointer
[6];
1376 BOOLEAN OperandSize
, AddressSize
;
1377 FAST486_MOD_REG_RM ModRegRm
;
1379 /* Make sure this is the right instruction */
1380 ASSERT(Opcode
== 0xB2);
1382 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1384 TOGGLE_OPSIZE(OperandSize
);
1385 TOGGLE_ADSIZE(AddressSize
);
1387 /* Get the operands */
1388 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1390 /* Exception occurred */
1394 if (!ModRegRm
.Memory
)
1397 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1401 if (!Fast486ReadMemory(State
,
1402 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1403 ? State
->SegmentOverride
: FAST486_REG_DS
,
1404 ModRegRm
.MemoryAddress
,
1407 OperandSize
? 6 : 4))
1409 /* Exception occurred */
1415 ULONG Offset
= *((PULONG
)FarPointer
);
1416 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1418 /* Set the register to the offset */
1419 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1421 /* Load the segment */
1422 return Fast486LoadSegment(State
,
1428 USHORT Offset
= *((PUSHORT
)FarPointer
);
1429 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1431 /* Set the register to the offset */
1432 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1434 /* Load the segment */
1435 return Fast486LoadSegment(State
,
1441 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr
)
1443 BOOLEAN OperandSize
, AddressSize
;
1444 FAST486_MOD_REG_RM ModRegRm
;
1448 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1449 TOGGLE_OPSIZE(OperandSize
);
1450 TOGGLE_ADSIZE(AddressSize
);
1452 /* Get the number of bits */
1453 if (OperandSize
) DataSize
= 32;
1456 /* Get the operands */
1457 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1459 /* Exception occurred */
1463 /* Get the bit number */
1464 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1465 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1467 if (ModRegRm
.Memory
)
1470 * For memory operands, add the bit offset divided by
1471 * the data size to the address
1473 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1476 /* Normalize the bit number */
1477 BitNumber
%= DataSize
;
1483 /* Read the value */
1484 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1486 /* Exception occurred */
1490 /* Set CF to the bit value */
1491 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1494 Value
&= ~(1 << BitNumber
);
1496 /* Write back the result */
1497 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1499 /* Exception occurred */
1507 /* Read the value */
1508 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1510 /* Exception occurred */
1514 /* Set CF to the bit value */
1515 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1518 Value
&= ~(1 << BitNumber
);
1520 /* Write back the result */
1521 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1523 /* Exception occurred */
1528 /* Return success */
1532 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs
)
1534 UCHAR FarPointer
[6];
1535 BOOLEAN OperandSize
, AddressSize
;
1536 FAST486_MOD_REG_RM ModRegRm
;
1538 /* Make sure this is the right instruction */
1539 ASSERT((Opcode
& 0xFE) == 0xB4);
1541 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1543 TOGGLE_OPSIZE(OperandSize
);
1544 TOGGLE_ADSIZE(AddressSize
);
1546 /* Get the operands */
1547 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1549 /* Exception occurred */
1553 if (!ModRegRm
.Memory
)
1556 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1560 if (!Fast486ReadMemory(State
,
1561 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1562 ? State
->SegmentOverride
: FAST486_REG_DS
,
1563 ModRegRm
.MemoryAddress
,
1566 OperandSize
? 6 : 4))
1568 /* Exception occurred */
1574 ULONG Offset
= *((PULONG
)FarPointer
);
1575 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
1577 /* Set the register to the offset */
1578 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
1580 /* Load the segment */
1581 return Fast486LoadSegment(State
,
1583 ? FAST486_REG_FS
: FAST486_REG_GS
,
1588 USHORT Offset
= *((PUSHORT
)FarPointer
);
1589 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
1591 /* Set the register to the offset */
1592 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
1594 /* Load the segment */
1595 return Fast486LoadSegment(State
,
1597 ? FAST486_REG_FS
: FAST486_REG_GS
,
1602 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte
)
1605 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1606 FAST486_MOD_REG_RM ModRegRm
;
1608 TOGGLE_ADSIZE(AddressSize
);
1610 /* Make sure this is the right instruction */
1611 ASSERT(Opcode
== 0xB6);
1613 /* Get the operands */
1614 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1616 /* Exception occurred */
1620 /* Read the operands */
1621 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1623 /* Exception occurred */
1627 /* Write back the zero-extended value */
1628 return Fast486WriteModrmDwordOperands(State
,
1634 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord
)
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
== 0xB7);
1645 /* Get the operands */
1646 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1648 /* Exception occurred */
1652 /* Read the operands */
1653 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1655 /* Exception occurred */
1659 /* Write back the zero-extended value */
1660 return Fast486WriteModrmDwordOperands(State
,
1666 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc
)
1668 BOOLEAN OperandSize
, AddressSize
;
1669 FAST486_MOD_REG_RM ModRegRm
;
1673 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1674 TOGGLE_OPSIZE(OperandSize
);
1675 TOGGLE_ADSIZE(AddressSize
);
1677 /* Get the number of bits */
1678 if (OperandSize
) DataSize
= 32;
1681 /* Get the operands */
1682 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1684 /* Exception occurred */
1688 /* Get the bit number */
1689 BitNumber
= OperandSize
? State
->GeneralRegs
[ModRegRm
.Register
].Long
1690 : (ULONG
)State
->GeneralRegs
[ModRegRm
.Register
].LowWord
;
1692 if (ModRegRm
.Memory
)
1695 * For memory operands, add the bit offset divided by
1696 * the data size to the address
1698 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1701 /* Normalize the bit number */
1702 BitNumber
%= DataSize
;
1708 /* Read the value */
1709 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1711 /* Exception occurred */
1715 /* Set CF to the bit value */
1716 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1718 /* Toggle the bit */
1719 Value
^= 1 << BitNumber
;
1721 /* Write back the result */
1722 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1724 /* Exception occurred */
1732 /* Read the value */
1733 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1735 /* Exception occurred */
1739 /* Set CF to the bit value */
1740 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1742 /* Toggle the bit */
1743 Value
^= 1 << BitNumber
;
1745 /* Write back the result */
1746 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1748 /* Exception occurred */
1753 /* Return success */
1757 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf
)
1761 BOOLEAN OperandSize
, AddressSize
;
1762 FAST486_MOD_REG_RM ModRegRm
;
1766 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1767 TOGGLE_OPSIZE(OperandSize
);
1768 TOGGLE_ADSIZE(AddressSize
);
1770 /* Make sure this is the right instruction */
1771 ASSERT(Opcode
== 0xBC);
1773 /* Get the number of bits */
1774 if (OperandSize
) DataSize
= 32;
1777 /* Get the operands */
1778 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1780 /* Exception occurred */
1784 /* Read the value */
1787 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1789 /* Exception occurred */
1795 if (!Fast486ReadModrmWordOperands(State
,
1800 /* Exception occurred */
1806 State
->Flags
.Zf
= (Value
== 0);
1807 if (State
->Flags
.Zf
) return TRUE
;
1809 for (i
= 0; i
< DataSize
; i
++)
1811 if(Value
& (1 << i
))
1813 /* Save the bit number */
1821 /* Write back the result */
1824 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1826 /* Exception occurred */
1832 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1834 /* Exception occurred */
1842 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr
)
1846 BOOLEAN OperandSize
, AddressSize
;
1847 FAST486_MOD_REG_RM ModRegRm
;
1851 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1852 TOGGLE_OPSIZE(OperandSize
);
1853 TOGGLE_ADSIZE(AddressSize
);
1855 /* Make sure this is the right instruction */
1856 ASSERT(Opcode
== 0xBD);
1858 /* Get the number of bits */
1859 if (OperandSize
) DataSize
= 32;
1862 /* Get the operands */
1863 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1865 /* Exception occurred */
1869 /* Read the value */
1872 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1874 /* Exception occurred */
1880 if (!Fast486ReadModrmWordOperands(State
,
1885 /* Exception occurred */
1890 /* Set ZF according to the value */
1891 State
->Flags
.Zf
= (Value
== 0);
1892 if (State
->Flags
.Zf
) return TRUE
;
1894 for (i
= DataSize
- 1; i
>= 0; i
--)
1896 if(Value
& (1 << i
))
1898 /* Save the bit number */
1906 /* Write back the result */
1909 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, BitNumber
))
1911 /* Exception occurred */
1917 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, LOWORD(BitNumber
)))
1919 /* Exception occurred */
1927 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte
)
1930 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1931 FAST486_MOD_REG_RM ModRegRm
;
1933 TOGGLE_ADSIZE(AddressSize
);
1935 /* Make sure this is the right instruction */
1936 ASSERT(Opcode
== 0xBE);
1938 /* Get the operands */
1939 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1941 /* Exception occurred */
1945 /* Read the operands */
1946 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, (PUCHAR
)&Value
))
1948 /* Exception occurred */
1952 /* Write back the sign-extended value */
1953 return Fast486WriteModrmDwordOperands(State
,
1956 (ULONG
)((LONG
)Value
));
1959 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord
)
1962 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1963 FAST486_MOD_REG_RM ModRegRm
;
1965 TOGGLE_ADSIZE(AddressSize
);
1967 /* Make sure this is the right instruction */
1968 ASSERT(Opcode
== 0xBF);
1970 /* Get the operands */
1971 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1973 /* Exception occurred */
1977 /* Read the operands */
1978 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1980 /* Exception occurred */
1984 /* Write back the sign-extended value */
1985 return Fast486WriteModrmDwordOperands(State
,
1988 (ULONG
)((LONG
)Value
));
1991 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp
)
1993 BOOLEAN Jump
= FALSE
;
1995 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1997 TOGGLE_OPSIZE(Size
);
2000 /* Make sure this is the right instruction */
2001 ASSERT((Opcode
& 0xF0) == 0x80);
2003 /* Fetch the offset */
2006 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
2008 /* Exception occurred */
2016 if (!Fast486FetchWord(State
, (PUSHORT
)&Value
))
2018 /* Exception occurred */
2023 Offset
= (LONG
)Value
;
2026 switch ((Opcode
& 0x0F) >> 1)
2031 Jump
= State
->Flags
.Of
;
2038 Jump
= State
->Flags
.Cf
;
2045 Jump
= State
->Flags
.Zf
;
2052 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2059 Jump
= State
->Flags
.Sf
;
2066 Jump
= State
->Flags
.Pf
;
2073 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2080 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2087 /* Invert the result */
2093 /* Move the instruction pointer */
2094 State
->InstPtr
.Long
+= Offset
;
2097 /* Return success */
2101 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet
)
2103 BOOLEAN Value
= FALSE
;
2104 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2105 FAST486_MOD_REG_RM ModRegRm
;
2107 TOGGLE_ADSIZE(AddressSize
);
2109 /* Get the operands */
2110 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2112 /* Exception occurred */
2116 /* Make sure this is the right instruction */
2117 ASSERT((Opcode
& 0xF0) == 0x90);
2119 switch ((Opcode
& 0x0F) >> 1)
2124 Value
= State
->Flags
.Of
;
2131 Value
= State
->Flags
.Cf
;
2138 Value
= State
->Flags
.Zf
;
2142 /* SETBE / SETNBE */
2145 Value
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
2152 Value
= State
->Flags
.Sf
;
2159 Value
= State
->Flags
.Pf
;
2166 Value
= State
->Flags
.Sf
!= State
->Flags
.Of
;
2170 /* SETLE / SETNLE */
2173 Value
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
2180 /* Invert the result */
2184 /* Write back the result */
2185 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
2188 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte
)
2190 UCHAR Source
, Destination
, Result
;
2191 FAST486_MOD_REG_RM ModRegRm
;
2192 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2194 /* Make sure this is the right instruction */
2195 ASSERT(Opcode
== 0xC0);
2197 TOGGLE_ADSIZE(AddressSize
);
2199 /* Get the operands */
2200 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2202 /* Exception occurred */
2206 if (!Fast486ReadModrmByteOperands(State
,
2211 /* Exception occurred */
2215 /* Calculate the result */
2216 Result
= Source
+ Destination
;
2218 /* Update the flags */
2219 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2220 State
->Flags
.Of
= ((Source
& SIGN_FLAG_BYTE
) == (Destination
& SIGN_FLAG_BYTE
))
2221 && ((Source
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2222 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2223 State
->Flags
.Zf
= (Result
== 0);
2224 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2225 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2227 /* Write the sum to the destination */
2228 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
))
2230 /* Exception occurred */
2234 /* Write the old value of the destination to the source */
2235 if (!Fast486WriteModrmByteOperands(State
, &ModRegRm
, TRUE
, Destination
))
2237 /* Exception occurred */
2244 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd
)
2246 FAST486_MOD_REG_RM ModRegRm
;
2247 BOOLEAN OperandSize
, AddressSize
;
2249 /* Make sure this is the right instruction */
2250 ASSERT(Opcode
== 0xC1);
2252 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2254 TOGGLE_ADSIZE(AddressSize
);
2255 TOGGLE_OPSIZE(OperandSize
);
2257 /* Get the operands */
2258 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2260 /* Exception occurred */
2264 /* Check the operand size */
2267 ULONG Source
, Destination
, Result
;
2269 if (!Fast486ReadModrmDwordOperands(State
,
2274 /* Exception occurred */
2278 /* Calculate the result */
2279 Result
= Source
+ Destination
;
2281 /* Update the flags */
2282 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2283 State
->Flags
.Of
= ((Source
& SIGN_FLAG_LONG
) == (Destination
& SIGN_FLAG_LONG
))
2284 && ((Source
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2285 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2286 State
->Flags
.Zf
= (Result
== 0);
2287 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2288 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2290 /* Write the old value of the destination to the source */
2291 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2293 /* Exception occurred */
2297 /* Write the sum to the destination */
2298 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
))
2300 /* Exception occurred */
2306 USHORT Source
, Destination
, Result
;
2308 if (!Fast486ReadModrmWordOperands(State
,
2313 /* Exception occurred */
2317 /* Calculate the result */
2318 Result
= Source
+ Destination
;
2320 /* Update the flags */
2321 State
->Flags
.Cf
= (Result
< Source
) && (Result
< Destination
);
2322 State
->Flags
.Of
= ((Source
& SIGN_FLAG_WORD
) == (Destination
& SIGN_FLAG_WORD
))
2323 && ((Source
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2324 State
->Flags
.Af
= ((((Source
& 0x0F) + (Destination
& 0x0F)) & 0x10) != 0);
2325 State
->Flags
.Zf
= (Result
== 0);
2326 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2327 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2329 /* Write the old value of the destination to the source */
2330 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, TRUE
, Destination
))
2332 /* Exception occurred */
2336 /* Write the sum to the destination */
2337 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Result
))
2339 /* Exception occurred */
2347 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap
)
2353 /* Get a pointer to the value */
2354 Pointer
= (PUCHAR
)&State
->GeneralRegs
[Opcode
& 0x07].Long
;
2356 /* Swap the byte order */
2357 SWAP(Pointer
[0], Pointer
[3]);
2358 SWAP(Pointer
[1], Pointer
[2]);
2360 /* Return success */
2364 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended
)
2368 /* Fetch the second operation code */
2369 if (!Fast486FetchByte(State
, &SecondOpcode
))
2371 /* Exception occurred */
2375 if (Fast486ExtendedHandlers
[SecondOpcode
] != NULL
)
2377 /* Call the extended opcode handler */
2378 return Fast486ExtendedHandlers
[SecondOpcode
](State
, SecondOpcode
);
2382 /* This is not a valid opcode */
2383 Fast486Exception(State
, FAST486_EXCEPTION_UD
);