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 *******************************************************************/
36 /* PUBLIC VARIABLES ***********************************************************/
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
41 Fast486OpcodeAddByteModrm
,
42 Fast486OpcodeAddModrm
,
43 Fast486OpcodeAddByteModrm
,
44 Fast486OpcodeAddModrm
,
49 Fast486OpcodeOrByteModrm
,
51 Fast486OpcodeOrByteModrm
,
56 Fast486OpcodeExtended
,
57 Fast486OpcodeAdcByteModrm
,
58 Fast486OpcodeAdcModrm
,
59 Fast486OpcodeAdcByteModrm
,
60 Fast486OpcodeAdcModrm
,
65 Fast486OpcodeSbbByteModrm
,
66 Fast486OpcodeSbbModrm
,
67 Fast486OpcodeSbbByteModrm
,
68 Fast486OpcodeSbbModrm
,
73 Fast486OpcodeAndByteModrm
,
74 Fast486OpcodeAndModrm
,
75 Fast486OpcodeAndByteModrm
,
76 Fast486OpcodeAndModrm
,
81 Fast486OpcodeCmpSubByteModrm
,
82 Fast486OpcodeCmpSubModrm
,
83 Fast486OpcodeCmpSubByteModrm
,
84 Fast486OpcodeCmpSubModrm
,
85 Fast486OpcodeCmpSubAl
,
86 Fast486OpcodeCmpSubEax
,
89 Fast486OpcodeXorByteModrm
,
90 Fast486OpcodeXorModrm
,
91 Fast486OpcodeXorByteModrm
,
92 Fast486OpcodeXorModrm
,
97 Fast486OpcodeCmpSubByteModrm
,
98 Fast486OpcodeCmpSubModrm
,
99 Fast486OpcodeCmpSubByteModrm
,
100 Fast486OpcodeCmpSubModrm
,
101 Fast486OpcodeCmpSubAl
,
102 Fast486OpcodeCmpSubEax
,
105 Fast486OpcodeIncrement
,
106 Fast486OpcodeIncrement
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeIncrement
,
113 Fast486OpcodeDecrement
,
114 Fast486OpcodeDecrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodeDecrement
,
121 Fast486OpcodePushReg
,
122 Fast486OpcodePushReg
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
128 Fast486OpcodePushReg
,
137 Fast486OpcodePushAll
,
145 Fast486OpcodePushImm
,
146 Fast486OpcodeImulModrmImm
,
147 Fast486OpcodePushByteImm
,
148 Fast486OpcodeImulModrmImm
,
153 Fast486OpcodeShortConditionalJmp
,
154 Fast486OpcodeShortConditionalJmp
,
155 Fast486OpcodeShortConditionalJmp
,
156 Fast486OpcodeShortConditionalJmp
,
157 Fast486OpcodeShortConditionalJmp
,
158 Fast486OpcodeShortConditionalJmp
,
159 Fast486OpcodeShortConditionalJmp
,
160 Fast486OpcodeShortConditionalJmp
,
161 Fast486OpcodeShortConditionalJmp
,
162 Fast486OpcodeShortConditionalJmp
,
163 Fast486OpcodeShortConditionalJmp
,
164 Fast486OpcodeShortConditionalJmp
,
165 Fast486OpcodeShortConditionalJmp
,
166 Fast486OpcodeShortConditionalJmp
,
167 Fast486OpcodeShortConditionalJmp
,
168 Fast486OpcodeShortConditionalJmp
,
169 Fast486OpcodeGroup8082
,
170 Fast486OpcodeGroup81
,
171 Fast486OpcodeGroup8082
,
172 Fast486OpcodeGroup83
,
173 Fast486OpcodeTestByteModrm
,
174 Fast486OpcodeTestModrm
,
175 Fast486OpcodeXchgByteModrm
,
176 Fast486OpcodeXchgModrm
,
177 Fast486OpcodeMovByteModrm
,
178 Fast486OpcodeMovModrm
,
179 Fast486OpcodeMovByteModrm
,
180 Fast486OpcodeMovModrm
,
181 Fast486OpcodeMovStoreSeg
,
183 Fast486OpcodeMovLoadSeg
,
184 Fast486OpcodeGroup8F
,
186 Fast486OpcodeExchangeEax
,
187 Fast486OpcodeExchangeEax
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
192 Fast486OpcodeExchangeEax
,
195 Fast486OpcodeCallAbs
,
197 Fast486OpcodePushFlags
,
198 Fast486OpcodePopFlags
,
201 Fast486OpcodeMovAlOffset
,
202 Fast486OpcodeMovEaxOffset
,
203 Fast486OpcodeMovOffsetAl
,
204 Fast486OpcodeMovOffsetEax
,
210 Fast486OpcodeTestEax
,
217 Fast486OpcodeMovByteRegImm
,
218 Fast486OpcodeMovByteRegImm
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovByteRegImm
,
225 Fast486OpcodeMovRegImm
,
226 Fast486OpcodeMovRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeMovRegImm
,
233 Fast486OpcodeGroupC0
,
234 Fast486OpcodeGroupC1
,
239 Fast486OpcodeGroupC6
,
240 Fast486OpcodeGroupC7
,
249 Fast486OpcodeGroupD0
,
250 Fast486OpcodeGroupD1
,
251 Fast486OpcodeGroupD2
,
252 Fast486OpcodeGroupD3
,
271 Fast486OpcodeOutByte
,
276 Fast486OpcodeShortJump
,
279 Fast486OpcodeOutByte
,
286 Fast486OpcodeComplCarry
,
287 Fast486OpcodeGroupF6
,
288 Fast486OpcodeGroupF7
,
289 Fast486OpcodeClearCarry
,
290 Fast486OpcodeSetCarry
,
291 Fast486OpcodeClearInt
,
293 Fast486OpcodeClearDir
,
295 Fast486OpcodeGroupFE
,
296 Fast486OpcodeGroupFF
,
299 /* PUBLIC FUNCTIONS ***********************************************************/
301 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
303 BOOLEAN Valid
= FALSE
;
310 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
312 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
313 State
->SegmentOverride
= FAST486_REG_ES
;
323 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
325 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
326 State
->SegmentOverride
= FAST486_REG_CS
;
336 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
338 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
339 State
->SegmentOverride
= FAST486_REG_SS
;
349 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
351 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
352 State
->SegmentOverride
= FAST486_REG_DS
;
362 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
364 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
365 State
->SegmentOverride
= FAST486_REG_FS
;
375 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
377 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
378 State
->SegmentOverride
= FAST486_REG_GS
;
388 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
390 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
400 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
402 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
411 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
413 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
423 /* Mutually exclusive with REP */
424 if (!(State
->PrefixFlags
425 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
427 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
437 /* Mutually exclusive with REPNZ */
438 if (!(State
->PrefixFlags
439 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
441 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
451 /* Clear all prefixes */
452 State
->PrefixFlags
= 0;
454 /* Throw an exception */
455 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
462 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
465 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
470 /* Make sure this is the right instruction */
471 ASSERT((Opcode
& 0xF8) == 0x40);
475 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
477 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
478 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
482 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
484 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
485 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
488 State
->Flags
.Zf
= (Value
== 0);
489 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
490 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
496 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
499 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
504 /* Make sure this is the right instruction */
505 ASSERT((Opcode
& 0xF8) == 0x48);
509 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
511 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
512 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
516 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
518 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
519 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
522 State
->Flags
.Zf
= (Value
== 0);
523 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
524 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
530 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
534 /* Make sure this is the right instruction */
535 ASSERT((Opcode
& 0xF8) == 0x50);
537 /* Call the internal function */
538 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
541 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
544 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
549 /* Make sure this is the right instruction */
550 ASSERT((Opcode
& 0xF8) == 0x58);
552 /* Call the internal function */
553 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
555 /* Store the value */
556 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
557 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
563 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
565 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
568 State
->IdleCallback(State
);
574 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
576 INT Reg
= Opcode
& 0x07;
577 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
582 /* Make sure this is the right instruction */
583 ASSERT((Opcode
& 0xF8) == 0x90);
585 /* Exchange the values */
590 Value
= State
->GeneralRegs
[Reg
].Long
;
591 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
592 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
598 Value
= State
->GeneralRegs
[Reg
].LowWord
;
599 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
600 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
606 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
608 BOOLEAN Jump
= FALSE
;
610 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
612 /* Make sure this is the right instruction */
613 ASSERT((Opcode
& 0xF0) == 0x70);
617 /* Fetch the offset */
618 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
620 /* An exception occurred */
624 switch ((Opcode
& 0x0F) >> 1)
629 Jump
= State
->Flags
.Of
;
636 Jump
= State
->Flags
.Cf
;
643 Jump
= State
->Flags
.Zf
;
650 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
657 Jump
= State
->Flags
.Sf
;
664 Jump
= State
->Flags
.Pf
;
671 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
678 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
685 /* Invert the result */
691 /* Move the instruction pointer */
692 State
->InstPtr
.Long
+= Offset
;
696 /* Clear the top half of EIP */
697 State
->InstPtr
.Long
&= 0xFFFF;
705 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
707 /* Make sure this is the right instruction */
708 ASSERT(Opcode
== 0xF8);
710 /* No prefixes allowed */
711 if (State
->PrefixFlags
)
713 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
717 /* Clear CF and return success */
718 State
->Flags
.Cf
= FALSE
;
722 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
724 /* Make sure this is the right instruction */
725 ASSERT(Opcode
== 0xF9);
727 /* No prefixes allowed */
728 if (State
->PrefixFlags
)
730 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
734 /* Set CF and return success*/
735 State
->Flags
.Cf
= TRUE
;
739 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
741 /* Make sure this is the right instruction */
742 ASSERT(Opcode
== 0xF5);
744 /* No prefixes allowed */
745 if (State
->PrefixFlags
)
747 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
751 /* Toggle CF and return success */
752 State
->Flags
.Cf
= !State
->Flags
.Cf
;
756 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
758 /* Make sure this is the right instruction */
759 ASSERT(Opcode
== 0xFA);
761 /* No prefixes allowed */
762 if (State
->PrefixFlags
)
764 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
768 /* Check for protected mode */
769 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
772 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
774 /* Clear the interrupt flag */
775 State
->Flags
.If
= FALSE
;
779 /* General Protection Fault */
780 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
786 /* Just clear the interrupt flag */
787 State
->Flags
.If
= FALSE
;
794 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
796 /* Make sure this is the right instruction */
797 ASSERT(Opcode
== 0xFB);
799 /* No prefixes allowed */
800 if (State
->PrefixFlags
)
802 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
806 /* Check for protected mode */
807 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
810 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
812 /* Set the interrupt flag */
813 State
->Flags
.If
= TRUE
;
817 /* General Protection Fault */
818 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
824 /* Just set the interrupt flag */
825 State
->Flags
.If
= TRUE
;
832 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
834 /* Make sure this is the right instruction */
835 ASSERT(Opcode
== 0xFC);
837 /* No prefixes allowed */
838 if (State
->PrefixFlags
)
840 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
844 /* Clear DF and return success */
845 State
->Flags
.Df
= FALSE
;
849 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
851 /* Make sure this is the right instruction */
852 ASSERT(Opcode
== 0xFD);
854 /* No prefixes allowed */
855 if (State
->PrefixFlags
)
857 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
861 /* Set DF and return success*/
862 State
->Flags
.Df
= TRUE
;
866 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
868 /* Make sure this is the right instruction */
869 ASSERT(Opcode
== 0xF4);
871 /* No prefixes allowed */
872 if (State
->PrefixFlags
)
874 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
878 /* Privileged instructions can only be executed under CPL = 0 */
879 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
881 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
886 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
892 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
897 /* Make sure this is the right instruction */
898 ASSERT((Opcode
& 0xF7) == 0xE4);
902 /* Fetch the parameter */
903 if (!Fast486FetchByte(State
, &Data
))
905 /* Exception occurred */
909 /* Set the port number to the parameter */
914 /* The port number is in DX */
915 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
918 /* Read a byte from the I/O port */
919 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
921 /* Store the result in AL */
922 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
927 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
930 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
932 /* Make sure this is the right instruction */
933 ASSERT((Opcode
& 0xF7) == 0xE5);
942 /* Fetch the parameter */
943 if (!Fast486FetchByte(State
, &Data
))
945 /* Exception occurred */
949 /* Set the port number to the parameter */
954 /* The port number is in DX */
955 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
962 /* Read a dword from the I/O port */
963 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
965 /* Store the value in EAX */
966 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
972 /* Read a word from the I/O port */
973 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
975 /* Store the value in AX */
976 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
982 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
987 /* Make sure this is the right instruction */
988 ASSERT((Opcode
& 0xF7) == 0xE6);
992 /* Fetch the parameter */
993 if (!Fast486FetchByte(State
, &Data
))
995 /* Exception occurred */
999 /* Set the port number to the parameter */
1004 /* The port number is in DX */
1005 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1008 /* Read the value from AL */
1009 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1011 /* Write the byte to the I/O port */
1012 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
1017 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1020 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1022 /* Make sure this is the right instruction */
1023 ASSERT((Opcode
& 0xF7) == 0xE7);
1025 TOGGLE_OPSIZE(Size
);
1032 /* Fetch the parameter */
1033 if (!Fast486FetchByte(State
, &Data
))
1035 /* Exception occurred */
1039 /* Set the port number to the parameter */
1044 /* The port number is in DX */
1045 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1050 /* Get the value from EAX */
1051 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1053 /* Write a dword to the I/O port */
1054 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1058 /* Get the value from AX */
1059 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1061 /* Write a word to the I/O port */
1062 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1068 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1071 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1073 TOGGLE_OPSIZE(Size
);
1075 /* Make sure this is the right instruction */
1076 ASSERT(Opcode
== 0xEB);
1078 /* Fetch the offset */
1079 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1081 /* An exception occurred */
1085 /* Move the instruction pointer */
1086 State
->InstPtr
.Long
+= Offset
;
1090 /* Clear the top half of EIP */
1091 State
->InstPtr
.Long
&= 0xFFFF;
1097 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1099 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1101 /* Make sure this is the right instruction */
1102 ASSERT((Opcode
& 0xF8) == 0xB8);
1104 TOGGLE_OPSIZE(Size
);
1111 /* Fetch the dword */
1112 if (!Fast486FetchDword(State
, &Value
))
1114 /* Exception occurred */
1118 /* Store the value in the register */
1119 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1125 /* Fetch the word */
1126 if (!Fast486FetchWord(State
, &Value
))
1128 /* Exception occurred */
1132 /* Store the value in the register */
1133 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1139 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1143 /* Make sure this is the right instruction */
1144 ASSERT((Opcode
& 0xF8) == 0xB0);
1146 if (State
->PrefixFlags
!= 0)
1148 /* Invalid prefix */
1149 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1153 /* Fetch the byte */
1154 if (!Fast486FetchByte(State
, &Value
))
1156 /* Exception occurred */
1162 /* AH, CH, DH or BH */
1163 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1167 /* AL, CL, DL or BL */
1168 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1174 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1176 UCHAR FirstValue
, SecondValue
, Result
;
1177 FAST486_MOD_REG_RM ModRegRm
;
1178 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1180 /* Make sure this is the right instruction */
1181 ASSERT((Opcode
& 0xFD) == 0x00);
1183 TOGGLE_ADSIZE(AddressSize
);
1185 /* Get the operands */
1186 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1188 /* Exception occurred */
1192 if (!Fast486ReadModrmByteOperands(State
,
1197 /* Exception occurred */
1201 /* Calculate the result */
1202 Result
= FirstValue
+ SecondValue
;
1204 /* Update the flags */
1205 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1206 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1207 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1208 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1209 State
->Flags
.Zf
= (Result
== 0);
1210 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1211 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1213 /* Write back the result */
1214 return Fast486WriteModrmByteOperands(State
,
1216 Opcode
& FAST486_OPCODE_WRITE_REG
,
1220 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1222 FAST486_MOD_REG_RM ModRegRm
;
1223 BOOLEAN OperandSize
, AddressSize
;
1225 /* Make sure this is the right instruction */
1226 ASSERT((Opcode
& 0xFD) == 0x01);
1228 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1230 TOGGLE_ADSIZE(AddressSize
);
1231 TOGGLE_OPSIZE(OperandSize
);
1233 /* Get the operands */
1234 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1236 /* Exception occurred */
1240 /* Check the operand size */
1243 ULONG FirstValue
, SecondValue
, Result
;
1245 if (!Fast486ReadModrmDwordOperands(State
,
1250 /* Exception occurred */
1254 /* Calculate the result */
1255 Result
= FirstValue
+ SecondValue
;
1257 /* Update the flags */
1258 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1259 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1260 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1261 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1262 State
->Flags
.Zf
= (Result
== 0);
1263 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1264 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1266 /* Write back the result */
1267 return Fast486WriteModrmDwordOperands(State
,
1269 Opcode
& FAST486_OPCODE_WRITE_REG
,
1274 USHORT FirstValue
, SecondValue
, Result
;
1276 if (!Fast486ReadModrmWordOperands(State
,
1281 /* Exception occurred */
1285 /* Calculate the result */
1286 Result
= FirstValue
+ SecondValue
;
1288 /* Update the flags */
1289 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1290 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1291 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1292 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1293 State
->Flags
.Zf
= (Result
== 0);
1294 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1295 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1297 /* Write back the result */
1298 return Fast486WriteModrmWordOperands(State
,
1300 Opcode
& FAST486_OPCODE_WRITE_REG
,
1305 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1307 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1308 UCHAR SecondValue
, Result
;
1310 /* Make sure this is the right instruction */
1311 ASSERT(Opcode
== 0x04);
1313 if (State
->PrefixFlags
)
1315 /* This opcode doesn't take any prefixes */
1316 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1320 if (!Fast486FetchByte(State
, &SecondValue
))
1322 /* Exception occurred */
1326 /* Calculate the result */
1327 Result
= FirstValue
+ SecondValue
;
1329 /* Update the flags */
1330 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1331 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1332 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1333 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1334 State
->Flags
.Zf
= (Result
== 0);
1335 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1336 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1338 /* Write back the result */
1339 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1344 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1346 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1348 /* Make sure this is the right instruction */
1349 ASSERT(Opcode
== 0x05);
1352 TOGGLE_OPSIZE(Size
);
1356 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1357 ULONG SecondValue
, Result
;
1359 if (!Fast486FetchDword(State
, &SecondValue
))
1361 /* Exception occurred */
1365 /* Calculate the result */
1366 Result
= FirstValue
+ SecondValue
;
1368 /* Update the flags */
1369 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1370 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1371 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1372 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1373 State
->Flags
.Zf
= (Result
== 0);
1374 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1375 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1377 /* Write back the result */
1378 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1382 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1383 USHORT SecondValue
, Result
;
1385 if (!Fast486FetchWord(State
, &SecondValue
))
1387 /* Exception occurred */
1391 /* Calculate the result */
1392 Result
= FirstValue
+ SecondValue
;
1394 /* Update the flags */
1395 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1396 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1397 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1398 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1399 State
->Flags
.Zf
= (Result
== 0);
1400 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1401 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1403 /* Write back the result */
1404 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1410 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1412 UCHAR FirstValue
, SecondValue
, Result
;
1413 FAST486_MOD_REG_RM ModRegRm
;
1414 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1416 /* Make sure this is the right instruction */
1417 ASSERT((Opcode
& 0xFD) == 0x08);
1419 TOGGLE_ADSIZE(AddressSize
);
1421 /* Get the operands */
1422 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1424 /* Exception occurred */
1428 if (!Fast486ReadModrmByteOperands(State
,
1433 /* Exception occurred */
1437 /* Calculate the result */
1438 Result
= FirstValue
| SecondValue
;
1440 /* Update the flags */
1441 State
->Flags
.Cf
= FALSE
;
1442 State
->Flags
.Of
= FALSE
;
1443 State
->Flags
.Zf
= (Result
== 0);
1444 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1445 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1447 /* Write back the result */
1448 return Fast486WriteModrmByteOperands(State
,
1450 Opcode
& FAST486_OPCODE_WRITE_REG
,
1454 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1456 FAST486_MOD_REG_RM ModRegRm
;
1457 BOOLEAN OperandSize
, AddressSize
;
1459 /* Make sure this is the right instruction */
1460 ASSERT((Opcode
& 0xFD) == 0x09);
1462 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1464 TOGGLE_ADSIZE(AddressSize
);
1465 TOGGLE_OPSIZE(OperandSize
);
1467 /* Get the operands */
1468 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1470 /* Exception occurred */
1474 /* Check the operand size */
1477 ULONG FirstValue
, SecondValue
, Result
;
1479 if (!Fast486ReadModrmDwordOperands(State
,
1484 /* Exception occurred */
1488 /* Calculate the result */
1489 Result
= FirstValue
| SecondValue
;
1491 /* Update the flags */
1492 State
->Flags
.Cf
= FALSE
;
1493 State
->Flags
.Of
= FALSE
;
1494 State
->Flags
.Zf
= (Result
== 0);
1495 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1496 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1498 /* Write back the result */
1499 return Fast486WriteModrmDwordOperands(State
,
1501 Opcode
& FAST486_OPCODE_WRITE_REG
,
1506 USHORT FirstValue
, SecondValue
, Result
;
1508 if (!Fast486ReadModrmWordOperands(State
,
1513 /* Exception occurred */
1517 /* Calculate the result */
1518 Result
= FirstValue
| SecondValue
;
1520 /* Update the flags */
1521 State
->Flags
.Cf
= FALSE
;
1522 State
->Flags
.Of
= FALSE
;
1523 State
->Flags
.Zf
= (Result
== 0);
1524 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1525 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1527 /* Write back the result */
1528 return Fast486WriteModrmWordOperands(State
,
1530 Opcode
& FAST486_OPCODE_WRITE_REG
,
1535 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1537 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1538 UCHAR SecondValue
, Result
;
1540 /* Make sure this is the right instruction */
1541 ASSERT(Opcode
== 0x0C);
1543 if (State
->PrefixFlags
)
1545 /* This opcode doesn't take any prefixes */
1546 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1550 if (!Fast486FetchByte(State
, &SecondValue
))
1552 /* Exception occurred */
1556 /* Calculate the result */
1557 Result
= FirstValue
| SecondValue
;
1559 /* Update the flags */
1560 State
->Flags
.Cf
= FALSE
;
1561 State
->Flags
.Of
= FALSE
;
1562 State
->Flags
.Zf
= (Result
== 0);
1563 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1564 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1566 /* Write back the result */
1567 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1572 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1574 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1576 /* Make sure this is the right instruction */
1577 ASSERT(Opcode
== 0x0D);
1580 TOGGLE_OPSIZE(Size
);
1584 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1585 ULONG SecondValue
, Result
;
1587 if (!Fast486FetchDword(State
, &SecondValue
))
1589 /* Exception occurred */
1593 /* Calculate the result */
1594 Result
= FirstValue
| SecondValue
;
1596 /* Update the flags */
1597 State
->Flags
.Cf
= FALSE
;
1598 State
->Flags
.Of
= FALSE
;
1599 State
->Flags
.Zf
= (Result
== 0);
1600 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1601 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1603 /* Write back the result */
1604 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1608 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1609 USHORT SecondValue
, Result
;
1611 if (!Fast486FetchWord(State
, &SecondValue
))
1613 /* Exception occurred */
1617 /* Calculate the result */
1618 Result
= FirstValue
| SecondValue
;
1620 /* Update the flags */
1621 State
->Flags
.Cf
= FALSE
;
1622 State
->Flags
.Of
= FALSE
;
1623 State
->Flags
.Zf
= (Result
== 0);
1624 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1625 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1627 /* Write back the result */
1628 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1634 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1636 UCHAR FirstValue
, SecondValue
, Result
;
1637 FAST486_MOD_REG_RM ModRegRm
;
1638 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1640 /* Make sure this is the right instruction */
1641 ASSERT((Opcode
& 0xFD) == 0x20);
1643 TOGGLE_ADSIZE(AddressSize
);
1645 /* Get the operands */
1646 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1648 /* Exception occurred */
1652 if (!Fast486ReadModrmByteOperands(State
,
1657 /* Exception occurred */
1661 /* Calculate the result */
1662 Result
= FirstValue
& SecondValue
;
1664 /* Update the flags */
1665 State
->Flags
.Cf
= FALSE
;
1666 State
->Flags
.Of
= FALSE
;
1667 State
->Flags
.Zf
= (Result
== 0);
1668 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1669 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1671 /* Write back the result */
1672 return Fast486WriteModrmByteOperands(State
,
1674 Opcode
& FAST486_OPCODE_WRITE_REG
,
1678 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1680 FAST486_MOD_REG_RM ModRegRm
;
1681 BOOLEAN OperandSize
, AddressSize
;
1683 /* Make sure this is the right instruction */
1684 ASSERT((Opcode
& 0xFD) == 0x21);
1686 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1688 TOGGLE_ADSIZE(AddressSize
);
1689 TOGGLE_OPSIZE(OperandSize
);
1691 /* Get the operands */
1692 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1694 /* Exception occurred */
1698 /* Check the operand size */
1701 ULONG FirstValue
, SecondValue
, Result
;
1703 if (!Fast486ReadModrmDwordOperands(State
,
1708 /* Exception occurred */
1712 /* Calculate the result */
1713 Result
= FirstValue
& SecondValue
;
1715 /* Update the flags */
1716 State
->Flags
.Cf
= FALSE
;
1717 State
->Flags
.Of
= FALSE
;
1718 State
->Flags
.Zf
= (Result
== 0);
1719 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1720 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1722 /* Write back the result */
1723 return Fast486WriteModrmDwordOperands(State
,
1725 Opcode
& FAST486_OPCODE_WRITE_REG
,
1730 USHORT FirstValue
, SecondValue
, Result
;
1732 if (!Fast486ReadModrmWordOperands(State
,
1737 /* Exception occurred */
1741 /* Calculate the result */
1742 Result
= FirstValue
& SecondValue
;
1744 /* Update the flags */
1745 State
->Flags
.Cf
= FALSE
;
1746 State
->Flags
.Of
= FALSE
;
1747 State
->Flags
.Zf
= (Result
== 0);
1748 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1749 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1751 /* Write back the result */
1752 return Fast486WriteModrmWordOperands(State
,
1754 Opcode
& FAST486_OPCODE_WRITE_REG
,
1759 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1761 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1762 UCHAR SecondValue
, Result
;
1764 /* Make sure this is the right instruction */
1765 ASSERT(Opcode
== 0x24);
1769 if (!Fast486FetchByte(State
, &SecondValue
))
1771 /* Exception occurred */
1775 /* Calculate the result */
1776 Result
= FirstValue
& SecondValue
;
1778 /* Update the flags */
1779 State
->Flags
.Cf
= FALSE
;
1780 State
->Flags
.Of
= FALSE
;
1781 State
->Flags
.Zf
= (Result
== 0);
1782 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1783 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1785 /* Write back the result */
1786 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1791 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1793 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1795 /* Make sure this is the right instruction */
1796 ASSERT(Opcode
== 0x25);
1799 TOGGLE_OPSIZE(Size
);
1803 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1804 ULONG SecondValue
, Result
;
1806 if (!Fast486FetchDword(State
, &SecondValue
))
1808 /* Exception occurred */
1812 /* Calculate the result */
1813 Result
= FirstValue
& SecondValue
;
1815 /* Update the flags */
1816 State
->Flags
.Cf
= FALSE
;
1817 State
->Flags
.Of
= FALSE
;
1818 State
->Flags
.Zf
= (Result
== 0);
1819 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1820 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1822 /* Write back the result */
1823 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1827 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1828 USHORT SecondValue
, Result
;
1830 if (!Fast486FetchWord(State
, &SecondValue
))
1832 /* Exception occurred */
1836 /* Calculate the result */
1837 Result
= FirstValue
& SecondValue
;
1839 /* Update the flags */
1840 State
->Flags
.Cf
= FALSE
;
1841 State
->Flags
.Of
= FALSE
;
1842 State
->Flags
.Zf
= (Result
== 0);
1843 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1844 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1846 /* Write back the result */
1847 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1853 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1855 UCHAR FirstValue
, SecondValue
, Result
;
1856 FAST486_MOD_REG_RM ModRegRm
;
1857 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1859 /* Make sure this is the right instruction */
1860 ASSERT((Opcode
& 0xFD) == 0x30);
1862 TOGGLE_ADSIZE(AddressSize
);
1864 /* Get the operands */
1865 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1867 /* Exception occurred */
1871 if (!Fast486ReadModrmByteOperands(State
,
1876 /* Exception occurred */
1880 /* Calculate the result */
1881 Result
= FirstValue
^ SecondValue
;
1883 /* Update the flags */
1884 State
->Flags
.Cf
= FALSE
;
1885 State
->Flags
.Of
= FALSE
;
1886 State
->Flags
.Zf
= (Result
== 0);
1887 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1888 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1890 /* Write back the result */
1891 return Fast486WriteModrmByteOperands(State
,
1893 Opcode
& FAST486_OPCODE_WRITE_REG
,
1897 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1899 FAST486_MOD_REG_RM ModRegRm
;
1900 BOOLEAN OperandSize
, AddressSize
;
1902 /* Make sure this is the right instruction */
1903 ASSERT((Opcode
& 0xFD) == 0x31);
1905 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1907 TOGGLE_ADSIZE(AddressSize
);
1908 TOGGLE_OPSIZE(OperandSize
);
1910 /* Get the operands */
1911 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1913 /* Exception occurred */
1917 /* Check the operand size */
1920 ULONG FirstValue
, SecondValue
, Result
;
1922 if (!Fast486ReadModrmDwordOperands(State
,
1927 /* Exception occurred */
1931 /* Calculate the result */
1932 Result
= FirstValue
^ SecondValue
;
1934 /* Update the flags */
1935 State
->Flags
.Cf
= FALSE
;
1936 State
->Flags
.Of
= FALSE
;
1937 State
->Flags
.Zf
= (Result
== 0);
1938 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1939 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1941 /* Write back the result */
1942 return Fast486WriteModrmDwordOperands(State
,
1944 Opcode
& FAST486_OPCODE_WRITE_REG
,
1949 USHORT FirstValue
, SecondValue
, Result
;
1951 if (!Fast486ReadModrmWordOperands(State
,
1956 /* Exception occurred */
1960 /* Calculate the result */
1961 Result
= FirstValue
^ SecondValue
;
1963 /* Update the flags */
1964 State
->Flags
.Cf
= FALSE
;
1965 State
->Flags
.Of
= FALSE
;
1966 State
->Flags
.Zf
= (Result
== 0);
1967 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1968 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1970 /* Write back the result */
1971 return Fast486WriteModrmWordOperands(State
,
1973 Opcode
& FAST486_OPCODE_WRITE_REG
,
1978 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1980 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1981 UCHAR SecondValue
, Result
;
1983 /* Make sure this is the right instruction */
1984 ASSERT(Opcode
== 0x34);
1986 if (State
->PrefixFlags
)
1988 /* This opcode doesn't take any prefixes */
1989 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1993 if (!Fast486FetchByte(State
, &SecondValue
))
1995 /* Exception occurred */
1999 /* Calculate the result */
2000 Result
= FirstValue
^ SecondValue
;
2002 /* Update the flags */
2003 State
->Flags
.Cf
= FALSE
;
2004 State
->Flags
.Of
= FALSE
;
2005 State
->Flags
.Zf
= (Result
== 0);
2006 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2007 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2009 /* Write back the result */
2010 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2015 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2017 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2019 /* Make sure this is the right instruction */
2020 ASSERT(Opcode
== 0x35);
2023 TOGGLE_OPSIZE(Size
);
2027 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2028 ULONG SecondValue
, Result
;
2030 if (!Fast486FetchDword(State
, &SecondValue
))
2032 /* Exception occurred */
2036 /* Calculate the result */
2037 Result
= FirstValue
^ SecondValue
;
2039 /* Update the flags */
2040 State
->Flags
.Cf
= FALSE
;
2041 State
->Flags
.Of
= FALSE
;
2042 State
->Flags
.Zf
= (Result
== 0);
2043 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2044 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2046 /* Write back the result */
2047 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2051 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2052 USHORT SecondValue
, Result
;
2054 if (!Fast486FetchWord(State
, &SecondValue
))
2056 /* Exception occurred */
2060 /* Calculate the result */
2061 Result
= FirstValue
^ SecondValue
;
2063 /* Update the flags */
2064 State
->Flags
.Cf
= FALSE
;
2065 State
->Flags
.Of
= FALSE
;
2066 State
->Flags
.Zf
= (Result
== 0);
2067 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2068 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2070 /* Write back the result */
2071 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2077 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2079 UCHAR FirstValue
, SecondValue
, Result
;
2080 FAST486_MOD_REG_RM ModRegRm
;
2081 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2083 /* Make sure this is the right instruction */
2084 ASSERT(Opcode
== 0x84);
2086 TOGGLE_ADSIZE(AddressSize
);
2088 /* Get the operands */
2089 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2091 /* Exception occurred */
2095 if (!Fast486ReadModrmByteOperands(State
,
2100 /* Exception occurred */
2103 /* Calculate the result */
2104 Result
= FirstValue
& SecondValue
;
2106 /* Update the flags */
2107 State
->Flags
.Cf
= FALSE
;
2108 State
->Flags
.Of
= FALSE
;
2109 State
->Flags
.Zf
= (Result
== 0);
2110 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2111 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2113 /* The result is discarded */
2117 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2119 FAST486_MOD_REG_RM ModRegRm
;
2120 BOOLEAN OperandSize
, AddressSize
;
2122 /* Make sure this is the right instruction */
2123 ASSERT(Opcode
== 0x85);
2125 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2127 TOGGLE_ADSIZE(AddressSize
);
2128 TOGGLE_OPSIZE(OperandSize
);
2130 /* Get the operands */
2131 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2133 /* Exception occurred */
2137 /* Check the operand size */
2140 ULONG FirstValue
, SecondValue
, Result
;
2142 if (!Fast486ReadModrmDwordOperands(State
,
2147 /* Exception occurred */
2151 /* Calculate the result */
2152 Result
= FirstValue
& SecondValue
;
2154 /* Update the flags */
2155 State
->Flags
.Cf
= FALSE
;
2156 State
->Flags
.Of
= FALSE
;
2157 State
->Flags
.Zf
= (Result
== 0);
2158 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2159 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2163 USHORT FirstValue
, SecondValue
, Result
;
2165 if (!Fast486ReadModrmWordOperands(State
,
2170 /* Exception occurred */
2174 /* Calculate the result */
2175 Result
= FirstValue
& SecondValue
;
2177 /* Update the flags */
2178 State
->Flags
.Cf
= FALSE
;
2179 State
->Flags
.Of
= FALSE
;
2180 State
->Flags
.Zf
= (Result
== 0);
2181 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2182 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2185 /* The result is discarded */
2189 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2191 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2192 UCHAR SecondValue
, Result
;
2194 /* Make sure this is the right instruction */
2195 ASSERT(Opcode
== 0xA8);
2197 if (State
->PrefixFlags
)
2199 /* This opcode doesn't take any prefixes */
2200 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2204 if (!Fast486FetchByte(State
, &SecondValue
))
2206 /* Exception occurred */
2210 /* Calculate the result */
2211 Result
= FirstValue
& SecondValue
;
2213 /* Update the flags */
2214 State
->Flags
.Cf
= FALSE
;
2215 State
->Flags
.Of
= FALSE
;
2216 State
->Flags
.Zf
= (Result
== 0);
2217 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2218 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2220 /* The result is discarded */
2224 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2226 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2228 /* Make sure this is the right instruction */
2229 ASSERT(Opcode
== 0xA9);
2232 TOGGLE_OPSIZE(Size
);
2236 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2237 ULONG SecondValue
, Result
;
2239 if (!Fast486FetchDword(State
, &SecondValue
))
2241 /* Exception occurred */
2245 /* Calculate the result */
2246 Result
= FirstValue
& SecondValue
;
2248 /* Update the flags */
2249 State
->Flags
.Cf
= FALSE
;
2250 State
->Flags
.Of
= FALSE
;
2251 State
->Flags
.Zf
= (Result
== 0);
2252 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2253 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2257 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2258 USHORT SecondValue
, Result
;
2260 if (!Fast486FetchWord(State
, &SecondValue
))
2262 /* Exception occurred */
2266 /* Calculate the result */
2267 Result
= FirstValue
& SecondValue
;
2269 /* Update the flags */
2270 State
->Flags
.Cf
= FALSE
;
2271 State
->Flags
.Of
= FALSE
;
2272 State
->Flags
.Zf
= (Result
== 0);
2273 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2274 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2277 /* The result is discarded */
2281 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2283 UCHAR FirstValue
, SecondValue
;
2284 FAST486_MOD_REG_RM ModRegRm
;
2285 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2287 /* Make sure this is the right instruction */
2288 ASSERT(Opcode
== 0x86);
2290 TOGGLE_ADSIZE(AddressSize
);
2292 /* Get the operands */
2293 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2295 /* Exception occurred */
2299 if (!Fast486ReadModrmByteOperands(State
,
2304 /* Exception occurred */
2308 /* Write the value from the register to the R/M */
2309 if (!Fast486WriteModrmByteOperands(State
,
2314 /* Exception occurred */
2318 /* Write the value from the R/M to the register */
2319 if (!Fast486WriteModrmByteOperands(State
,
2324 /* Exception occurred */
2331 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2333 FAST486_MOD_REG_RM ModRegRm
;
2334 BOOLEAN OperandSize
, AddressSize
;
2336 /* Make sure this is the right instruction */
2337 ASSERT(Opcode
== 0x87);
2339 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2341 TOGGLE_ADSIZE(AddressSize
);
2342 TOGGLE_OPSIZE(OperandSize
);
2344 /* Get the operands */
2345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2347 /* Exception occurred */
2351 /* Check the operand size */
2354 ULONG FirstValue
, SecondValue
;
2356 if (!Fast486ReadModrmDwordOperands(State
,
2361 /* Exception occurred */
2365 /* Write the value from the register to the R/M */
2366 if (!Fast486WriteModrmDwordOperands(State
,
2371 /* Exception occurred */
2375 /* Write the value from the R/M to the register */
2376 if (!Fast486WriteModrmDwordOperands(State
,
2381 /* Exception occurred */
2387 USHORT FirstValue
, SecondValue
;
2389 if (!Fast486ReadModrmWordOperands(State
,
2394 /* Exception occurred */
2398 /* Write the value from the register to the R/M */
2399 if (!Fast486WriteModrmWordOperands(State
,
2404 /* Exception occurred */
2408 /* Write the value from the R/M to the register */
2409 if (!Fast486WriteModrmWordOperands(State
,
2414 /* Exception occurred */
2419 /* The result is discarded */
2423 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2425 /* Call the internal API */
2426 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2429 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2433 if (!Fast486StackPop(State
, &NewSelector
))
2435 /* Exception occurred */
2439 /* Call the internal API */
2440 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2443 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2445 /* Call the internal API */
2446 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2449 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2451 UCHAR FirstValue
, SecondValue
, Result
;
2452 FAST486_MOD_REG_RM ModRegRm
;
2453 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2455 /* Make sure this is the right instruction */
2456 ASSERT((Opcode
& 0xFD) == 0x10);
2458 TOGGLE_ADSIZE(AddressSize
);
2460 /* Get the operands */
2461 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2463 /* Exception occurred */
2467 if (!Fast486ReadModrmByteOperands(State
,
2472 /* Exception occurred */
2476 /* Calculate the result */
2477 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2479 /* Special exception for CF */
2480 State
->Flags
.Cf
= State
->Flags
.Cf
2481 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2483 /* Update the flags */
2484 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2485 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2486 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2487 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2488 State
->Flags
.Zf
= (Result
== 0);
2489 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2490 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2492 /* Write back the result */
2493 return Fast486WriteModrmByteOperands(State
,
2495 Opcode
& FAST486_OPCODE_WRITE_REG
,
2499 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2501 FAST486_MOD_REG_RM ModRegRm
;
2502 BOOLEAN OperandSize
, AddressSize
;
2504 /* Make sure this is the right instruction */
2505 ASSERT((Opcode
& 0xFD) == 0x11);
2507 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2509 TOGGLE_ADSIZE(AddressSize
);
2510 TOGGLE_OPSIZE(OperandSize
);
2512 /* Get the operands */
2513 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2515 /* Exception occurred */
2519 /* Check the operand size */
2522 ULONG FirstValue
, SecondValue
, Result
;
2524 if (!Fast486ReadModrmDwordOperands(State
,
2529 /* Exception occurred */
2533 /* Calculate the result */
2534 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2536 /* Special exception for CF */
2537 State
->Flags
.Cf
= State
->Flags
.Cf
2538 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2540 /* Update the flags */
2541 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2542 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2543 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2544 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2545 State
->Flags
.Zf
= (Result
== 0);
2546 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2547 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2549 /* Write back the result */
2550 return Fast486WriteModrmDwordOperands(State
,
2552 Opcode
& FAST486_OPCODE_WRITE_REG
,
2557 USHORT FirstValue
, SecondValue
, Result
;
2559 if (!Fast486ReadModrmWordOperands(State
,
2564 /* Exception occurred */
2568 /* Calculate the result */
2569 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2571 /* Special exception for CF */
2572 State
->Flags
.Cf
= State
->Flags
.Cf
2573 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2575 /* Update the flags */
2576 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2577 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2578 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2579 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2580 State
->Flags
.Zf
= (Result
== 0);
2581 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2582 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2584 /* Write back the result */
2585 return Fast486WriteModrmWordOperands(State
,
2587 Opcode
& FAST486_OPCODE_WRITE_REG
,
2593 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2595 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2596 UCHAR SecondValue
, Result
;
2598 /* Make sure this is the right instruction */
2599 ASSERT(Opcode
== 0x14);
2601 if (State
->PrefixFlags
)
2603 /* This opcode doesn't take any prefixes */
2604 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2608 if (!Fast486FetchByte(State
, &SecondValue
))
2610 /* Exception occurred */
2614 /* Calculate the result */
2615 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2617 /* Special exception for CF */
2618 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2619 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2621 /* Update the flags */
2622 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2623 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2624 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2625 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2626 State
->Flags
.Zf
= (Result
== 0);
2627 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2628 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2630 /* Write back the result */
2631 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2636 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2638 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2640 /* Make sure this is the right instruction */
2641 ASSERT(Opcode
== 0x15);
2644 TOGGLE_OPSIZE(Size
);
2648 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2649 ULONG SecondValue
, Result
;
2651 if (!Fast486FetchDword(State
, &SecondValue
))
2653 /* Exception occurred */
2657 /* Calculate the result */
2658 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2660 /* Special exception for CF */
2661 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2662 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2664 /* Update the flags */
2665 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2666 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2667 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2668 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2669 State
->Flags
.Zf
= (Result
== 0);
2670 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2671 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2673 /* Write back the result */
2674 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2678 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2679 USHORT SecondValue
, Result
;
2681 if (!Fast486FetchWord(State
, &SecondValue
))
2683 /* Exception occurred */
2687 /* Calculate the result */
2688 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2690 /* Special exception for CF */
2691 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2692 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2694 /* Update the flags */
2695 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2696 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2697 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2698 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2699 State
->Flags
.Zf
= (Result
== 0);
2700 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2701 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2703 /* Write back the result */
2704 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2710 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2712 /* Call the internal API */
2713 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2716 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2720 if (!Fast486StackPop(State
, &NewSelector
))
2722 /* Exception occurred */
2726 /* Call the internal API */
2727 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2730 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2732 UCHAR FirstValue
, SecondValue
, Result
;
2733 FAST486_MOD_REG_RM ModRegRm
;
2734 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2735 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2737 /* Make sure this is the right instruction */
2738 ASSERT((Opcode
& 0xFD) == 0x18);
2740 TOGGLE_ADSIZE(AddressSize
);
2742 /* Get the operands */
2743 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2745 /* Exception occurred */
2749 if (!Fast486ReadModrmByteOperands(State
,
2754 /* Exception occurred */
2758 /* Check if this is the instruction that writes to R/M */
2759 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2761 /* Swap the order */
2762 SWAP(FirstValue
, SecondValue
);
2765 /* Calculate the result */
2766 Result
= FirstValue
- SecondValue
- Carry
;
2768 /* Update the flags */
2769 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2770 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2771 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2772 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2773 State
->Flags
.Zf
= (Result
== 0);
2774 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2775 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2777 /* Write back the result */
2778 return Fast486WriteModrmByteOperands(State
,
2780 Opcode
& FAST486_OPCODE_WRITE_REG
,
2784 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2786 FAST486_MOD_REG_RM ModRegRm
;
2787 BOOLEAN OperandSize
, AddressSize
;
2788 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2790 /* Make sure this is the right instruction */
2791 ASSERT((Opcode
& 0xFD) == 0x19);
2793 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2795 TOGGLE_ADSIZE(AddressSize
);
2796 TOGGLE_OPSIZE(OperandSize
);
2798 /* Get the operands */
2799 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2801 /* Exception occurred */
2805 /* Check the operand size */
2808 ULONG FirstValue
, SecondValue
, Result
;
2810 if (!Fast486ReadModrmDwordOperands(State
,
2815 /* Exception occurred */
2819 /* Check if this is the instruction that writes to R/M */
2820 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2822 /* Swap the order */
2823 SWAP(FirstValue
, SecondValue
);
2826 /* Calculate the result */
2827 Result
= FirstValue
- SecondValue
- Carry
;
2829 /* Update the flags */
2830 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2831 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2832 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2833 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2834 State
->Flags
.Zf
= (Result
== 0);
2835 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2836 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2838 /* Write back the result */
2839 return Fast486WriteModrmDwordOperands(State
,
2841 Opcode
& FAST486_OPCODE_WRITE_REG
,
2846 USHORT FirstValue
, SecondValue
, Result
;
2848 if (!Fast486ReadModrmWordOperands(State
,
2853 /* Exception occurred */
2857 /* Check if this is the instruction that writes to R/M */
2858 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2860 /* Swap the order */
2861 SWAP(FirstValue
, SecondValue
);
2864 /* Calculate the result */
2865 Result
= FirstValue
- SecondValue
- Carry
;
2867 /* Update the flags */
2868 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2869 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2870 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2871 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2872 State
->Flags
.Zf
= (Result
== 0);
2873 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2874 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2876 /* Write back the result */
2877 return Fast486WriteModrmWordOperands(State
,
2879 Opcode
& FAST486_OPCODE_WRITE_REG
,
2884 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2886 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2887 UCHAR SecondValue
, Result
;
2888 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2890 /* Make sure this is the right instruction */
2891 ASSERT(Opcode
== 0x1C);
2893 if (State
->PrefixFlags
)
2895 /* This opcode doesn't take any prefixes */
2896 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2900 if (!Fast486FetchByte(State
, &SecondValue
))
2902 /* Exception occurred */
2906 /* Calculate the result */
2907 Result
= FirstValue
- SecondValue
- Carry
;
2909 /* Update the flags */
2910 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2911 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2912 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2913 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2914 State
->Flags
.Zf
= (Result
== 0);
2915 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2916 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2918 /* Write back the result */
2919 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2925 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2927 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2928 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2930 /* Make sure this is the right instruction */
2931 ASSERT(Opcode
== 0x1D);
2934 TOGGLE_OPSIZE(Size
);
2938 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2939 ULONG SecondValue
, Result
;
2941 if (!Fast486FetchDword(State
, &SecondValue
))
2943 /* Exception occurred */
2947 /* Calculate the result */
2948 Result
= FirstValue
- SecondValue
- Carry
;
2950 /* Update the flags */
2951 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2952 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2953 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2954 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2955 State
->Flags
.Zf
= (Result
== 0);
2956 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2957 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2959 /* Write back the result */
2960 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2964 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2965 USHORT SecondValue
, Result
;
2967 if (!Fast486FetchWord(State
, &SecondValue
))
2969 /* Exception occurred */
2973 /* Calculate the result */
2974 Result
= FirstValue
- SecondValue
- Carry
;
2976 /* Update the flags */
2977 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2978 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2979 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2980 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2981 State
->Flags
.Zf
= (Result
== 0);
2982 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2983 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2985 /* Write back the result */
2986 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2993 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2995 /* Call the internal API */
2996 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2999 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3003 if (!Fast486StackPop(State
, &NewSelector
))
3005 /* Exception occurred */
3009 /* Call the internal API */
3010 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3013 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3015 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3016 BOOLEAN Carry
= State
->Flags
.Cf
;
3018 /* Clear the carry flag */
3019 State
->Flags
.Cf
= FALSE
;
3021 /* Check if the first BCD digit is invalid or there was a carry from it */
3022 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3025 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3026 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3028 /* A carry occurred */
3029 State
->Flags
.Cf
= TRUE
;
3032 /* Set the adjust flag */
3033 State
->Flags
.Af
= TRUE
;
3036 /* Check if the second BCD digit is invalid or there was a carry from it */
3037 if ((Value
> 0x99) || Carry
)
3040 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3042 /* There was a carry */
3043 State
->Flags
.Cf
= TRUE
;
3046 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3048 /* Update the flags */
3049 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3050 State
->Flags
.Zf
= (Value
== 0);
3051 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3056 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3058 UCHAR FirstValue
, SecondValue
, Result
;
3059 FAST486_MOD_REG_RM ModRegRm
;
3060 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3062 /* Make sure this is the right instruction */
3063 ASSERT((Opcode
& 0xED) == 0x28);
3065 TOGGLE_ADSIZE(AddressSize
);
3067 /* Get the operands */
3068 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3070 /* Exception occurred */
3074 if (!Fast486ReadModrmByteOperands(State
,
3079 /* Exception occurred */
3083 /* Check if this is the instruction that writes to R/M */
3084 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3086 /* Swap the order */
3087 SWAP(FirstValue
, SecondValue
);
3090 /* Calculate the result */
3091 Result
= FirstValue
- SecondValue
;
3093 /* Update the flags */
3094 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3095 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3096 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3097 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3098 State
->Flags
.Zf
= (Result
== 0);
3099 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3100 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3102 /* Check if this is not a CMP */
3103 if (!(Opcode
& 0x10))
3105 /* Write back the result */
3106 return Fast486WriteModrmByteOperands(State
,
3108 Opcode
& FAST486_OPCODE_WRITE_REG
,
3113 /* Discard the result */
3118 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3120 FAST486_MOD_REG_RM ModRegRm
;
3121 BOOLEAN OperandSize
, AddressSize
;
3123 /* Make sure this is the right instruction */
3124 ASSERT((Opcode
& 0xED) == 0x29);
3126 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3128 TOGGLE_ADSIZE(AddressSize
);
3129 TOGGLE_OPSIZE(OperandSize
);
3131 /* Get the operands */
3132 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3134 /* Exception occurred */
3138 /* Check the operand size */
3141 ULONG FirstValue
, SecondValue
, Result
;
3143 if (!Fast486ReadModrmDwordOperands(State
,
3148 /* Exception occurred */
3152 /* Check if this is the instruction that writes to R/M */
3153 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3155 /* Swap the order */
3156 SWAP(FirstValue
, SecondValue
);
3159 /* Calculate the result */
3160 Result
= FirstValue
- SecondValue
;
3162 /* Update the flags */
3163 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3164 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3165 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3166 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3167 State
->Flags
.Zf
= (Result
== 0);
3168 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3169 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3171 /* Check if this is not a CMP */
3172 if (!(Opcode
& 0x10))
3174 /* Write back the result */
3175 return Fast486WriteModrmDwordOperands(State
,
3177 Opcode
& FAST486_OPCODE_WRITE_REG
,
3182 /* Discard the result */
3188 USHORT FirstValue
, SecondValue
, Result
;
3190 if (!Fast486ReadModrmWordOperands(State
,
3195 /* Exception occurred */
3199 /* Check if this is the instruction that writes to R/M */
3200 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3202 /* Swap the order */
3203 SWAP(FirstValue
, SecondValue
);
3206 /* Calculate the result */
3207 Result
= FirstValue
- SecondValue
;
3209 /* Update the flags */
3210 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3211 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3212 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3213 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3214 State
->Flags
.Zf
= (Result
== 0);
3215 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3216 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3218 /* Check if this is not a CMP */
3219 if (!(Opcode
& 0x10))
3221 /* Write back the result */
3222 return Fast486WriteModrmWordOperands(State
,
3224 Opcode
& FAST486_OPCODE_WRITE_REG
,
3229 /* Discard the result */
3235 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3237 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3238 UCHAR SecondValue
, Result
;
3240 /* Make sure this is the right instruction */
3241 ASSERT((Opcode
& 0xEF) == 0x2C);
3243 if (State
->PrefixFlags
)
3245 /* This opcode doesn't take any prefixes */
3246 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3250 if (!Fast486FetchByte(State
, &SecondValue
))
3252 /* Exception occurred */
3256 /* Calculate the result */
3257 Result
= FirstValue
- SecondValue
;
3259 /* Update the flags */
3260 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3261 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3262 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3263 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3264 State
->Flags
.Zf
= (Result
== 0);
3265 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3266 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3268 /* Check if this is not a CMP */
3269 if (!(Opcode
& 0x10))
3271 /* Write back the result */
3272 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3278 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3280 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3282 /* Make sure this is the right instruction */
3283 ASSERT((Opcode
& 0xEF) == 0x2D);
3286 TOGGLE_OPSIZE(Size
);
3290 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3291 ULONG SecondValue
, Result
;
3293 if (!Fast486FetchDword(State
, &SecondValue
))
3295 /* Exception occurred */
3299 /* Calculate the result */
3300 Result
= FirstValue
- SecondValue
;
3302 /* Update the flags */
3303 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3304 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3305 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3306 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3307 State
->Flags
.Zf
= (Result
== 0);
3308 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3309 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3311 /* Check if this is not a CMP */
3312 if (!(Opcode
& 0x10))
3314 /* Write back the result */
3315 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3320 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3321 USHORT SecondValue
, Result
;
3323 if (!Fast486FetchWord(State
, &SecondValue
))
3325 /* Exception occurred */
3329 /* Calculate the result */
3330 Result
= FirstValue
- SecondValue
;
3332 /* Update the flags */
3333 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3334 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3335 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3336 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3337 State
->Flags
.Zf
= (Result
== 0);
3338 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3339 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3341 /* Check if this is not a CMP */
3342 if (!(Opcode
& 0x10))
3344 /* Write back the result */
3345 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3352 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3354 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3355 BOOLEAN Carry
= State
->Flags
.Cf
;
3357 /* Clear the carry flag */
3358 State
->Flags
.Cf
= FALSE
;
3360 /* Check if the first BCD digit is invalid or there was a borrow */
3361 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3364 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3365 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3367 /* A borrow occurred */
3368 State
->Flags
.Cf
= TRUE
;
3371 /* Set the adjust flag */
3372 State
->Flags
.Af
= TRUE
;
3375 /* Check if the second BCD digit is invalid or there was a borrow */
3376 if ((Value
> 0x99) || Carry
)
3379 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3381 /* There was a borrow */
3382 State
->Flags
.Cf
= TRUE
;
3385 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3387 /* Update the flags */
3388 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3389 State
->Flags
.Zf
= (Value
== 0);
3390 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3395 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3397 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3400 * Check if the value in AL is not a valid BCD digit,
3401 * or there was a carry from the lowest 4 bits of AL
3403 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3406 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3407 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3410 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3414 /* Clear CF and AF */
3415 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3418 /* Keep only the lowest 4 bits of AL */
3419 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3424 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3426 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3429 * Check if the value in AL is not a valid BCD digit,
3430 * or there was a borrow from the lowest 4 bits of AL
3432 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3435 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3436 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3439 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3443 /* Clear CF and AF */
3444 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3447 /* Keep only the lowest 4 bits of AL */
3448 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3453 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3456 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3457 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3459 /* Make sure this is the right instruction */
3460 ASSERT(Opcode
== 0x60);
3462 TOGGLE_OPSIZE(Size
);
3465 /* Push all the registers in order */
3466 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3468 if (i
== FAST486_REG_ESP
)
3470 /* Use the saved ESP instead */
3471 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3473 /* Exception occurred */
3479 /* Push the register */
3480 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3481 : State
->GeneralRegs
[i
].LowWord
))
3483 /* Exception occurred */
3492 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3495 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3498 /* Make sure this is the right instruction */
3499 ASSERT(Opcode
== 0x61);
3501 TOGGLE_OPSIZE(Size
);
3504 /* Pop all the registers in reverse order */
3505 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3508 if (!Fast486StackPop(State
, &Value
))
3510 /* Exception occurred */
3514 /* Don't modify ESP */
3515 if (i
!= FAST486_REG_ESP
)
3517 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3518 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3525 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3527 BOOLEAN OperandSize
, AddressSize
;
3528 FAST486_MOD_REG_RM ModRegRm
;
3529 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3531 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3534 TOGGLE_OPSIZE(OperandSize
);
3535 TOGGLE_ADSIZE(AddressSize
);
3537 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3539 /* Exception occurred */
3543 if (!ModRegRm
.Memory
)
3546 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3550 /* Check for the segment override */
3551 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3553 /* Use the override segment instead */
3554 Segment
= State
->SegmentOverride
;
3559 LONG Index
, LowerBound
, UpperBound
;
3561 /* Read the operands */
3562 if (!Fast486ReadModrmDwordOperands(State
,
3565 (PULONG
)&LowerBound
))
3567 /* Exception occurred */
3571 if (!Fast486ReadMemory(State
,
3573 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3578 /* Exception occurred */
3582 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3585 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3591 SHORT Index
, LowerBound
, UpperBound
;
3593 /* Read the operands */
3594 if (!Fast486ReadModrmWordOperands(State
,
3597 (PUSHORT
)&LowerBound
))
3599 /* Exception occurred */
3603 if (!Fast486ReadMemory(State
,
3605 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3610 /* Exception occurred */
3614 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3617 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3625 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3627 USHORT FirstValue
, SecondValue
;
3628 FAST486_MOD_REG_RM ModRegRm
;
3629 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3631 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3633 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3635 /* Cannot be used in real mode or with a LOCK prefix */
3636 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3640 TOGGLE_ADSIZE(AddressSize
);
3642 /* Get the operands */
3643 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3645 /* Exception occurred */
3649 /* Read the operands */
3650 if (!Fast486ReadModrmWordOperands(State
,
3655 /* Exception occurred */
3659 /* Check if the RPL needs adjusting */
3660 if ((SecondValue
& 3) < (FirstValue
& 3))
3662 /* Adjust the RPL */
3664 SecondValue
|= FirstValue
& 3;
3667 State
->Flags
.Zf
= TRUE
;
3669 /* Write back the result */
3670 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3675 State
->Flags
.Zf
= FALSE
;
3680 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3682 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3684 /* Make sure this is the right instruction */
3685 ASSERT(Opcode
== 0x68);
3688 TOGGLE_OPSIZE(Size
);
3694 if (!Fast486FetchDword(State
, &Data
))
3696 /* Exception occurred */
3700 /* Call the internal API */
3701 return Fast486StackPush(State
, Data
);
3707 if (!Fast486FetchWord(State
, &Data
))
3709 /* Exception occurred */
3713 /* Call the internal API */
3714 return Fast486StackPush(State
, Data
);
3718 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3720 BOOLEAN OperandSize
, AddressSize
;
3721 FAST486_MOD_REG_RM ModRegRm
;
3724 /* Make sure this is the right instruction */
3725 ASSERT((Opcode
& 0xFD) == 0x69);
3727 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3729 TOGGLE_ADSIZE(AddressSize
);
3730 TOGGLE_OPSIZE(OperandSize
);
3732 /* Fetch the parameters */
3733 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3735 /* Exception occurred */
3743 /* Fetch the immediate operand */
3744 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3746 /* Exception occurred */
3750 Multiplier
= (LONG
)Byte
;
3758 /* Fetch the immediate operand */
3759 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3761 /* Exception occurred */
3771 /* Fetch the immediate operand */
3772 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3774 /* Exception occurred */
3778 Multiplier
= (LONG
)Word
;
3784 LONG RegValue
, Multiplicand
;
3787 /* Read the operands */
3788 if (!Fast486ReadModrmDwordOperands(State
,
3791 (PULONG
)&Multiplicand
))
3793 /* Exception occurred */
3798 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3800 /* Check for carry/overflow */
3801 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3803 /* Write-back the result */
3804 return Fast486WriteModrmDwordOperands(State
,
3807 (ULONG
)((LONG
)Product
));
3811 SHORT RegValue
, Multiplicand
;
3814 /* Read the operands */
3815 if (!Fast486ReadModrmWordOperands(State
,
3818 (PUSHORT
)&Multiplicand
))
3820 /* Exception occurred */
3825 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3827 /* Check for carry/overflow */
3828 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3830 /* Write-back the result */
3831 return Fast486WriteModrmWordOperands(State
,
3834 (USHORT
)((SHORT
)Product
));
3838 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3842 /* Make sure this is the right instruction */
3843 ASSERT(Opcode
== 0x6A);
3845 if (!Fast486FetchByte(State
, &Data
))
3847 /* Exception occurred */
3851 /* Call the internal API */
3852 return Fast486StackPush(State
, Data
);
3855 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3857 UCHAR FirstValue
, SecondValue
, Result
;
3858 FAST486_MOD_REG_RM ModRegRm
;
3859 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3861 /* Make sure this is the right instruction */
3862 ASSERT((Opcode
& 0xFD) == 0x88);
3864 TOGGLE_ADSIZE(AddressSize
);
3866 /* Get the operands */
3867 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3869 /* Exception occurred */
3873 if (!Fast486ReadModrmByteOperands(State
,
3878 /* Exception occurred */
3882 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3883 else Result
= FirstValue
;
3885 /* Write back the result */
3886 return Fast486WriteModrmByteOperands(State
,
3888 Opcode
& FAST486_OPCODE_WRITE_REG
,
3893 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3895 FAST486_MOD_REG_RM ModRegRm
;
3896 BOOLEAN OperandSize
, AddressSize
;
3898 /* Make sure this is the right instruction */
3899 ASSERT((Opcode
& 0xFD) == 0x89);
3901 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3903 TOGGLE_ADSIZE(AddressSize
);
3904 TOGGLE_OPSIZE(OperandSize
);
3906 /* Get the operands */
3907 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3909 /* Exception occurred */
3913 /* Check the operand size */
3916 ULONG FirstValue
, SecondValue
, Result
;
3918 if (!Fast486ReadModrmDwordOperands(State
,
3923 /* Exception occurred */
3927 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3928 else Result
= FirstValue
;
3930 /* Write back the result */
3931 return Fast486WriteModrmDwordOperands(State
,
3933 Opcode
& FAST486_OPCODE_WRITE_REG
,
3938 USHORT FirstValue
, SecondValue
, Result
;
3940 if (!Fast486ReadModrmWordOperands(State
,
3945 /* Exception occurred */
3949 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3950 else Result
= FirstValue
;
3952 /* Write back the result */
3953 return Fast486WriteModrmWordOperands(State
,
3955 Opcode
& FAST486_OPCODE_WRITE_REG
,
3960 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3962 BOOLEAN OperandSize
, AddressSize
;
3963 FAST486_MOD_REG_RM ModRegRm
;
3965 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3967 /* Make sure this is the right instruction */
3968 ASSERT(Opcode
== 0x8C);
3970 TOGGLE_ADSIZE(AddressSize
);
3971 TOGGLE_OPSIZE(OperandSize
);
3973 /* Get the operands */
3974 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3976 /* Exception occurred */
3980 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3983 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3989 return Fast486WriteModrmDwordOperands(State
,
3992 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3996 return Fast486WriteModrmWordOperands(State
,
3999 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4003 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
4005 FAST486_MOD_REG_RM ModRegRm
;
4006 BOOLEAN OperandSize
, AddressSize
;
4008 /* Make sure this is the right instruction */
4009 ASSERT(Opcode
== 0x8D);
4011 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4013 TOGGLE_ADSIZE(AddressSize
);
4014 TOGGLE_OPSIZE(OperandSize
);
4016 /* Get the operands */
4017 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4019 /* Exception occurred */
4023 /* The second operand must be memory */
4024 if (!ModRegRm
.Memory
)
4027 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4031 /* Write the address to the register */
4034 return Fast486WriteModrmDwordOperands(State
,
4037 ModRegRm
.MemoryAddress
);
4041 return Fast486WriteModrmWordOperands(State
,
4044 ModRegRm
.MemoryAddress
);
4049 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
4051 BOOLEAN OperandSize
, AddressSize
;
4052 FAST486_MOD_REG_RM ModRegRm
;
4054 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4056 /* Make sure this is the right instruction */
4057 ASSERT(Opcode
== 0x8E);
4059 TOGGLE_ADSIZE(AddressSize
);
4060 TOGGLE_OPSIZE(OperandSize
);
4062 /* Get the operands */
4063 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4065 /* Exception occurred */
4069 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4070 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
4073 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4081 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4083 /* Exception occurred */
4087 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4093 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4095 /* Exception occurred */
4099 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4103 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4105 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4107 /* Make sure this is the right instruction */
4108 ASSERT(Opcode
== 0x98);
4110 TOGGLE_OPSIZE(Size
);
4115 /* Sign extend AX to EAX */
4116 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4118 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4119 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4125 /* Sign extend AL to AX */
4126 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4127 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4134 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4136 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4138 /* Make sure this is the right instruction */
4139 ASSERT(Opcode
== 0x99);
4141 TOGGLE_OPSIZE(Size
);
4146 /* Sign extend EAX to EDX:EAX */
4147 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4148 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4149 ? 0xFFFFFFFF : 0x00000000;
4153 /* Sign extend AX to DX:AX */
4154 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4155 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4162 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4166 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4168 /* Make sure this is the right instruction */
4169 ASSERT(Opcode
== 0x9A);
4171 TOGGLE_OPSIZE(Size
);
4174 /* Fetch the offset */
4177 if (!Fast486FetchDword(State
, &Offset
))
4179 /* Exception occurred */
4185 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4187 /* Exception occurred */
4192 /* Fetch the segment */
4193 if (!Fast486FetchWord(State
, &Segment
))
4195 /* Exception occurred */
4199 /* Push the current code segment selector */
4200 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4202 /* Exception occurred */
4206 /* Push the current value of the instruction pointer */
4207 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4209 /* Exception occurred */
4213 /* Load the new CS */
4214 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4216 /* Exception occurred */
4220 /* Load new (E)IP */
4221 if (Size
) State
->InstPtr
.Long
= Offset
;
4222 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4227 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4229 // TODO: NOT IMPLEMENTED
4235 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4237 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4240 TOGGLE_OPSIZE(Size
);
4242 /* Check for VM86 mode when IOPL is not 3 */
4243 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4245 /* Call the VM86 monitor */
4246 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4250 /* Push the flags */
4251 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4252 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4255 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4257 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4258 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4259 FAST486_FLAGS_REG NewFlags
;
4262 TOGGLE_OPSIZE(Size
);
4264 /* Pop the new flags */
4265 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4267 /* Exception occurred */
4271 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4273 /* Call the VM86 monitor */
4274 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4278 State
->Flags
.Cf
= NewFlags
.Cf
;
4279 State
->Flags
.Pf
= NewFlags
.Pf
;
4280 State
->Flags
.Af
= NewFlags
.Af
;
4281 State
->Flags
.Zf
= NewFlags
.Zf
;
4282 State
->Flags
.Sf
= NewFlags
.Sf
;
4283 State
->Flags
.Tf
= NewFlags
.Tf
;
4284 State
->Flags
.Df
= NewFlags
.Df
;
4285 State
->Flags
.Of
= NewFlags
.Of
;
4286 State
->Flags
.Nt
= NewFlags
.Nt
;
4288 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4289 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4294 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4296 /* Make sure this is the right instruction */
4297 ASSERT(Opcode
== 0x9E);
4299 /* Set the low-order byte of FLAGS to AH */
4300 State
->Flags
.Long
&= 0xFFFFFF00;
4301 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4303 /* Restore the reserved bits of FLAGS */
4304 State
->Flags
.AlwaysSet
= TRUE
;
4305 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4310 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4312 /* Make sure this is the right instruction */
4313 ASSERT(Opcode
== 0x9F);
4315 /* Set AH to the low-order byte of FLAGS */
4316 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4321 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4323 ULONG ReturnAddress
;
4324 USHORT BytesToPop
= 0;
4325 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4327 /* Make sure this is the right instruction */
4328 ASSERT((Opcode
& 0xFE) == 0xC2);
4331 TOGGLE_OPSIZE(Size
);
4335 /* Fetch the number of bytes to pop after the return */
4336 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4339 /* Pop the return address */
4340 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4342 /* Return to the calling procedure, and if necessary, pop the parameters */
4345 State
->InstPtr
.Long
= ReturnAddress
;
4346 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4350 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4351 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4357 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4359 UCHAR FarPointer
[6];
4360 BOOLEAN OperandSize
, AddressSize
;
4361 FAST486_MOD_REG_RM ModRegRm
;
4363 /* Make sure this is the right instruction */
4364 ASSERT((Opcode
& 0xFE) == 0xC4);
4366 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4368 TOGGLE_OPSIZE(OperandSize
);
4369 TOGGLE_ADSIZE(AddressSize
);
4371 /* Get the operands */
4372 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4374 /* Exception occurred */
4378 if (!ModRegRm
.Memory
)
4380 /* Check if this is a BOP and the host supports BOPs */
4381 if ((Opcode
== 0xC4)
4382 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4383 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4384 && (State
->BopCallback
!= NULL
))
4388 /* Fetch the BOP code */
4389 if (!Fast486FetchByte(State
, &BopCode
))
4391 /* Exception occurred */
4395 /* Call the BOP handler */
4396 State
->BopCallback(State
, BopCode
);
4398 /* Return success */
4403 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4407 if (!Fast486ReadMemory(State
,
4408 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4409 ? State
->SegmentOverride
: FAST486_REG_DS
,
4410 ModRegRm
.MemoryAddress
,
4413 OperandSize
? 6 : 4))
4415 /* Exception occurred */
4421 ULONG Offset
= *((PULONG
)FarPointer
);
4422 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4424 /* Set the register to the offset */
4425 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4427 /* Load the segment */
4428 return Fast486LoadSegment(State
,
4430 ? FAST486_REG_ES
: FAST486_REG_DS
,
4435 USHORT Offset
= *((PUSHORT
)FarPointer
);
4436 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4438 /* Set the register to the offset */
4439 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4441 /* Load the segment */
4442 return Fast486LoadSegment(State
,
4444 ? FAST486_REG_ES
: FAST486_REG_DS
,
4449 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4452 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4455 FAST486_REG FramePointer
;
4457 /* Make sure this is the right instruction */
4458 ASSERT(Opcode
== 0xC8);
4461 TOGGLE_OPSIZE(Size
);
4463 if (!Fast486FetchWord(State
, &FrameSize
))
4465 /* Exception occurred */
4469 if (!Fast486FetchByte(State
, &NestingLevel
))
4471 /* Exception occurred */
4476 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4478 /* Exception occurred */
4483 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4485 /* Set up the nested procedure stacks */
4486 for (i
= 1; i
< NestingLevel
; i
++)
4490 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4491 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4495 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4496 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4500 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4502 /* Set EBP to the frame pointer */
4503 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4505 /* Reserve space for the frame */
4506 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4507 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4512 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4514 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4516 /* Make sure this is the right instruction */
4517 ASSERT(Opcode
== 0xC9);
4520 TOGGLE_OPSIZE(Size
);
4524 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4525 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4527 /* Pop the saved base pointer from the stack */
4528 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4534 /* Set the stack pointer (SP) to the base pointer (BP) */
4535 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4537 /* Pop the saved base pointer from the stack */
4538 if (Fast486StackPop(State
, &Value
))
4540 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4547 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4551 USHORT BytesToPop
= 0;
4552 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4554 /* Make sure this is the right instruction */
4555 ASSERT((Opcode
& 0xFE) == 0xCA);
4557 TOGGLE_OPSIZE(Size
);
4562 /* Fetch the number of bytes to pop after the return */
4563 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4566 /* Pop the offset */
4567 if (!Fast486StackPop(State
, &Offset
))
4569 /* Exception occurred */
4573 /* Pop the segment */
4574 if (!Fast486StackPop(State
, &Segment
))
4576 /* Exception occurred */
4580 /* Load the new CS */
4581 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4583 /* Exception occurred */
4587 /* Load new (E)IP, and if necessary, pop the parameters */
4590 State
->InstPtr
.Long
= Offset
;
4591 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4595 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4596 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4602 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4605 FAST486_IDT_ENTRY IdtEntry
;
4611 /* This is the INT3 instruction */
4618 /* Fetch the interrupt number */
4619 if (!Fast486FetchByte(State
, &IntNum
))
4621 /* Exception occurred */
4630 /* Don't do anything if OF is cleared */
4631 if (!State
->Flags
.Of
) return TRUE
;
4634 IntNum
= FAST486_EXCEPTION_OF
;
4641 /* Should not happen */
4646 /* Get the interrupt vector */
4647 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4649 /* Exception occurred */
4653 /* Perform the interrupt */
4654 if (!Fast486InterruptInternal(State
,
4656 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4659 /* Exception occurred */
4666 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4669 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4670 FAST486_FLAGS_REG NewFlags
;
4671 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4673 /* Make sure this is the right instruction */
4674 ASSERT(Opcode
== 0xCF);
4677 TOGGLE_OPSIZE(Size
);
4680 if (!Fast486StackPop(State
, &InstPtr
))
4682 /* Exception occurred */
4687 if (!Fast486StackPop(State
, &CodeSel
))
4689 /* Exception occurred */
4694 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4696 /* Exception occurred */
4700 /* Check for protected mode */
4701 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4703 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4705 if (State
->Flags
.Vm
)
4707 /* Return from VM86 mode */
4709 /* Check the IOPL */
4710 if (State
->Flags
.Iopl
== 3)
4713 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4716 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4718 /* Exception occurred */
4722 /* Set the new flags */
4723 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4724 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4725 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4726 State
->Flags
.Iopl
= 3;
4730 /* Call the VM86 monitor */
4731 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4738 if (State
->Flags
.Nt
)
4740 /* Nested task return */
4748 /* Return to VM86 mode */
4749 ULONG Es
, Ds
, Fs
, Gs
;
4751 /* Pop ESP, SS, ES, FS, GS */
4752 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4753 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4754 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4755 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4756 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4757 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4759 /* Set the new IP */
4760 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4762 /* Set the new flags */
4763 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4764 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4765 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4767 /* Load the new segments */
4768 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4769 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4770 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4771 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4772 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4773 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4778 /* Load the new CS */
4779 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4781 /* Exception occurred */
4786 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4787 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4789 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4792 if (!Fast486StackPop(State
, &StackPtr
))
4799 if (!Fast486StackPop(State
, &StackSel
))
4806 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4813 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4814 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4817 /* Set the new flags */
4818 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4819 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4820 State
->Flags
.AlwaysSet
= TRUE
;
4822 /* Set additional flags */
4823 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4824 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4826 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4828 /* Update the CPL */
4829 Cpl
= Fast486GetCurrentPrivLevel(State
);
4831 /* Check segment security */
4832 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4834 /* Don't check CS or SS */
4835 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4837 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4838 && (!State
->SegmentRegs
[i
].Executable
4839 || !State
->SegmentRegs
[i
].DirConf
))
4841 /* Load the NULL descriptor in the segment */
4842 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4849 if (Size
&& (InstPtr
& 0xFFFF0000))
4852 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4857 State
->InstPtr
.Long
= InstPtr
;
4860 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4862 /* Exception occurred */
4866 /* Set the new flags */
4867 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4868 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4869 State
->Flags
.AlwaysSet
= TRUE
;
4875 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4878 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4882 /* Fetch the base */
4883 if (!Fast486FetchByte(State
, &Base
))
4885 /* Exception occurred */
4889 /* Check if the base is zero */
4893 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4898 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4899 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4902 State
->Flags
.Af
= FALSE
;
4903 State
->Flags
.Zf
= (Value
== 0);
4904 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4905 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4910 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4913 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4917 /* Fetch the base */
4918 if (!Fast486FetchByte(State
, &Base
))
4920 /* Exception occurred */
4925 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4926 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4929 State
->Flags
.Af
= FALSE
;
4930 State
->Flags
.Zf
= (Value
== 0);
4931 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4932 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4937 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4940 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4942 TOGGLE_ADSIZE(AddressSize
);
4944 /* Read a byte from DS:[(E)BX + AL] */
4945 if (!Fast486ReadMemory(State
,
4947 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4948 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4949 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4954 /* Exception occurred */
4958 /* Set AL to the result */
4959 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4961 /* Return success */
4965 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4968 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4971 /* Make sure this is the right instruction */
4972 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4975 TOGGLE_ADSIZE(Size
);
4977 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4978 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4982 /* Additional rule for LOOPNZ */
4983 if (State
->Flags
.Zf
) Condition
= FALSE
;
4988 /* Additional rule for LOOPZ */
4989 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4992 /* Fetch the offset */
4993 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4995 /* An exception occurred */
5001 /* Move the instruction pointer */
5002 if (Size
) State
->InstPtr
.Long
+= Offset
;
5003 else State
->InstPtr
.LowWord
+= Offset
;
5009 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5012 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5015 /* Make sure this is the right instruction */
5016 ASSERT(Opcode
== 0xE3);
5019 TOGGLE_ADSIZE(Size
);
5021 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5022 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5024 /* Fetch the offset */
5025 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5027 /* An exception occurred */
5033 /* Move the instruction pointer */
5034 if (Size
) State
->InstPtr
.Long
+= Offset
;
5035 else State
->InstPtr
.LowWord
+= Offset
;
5041 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5043 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5045 /* Make sure this is the right instruction */
5046 ASSERT(Opcode
== 0xE8);
5048 TOGGLE_OPSIZE(Size
);
5055 /* Fetch the offset */
5056 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5058 /* An exception occurred */
5062 /* Push the current value of the instruction pointer */
5063 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5065 /* Exception occurred */
5069 /* Move the instruction pointer */
5070 State
->InstPtr
.Long
+= Offset
;
5076 /* Fetch the offset */
5077 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5079 /* An exception occurred */
5083 /* Push the current value of the instruction pointer */
5084 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5086 /* Exception occurred */
5090 /* Move the instruction pointer */
5091 State
->InstPtr
.LowWord
+= Offset
;
5097 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5099 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5101 /* Make sure this is the right instruction */
5102 ASSERT(Opcode
== 0xE9);
5104 TOGGLE_OPSIZE(Size
);
5111 /* Fetch the offset */
5112 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5114 /* An exception occurred */
5118 /* Move the instruction pointer */
5119 State
->InstPtr
.Long
+= Offset
;
5125 /* Fetch the offset */
5126 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5128 /* An exception occurred */
5132 /* Move the instruction pointer */
5133 State
->InstPtr
.Long
+= Offset
;
5135 /* Clear the top half of EIP */
5136 State
->InstPtr
.Long
&= 0xFFFF;
5142 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5146 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5148 /* Make sure this is the right instruction */
5149 ASSERT(Opcode
== 0xEA);
5151 TOGGLE_OPSIZE(Size
);
5154 /* Fetch the offset */
5157 if (!Fast486FetchDword(State
, &Offset
))
5159 /* Exception occurred */
5165 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5167 /* Exception occurred */
5172 /* Fetch the segment */
5173 if (!Fast486FetchWord(State
, &Segment
))
5175 /* Exception occurred */
5179 /* Load the new CS */
5180 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5182 /* Exception occurred */
5187 State
->InstPtr
.Long
= Offset
;
5192 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5194 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5197 /* Make sure this is the right instruction */
5198 ASSERT(Opcode
== 0xA0);
5200 TOGGLE_ADSIZE(AddressSize
);
5204 if (!Fast486FetchDword(State
, &Offset
))
5206 /* Exception occurred */
5214 if (!Fast486FetchWord(State
, &WordOffset
))
5216 /* Exception occurred */
5220 Offset
= (ULONG
)WordOffset
;
5223 /* Read from memory */
5224 return Fast486ReadMemory(State
,
5225 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5226 State
->SegmentOverride
: FAST486_REG_DS
,
5229 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5233 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5235 BOOLEAN OperandSize
, AddressSize
;
5237 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5239 /* Make sure this is the right instruction */
5240 ASSERT(Opcode
== 0xA1);
5242 TOGGLE_OPSIZE(OperandSize
);
5243 TOGGLE_ADSIZE(AddressSize
);
5249 if (!Fast486FetchDword(State
, &Offset
))
5251 /* Exception occurred */
5255 /* Read from memory */
5258 return Fast486ReadMemory(State
,
5259 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5260 State
->SegmentOverride
: FAST486_REG_DS
,
5263 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5268 return Fast486ReadMemory(State
,
5269 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5270 State
->SegmentOverride
: FAST486_REG_DS
,
5273 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5281 if (!Fast486FetchWord(State
, &Offset
))
5283 /* Exception occurred */
5287 /* Read from memory */
5290 return Fast486ReadMemory(State
,
5291 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5292 State
->SegmentOverride
: FAST486_REG_DS
,
5295 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5300 return Fast486ReadMemory(State
,
5301 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5302 State
->SegmentOverride
: FAST486_REG_DS
,
5305 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5311 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5313 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5316 /* Make sure this is the right instruction */
5317 ASSERT(Opcode
== 0xA2);
5319 TOGGLE_ADSIZE(AddressSize
);
5323 if (!Fast486FetchDword(State
, &Offset
))
5325 /* Exception occurred */
5333 if (!Fast486FetchWord(State
, &WordOffset
))
5335 /* Exception occurred */
5339 Offset
= (ULONG
)WordOffset
;
5342 /* Write to memory */
5343 return Fast486WriteMemory(State
,
5344 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5345 State
->SegmentOverride
: FAST486_REG_DS
,
5347 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5351 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5353 BOOLEAN OperandSize
, AddressSize
;
5355 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5357 /* Make sure this is the right instruction */
5358 ASSERT(Opcode
== 0xA3);
5360 TOGGLE_OPSIZE(OperandSize
);
5361 TOGGLE_ADSIZE(AddressSize
);
5367 if (!Fast486FetchDword(State
, &Offset
))
5369 /* Exception occurred */
5373 /* Write to memory */
5376 return Fast486WriteMemory(State
,
5377 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5378 State
->SegmentOverride
: FAST486_REG_DS
,
5380 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5385 return Fast486WriteMemory(State
,
5386 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5387 State
->SegmentOverride
: FAST486_REG_DS
,
5389 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5397 if (!Fast486FetchWord(State
, &Offset
))
5399 /* Exception occurred */
5403 /* Write to memory */
5406 return Fast486WriteMemory(State
,
5407 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5408 State
->SegmentOverride
: FAST486_REG_DS
,
5410 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5415 return Fast486WriteMemory(State
,
5416 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5417 State
->SegmentOverride
: FAST486_REG_DS
,
5419 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5425 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5427 /* Make sure this is the right instruction */
5428 ASSERT(Opcode
== 0xD6);
5432 /* Set all the bits of AL to CF */
5433 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5438 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5440 ULONG Data
, DataSize
;
5441 BOOLEAN OperandSize
, AddressSize
;
5442 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5444 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5446 /* Make sure this is the right instruction */
5447 ASSERT((Opcode
& 0xFE) == 0xA4);
5449 TOGGLE_OPSIZE(OperandSize
);
5450 TOGGLE_ADSIZE(AddressSize
);
5452 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5454 /* Use the override segment instead of DS */
5455 Segment
= State
->SegmentOverride
;
5458 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5460 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5461 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5468 /* Calculate the size */
5469 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5470 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5472 /* Read from the source operand */
5473 if (!Fast486ReadMemory(State
,
5475 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5476 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5481 /* Exception occurred */
5485 /* Write to the destination operand */
5486 if (!Fast486WriteMemory(State
,
5488 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5489 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5493 /* Exception occurred */
5497 /* Increment/decrement ESI and EDI */
5500 if (!State
->Flags
.Df
)
5502 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5503 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5507 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5508 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5513 if (!State
->Flags
.Df
)
5515 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5516 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5520 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5521 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5525 // FIXME: This method is slow!
5526 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5530 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5532 /* Repeat the instruction */
5533 State
->InstPtr
= State
->SavedInstPtr
;
5538 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5540 /* Repeat the instruction */
5541 State
->InstPtr
= State
->SavedInstPtr
;
5546 /* Return success */
5550 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5552 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5553 ULONG DataSize
, DataMask
, SignFlag
;
5554 BOOLEAN OperandSize
, AddressSize
;
5555 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5557 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5559 /* Make sure this is the right instruction */
5560 ASSERT((Opcode
& 0xFE) == 0xA6);
5562 TOGGLE_OPSIZE(OperandSize
);
5563 TOGGLE_ADSIZE(AddressSize
);
5565 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5567 /* Use the override segment instead of DS */
5568 Segment
= State
->SegmentOverride
;
5571 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5572 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5574 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5575 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5582 /* Calculate the size */
5583 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5584 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5586 /* Calculate the mask and sign flag */
5587 SignFlag
= 1 << ((DataSize
* 8) - 1);
5588 DataMask
= SignFlag
| (SignFlag
- 1);
5590 /* Read from the first source operand */
5591 if (!Fast486ReadMemory(State
,
5593 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5594 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5599 /* Exception occurred */
5603 /* Read from the second source operand */
5604 if (!Fast486ReadMemory(State
,
5606 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5607 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5612 /* Exception occurred */
5616 /* Calculate the result */
5617 FirstValue
&= DataMask
;
5618 SecondValue
&= DataMask
;
5619 Result
= (FirstValue
- SecondValue
) & DataMask
;
5621 /* Update the flags */
5622 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5623 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5624 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5625 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5626 State
->Flags
.Zf
= (Result
== 0);
5627 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5628 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5630 /* Increment/decrement ESI and EDI */
5633 if (!State
->Flags
.Df
)
5635 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5636 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5640 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5641 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5646 if (!State
->Flags
.Df
)
5648 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5649 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5653 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5654 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5658 // FIXME: This method is slow!
5659 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5660 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5662 BOOLEAN Repeat
= TRUE
;
5666 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5674 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5681 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5682 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5684 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5690 /* Repeat the instruction */
5691 State
->InstPtr
= State
->SavedInstPtr
;
5695 /* Return success */
5699 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5702 BOOLEAN OperandSize
, AddressSize
;
5704 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5706 /* Make sure this is the right instruction */
5707 ASSERT((Opcode
& 0xFE) == 0xAA);
5709 TOGGLE_OPSIZE(OperandSize
);
5710 TOGGLE_ADSIZE(AddressSize
);
5712 /* Calculate the size */
5713 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5714 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5716 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5718 UCHAR Block
[STRING_BLOCK_SIZE
];
5719 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5720 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5722 /* Fill the memory block with the data */
5723 if (DataSize
== sizeof(UCHAR
))
5725 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5731 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5733 if (DataSize
== sizeof(USHORT
))
5735 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5739 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5744 /* Transfer until finished */
5747 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5749 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5752 ULONG MaxBytes
= State
->Flags
.Df
5753 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5754 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5756 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5757 if (Processed
== 0) Processed
= 1;
5760 if (State
->Flags
.Df
)
5762 /* Set EDI to the starting location */
5763 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5764 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5767 /* Write to memory */
5768 if (!Fast486WriteMemory(State
,
5770 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5771 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5773 Processed
* DataSize
))
5776 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5777 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5779 /* Exception occurred */
5783 if (!State
->Flags
.Df
)
5785 /* Increase EDI by the number of bytes transfered */
5786 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5787 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5792 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5793 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5796 /* Reduce the total count by the number processed in this run */
5801 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5802 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5806 /* Write to the destination operand */
5807 if (!Fast486WriteMemory(State
,
5809 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5810 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5811 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5814 /* Exception occurred */
5818 /* Increment/decrement EDI */
5821 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5822 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5826 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5827 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5831 /* Return success */
5835 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5838 BOOLEAN OperandSize
, AddressSize
;
5839 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5841 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5843 /* Make sure this is the right instruction */
5844 ASSERT((Opcode
& 0xFE) == 0xAC);
5846 TOGGLE_OPSIZE(OperandSize
);
5847 TOGGLE_ADSIZE(AddressSize
);
5849 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5851 /* Use the override segment instead of DS */
5852 Segment
= State
->SegmentOverride
;
5855 /* Calculate the size */
5856 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5857 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5859 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5861 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5862 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5864 /* If the count is 0, do nothing */
5865 if (Count
== 0) return TRUE
;
5867 /* Only the last entry will be loaded */
5868 if (!State
->Flags
.Df
)
5870 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5871 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5875 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5876 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5880 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5881 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5884 /* Read from the source operand */
5885 if (!Fast486ReadMemory(State
,
5887 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5888 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5890 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5893 /* Exception occurred */
5897 /* Increment/decrement ESI */
5900 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5901 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5905 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5906 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5909 /* Return success */
5913 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5915 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5916 ULONG SecondValue
= 0;
5918 ULONG DataSize
, DataMask
, SignFlag
;
5919 BOOLEAN OperandSize
, AddressSize
;
5921 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5923 /* Make sure this is the right instruction */
5924 ASSERT((Opcode
& 0xFE) == 0xAE);
5926 TOGGLE_OPSIZE(OperandSize
);
5927 TOGGLE_ADSIZE(AddressSize
);
5929 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5930 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5932 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5933 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5940 /* Calculate the size */
5941 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5942 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5944 /* Calculate the mask and sign flag */
5945 SignFlag
= 1 << ((DataSize
* 8) - 1);
5946 DataMask
= SignFlag
| (SignFlag
- 1);
5948 /* Read from the source operand */
5949 if (!Fast486ReadMemory(State
,
5951 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5952 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5957 /* Exception occurred */
5961 /* Calculate the result */
5962 FirstValue
&= DataMask
;
5963 SecondValue
&= DataMask
;
5964 Result
= (FirstValue
- SecondValue
) & DataMask
;
5966 /* Update the flags */
5967 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5968 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5969 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5970 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5971 State
->Flags
.Zf
= (Result
== 0);
5972 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5973 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5975 /* Increment/decrement EDI */
5978 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5979 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5983 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5984 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5987 // FIXME: This method is slow!
5988 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5989 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5991 BOOLEAN Repeat
= TRUE
;
5995 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6003 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6010 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6011 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6013 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6019 /* Repeat the instruction */
6020 State
->InstPtr
= State
->SavedInstPtr
;
6024 /* Return success */
6028 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6031 BOOLEAN OperandSize
, AddressSize
;
6033 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6035 /* Make sure this is the right instruction */
6036 ASSERT((Opcode
& 0xFE) == 0x6C);
6038 TOGGLE_OPSIZE(OperandSize
);
6039 TOGGLE_ADSIZE(AddressSize
);
6041 /* Calculate the size */
6042 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6043 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6045 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6047 UCHAR Block
[STRING_BLOCK_SIZE
];
6048 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6049 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6051 /* Clear the memory block */
6052 RtlZeroMemory(Block
, sizeof(Block
));
6054 /* Transfer until finished */
6057 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6059 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6062 ULONG MaxBytes
= State
->Flags
.Df
6063 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6064 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6066 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6067 if (Processed
== 0) Processed
= 1;
6070 /* Read from the I/O port */
6071 State
->IoReadCallback(State
,
6072 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6077 if (State
->Flags
.Df
)
6081 /* Reduce EDI by the number of bytes to transfer */
6082 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6083 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6085 /* Reverse the block data */
6086 for (i
= 0; i
< Processed
/ 2; i
++)
6088 /* Swap the values */
6089 for (j
= 0; j
< DataSize
; j
++)
6091 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6092 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6093 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6098 /* Write to memory */
6099 if (!Fast486WriteMemory(State
,
6101 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6102 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6104 Processed
* DataSize
))
6107 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6108 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6110 /* Exception occurred */
6114 if (!State
->Flags
.Df
)
6116 /* Increase EDI by the number of bytes transfered */
6117 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6118 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6121 /* Reduce the total count by the number processed in this run */
6126 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6127 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6133 /* Read from the I/O port */
6134 State
->IoReadCallback(State
,
6135 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6140 /* Write to the destination operand */
6141 if (!Fast486WriteMemory(State
,
6143 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6144 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6148 /* Exception occurred */
6152 /* Increment/decrement EDI */
6155 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6156 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6160 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6161 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6165 /* Return success */
6169 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6172 BOOLEAN OperandSize
, AddressSize
;
6174 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6176 /* Make sure this is the right instruction */
6177 ASSERT((Opcode
& 0xFE) == 0x6E);
6179 TOGGLE_OPSIZE(OperandSize
);
6180 TOGGLE_ADSIZE(AddressSize
);
6182 /* Calculate the size */
6183 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6184 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6186 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6188 UCHAR Block
[STRING_BLOCK_SIZE
];
6189 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6190 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6192 /* Clear the memory block */
6193 RtlZeroMemory(Block
, sizeof(Block
));
6195 /* Transfer until finished */
6198 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6200 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6203 ULONG MaxBytes
= State
->Flags
.Df
6204 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6205 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6207 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6208 if (Processed
== 0) Processed
= 1;
6211 /* Read from memory */
6212 if (!Fast486ReadMemory(State
,
6214 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6215 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6218 Processed
* DataSize
))
6221 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6222 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6224 /* Exception occurred */
6228 if (State
->Flags
.Df
)
6232 /* Reduce EDI by the number of bytes to transfer */
6233 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6234 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6236 /* Reverse the block data */
6237 for (i
= 0; i
< Processed
/ 2; i
++)
6239 /* Swap the values */
6240 for (j
= 0; j
< DataSize
; j
++)
6242 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6243 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6244 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6249 /* Write to the I/O port */
6250 State
->IoWriteCallback(State
,
6251 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6256 if (!State
->Flags
.Df
)
6258 /* Increase EDI by the number of bytes transfered */
6259 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6260 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6263 /* Reduce the total count by the number processed in this run */
6268 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6269 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6275 /* Read from the source operand */
6276 if (!Fast486ReadMemory(State
,
6278 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6279 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6284 /* Exception occurred */
6288 /* Write to the I/O port */
6289 State
->IoWriteCallback(State
,
6290 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6295 /* Increment/decrement ESI */
6298 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6299 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6303 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6304 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6308 /* Return success */