2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /* INCLUDES *******************************************************************/
35 /* PUBLIC VARIABLES ***********************************************************/
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
40 Fast486OpcodeAddByteModrm
,
41 Fast486OpcodeAddModrm
,
42 Fast486OpcodeAddByteModrm
,
43 Fast486OpcodeAddModrm
,
48 Fast486OpcodeOrByteModrm
,
50 Fast486OpcodeOrByteModrm
,
55 Fast486OpcodeExtended
,
56 Fast486OpcodeAdcByteModrm
,
57 Fast486OpcodeAdcModrm
,
58 Fast486OpcodeAdcByteModrm
,
59 Fast486OpcodeAdcModrm
,
64 Fast486OpcodeSbbByteModrm
,
65 Fast486OpcodeSbbModrm
,
66 Fast486OpcodeSbbByteModrm
,
67 Fast486OpcodeSbbModrm
,
72 Fast486OpcodeAndByteModrm
,
73 Fast486OpcodeAndModrm
,
74 Fast486OpcodeAndByteModrm
,
75 Fast486OpcodeAndModrm
,
80 Fast486OpcodeCmpSubByteModrm
,
81 Fast486OpcodeCmpSubModrm
,
82 Fast486OpcodeCmpSubByteModrm
,
83 Fast486OpcodeCmpSubModrm
,
84 Fast486OpcodeCmpSubAl
,
85 Fast486OpcodeCmpSubEax
,
88 Fast486OpcodeXorByteModrm
,
89 Fast486OpcodeXorModrm
,
90 Fast486OpcodeXorByteModrm
,
91 Fast486OpcodeXorModrm
,
96 Fast486OpcodeCmpSubByteModrm
,
97 Fast486OpcodeCmpSubModrm
,
98 Fast486OpcodeCmpSubByteModrm
,
99 Fast486OpcodeCmpSubModrm
,
100 Fast486OpcodeCmpSubAl
,
101 Fast486OpcodeCmpSubEax
,
104 Fast486OpcodeIncrement
,
105 Fast486OpcodeIncrement
,
106 Fast486OpcodeIncrement
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeDecrement
,
113 Fast486OpcodeDecrement
,
114 Fast486OpcodeDecrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodePushReg
,
121 Fast486OpcodePushReg
,
122 Fast486OpcodePushReg
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
136 Fast486OpcodePushAll
,
144 Fast486OpcodePushImm
,
145 Fast486OpcodeImulModrmImm
,
146 Fast486OpcodePushByteImm
,
147 Fast486OpcodeImulModrmImm
,
152 Fast486OpcodeShortConditionalJmp
,
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 Fast486OpcodeGroup8082
,
169 Fast486OpcodeGroup81
,
170 Fast486OpcodeGroup8082
,
171 Fast486OpcodeGroup83
,
172 Fast486OpcodeTestByteModrm
,
173 Fast486OpcodeTestModrm
,
174 Fast486OpcodeXchgByteModrm
,
175 Fast486OpcodeXchgModrm
,
176 Fast486OpcodeMovByteModrm
,
177 Fast486OpcodeMovModrm
,
178 Fast486OpcodeMovByteModrm
,
179 Fast486OpcodeMovModrm
,
180 Fast486OpcodeMovStoreSeg
,
182 Fast486OpcodeMovLoadSeg
,
183 Fast486OpcodeGroup8F
,
185 Fast486OpcodeExchangeEax
,
186 Fast486OpcodeExchangeEax
,
187 Fast486OpcodeExchangeEax
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
194 Fast486OpcodeCallAbs
,
196 Fast486OpcodePushFlags
,
197 Fast486OpcodePopFlags
,
200 Fast486OpcodeMovAlOffset
,
201 Fast486OpcodeMovEaxOffset
,
202 Fast486OpcodeMovOffsetAl
,
203 Fast486OpcodeMovOffsetEax
,
209 Fast486OpcodeTestEax
,
216 Fast486OpcodeMovByteRegImm
,
217 Fast486OpcodeMovByteRegImm
,
218 Fast486OpcodeMovByteRegImm
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovRegImm
,
225 Fast486OpcodeMovRegImm
,
226 Fast486OpcodeMovRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeGroupC0
,
233 Fast486OpcodeGroupC1
,
238 Fast486OpcodeGroupC6
,
239 Fast486OpcodeGroupC7
,
248 Fast486OpcodeGroupD0
,
249 Fast486OpcodeGroupD1
,
250 Fast486OpcodeGroupD2
,
251 Fast486OpcodeGroupD3
,
256 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
257 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
258 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
259 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
260 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
261 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
262 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
263 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
270 Fast486OpcodeOutByte
,
275 Fast486OpcodeShortJump
,
278 Fast486OpcodeOutByte
,
285 Fast486OpcodeComplCarry
,
286 Fast486OpcodeGroupF6
,
287 Fast486OpcodeGroupF7
,
288 Fast486OpcodeClearCarry
,
289 Fast486OpcodeSetCarry
,
290 Fast486OpcodeClearInt
,
292 Fast486OpcodeClearDir
,
294 Fast486OpcodeGroupFE
,
295 Fast486OpcodeGroupFF
,
298 /* PUBLIC FUNCTIONS ***********************************************************/
300 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
302 BOOLEAN Valid
= FALSE
;
309 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
311 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
312 State
->SegmentOverride
= FAST486_REG_ES
;
322 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
324 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
325 State
->SegmentOverride
= FAST486_REG_CS
;
335 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
337 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
338 State
->SegmentOverride
= FAST486_REG_SS
;
348 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
350 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
351 State
->SegmentOverride
= FAST486_REG_DS
;
361 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
363 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
364 State
->SegmentOverride
= FAST486_REG_FS
;
374 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
376 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
377 State
->SegmentOverride
= FAST486_REG_GS
;
387 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
389 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
399 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
401 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
410 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
412 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
422 /* Mutually exclusive with REP */
423 if (!(State
->PrefixFlags
424 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
426 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
436 /* Mutually exclusive with REPNZ */
437 if (!(State
->PrefixFlags
438 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
440 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
450 /* Clear all prefixes */
451 State
->PrefixFlags
= 0;
453 /* Throw an exception */
454 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
461 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
464 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
469 /* Make sure this is the right instruction */
470 ASSERT((Opcode
& 0xF8) == 0x40);
474 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
476 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
477 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
481 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
483 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
484 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
487 State
->Flags
.Zf
= (Value
== 0);
488 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
489 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
495 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
498 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
503 /* Make sure this is the right instruction */
504 ASSERT((Opcode
& 0xF8) == 0x48);
508 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
510 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
511 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
515 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
517 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
518 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
521 State
->Flags
.Zf
= (Value
== 0);
522 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
523 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
529 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
533 /* Make sure this is the right instruction */
534 ASSERT((Opcode
& 0xF8) == 0x50);
536 /* Call the internal function */
537 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
540 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
543 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_SS
].Size
;
548 /* Make sure this is the right instruction */
549 ASSERT((Opcode
& 0xF8) == 0x58);
551 /* Call the internal function */
552 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
554 /* Store the value */
555 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
556 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
562 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
564 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
567 State
->IdleCallback(State
);
573 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
575 INT Reg
= Opcode
& 0x07;
576 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
581 /* Make sure this is the right instruction */
582 ASSERT((Opcode
& 0xF8) == 0x90);
584 /* Exchange the values */
589 Value
= State
->GeneralRegs
[Reg
].Long
;
590 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
591 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
597 Value
= State
->GeneralRegs
[Reg
].LowWord
;
598 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
599 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
605 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
607 BOOLEAN Jump
= FALSE
;
610 /* Make sure this is the right instruction */
611 ASSERT((Opcode
& 0xF0) == 0x70);
613 /* Fetch the offset */
614 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
616 /* An exception occurred */
620 switch ((Opcode
& 0x0F) >> 1)
625 Jump
= State
->Flags
.Of
;
632 Jump
= State
->Flags
.Cf
;
639 Jump
= State
->Flags
.Zf
;
646 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
653 Jump
= State
->Flags
.Sf
;
660 Jump
= State
->Flags
.Pf
;
667 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
674 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
681 /* Invert the result */
687 /* Move the instruction pointer */
688 State
->InstPtr
.Long
+= Offset
;
695 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
697 /* Make sure this is the right instruction */
698 ASSERT(Opcode
== 0xF8);
700 /* No prefixes allowed */
701 if (State
->PrefixFlags
)
703 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
707 /* Clear CF and return success */
708 State
->Flags
.Cf
= FALSE
;
712 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
714 /* Make sure this is the right instruction */
715 ASSERT(Opcode
== 0xF9);
717 /* No prefixes allowed */
718 if (State
->PrefixFlags
)
720 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
724 /* Set CF and return success*/
725 State
->Flags
.Cf
= TRUE
;
729 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
731 /* Make sure this is the right instruction */
732 ASSERT(Opcode
== 0xF5);
734 /* No prefixes allowed */
735 if (State
->PrefixFlags
)
737 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
741 /* Toggle CF and return success */
742 State
->Flags
.Cf
= !State
->Flags
.Cf
;
746 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
748 /* Make sure this is the right instruction */
749 ASSERT(Opcode
== 0xFA);
751 /* No prefixes allowed */
752 if (State
->PrefixFlags
)
754 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
758 /* Check for protected mode */
759 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
762 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
764 /* Clear the interrupt flag */
765 State
->Flags
.If
= FALSE
;
769 /* General Protection Fault */
770 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
776 /* Just clear the interrupt flag */
777 State
->Flags
.If
= FALSE
;
784 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
786 /* Make sure this is the right instruction */
787 ASSERT(Opcode
== 0xFB);
789 /* No prefixes allowed */
790 if (State
->PrefixFlags
)
792 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
796 /* Check for protected mode */
797 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
800 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
802 /* Set the interrupt flag */
803 State
->Flags
.If
= TRUE
;
807 /* General Protection Fault */
808 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
814 /* Just set the interrupt flag */
815 State
->Flags
.If
= TRUE
;
822 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
824 /* Make sure this is the right instruction */
825 ASSERT(Opcode
== 0xFC);
827 /* No prefixes allowed */
828 if (State
->PrefixFlags
)
830 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
834 /* Clear DF and return success */
835 State
->Flags
.Df
= FALSE
;
839 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
841 /* Make sure this is the right instruction */
842 ASSERT(Opcode
== 0xFD);
844 /* No prefixes allowed */
845 if (State
->PrefixFlags
)
847 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
851 /* Set DF and return success*/
852 State
->Flags
.Df
= TRUE
;
856 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
858 /* Make sure this is the right instruction */
859 ASSERT(Opcode
== 0xF4);
861 /* No prefixes allowed */
862 if (State
->PrefixFlags
)
864 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
868 /* Privileged instructions can only be executed under CPL = 0 */
869 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
871 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
876 while (State
->IntStatus
!= FAST486_INT_SIGNAL
) State
->IdleCallback(State
);
882 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
887 /* Make sure this is the right instruction */
888 ASSERT((Opcode
& 0xF7) == 0xE4);
892 /* Fetch the parameter */
893 if (!Fast486FetchByte(State
, &Data
))
895 /* Exception occurred */
899 /* Set the port number to the parameter */
904 /* The port number is in DX */
905 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
908 /* Read a byte from the I/O port */
909 State
->IoReadCallback(State
, Port
, &Data
, sizeof(UCHAR
));
911 /* Store the result in AL */
912 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
917 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
920 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
922 /* Make sure this is the right instruction */
923 ASSERT((Opcode
& 0xF7) == 0xE5);
932 /* Fetch the parameter */
933 if (!Fast486FetchByte(State
, &Data
))
935 /* Exception occurred */
939 /* Set the port number to the parameter */
944 /* The port number is in DX */
945 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
952 /* Read a dword from the I/O port */
953 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
955 /* Store the value in EAX */
956 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
962 /* Read a word from the I/O port */
963 State
->IoReadCallback(State
, Port
, &Data
, sizeof(USHORT
));
965 /* Store the value in AX */
966 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
972 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
977 /* Make sure this is the right instruction */
978 ASSERT((Opcode
& 0xF7) == 0xE6);
982 /* Fetch the parameter */
983 if (!Fast486FetchByte(State
, &Data
))
985 /* Exception occurred */
989 /* Set the port number to the parameter */
994 /* The port number is in DX */
995 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
998 /* Read the value from AL */
999 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1001 /* Write the byte to the I/O port */
1002 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(UCHAR
));
1007 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1010 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1012 /* Make sure this is the right instruction */
1013 ASSERT((Opcode
& 0xF7) == 0xE7);
1015 TOGGLE_OPSIZE(Size
);
1022 /* Fetch the parameter */
1023 if (!Fast486FetchByte(State
, &Data
))
1025 /* Exception occurred */
1029 /* Set the port number to the parameter */
1034 /* The port number is in DX */
1035 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1040 /* Get the value from EAX */
1041 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1043 /* Write a dword to the I/O port */
1044 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1048 /* Get the value from AX */
1049 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1051 /* Write a word to the I/O port */
1052 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(USHORT
));
1058 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1062 /* Make sure this is the right instruction */
1063 ASSERT(Opcode
== 0xEB);
1065 /* Fetch the offset */
1066 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1068 /* An exception occurred */
1072 /* Move the instruction pointer */
1073 State
->InstPtr
.Long
+= Offset
;
1078 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1080 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1082 /* Make sure this is the right instruction */
1083 ASSERT((Opcode
& 0xF8) == 0xB8);
1085 TOGGLE_OPSIZE(Size
);
1092 /* Fetch the dword */
1093 if (!Fast486FetchDword(State
, &Value
))
1095 /* Exception occurred */
1099 /* Store the value in the register */
1100 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1106 /* Fetch the word */
1107 if (!Fast486FetchWord(State
, &Value
))
1109 /* Exception occurred */
1113 /* Store the value in the register */
1114 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1120 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1124 /* Make sure this is the right instruction */
1125 ASSERT((Opcode
& 0xF8) == 0xB0);
1127 if (State
->PrefixFlags
!= 0)
1129 /* Invalid prefix */
1130 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1134 /* Fetch the byte */
1135 if (!Fast486FetchByte(State
, &Value
))
1137 /* Exception occurred */
1143 /* AH, CH, DH or BH */
1144 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1148 /* AL, CL, DL or BL */
1149 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1155 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1157 UCHAR FirstValue
, SecondValue
, Result
;
1158 FAST486_MOD_REG_RM ModRegRm
;
1159 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1161 /* Make sure this is the right instruction */
1162 ASSERT((Opcode
& 0xFD) == 0x00);
1164 TOGGLE_ADSIZE(AddressSize
);
1166 /* Get the operands */
1167 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1169 /* Exception occurred */
1173 if (!Fast486ReadModrmByteOperands(State
,
1178 /* Exception occurred */
1182 /* Calculate the result */
1183 Result
= FirstValue
+ SecondValue
;
1185 /* Update the flags */
1186 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1187 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1188 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1189 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1190 State
->Flags
.Zf
= (Result
== 0);
1191 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1192 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1194 /* Write back the result */
1195 return Fast486WriteModrmByteOperands(State
,
1197 Opcode
& FAST486_OPCODE_WRITE_REG
,
1201 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1203 FAST486_MOD_REG_RM ModRegRm
;
1204 BOOLEAN OperandSize
, AddressSize
;
1206 /* Make sure this is the right instruction */
1207 ASSERT((Opcode
& 0xFD) == 0x01);
1209 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1211 TOGGLE_ADSIZE(AddressSize
);
1212 TOGGLE_OPSIZE(OperandSize
);
1214 /* Get the operands */
1215 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1217 /* Exception occurred */
1221 /* Check the operand size */
1224 ULONG FirstValue
, SecondValue
, Result
;
1226 if (!Fast486ReadModrmDwordOperands(State
,
1231 /* Exception occurred */
1235 /* Calculate the result */
1236 Result
= FirstValue
+ SecondValue
;
1238 /* Update the flags */
1239 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1240 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1241 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1242 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1243 State
->Flags
.Zf
= (Result
== 0);
1244 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1245 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1247 /* Write back the result */
1248 return Fast486WriteModrmDwordOperands(State
,
1250 Opcode
& FAST486_OPCODE_WRITE_REG
,
1255 USHORT FirstValue
, SecondValue
, Result
;
1257 if (!Fast486ReadModrmWordOperands(State
,
1262 /* Exception occurred */
1266 /* Calculate the result */
1267 Result
= FirstValue
+ SecondValue
;
1269 /* Update the flags */
1270 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1271 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1272 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1273 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1274 State
->Flags
.Zf
= (Result
== 0);
1275 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1276 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1278 /* Write back the result */
1279 return Fast486WriteModrmWordOperands(State
,
1281 Opcode
& FAST486_OPCODE_WRITE_REG
,
1286 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1288 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1289 UCHAR SecondValue
, Result
;
1291 /* Make sure this is the right instruction */
1292 ASSERT(Opcode
== 0x04);
1294 if (State
->PrefixFlags
)
1296 /* This opcode doesn't take any prefixes */
1297 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1301 if (!Fast486FetchByte(State
, &SecondValue
))
1303 /* Exception occurred */
1307 /* Calculate the result */
1308 Result
= FirstValue
+ SecondValue
;
1310 /* Update the flags */
1311 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1312 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1313 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1314 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1315 State
->Flags
.Zf
= (Result
== 0);
1316 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1317 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1319 /* Write back the result */
1320 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1325 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1327 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1329 /* Make sure this is the right instruction */
1330 ASSERT(Opcode
== 0x05);
1333 TOGGLE_OPSIZE(Size
);
1337 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1338 ULONG SecondValue
, Result
;
1340 if (!Fast486FetchDword(State
, &SecondValue
))
1342 /* Exception occurred */
1346 /* Calculate the result */
1347 Result
= FirstValue
+ SecondValue
;
1349 /* Update the flags */
1350 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1351 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1352 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1353 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1354 State
->Flags
.Zf
= (Result
== 0);
1355 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1356 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1358 /* Write back the result */
1359 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1363 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1364 USHORT SecondValue
, Result
;
1366 if (!Fast486FetchWord(State
, &SecondValue
))
1368 /* Exception occurred */
1372 /* Calculate the result */
1373 Result
= FirstValue
+ SecondValue
;
1375 /* Update the flags */
1376 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1377 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1378 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1379 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1380 State
->Flags
.Zf
= (Result
== 0);
1381 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1382 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1384 /* Write back the result */
1385 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1391 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1393 UCHAR FirstValue
, SecondValue
, Result
;
1394 FAST486_MOD_REG_RM ModRegRm
;
1395 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1397 /* Make sure this is the right instruction */
1398 ASSERT((Opcode
& 0xFD) == 0x08);
1400 TOGGLE_ADSIZE(AddressSize
);
1402 /* Get the operands */
1403 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1405 /* Exception occurred */
1409 if (!Fast486ReadModrmByteOperands(State
,
1414 /* Exception occurred */
1418 /* Calculate the result */
1419 Result
= FirstValue
| SecondValue
;
1421 /* Update the flags */
1422 State
->Flags
.Cf
= FALSE
;
1423 State
->Flags
.Of
= FALSE
;
1424 State
->Flags
.Zf
= (Result
== 0);
1425 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1426 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1428 /* Write back the result */
1429 return Fast486WriteModrmByteOperands(State
,
1431 Opcode
& FAST486_OPCODE_WRITE_REG
,
1435 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1437 FAST486_MOD_REG_RM ModRegRm
;
1438 BOOLEAN OperandSize
, AddressSize
;
1440 /* Make sure this is the right instruction */
1441 ASSERT((Opcode
& 0xFD) == 0x09);
1443 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1445 TOGGLE_ADSIZE(AddressSize
);
1446 TOGGLE_OPSIZE(OperandSize
);
1448 /* Get the operands */
1449 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1451 /* Exception occurred */
1455 /* Check the operand size */
1458 ULONG FirstValue
, SecondValue
, Result
;
1460 if (!Fast486ReadModrmDwordOperands(State
,
1465 /* Exception occurred */
1469 /* Calculate the result */
1470 Result
= FirstValue
| SecondValue
;
1472 /* Update the flags */
1473 State
->Flags
.Cf
= FALSE
;
1474 State
->Flags
.Of
= FALSE
;
1475 State
->Flags
.Zf
= (Result
== 0);
1476 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1477 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1479 /* Write back the result */
1480 return Fast486WriteModrmDwordOperands(State
,
1482 Opcode
& FAST486_OPCODE_WRITE_REG
,
1487 USHORT FirstValue
, SecondValue
, Result
;
1489 if (!Fast486ReadModrmWordOperands(State
,
1494 /* Exception occurred */
1498 /* Calculate the result */
1499 Result
= FirstValue
| SecondValue
;
1501 /* Update the flags */
1502 State
->Flags
.Cf
= FALSE
;
1503 State
->Flags
.Of
= FALSE
;
1504 State
->Flags
.Zf
= (Result
== 0);
1505 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1506 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1508 /* Write back the result */
1509 return Fast486WriteModrmWordOperands(State
,
1511 Opcode
& FAST486_OPCODE_WRITE_REG
,
1516 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1518 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1519 UCHAR SecondValue
, Result
;
1521 /* Make sure this is the right instruction */
1522 ASSERT(Opcode
== 0x0C);
1524 if (State
->PrefixFlags
)
1526 /* This opcode doesn't take any prefixes */
1527 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1531 if (!Fast486FetchByte(State
, &SecondValue
))
1533 /* Exception occurred */
1537 /* Calculate the result */
1538 Result
= FirstValue
| SecondValue
;
1540 /* Update the flags */
1541 State
->Flags
.Cf
= FALSE
;
1542 State
->Flags
.Of
= FALSE
;
1543 State
->Flags
.Zf
= (Result
== 0);
1544 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1545 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1547 /* Write back the result */
1548 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1553 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1555 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1557 /* Make sure this is the right instruction */
1558 ASSERT(Opcode
== 0x0D);
1561 TOGGLE_OPSIZE(Size
);
1565 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1566 ULONG SecondValue
, Result
;
1568 if (!Fast486FetchDword(State
, &SecondValue
))
1570 /* Exception occurred */
1574 /* Calculate the result */
1575 Result
= FirstValue
| SecondValue
;
1577 /* Update the flags */
1578 State
->Flags
.Cf
= FALSE
;
1579 State
->Flags
.Of
= FALSE
;
1580 State
->Flags
.Zf
= (Result
== 0);
1581 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1582 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1584 /* Write back the result */
1585 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1589 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1590 USHORT SecondValue
, Result
;
1592 if (!Fast486FetchWord(State
, &SecondValue
))
1594 /* Exception occurred */
1598 /* Calculate the result */
1599 Result
= FirstValue
| SecondValue
;
1601 /* Update the flags */
1602 State
->Flags
.Cf
= FALSE
;
1603 State
->Flags
.Of
= FALSE
;
1604 State
->Flags
.Zf
= (Result
== 0);
1605 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1606 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1608 /* Write back the result */
1609 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1615 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1617 UCHAR FirstValue
, SecondValue
, Result
;
1618 FAST486_MOD_REG_RM ModRegRm
;
1619 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1621 /* Make sure this is the right instruction */
1622 ASSERT((Opcode
& 0xFD) == 0x20);
1624 TOGGLE_ADSIZE(AddressSize
);
1626 /* Get the operands */
1627 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1629 /* Exception occurred */
1633 if (!Fast486ReadModrmByteOperands(State
,
1638 /* Exception occurred */
1642 /* Calculate the result */
1643 Result
= FirstValue
& SecondValue
;
1645 /* Update the flags */
1646 State
->Flags
.Cf
= FALSE
;
1647 State
->Flags
.Of
= FALSE
;
1648 State
->Flags
.Zf
= (Result
== 0);
1649 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1650 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1652 /* Write back the result */
1653 return Fast486WriteModrmByteOperands(State
,
1655 Opcode
& FAST486_OPCODE_WRITE_REG
,
1659 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1661 FAST486_MOD_REG_RM ModRegRm
;
1662 BOOLEAN OperandSize
, AddressSize
;
1664 /* Make sure this is the right instruction */
1665 ASSERT((Opcode
& 0xFD) == 0x21);
1667 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1669 TOGGLE_ADSIZE(AddressSize
);
1670 TOGGLE_OPSIZE(OperandSize
);
1672 /* Get the operands */
1673 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1675 /* Exception occurred */
1679 /* Check the operand size */
1682 ULONG FirstValue
, SecondValue
, Result
;
1684 if (!Fast486ReadModrmDwordOperands(State
,
1689 /* Exception occurred */
1693 /* Calculate the result */
1694 Result
= FirstValue
& SecondValue
;
1696 /* Update the flags */
1697 State
->Flags
.Cf
= FALSE
;
1698 State
->Flags
.Of
= FALSE
;
1699 State
->Flags
.Zf
= (Result
== 0);
1700 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1701 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1703 /* Write back the result */
1704 return Fast486WriteModrmDwordOperands(State
,
1706 Opcode
& FAST486_OPCODE_WRITE_REG
,
1711 USHORT FirstValue
, SecondValue
, Result
;
1713 if (!Fast486ReadModrmWordOperands(State
,
1718 /* Exception occurred */
1722 /* Calculate the result */
1723 Result
= FirstValue
& SecondValue
;
1725 /* Update the flags */
1726 State
->Flags
.Cf
= FALSE
;
1727 State
->Flags
.Of
= FALSE
;
1728 State
->Flags
.Zf
= (Result
== 0);
1729 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1730 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1732 /* Write back the result */
1733 return Fast486WriteModrmWordOperands(State
,
1735 Opcode
& FAST486_OPCODE_WRITE_REG
,
1740 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1742 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1743 UCHAR SecondValue
, Result
;
1745 /* Make sure this is the right instruction */
1746 ASSERT(Opcode
== 0x24);
1750 if (!Fast486FetchByte(State
, &SecondValue
))
1752 /* Exception occurred */
1756 /* Calculate the result */
1757 Result
= FirstValue
& SecondValue
;
1759 /* Update the flags */
1760 State
->Flags
.Cf
= FALSE
;
1761 State
->Flags
.Of
= FALSE
;
1762 State
->Flags
.Zf
= (Result
== 0);
1763 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1764 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1766 /* Write back the result */
1767 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1772 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1774 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1776 /* Make sure this is the right instruction */
1777 ASSERT(Opcode
== 0x25);
1780 TOGGLE_OPSIZE(Size
);
1784 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1785 ULONG SecondValue
, Result
;
1787 if (!Fast486FetchDword(State
, &SecondValue
))
1789 /* Exception occurred */
1793 /* Calculate the result */
1794 Result
= FirstValue
& SecondValue
;
1796 /* Update the flags */
1797 State
->Flags
.Cf
= FALSE
;
1798 State
->Flags
.Of
= FALSE
;
1799 State
->Flags
.Zf
= (Result
== 0);
1800 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1801 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1803 /* Write back the result */
1804 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1808 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1809 USHORT SecondValue
, Result
;
1811 if (!Fast486FetchWord(State
, &SecondValue
))
1813 /* Exception occurred */
1817 /* Calculate the result */
1818 Result
= FirstValue
& SecondValue
;
1820 /* Update the flags */
1821 State
->Flags
.Cf
= FALSE
;
1822 State
->Flags
.Of
= FALSE
;
1823 State
->Flags
.Zf
= (Result
== 0);
1824 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1825 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1827 /* Write back the result */
1828 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1834 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1836 UCHAR FirstValue
, SecondValue
, Result
;
1837 FAST486_MOD_REG_RM ModRegRm
;
1838 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1840 /* Make sure this is the right instruction */
1841 ASSERT((Opcode
& 0xFD) == 0x30);
1843 TOGGLE_ADSIZE(AddressSize
);
1845 /* Get the operands */
1846 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1848 /* Exception occurred */
1852 if (!Fast486ReadModrmByteOperands(State
,
1857 /* Exception occurred */
1861 /* Calculate the result */
1862 Result
= FirstValue
^ SecondValue
;
1864 /* Update the flags */
1865 State
->Flags
.Cf
= FALSE
;
1866 State
->Flags
.Of
= FALSE
;
1867 State
->Flags
.Zf
= (Result
== 0);
1868 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1869 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1871 /* Write back the result */
1872 return Fast486WriteModrmByteOperands(State
,
1874 Opcode
& FAST486_OPCODE_WRITE_REG
,
1878 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1880 FAST486_MOD_REG_RM ModRegRm
;
1881 BOOLEAN OperandSize
, AddressSize
;
1883 /* Make sure this is the right instruction */
1884 ASSERT((Opcode
& 0xFD) == 0x31);
1886 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1888 TOGGLE_ADSIZE(AddressSize
);
1889 TOGGLE_OPSIZE(OperandSize
);
1891 /* Get the operands */
1892 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1894 /* Exception occurred */
1898 /* Check the operand size */
1901 ULONG FirstValue
, SecondValue
, Result
;
1903 if (!Fast486ReadModrmDwordOperands(State
,
1908 /* Exception occurred */
1912 /* Calculate the result */
1913 Result
= FirstValue
^ SecondValue
;
1915 /* Update the flags */
1916 State
->Flags
.Cf
= FALSE
;
1917 State
->Flags
.Of
= FALSE
;
1918 State
->Flags
.Zf
= (Result
== 0);
1919 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1920 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1922 /* Write back the result */
1923 return Fast486WriteModrmDwordOperands(State
,
1925 Opcode
& FAST486_OPCODE_WRITE_REG
,
1930 USHORT FirstValue
, SecondValue
, Result
;
1932 if (!Fast486ReadModrmWordOperands(State
,
1937 /* Exception occurred */
1941 /* Calculate the result */
1942 Result
= FirstValue
^ SecondValue
;
1944 /* Update the flags */
1945 State
->Flags
.Cf
= FALSE
;
1946 State
->Flags
.Of
= FALSE
;
1947 State
->Flags
.Zf
= (Result
== 0);
1948 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1949 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1951 /* Write back the result */
1952 return Fast486WriteModrmWordOperands(State
,
1954 Opcode
& FAST486_OPCODE_WRITE_REG
,
1959 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1961 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1962 UCHAR SecondValue
, Result
;
1964 /* Make sure this is the right instruction */
1965 ASSERT(Opcode
== 0x34);
1967 if (State
->PrefixFlags
)
1969 /* This opcode doesn't take any prefixes */
1970 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1974 if (!Fast486FetchByte(State
, &SecondValue
))
1976 /* Exception occurred */
1980 /* Calculate the result */
1981 Result
= FirstValue
^ SecondValue
;
1983 /* Update the flags */
1984 State
->Flags
.Cf
= FALSE
;
1985 State
->Flags
.Of
= FALSE
;
1986 State
->Flags
.Zf
= (Result
== 0);
1987 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1988 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1990 /* Write back the result */
1991 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1996 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
1998 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2000 /* Make sure this is the right instruction */
2001 ASSERT(Opcode
== 0x35);
2004 TOGGLE_OPSIZE(Size
);
2008 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2009 ULONG SecondValue
, Result
;
2011 if (!Fast486FetchDword(State
, &SecondValue
))
2013 /* Exception occurred */
2017 /* Calculate the result */
2018 Result
= FirstValue
^ SecondValue
;
2020 /* Update the flags */
2021 State
->Flags
.Cf
= FALSE
;
2022 State
->Flags
.Of
= FALSE
;
2023 State
->Flags
.Zf
= (Result
== 0);
2024 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2025 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2027 /* Write back the result */
2028 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2032 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2033 USHORT SecondValue
, Result
;
2035 if (!Fast486FetchWord(State
, &SecondValue
))
2037 /* Exception occurred */
2041 /* Calculate the result */
2042 Result
= FirstValue
^ SecondValue
;
2044 /* Update the flags */
2045 State
->Flags
.Cf
= FALSE
;
2046 State
->Flags
.Of
= FALSE
;
2047 State
->Flags
.Zf
= (Result
== 0);
2048 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2049 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2051 /* Write back the result */
2052 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2058 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2060 UCHAR FirstValue
, SecondValue
, Result
;
2061 FAST486_MOD_REG_RM ModRegRm
;
2062 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2064 /* Make sure this is the right instruction */
2065 ASSERT(Opcode
== 0x84);
2067 TOGGLE_ADSIZE(AddressSize
);
2069 /* Get the operands */
2070 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2072 /* Exception occurred */
2076 if (!Fast486ReadModrmByteOperands(State
,
2081 /* Exception occurred */
2084 /* Calculate the result */
2085 Result
= FirstValue
& SecondValue
;
2087 /* Update the flags */
2088 State
->Flags
.Cf
= FALSE
;
2089 State
->Flags
.Of
= FALSE
;
2090 State
->Flags
.Zf
= (Result
== 0);
2091 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2092 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2094 /* The result is discarded */
2098 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2100 FAST486_MOD_REG_RM ModRegRm
;
2101 BOOLEAN OperandSize
, AddressSize
;
2103 /* Make sure this is the right instruction */
2104 ASSERT(Opcode
== 0x85);
2106 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2108 TOGGLE_ADSIZE(AddressSize
);
2109 TOGGLE_OPSIZE(OperandSize
);
2111 /* Get the operands */
2112 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2114 /* Exception occurred */
2118 /* Check the operand size */
2121 ULONG FirstValue
, SecondValue
, Result
;
2123 if (!Fast486ReadModrmDwordOperands(State
,
2128 /* Exception occurred */
2132 /* Calculate the result */
2133 Result
= FirstValue
& SecondValue
;
2135 /* Update the flags */
2136 State
->Flags
.Cf
= FALSE
;
2137 State
->Flags
.Of
= FALSE
;
2138 State
->Flags
.Zf
= (Result
== 0);
2139 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2140 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2144 USHORT FirstValue
, SecondValue
, Result
;
2146 if (!Fast486ReadModrmWordOperands(State
,
2151 /* Exception occurred */
2155 /* Calculate the result */
2156 Result
= FirstValue
& SecondValue
;
2158 /* Update the flags */
2159 State
->Flags
.Cf
= FALSE
;
2160 State
->Flags
.Of
= FALSE
;
2161 State
->Flags
.Zf
= (Result
== 0);
2162 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2163 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2166 /* The result is discarded */
2170 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2172 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2173 UCHAR SecondValue
, Result
;
2175 /* Make sure this is the right instruction */
2176 ASSERT(Opcode
== 0xA8);
2178 if (State
->PrefixFlags
)
2180 /* This opcode doesn't take any prefixes */
2181 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2185 if (!Fast486FetchByte(State
, &SecondValue
))
2187 /* Exception occurred */
2191 /* Calculate the result */
2192 Result
= FirstValue
& SecondValue
;
2194 /* Update the flags */
2195 State
->Flags
.Cf
= FALSE
;
2196 State
->Flags
.Of
= FALSE
;
2197 State
->Flags
.Zf
= (Result
== 0);
2198 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2199 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2201 /* The result is discarded */
2205 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2207 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2209 /* Make sure this is the right instruction */
2210 ASSERT(Opcode
== 0xA9);
2213 TOGGLE_OPSIZE(Size
);
2217 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2218 ULONG SecondValue
, Result
;
2220 if (!Fast486FetchDword(State
, &SecondValue
))
2222 /* Exception occurred */
2226 /* Calculate the result */
2227 Result
= FirstValue
& SecondValue
;
2229 /* Update the flags */
2230 State
->Flags
.Cf
= FALSE
;
2231 State
->Flags
.Of
= FALSE
;
2232 State
->Flags
.Zf
= (Result
== 0);
2233 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2234 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2238 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2239 USHORT SecondValue
, Result
;
2241 if (!Fast486FetchWord(State
, &SecondValue
))
2243 /* Exception occurred */
2247 /* Calculate the result */
2248 Result
= FirstValue
& SecondValue
;
2250 /* Update the flags */
2251 State
->Flags
.Cf
= FALSE
;
2252 State
->Flags
.Of
= FALSE
;
2253 State
->Flags
.Zf
= (Result
== 0);
2254 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2255 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2258 /* The result is discarded */
2262 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2264 UCHAR FirstValue
, SecondValue
;
2265 FAST486_MOD_REG_RM ModRegRm
;
2266 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2268 /* Make sure this is the right instruction */
2269 ASSERT(Opcode
== 0x86);
2271 TOGGLE_ADSIZE(AddressSize
);
2273 /* Get the operands */
2274 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2276 /* Exception occurred */
2280 if (!Fast486ReadModrmByteOperands(State
,
2285 /* Exception occurred */
2289 /* Write the value from the register to the R/M */
2290 if (!Fast486WriteModrmByteOperands(State
,
2295 /* Exception occurred */
2299 /* Write the value from the R/M to the register */
2300 if (!Fast486WriteModrmByteOperands(State
,
2305 /* Exception occurred */
2312 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2314 FAST486_MOD_REG_RM ModRegRm
;
2315 BOOLEAN OperandSize
, AddressSize
;
2317 /* Make sure this is the right instruction */
2318 ASSERT(Opcode
== 0x87);
2320 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2322 TOGGLE_ADSIZE(AddressSize
);
2323 TOGGLE_OPSIZE(OperandSize
);
2325 /* Get the operands */
2326 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2328 /* Exception occurred */
2332 /* Check the operand size */
2335 ULONG FirstValue
, SecondValue
;
2337 if (!Fast486ReadModrmDwordOperands(State
,
2342 /* Exception occurred */
2346 /* Write the value from the register to the R/M */
2347 if (!Fast486WriteModrmDwordOperands(State
,
2352 /* Exception occurred */
2356 /* Write the value from the R/M to the register */
2357 if (!Fast486WriteModrmDwordOperands(State
,
2362 /* Exception occurred */
2368 USHORT FirstValue
, SecondValue
;
2370 if (!Fast486ReadModrmWordOperands(State
,
2375 /* Exception occurred */
2379 /* Write the value from the register to the R/M */
2380 if (!Fast486WriteModrmWordOperands(State
,
2385 /* Exception occurred */
2389 /* Write the value from the R/M to the register */
2390 if (!Fast486WriteModrmWordOperands(State
,
2395 /* Exception occurred */
2400 /* The result is discarded */
2404 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2406 /* Call the internal API */
2407 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2410 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2414 if (!Fast486StackPop(State
, &NewSelector
))
2416 /* Exception occurred */
2420 /* Call the internal API */
2421 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2424 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2426 /* Call the internal API */
2427 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2430 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2432 UCHAR FirstValue
, SecondValue
, Result
;
2433 FAST486_MOD_REG_RM ModRegRm
;
2434 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2436 /* Make sure this is the right instruction */
2437 ASSERT((Opcode
& 0xFD) == 0x10);
2439 TOGGLE_ADSIZE(AddressSize
);
2441 /* Get the operands */
2442 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2444 /* Exception occurred */
2448 if (!Fast486ReadModrmByteOperands(State
,
2453 /* Exception occurred */
2457 /* Calculate the result */
2458 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2460 /* Special exception for CF */
2461 State
->Flags
.Cf
= State
->Flags
.Cf
2462 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2464 /* Update the flags */
2465 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2466 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2467 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2468 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2469 State
->Flags
.Zf
= (Result
== 0);
2470 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2471 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2473 /* Write back the result */
2474 return Fast486WriteModrmByteOperands(State
,
2476 Opcode
& FAST486_OPCODE_WRITE_REG
,
2480 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2482 FAST486_MOD_REG_RM ModRegRm
;
2483 BOOLEAN OperandSize
, AddressSize
;
2485 /* Make sure this is the right instruction */
2486 ASSERT((Opcode
& 0xFD) == 0x11);
2488 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2490 TOGGLE_ADSIZE(AddressSize
);
2491 TOGGLE_OPSIZE(OperandSize
);
2493 /* Get the operands */
2494 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2496 /* Exception occurred */
2500 /* Check the operand size */
2503 ULONG FirstValue
, SecondValue
, Result
;
2505 if (!Fast486ReadModrmDwordOperands(State
,
2510 /* Exception occurred */
2514 /* Calculate the result */
2515 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2517 /* Special exception for CF */
2518 State
->Flags
.Cf
= State
->Flags
.Cf
2519 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2521 /* Update the flags */
2522 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2523 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2524 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2525 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2526 State
->Flags
.Zf
= (Result
== 0);
2527 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2528 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2530 /* Write back the result */
2531 return Fast486WriteModrmDwordOperands(State
,
2533 Opcode
& FAST486_OPCODE_WRITE_REG
,
2538 USHORT FirstValue
, SecondValue
, Result
;
2540 if (!Fast486ReadModrmWordOperands(State
,
2545 /* Exception occurred */
2549 /* Calculate the result */
2550 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2552 /* Special exception for CF */
2553 State
->Flags
.Cf
= State
->Flags
.Cf
2554 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2556 /* Update the flags */
2557 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2558 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2559 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2560 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2561 State
->Flags
.Zf
= (Result
== 0);
2562 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2563 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2565 /* Write back the result */
2566 return Fast486WriteModrmWordOperands(State
,
2568 Opcode
& FAST486_OPCODE_WRITE_REG
,
2574 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2576 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2577 UCHAR SecondValue
, Result
;
2579 /* Make sure this is the right instruction */
2580 ASSERT(Opcode
== 0x14);
2582 if (State
->PrefixFlags
)
2584 /* This opcode doesn't take any prefixes */
2585 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2589 if (!Fast486FetchByte(State
, &SecondValue
))
2591 /* Exception occurred */
2595 /* Calculate the result */
2596 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2598 /* Special exception for CF */
2599 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2600 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2602 /* Update the flags */
2603 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2604 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2605 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2606 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2607 State
->Flags
.Zf
= (Result
== 0);
2608 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2609 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2611 /* Write back the result */
2612 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2617 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2619 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2621 /* Make sure this is the right instruction */
2622 ASSERT(Opcode
== 0x15);
2625 TOGGLE_OPSIZE(Size
);
2629 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2630 ULONG SecondValue
, Result
;
2632 if (!Fast486FetchDword(State
, &SecondValue
))
2634 /* Exception occurred */
2638 /* Calculate the result */
2639 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2641 /* Special exception for CF */
2642 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2643 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2645 /* Update the flags */
2646 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2647 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2648 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2649 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2650 State
->Flags
.Zf
= (Result
== 0);
2651 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2652 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2654 /* Write back the result */
2655 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2659 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2660 USHORT SecondValue
, Result
;
2662 if (!Fast486FetchWord(State
, &SecondValue
))
2664 /* Exception occurred */
2668 /* Calculate the result */
2669 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2671 /* Special exception for CF */
2672 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2673 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2675 /* Update the flags */
2676 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2677 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2678 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2679 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2680 State
->Flags
.Zf
= (Result
== 0);
2681 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2682 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2684 /* Write back the result */
2685 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2691 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2693 /* Call the internal API */
2694 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2697 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2701 if (!Fast486StackPop(State
, &NewSelector
))
2703 /* Exception occurred */
2707 /* Call the internal API */
2708 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2711 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2713 UCHAR FirstValue
, SecondValue
, Result
;
2714 FAST486_MOD_REG_RM ModRegRm
;
2715 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2716 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2718 /* Make sure this is the right instruction */
2719 ASSERT((Opcode
& 0xFD) == 0x18);
2721 TOGGLE_ADSIZE(AddressSize
);
2723 /* Get the operands */
2724 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2726 /* Exception occurred */
2730 if (!Fast486ReadModrmByteOperands(State
,
2735 /* Exception occurred */
2739 /* Check if this is the instruction that writes to R/M */
2740 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2742 /* Swap the order */
2743 SWAP(FirstValue
, SecondValue
);
2746 /* Calculate the result */
2747 Result
= FirstValue
- SecondValue
- Carry
;
2749 /* Update the flags */
2750 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ 1);
2751 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2752 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2753 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2754 State
->Flags
.Zf
= (Result
== 0);
2755 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2756 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2758 /* Write back the result */
2759 return Fast486WriteModrmByteOperands(State
,
2761 Opcode
& FAST486_OPCODE_WRITE_REG
,
2765 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2767 FAST486_MOD_REG_RM ModRegRm
;
2768 BOOLEAN OperandSize
, AddressSize
;
2769 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2771 /* Make sure this is the right instruction */
2772 ASSERT((Opcode
& 0xFD) == 0x19);
2774 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2776 TOGGLE_ADSIZE(AddressSize
);
2777 TOGGLE_OPSIZE(OperandSize
);
2779 /* Get the operands */
2780 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2782 /* Exception occurred */
2786 /* Check the operand size */
2789 ULONG FirstValue
, SecondValue
, Result
;
2791 if (!Fast486ReadModrmDwordOperands(State
,
2796 /* Exception occurred */
2800 /* Check if this is the instruction that writes to R/M */
2801 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2803 /* Swap the order */
2804 SWAP(FirstValue
, SecondValue
);
2807 /* Calculate the result */
2808 Result
= FirstValue
- SecondValue
- Carry
;
2810 /* Update the flags */
2811 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2812 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2813 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2814 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2815 State
->Flags
.Zf
= (Result
== 0);
2816 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2817 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2819 /* Write back the result */
2820 return Fast486WriteModrmDwordOperands(State
,
2822 Opcode
& FAST486_OPCODE_WRITE_REG
,
2827 USHORT FirstValue
, SecondValue
, Result
;
2829 if (!Fast486ReadModrmWordOperands(State
,
2834 /* Exception occurred */
2838 /* Check if this is the instruction that writes to R/M */
2839 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2841 /* Swap the order */
2842 SWAP(FirstValue
, SecondValue
);
2845 /* Calculate the result */
2846 Result
= FirstValue
- SecondValue
- Carry
;
2848 /* Update the flags */
2849 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2850 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2851 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2852 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2853 State
->Flags
.Zf
= (Result
== 0);
2854 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2855 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2857 /* Write back the result */
2858 return Fast486WriteModrmWordOperands(State
,
2860 Opcode
& FAST486_OPCODE_WRITE_REG
,
2865 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2867 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2868 UCHAR SecondValue
, Result
;
2869 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2871 /* Make sure this is the right instruction */
2872 ASSERT(Opcode
== 0x1C);
2874 if (State
->PrefixFlags
)
2876 /* This opcode doesn't take any prefixes */
2877 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2881 if (!Fast486FetchByte(State
, &SecondValue
))
2883 /* Exception occurred */
2887 /* Calculate the result */
2888 Result
= FirstValue
- SecondValue
- Carry
;
2890 /* Update the flags */
2891 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2892 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2893 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2894 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2895 State
->Flags
.Zf
= (Result
== 0);
2896 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2897 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2899 /* Write back the result */
2900 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2906 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2908 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2909 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2911 /* Make sure this is the right instruction */
2912 ASSERT(Opcode
== 0x1D);
2915 TOGGLE_OPSIZE(Size
);
2919 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2920 ULONG SecondValue
, Result
;
2922 if (!Fast486FetchDword(State
, &SecondValue
))
2924 /* Exception occurred */
2928 /* Calculate the result */
2929 Result
= FirstValue
- SecondValue
- Carry
;
2931 /* Update the flags */
2932 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2933 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2934 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2935 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
2936 State
->Flags
.Zf
= (Result
== 0);
2937 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2938 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2940 /* Write back the result */
2941 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2945 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2946 USHORT SecondValue
, Result
;
2948 if (!Fast486FetchWord(State
, &SecondValue
))
2950 /* Exception occurred */
2954 /* Calculate the result */
2955 Result
= FirstValue
- SecondValue
- Carry
;
2957 /* Update the flags */
2958 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2959 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2960 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2961 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
2962 State
->Flags
.Zf
= (Result
== 0);
2963 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2964 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2966 /* Write back the result */
2967 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2974 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2976 /* Call the internal API */
2977 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2980 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
2984 if (!Fast486StackPop(State
, &NewSelector
))
2986 /* Exception occurred */
2990 /* Call the internal API */
2991 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
2994 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
2996 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2997 BOOLEAN Carry
= State
->Flags
.Cf
;
2999 /* Clear the carry flag */
3000 State
->Flags
.Cf
= FALSE
;
3002 /* Check if the first BCD digit is invalid or there was a carry from it */
3003 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3006 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3007 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3009 /* A carry occurred */
3010 State
->Flags
.Cf
= TRUE
;
3013 /* Set the adjust flag */
3014 State
->Flags
.Af
= TRUE
;
3017 /* Check if the second BCD digit is invalid or there was a carry from it */
3018 if ((Value
> 0x99) || Carry
)
3021 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3023 /* There was a carry */
3024 State
->Flags
.Cf
= TRUE
;
3030 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3032 UCHAR FirstValue
, SecondValue
, Result
;
3033 FAST486_MOD_REG_RM ModRegRm
;
3034 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3036 /* Make sure this is the right instruction */
3037 ASSERT((Opcode
& 0xED) == 0x28);
3039 TOGGLE_ADSIZE(AddressSize
);
3041 /* Get the operands */
3042 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3044 /* Exception occurred */
3048 if (!Fast486ReadModrmByteOperands(State
,
3053 /* Exception occurred */
3057 /* Check if this is the instruction that writes to R/M */
3058 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3060 /* Swap the order */
3061 SWAP(FirstValue
, SecondValue
);
3064 /* Calculate the result */
3065 Result
= FirstValue
- SecondValue
;
3067 /* Update the flags */
3068 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3069 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3070 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3071 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3072 State
->Flags
.Zf
= (Result
== 0);
3073 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3074 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3076 /* Check if this is not a CMP */
3077 if (!(Opcode
& 0x10))
3079 /* Write back the result */
3080 return Fast486WriteModrmByteOperands(State
,
3082 Opcode
& FAST486_OPCODE_WRITE_REG
,
3087 /* Discard the result */
3092 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3094 FAST486_MOD_REG_RM ModRegRm
;
3095 BOOLEAN OperandSize
, AddressSize
;
3097 /* Make sure this is the right instruction */
3098 ASSERT((Opcode
& 0xED) == 0x29);
3100 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3102 TOGGLE_ADSIZE(AddressSize
);
3103 TOGGLE_OPSIZE(OperandSize
);
3105 /* Get the operands */
3106 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3108 /* Exception occurred */
3112 /* Check the operand size */
3115 ULONG FirstValue
, SecondValue
, Result
;
3117 if (!Fast486ReadModrmDwordOperands(State
,
3122 /* Exception occurred */
3126 /* Check if this is the instruction that writes to R/M */
3127 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3129 /* Swap the order */
3130 SWAP(FirstValue
, SecondValue
);
3133 /* Calculate the result */
3134 Result
= FirstValue
- SecondValue
;
3136 /* Update the flags */
3137 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3138 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3139 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3140 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3141 State
->Flags
.Zf
= (Result
== 0);
3142 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3143 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3145 /* Check if this is not a CMP */
3146 if (!(Opcode
& 0x10))
3148 /* Write back the result */
3149 return Fast486WriteModrmDwordOperands(State
,
3151 Opcode
& FAST486_OPCODE_WRITE_REG
,
3156 /* Discard the result */
3162 USHORT FirstValue
, SecondValue
, Result
;
3164 if (!Fast486ReadModrmWordOperands(State
,
3169 /* Exception occurred */
3173 /* Check if this is the instruction that writes to R/M */
3174 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3176 /* Swap the order */
3177 SWAP(FirstValue
, SecondValue
);
3180 /* Calculate the result */
3181 Result
= FirstValue
- SecondValue
;
3183 /* Update the flags */
3184 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3185 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3186 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3187 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3188 State
->Flags
.Zf
= (Result
== 0);
3189 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3190 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3192 /* Check if this is not a CMP */
3193 if (!(Opcode
& 0x10))
3195 /* Write back the result */
3196 return Fast486WriteModrmWordOperands(State
,
3198 Opcode
& FAST486_OPCODE_WRITE_REG
,
3203 /* Discard the result */
3209 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3211 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3212 UCHAR SecondValue
, Result
;
3214 /* Make sure this is the right instruction */
3215 ASSERT((Opcode
& 0xEF) == 0x2C);
3217 if (State
->PrefixFlags
)
3219 /* This opcode doesn't take any prefixes */
3220 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3224 if (!Fast486FetchByte(State
, &SecondValue
))
3226 /* Exception occurred */
3230 /* Calculate the result */
3231 Result
= FirstValue
- SecondValue
;
3233 /* Update the flags */
3234 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3235 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3236 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3237 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3238 State
->Flags
.Zf
= (Result
== 0);
3239 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3240 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3242 /* Check if this is not a CMP */
3243 if (!(Opcode
& 0x10))
3245 /* Write back the result */
3246 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3252 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3254 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3256 /* Make sure this is the right instruction */
3257 ASSERT((Opcode
& 0xEF) == 0x2D);
3260 TOGGLE_OPSIZE(Size
);
3264 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3265 ULONG SecondValue
, Result
;
3267 if (!Fast486FetchDword(State
, &SecondValue
))
3269 /* Exception occurred */
3273 /* Calculate the result */
3274 Result
= FirstValue
- SecondValue
;
3276 /* Update the flags */
3277 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3278 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3279 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3280 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3281 State
->Flags
.Zf
= (Result
== 0);
3282 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3283 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3285 /* Check if this is not a CMP */
3286 if (!(Opcode
& 0x10))
3288 /* Write back the result */
3289 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3294 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3295 USHORT SecondValue
, Result
;
3297 if (!Fast486FetchWord(State
, &SecondValue
))
3299 /* Exception occurred */
3303 /* Calculate the result */
3304 Result
= FirstValue
- SecondValue
;
3306 /* Update the flags */
3307 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3308 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3309 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3310 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3311 State
->Flags
.Zf
= (Result
== 0);
3312 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3313 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3315 /* Check if this is not a CMP */
3316 if (!(Opcode
& 0x10))
3318 /* Write back the result */
3319 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3326 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3328 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3329 BOOLEAN Carry
= State
->Flags
.Cf
;
3331 /* Clear the carry flag */
3332 State
->Flags
.Cf
= FALSE
;
3334 /* Check if the first BCD digit is invalid or there was a borrow */
3335 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3338 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3339 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3341 /* A borrow occurred */
3342 State
->Flags
.Cf
= TRUE
;
3345 /* Set the adjust flag */
3346 State
->Flags
.Af
= TRUE
;
3349 /* Check if the second BCD digit is invalid or there was a borrow */
3350 if ((Value
> 0x99) || Carry
)
3353 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3355 /* There was a borrow */
3356 State
->Flags
.Cf
= TRUE
;
3362 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3364 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3367 * Check if the value in AL is not a valid BCD digit,
3368 * or there was a carry from the lowest 4 bits of AL
3370 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3373 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3374 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3377 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3381 /* Clear CF and AF */
3382 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3385 /* Keep only the lowest 4 bits of AL */
3386 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3391 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3393 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3396 * Check if the value in AL is not a valid BCD digit,
3397 * or there was a borrow from the lowest 4 bits of AL
3399 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3402 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3403 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3406 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3410 /* Clear CF and AF */
3411 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3414 /* Keep only the lowest 4 bits of AL */
3415 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3420 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3423 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3424 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3426 /* Make sure this is the right instruction */
3427 ASSERT(Opcode
== 0x60);
3429 TOGGLE_OPSIZE(Size
);
3432 /* Push all the registers in order */
3433 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3435 if (i
== FAST486_REG_ESP
)
3437 /* Use the saved ESP instead */
3438 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3440 /* Exception occurred */
3446 /* Push the register */
3447 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3448 : State
->GeneralRegs
[i
].LowWord
))
3450 /* Exception occurred */
3459 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3462 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3465 /* Make sure this is the right instruction */
3466 ASSERT(Opcode
== 0x61);
3468 TOGGLE_OPSIZE(Size
);
3471 /* Pop all the registers in reverse order */
3472 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3475 if (!Fast486StackPop(State
, &Value
))
3477 /* Exception occurred */
3481 /* Don't modify ESP */
3482 if (i
!= FAST486_REG_ESP
)
3484 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3485 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3492 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3494 // TODO: NOT IMPLEMENTED
3500 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3502 USHORT FirstValue
, SecondValue
;
3503 FAST486_MOD_REG_RM ModRegRm
;
3504 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3506 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3508 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3510 /* Cannot be used in real mode or with a LOCK prefix */
3511 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3515 TOGGLE_ADSIZE(AddressSize
);
3517 /* Get the operands */
3518 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3520 /* Exception occurred */
3524 /* Read the operands */
3525 if (!Fast486ReadModrmWordOperands(State
,
3530 /* Exception occurred */
3534 /* Check if the RPL needs adjusting */
3535 if ((SecondValue
& 3) < (FirstValue
& 3))
3537 /* Adjust the RPL */
3539 SecondValue
|= FirstValue
& 3;
3542 State
->Flags
.Zf
= TRUE
;
3544 /* Write back the result */
3545 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3550 State
->Flags
.Zf
= FALSE
;
3555 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3557 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3559 /* Make sure this is the right instruction */
3560 ASSERT(Opcode
== 0x68);
3563 TOGGLE_OPSIZE(Size
);
3569 if (!Fast486FetchDword(State
, &Data
))
3571 /* Exception occurred */
3575 /* Call the internal API */
3576 return Fast486StackPush(State
, Data
);
3582 if (!Fast486FetchWord(State
, &Data
))
3584 /* Exception occurred */
3588 /* Call the internal API */
3589 return Fast486StackPush(State
, Data
);
3593 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3595 BOOLEAN OperandSize
, AddressSize
;
3596 FAST486_MOD_REG_RM ModRegRm
;
3600 /* Make sure this is the right instruction */
3601 ASSERT((Opcode
& 0xFD) == 0x69);
3603 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3605 TOGGLE_ADSIZE(AddressSize
);
3606 TOGGLE_OPSIZE(OperandSize
);
3608 /* Fetch the parameters */
3609 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3611 /* Exception occurred */
3619 /* Fetch the immediate operand */
3620 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3622 /* Exception occurred */
3626 Multiplier
= (LONG
)Byte
;
3634 /* Fetch the immediate operand */
3635 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3637 /* Exception occurred */
3647 /* Fetch the immediate operand */
3648 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3650 /* Exception occurred */
3654 Multiplier
= (LONG
)Word
;
3660 LONG RegValue
, Multiplicand
;
3662 /* Read the operands */
3663 if (!Fast486ReadModrmDwordOperands(State
,
3666 (PULONG
)&Multiplicand
))
3668 /* Exception occurred */
3673 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3677 SHORT RegValue
, Multiplicand
;
3679 /* Read the operands */
3680 if (!Fast486ReadModrmWordOperands(State
,
3683 (PUSHORT
)&Multiplicand
))
3685 /* Exception occurred */
3690 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3693 /* Check for carry/overflow */
3694 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3696 /* Write-back the result */
3697 return Fast486WriteModrmDwordOperands(State
,
3700 (ULONG
)((LONG
)Product
));
3703 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3707 /* Make sure this is the right instruction */
3708 ASSERT(Opcode
== 0x6A);
3710 if (!Fast486FetchByte(State
, &Data
))
3712 /* Exception occurred */
3716 /* Call the internal API */
3717 return Fast486StackPush(State
, Data
);
3720 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3722 UCHAR FirstValue
, SecondValue
, Result
;
3723 FAST486_MOD_REG_RM ModRegRm
;
3724 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3726 /* Make sure this is the right instruction */
3727 ASSERT((Opcode
& 0xFD) == 0x88);
3729 TOGGLE_ADSIZE(AddressSize
);
3731 /* Get the operands */
3732 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3734 /* Exception occurred */
3738 if (!Fast486ReadModrmByteOperands(State
,
3743 /* Exception occurred */
3747 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3748 else Result
= FirstValue
;
3750 /* Write back the result */
3751 return Fast486WriteModrmByteOperands(State
,
3753 Opcode
& FAST486_OPCODE_WRITE_REG
,
3758 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3760 FAST486_MOD_REG_RM ModRegRm
;
3761 BOOLEAN OperandSize
, AddressSize
;
3763 /* Make sure this is the right instruction */
3764 ASSERT((Opcode
& 0xFD) == 0x89);
3766 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3768 TOGGLE_ADSIZE(AddressSize
);
3769 TOGGLE_OPSIZE(OperandSize
);
3771 /* Get the operands */
3772 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3774 /* Exception occurred */
3778 /* Check the operand size */
3781 ULONG FirstValue
, SecondValue
, Result
;
3783 if (!Fast486ReadModrmDwordOperands(State
,
3788 /* Exception occurred */
3792 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3793 else Result
= FirstValue
;
3795 /* Write back the result */
3796 return Fast486WriteModrmDwordOperands(State
,
3798 Opcode
& FAST486_OPCODE_WRITE_REG
,
3803 USHORT FirstValue
, SecondValue
, Result
;
3805 if (!Fast486ReadModrmWordOperands(State
,
3810 /* Exception occurred */
3814 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3815 else Result
= FirstValue
;
3817 /* Write back the result */
3818 return Fast486WriteModrmWordOperands(State
,
3820 Opcode
& FAST486_OPCODE_WRITE_REG
,
3825 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3827 BOOLEAN OperandSize
, AddressSize
;
3828 FAST486_MOD_REG_RM ModRegRm
;
3830 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3832 /* Make sure this is the right instruction */
3833 ASSERT(Opcode
== 0x8C);
3835 TOGGLE_ADSIZE(AddressSize
);
3836 TOGGLE_OPSIZE(OperandSize
);
3838 /* Get the operands */
3839 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3841 /* Exception occurred */
3845 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3848 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3854 return Fast486WriteModrmDwordOperands(State
,
3857 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3861 return Fast486WriteModrmWordOperands(State
,
3864 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3868 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3870 FAST486_MOD_REG_RM ModRegRm
;
3871 BOOLEAN OperandSize
, AddressSize
;
3873 /* Make sure this is the right instruction */
3874 ASSERT(Opcode
== 0x8D);
3876 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3878 TOGGLE_ADSIZE(AddressSize
);
3879 TOGGLE_OPSIZE(OperandSize
);
3881 /* Get the operands */
3882 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3884 /* Exception occurred */
3888 /* The second operand must be memory */
3889 if (!ModRegRm
.Memory
)
3892 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3896 /* Write the address to the register */
3899 return Fast486WriteModrmDwordOperands(State
,
3902 ModRegRm
.MemoryAddress
);
3906 return Fast486WriteModrmWordOperands(State
,
3909 ModRegRm
.MemoryAddress
);
3914 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3916 BOOLEAN OperandSize
, AddressSize
;
3917 FAST486_MOD_REG_RM ModRegRm
;
3919 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3921 /* Make sure this is the right instruction */
3922 ASSERT(Opcode
== 0x8E);
3924 TOGGLE_ADSIZE(AddressSize
);
3925 TOGGLE_OPSIZE(OperandSize
);
3927 /* Get the operands */
3928 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3930 /* Exception occurred */
3934 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3935 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3938 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3944 ULONG Dummy
, Selector
;
3946 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
3948 /* Exception occurred */
3952 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
3956 USHORT Dummy
, Selector
;
3958 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
3960 /* Exception occurred */
3964 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
3968 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
3970 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3972 /* Make sure this is the right instruction */
3973 ASSERT(Opcode
== 0x98);
3975 TOGGLE_OPSIZE(Size
);
3980 /* Sign extend AX to EAX */
3981 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
3983 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
3984 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
3990 /* Sign extend AL to AX */
3991 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
3992 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
3999 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4001 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4003 /* Make sure this is the right instruction */
4004 ASSERT(Opcode
== 0x99);
4006 TOGGLE_OPSIZE(Size
);
4011 /* Sign extend EAX to EDX:EAX */
4012 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4013 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4014 ? 0xFFFFFFFF : 0x00000000;
4018 /* Sign extend AX to DX:AX */
4019 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4020 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4027 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4031 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4033 /* Make sure this is the right instruction */
4034 ASSERT(Opcode
== 0x9A);
4036 TOGGLE_OPSIZE(Size
);
4039 /* Fetch the offset */
4042 if (!Fast486FetchDword(State
, &Offset
))
4044 /* Exception occurred */
4050 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4052 /* Exception occurred */
4057 /* Fetch the segment */
4058 if (!Fast486FetchWord(State
, &Segment
))
4060 /* Exception occurred */
4064 /* Push the current code segment selector */
4065 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4067 /* Exception occurred */
4071 /* Push the current value of the instruction pointer */
4072 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4074 /* Exception occurred */
4078 /* Load the new CS */
4079 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4081 /* Exception occurred */
4085 /* Load new (E)IP */
4086 if (Size
) State
->InstPtr
.Long
= Offset
;
4087 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4092 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4094 // TODO: NOT IMPLEMENTED
4100 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4102 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4105 TOGGLE_OPSIZE(Size
);
4107 /* Check for VM86 mode when IOPL is not 3 */
4108 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4110 /* Call the VM86 monitor */
4111 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4115 /* Push the flags */
4116 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4117 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4120 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4122 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4123 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4127 TOGGLE_OPSIZE(Size
);
4129 /* Pop the new flags */
4130 if (!Fast486StackPop(State
, &NewFlags
))
4132 /* Exception occurred */
4136 if (!State
->Flags
.Vm
)
4138 /* Check the current privilege level */
4146 /* Memorize the old state of RF */
4147 BOOLEAN OldRf
= State
->Flags
.Rf
;
4149 State
->Flags
.Long
= NewFlags
;
4151 /* Restore VM and RF */
4152 State
->Flags
.Vm
= FALSE
;
4153 State
->Flags
.Rf
= OldRf
;
4155 /* Clear VIF and VIP */
4156 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4158 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4160 /* Restore the reserved bits */
4161 State
->Flags
.AlwaysSet
= TRUE
;
4162 State
->Flags
.Reserved0
= FALSE
;
4163 State
->Flags
.Reserved1
= FALSE
;
4169 /* Memorize the old state of IF and IOPL */
4170 BOOLEAN OldIf
= State
->Flags
.If
;
4171 UINT OldIopl
= State
->Flags
.Iopl
;
4176 /* Memorize the old state of RF */
4177 BOOLEAN OldRf
= State
->Flags
.Rf
;
4179 State
->Flags
.Long
= NewFlags
;
4181 /* Restore VM and RF */
4182 State
->Flags
.Vm
= FALSE
;
4183 State
->Flags
.Rf
= OldRf
;
4185 /* Clear VIF and VIP */
4186 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4188 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4190 /* Restore the reserved bits and IOPL */
4191 State
->Flags
.AlwaysSet
= TRUE
;
4192 State
->Flags
.Reserved0
= FALSE
;
4193 State
->Flags
.Reserved1
= FALSE
;
4194 State
->Flags
.Iopl
= OldIopl
;
4196 /* Check if the user doesn't have the privilege to change IF */
4197 if (Cpl
> State
->Flags
.Iopl
)
4200 State
->Flags
.If
= OldIf
;
4206 /* Check the IOPL */
4207 if (State
->Flags
.Iopl
== 3)
4211 /* Memorize the old state of RF, VIF and VIP */
4212 BOOLEAN OldRf
= State
->Flags
.Rf
;
4213 BOOLEAN OldVif
= State
->Flags
.Vif
;
4214 BOOLEAN OldVip
= State
->Flags
.Vip
;
4216 State
->Flags
.Long
= NewFlags
;
4218 /* Restore VM, RF, VIF and VIP */
4219 State
->Flags
.Vm
= TRUE
;
4220 State
->Flags
.Rf
= OldRf
;
4221 State
->Flags
.Vif
= OldVif
;
4222 State
->Flags
.Vip
= OldVip
;
4224 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4226 /* Restore the reserved bits and IOPL */
4227 State
->Flags
.AlwaysSet
= TRUE
;
4228 State
->Flags
.Reserved0
= FALSE
;
4229 State
->Flags
.Reserved1
= FALSE
;
4230 State
->Flags
.Iopl
= 3;
4234 /* Call the VM86 monitor */
4235 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4243 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4245 /* Make sure this is the right instruction */
4246 ASSERT(Opcode
== 0x9E);
4248 /* Set the low-order byte of FLAGS to AH */
4249 State
->Flags
.Long
&= 0xFFFFFF00;
4250 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4252 /* Restore the reserved bits of FLAGS */
4253 State
->Flags
.AlwaysSet
= TRUE
;
4254 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4259 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4261 /* Make sure this is the right instruction */
4262 ASSERT(Opcode
== 0x9F);
4264 /* Set AH to the low-order byte of FLAGS */
4265 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4270 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4272 ULONG ReturnAddress
;
4273 USHORT BytesToPop
= 0;
4274 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4276 /* Make sure this is the right instruction */
4277 ASSERT((Opcode
& 0xFE) == 0xC2);
4280 TOGGLE_OPSIZE(Size
);
4284 /* Fetch the number of bytes to pop after the return */
4285 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4288 /* Pop the return address */
4289 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4291 /* Return to the calling procedure, and if necessary, pop the parameters */
4294 State
->InstPtr
.Long
= ReturnAddress
;
4295 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4299 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4300 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4306 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4308 UCHAR FarPointer
[6];
4309 BOOLEAN OperandSize
, AddressSize
;
4310 FAST486_MOD_REG_RM ModRegRm
;
4312 /* Make sure this is the right instruction */
4313 ASSERT((Opcode
& 0xFE) == 0xC4);
4315 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4317 TOGGLE_ADSIZE(AddressSize
);
4319 /* Get the operands */
4320 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4322 /* Exception occurred */
4326 if (!ModRegRm
.Memory
)
4328 /* Check if this is a BOP and the host supports BOPs */
4329 if ((Opcode
== 0xC4)
4330 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4331 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4332 && (State
->BopCallback
!= NULL
))
4336 /* Fetch the BOP code */
4337 if (!Fast486FetchByte(State
, &BopCode
))
4339 /* Exception occurred */
4343 /* Call the BOP handler */
4344 State
->BopCallback(State
, BopCode
);
4346 /* Return success */
4351 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4355 if (!Fast486ReadMemory(State
,
4356 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4357 ? State
->SegmentOverride
: FAST486_REG_DS
,
4358 ModRegRm
.MemoryAddress
,
4361 OperandSize
? 6 : 4))
4363 /* Exception occurred */
4369 ULONG Offset
= *((PULONG
)FarPointer
);
4370 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4372 /* Set the register to the offset */
4373 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4375 /* Load the segment */
4376 return Fast486LoadSegment(State
,
4378 ? FAST486_REG_ES
: FAST486_REG_DS
,
4383 USHORT Offset
= *((PUSHORT
)FarPointer
);
4384 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4386 /* Set the register to the offset */
4387 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4389 /* Load the segment */
4390 return Fast486LoadSegment(State
,
4392 ? FAST486_REG_ES
: FAST486_REG_DS
,
4397 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4400 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4403 FAST486_REG FramePointer
;
4405 /* Make sure this is the right instruction */
4406 ASSERT(Opcode
== 0xC8);
4409 TOGGLE_OPSIZE(Size
);
4411 if (!Fast486FetchWord(State
, &FrameSize
))
4413 /* Exception occurred */
4417 if (!Fast486FetchByte(State
, &NestingLevel
))
4419 /* Exception occurred */
4424 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4426 /* Exception occurred */
4431 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4433 /* Set up the nested procedure stacks */
4434 for (i
= 1; i
< NestingLevel
; i
++)
4438 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4439 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4443 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4444 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4448 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4450 /* Set EBP to the frame pointer */
4451 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4453 /* Reserve space for the frame */
4454 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4455 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4460 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4462 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4464 /* Make sure this is the right instruction */
4465 ASSERT(Opcode
== 0xC9);
4468 TOGGLE_OPSIZE(Size
);
4472 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4473 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4475 /* Pop the saved base pointer from the stack */
4476 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4482 /* Set the stack pointer (SP) to the base pointer (BP) */
4483 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4485 /* Pop the saved base pointer from the stack */
4486 if (Fast486StackPop(State
, &Value
))
4488 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4495 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4499 USHORT BytesToPop
= 0;
4500 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4502 /* Make sure this is the right instruction */
4503 ASSERT((Opcode
& 0xFE) == 0xCA);
4505 TOGGLE_OPSIZE(Size
);
4510 /* Fetch the number of bytes to pop after the return */
4511 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4514 /* Pop the offset */
4515 if (!Fast486StackPop(State
, &Offset
))
4517 /* Exception occurred */
4521 /* Pop the segment */
4522 if (!Fast486StackPop(State
, &Segment
))
4524 /* Exception occurred */
4528 /* Load the new CS */
4529 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4531 /* Exception occurred */
4535 /* Load new (E)IP, and if necessary, pop the parameters */
4538 State
->InstPtr
.Long
= Offset
;
4539 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4543 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4544 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4550 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4553 FAST486_IDT_ENTRY IdtEntry
;
4559 /* This is the INT3 instruction */
4566 /* Fetch the interrupt number */
4567 if (!Fast486FetchByte(State
, &IntNum
))
4569 /* Exception occurred */
4578 /* Don't do anything if OF is cleared */
4579 if (!State
->Flags
.Of
) return TRUE
;
4582 IntNum
= FAST486_EXCEPTION_OF
;
4589 /* Should not happen */
4594 /* Get the interrupt vector */
4595 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4597 /* Exception occurred */
4601 /* Perform the interrupt */
4602 if (!Fast486InterruptInternal(State
,
4604 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4607 /* Exception occurred */
4614 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4617 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4618 FAST486_FLAGS_REG NewFlags
;
4619 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4621 /* Make sure this is the right instruction */
4622 ASSERT(Opcode
== 0xCF);
4625 TOGGLE_OPSIZE(Size
);
4628 if (!Fast486StackPop(State
, &InstPtr
))
4630 /* Exception occurred */
4635 if (!Fast486StackPop(State
, &CodeSel
))
4637 /* Exception occurred */
4642 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4644 /* Exception occurred */
4648 /* Check for protected mode */
4649 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4651 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4653 if (State
->Flags
.Vm
)
4655 /* Return from VM86 mode */
4657 /* Check the IOPL */
4658 if (State
->Flags
.Iopl
== 3)
4661 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4664 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4666 /* Exception occurred */
4670 /* Set the new flags */
4671 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4672 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4673 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4674 State
->Flags
.Iopl
= 3;
4678 /* Call the VM86 monitor */
4679 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4686 if (State
->Flags
.Nt
)
4688 /* Nested task return */
4696 /* Return to VM86 mode */
4697 ULONG Es
, Ds
, Fs
, Gs
;
4699 /* Pop ESP, SS, ES, FS, GS */
4700 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4701 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4702 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4703 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4704 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4705 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4707 /* Set the new IP */
4708 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4710 /* Set the new flags */
4711 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4712 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4713 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4715 /* Load the new segments */
4716 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4717 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4718 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4719 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4720 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4721 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4726 /* Load the new CS */
4727 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4729 /* Exception occurred */
4734 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4735 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4737 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4740 if (!Fast486StackPop(State
, &StackPtr
))
4747 if (!Fast486StackPop(State
, &StackSel
))
4754 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4761 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4762 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4765 /* Set the new flags */
4766 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4767 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4768 State
->Flags
.AlwaysSet
= TRUE
;
4770 /* Set additional flags */
4771 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4772 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4774 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4776 /* Update the CPL */
4777 Cpl
= Fast486GetCurrentPrivLevel(State
);
4779 /* Check segment security */
4780 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4782 /* Don't check CS or SS */
4783 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4785 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4786 && (!State
->SegmentRegs
[i
].Executable
4787 || !State
->SegmentRegs
[i
].DirConf
))
4789 /* Load the NULL descriptor in the segment */
4790 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4797 if (Size
&& (InstPtr
& 0xFFFF0000))
4800 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4805 State
->InstPtr
.Long
= InstPtr
;
4808 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4810 /* Exception occurred */
4814 /* Set the new flags */
4815 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4816 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4817 State
->Flags
.AlwaysSet
= TRUE
;
4823 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4826 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4830 /* Fetch the base */
4831 if (!Fast486FetchByte(State
, &Base
))
4833 /* Exception occurred */
4837 /* Check if the base is zero */
4841 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4846 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4847 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4850 State
->Flags
.Zf
= (Value
== 0);
4851 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4852 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4857 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4860 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4864 /* Fetch the base */
4865 if (!Fast486FetchByte(State
, &Base
))
4867 /* Exception occurred */
4872 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4873 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4876 State
->Flags
.Zf
= (Value
== 0);
4877 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4878 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4883 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4886 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4888 TOGGLE_ADSIZE(AddressSize
);
4890 /* Read a byte from DS:[(E)BX + AL] */
4891 if (!Fast486ReadMemory(State
,
4893 AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4894 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
4895 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4900 /* Exception occurred */
4904 /* Set AL to the result */
4905 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4907 /* Return success */
4911 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4914 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4917 /* Make sure this is the right instruction */
4918 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4921 TOGGLE_OPSIZE(Size
);
4923 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4924 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4928 /* Additional rule for LOOPNZ */
4929 if (State
->Flags
.Zf
) Condition
= FALSE
;
4934 /* Additional rule for LOOPZ */
4935 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4938 /* Fetch the offset */
4939 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4941 /* An exception occurred */
4947 /* Move the instruction pointer */
4948 State
->InstPtr
.Long
+= Offset
;
4954 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
4957 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4960 /* Make sure this is the right instruction */
4961 ASSERT(Opcode
== 0xE3);
4964 TOGGLE_OPSIZE(Size
);
4966 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
4967 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
4969 /* Fetch the offset */
4970 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4972 /* An exception occurred */
4978 /* Move the instruction pointer */
4979 State
->InstPtr
.Long
+= Offset
;
4985 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
4987 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4989 /* Make sure this is the right instruction */
4990 ASSERT(Opcode
== 0xE8);
4992 TOGGLE_OPSIZE(Size
);
4999 /* Fetch the offset */
5000 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5002 /* An exception occurred */
5006 /* Push the current value of the instruction pointer */
5007 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5009 /* Exception occurred */
5013 /* Move the instruction pointer */
5014 State
->InstPtr
.Long
+= Offset
;
5020 /* Fetch the offset */
5021 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5023 /* An exception occurred */
5027 /* Push the current value of the instruction pointer */
5028 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5030 /* Exception occurred */
5034 /* Move the instruction pointer */
5035 State
->InstPtr
.LowWord
+= Offset
;
5041 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5043 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5045 /* Make sure this is the right instruction */
5046 ASSERT(Opcode
== 0xE9);
5048 TOGGLE_OPSIZE(Size
);
5055 /* Fetch the offset */
5056 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5058 /* An exception occurred */
5062 /* Move the instruction pointer */
5063 State
->InstPtr
.Long
+= Offset
;
5069 /* Fetch the offset */
5070 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5072 /* An exception occurred */
5076 /* Move the instruction pointer */
5077 State
->InstPtr
.LowWord
+= Offset
;
5083 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5087 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5089 /* Make sure this is the right instruction */
5090 ASSERT(Opcode
== 0xEA);
5092 TOGGLE_OPSIZE(Size
);
5095 /* Fetch the offset */
5098 if (!Fast486FetchDword(State
, &Offset
))
5100 /* Exception occurred */
5106 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5108 /* Exception occurred */
5113 /* Fetch the segment */
5114 if (!Fast486FetchWord(State
, &Segment
))
5116 /* Exception occurred */
5120 /* Load the new CS */
5121 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5123 /* Exception occurred */
5127 /* Load new (E)IP */
5128 if (Size
) State
->InstPtr
.Long
= Offset
;
5129 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
5134 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5136 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5139 /* Make sure this is the right instruction */
5140 ASSERT(Opcode
== 0xA0);
5142 TOGGLE_OPSIZE(Size
);
5146 if (!Fast486FetchDword(State
, &Offset
))
5148 /* Exception occurred */
5156 if (!Fast486FetchWord(State
, &WordOffset
))
5158 /* Exception occurred */
5162 Offset
= (ULONG
)WordOffset
;
5165 /* Read from memory */
5166 return Fast486ReadMemory(State
,
5167 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5168 State
->SegmentOverride
: FAST486_REG_DS
,
5171 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5175 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5177 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5179 /* Make sure this is the right instruction */
5180 ASSERT(Opcode
== 0xA1);
5182 TOGGLE_OPSIZE(Size
);
5188 if (!Fast486FetchDword(State
, &Offset
))
5190 /* Exception occurred */
5194 /* Read from memory */
5195 return Fast486ReadMemory(State
,
5196 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5197 State
->SegmentOverride
: FAST486_REG_DS
,
5200 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5207 if (!Fast486FetchWord(State
, &Offset
))
5209 /* Exception occurred */
5213 /* Read from memory */
5214 return Fast486ReadMemory(State
,
5215 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5216 State
->SegmentOverride
: FAST486_REG_DS
,
5219 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5224 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5226 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5229 /* Make sure this is the right instruction */
5230 ASSERT(Opcode
== 0xA2);
5232 TOGGLE_OPSIZE(Size
);
5236 if (!Fast486FetchDword(State
, &Offset
))
5238 /* Exception occurred */
5246 if (!Fast486FetchWord(State
, &WordOffset
))
5248 /* Exception occurred */
5252 Offset
= (ULONG
)WordOffset
;
5255 /* Write to memory */
5256 return Fast486WriteMemory(State
,
5257 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5258 State
->SegmentOverride
: FAST486_REG_DS
,
5260 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5264 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5266 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5268 /* Make sure this is the right instruction */
5269 ASSERT(Opcode
== 0xA3);
5271 TOGGLE_OPSIZE(Size
);
5277 if (!Fast486FetchDword(State
, &Offset
))
5279 /* Exception occurred */
5283 /* Write to memory */
5284 return Fast486WriteMemory(State
,
5285 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5286 State
->SegmentOverride
: FAST486_REG_DS
,
5288 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5295 if (!Fast486FetchWord(State
, &Offset
))
5297 /* Exception occurred */
5301 /* Write to memory */
5302 return Fast486WriteMemory(State
,
5303 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5304 State
->SegmentOverride
: FAST486_REG_DS
,
5306 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5311 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5313 /* Make sure this is the right instruction */
5314 ASSERT(Opcode
== 0xD6);
5318 /* Set all the bits of AL to CF */
5319 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5324 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5326 ULONG Data
, DataSize
;
5327 BOOLEAN OperandSize
, AddressSize
;
5328 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5330 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5332 /* Make sure this is the right instruction */
5333 ASSERT((Opcode
& 0xFE) == 0xA4);
5335 TOGGLE_OPSIZE(OperandSize
);
5336 TOGGLE_ADSIZE(AddressSize
);
5338 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5340 /* Use the override segment instead of DS */
5341 Segment
= State
->SegmentOverride
;
5344 /* Calculate the size */
5345 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5346 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5348 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5350 UCHAR Block
[STRING_BLOCK_SIZE
];
5351 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5352 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5354 /* Clear the memory block */
5355 RtlZeroMemory(Block
, sizeof(Block
));
5357 /* Transfer until finished */
5360 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5362 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5365 ULONG MaxBytesSrc
= State
->Flags
.Df
5366 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
5367 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
5368 ULONG MaxBytesDest
= State
->Flags
.Df
5369 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5370 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5373 Processed
= min(Processed
, min(MaxBytesSrc
, MaxBytesDest
) / DataSize
);
5374 if (Processed
== 0) Processed
= 1;
5377 if (State
->Flags
.Df
)
5379 /* Reduce ESI and EDI by the number of bytes to transfer */
5382 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
5383 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5387 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
5388 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5392 /* Read from memory */
5393 if (!Fast486ReadMemory(State
,
5395 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5396 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5399 Processed
* DataSize
))
5402 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5403 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5405 /* Exception occurred */
5409 /* Write to memory */
5410 if (!Fast486WriteMemory(State
,
5412 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5413 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5415 Processed
* DataSize
))
5418 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5419 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5421 /* Exception occurred */
5425 if (!State
->Flags
.Df
)
5427 /* Increase ESI and EDI by the number of bytes transfered */
5430 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
5431 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5435 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
5436 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5440 /* Reduce the total count by the number processed in this run */
5445 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5446 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5450 /* Read from the source operand */
5451 if (!Fast486ReadMemory(State
,
5453 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5454 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5459 /* Exception occurred */
5463 /* Write to the destination operand */
5464 if (!Fast486WriteMemory(State
,
5466 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5467 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5471 /* Exception occurred */
5475 /* Increment/decrement ESI and EDI */
5478 if (!State
->Flags
.Df
)
5480 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5481 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5485 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5486 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5491 if (!State
->Flags
.Df
)
5493 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5494 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5498 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5499 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5504 /* Return success */
5508 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5510 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5511 ULONG DataSize
, DataMask
, SignFlag
;
5512 BOOLEAN OperandSize
, AddressSize
;
5513 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5515 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5517 /* Make sure this is the right instruction */
5518 ASSERT((Opcode
& 0xFE) == 0xA6);
5520 TOGGLE_OPSIZE(OperandSize
);
5521 TOGGLE_ADSIZE(AddressSize
);
5523 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5525 /* Use the override segment instead of DS */
5526 Segment
= State
->SegmentOverride
;
5529 /* Calculate the size */
5530 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5531 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5533 /* Calculate the mask and sign flag */
5534 DataMask
= (1 << (DataSize
* 8)) - 1;
5535 SignFlag
= 1 << ((DataSize
* 8) - 1);
5537 /* Read from the first source operand */
5538 if (!Fast486ReadMemory(State
,
5540 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5541 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5546 /* Exception occurred */
5550 /* Read from the second source operand */
5551 if (!Fast486ReadMemory(State
,
5553 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5554 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5559 /* Exception occurred */
5563 /* Calculate the result */
5564 FirstValue
&= DataMask
;
5565 SecondValue
&= DataMask
;
5566 Result
= (FirstValue
- SecondValue
) & DataMask
;
5568 /* Update the flags */
5569 State
->Flags
.Cf
= FirstValue
< SecondValue
;
5570 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5571 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5572 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5573 State
->Flags
.Zf
= (Result
== 0);
5574 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5575 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5577 /* Increment/decrement ESI and EDI */
5580 if (!State
->Flags
.Df
)
5582 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5583 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5587 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5588 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5593 if (!State
->Flags
.Df
)
5595 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5596 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5600 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5601 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5605 // FIXME: This method is slow!
5606 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5607 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5609 BOOLEAN Repeat
= TRUE
;
5613 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5621 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5628 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5629 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5631 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5637 /* Repeat the instruction */
5638 State
->InstPtr
= State
->SavedInstPtr
;
5642 /* Return success */
5646 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5649 BOOLEAN OperandSize
, AddressSize
;
5651 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5653 /* Make sure this is the right instruction */
5654 ASSERT((Opcode
& 0xFE) == 0xAA);
5656 TOGGLE_OPSIZE(OperandSize
);
5657 TOGGLE_ADSIZE(AddressSize
);
5659 /* Calculate the size */
5660 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5661 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5663 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5665 UCHAR Block
[STRING_BLOCK_SIZE
];
5666 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5667 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5669 /* Fill the memory block with the data */
5670 if (DataSize
== sizeof(UCHAR
))
5672 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5678 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5680 if (DataSize
== sizeof(USHORT
))
5682 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5686 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5691 /* Transfer until finished */
5694 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5696 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5699 ULONG MaxBytes
= State
->Flags
.Df
5700 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5701 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5703 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5704 if (Processed
== 0) Processed
= 1;
5707 if (State
->Flags
.Df
)
5709 /* Reduce EDI by the number of bytes to transfer */
5710 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5711 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5714 /* Write to memory */
5715 if (!Fast486WriteMemory(State
,
5717 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5718 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5720 Processed
* DataSize
))
5723 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5724 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5726 /* Exception occurred */
5730 if (!State
->Flags
.Df
)
5732 /* Increase EDI by the number of bytes transfered */
5733 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5734 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5737 /* Reduce the total count by the number processed in this run */
5742 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5743 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5747 /* Write to the destination operand */
5748 if (!Fast486WriteMemory(State
,
5750 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5751 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5752 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5755 /* Exception occurred */
5759 /* Increment/decrement EDI */
5762 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5763 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5767 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5768 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5772 /* Return success */
5776 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5779 BOOLEAN OperandSize
, AddressSize
;
5780 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5782 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5784 /* Make sure this is the right instruction */
5785 ASSERT((Opcode
& 0xFE) == 0xAC);
5787 TOGGLE_OPSIZE(OperandSize
);
5788 TOGGLE_ADSIZE(AddressSize
);
5790 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5792 /* Use the override segment instead of DS */
5793 Segment
= State
->SegmentOverride
;
5796 /* Calculate the size */
5797 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5798 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5800 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5802 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5803 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5805 /* If the count is 0, do nothing */
5806 if (Count
== 0) return TRUE
;
5808 /* Only the last entry will be loaded */
5809 if (!State
->Flags
.Df
)
5811 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5812 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5816 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5817 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5821 /* Read from the source operand */
5822 if (!Fast486ReadMemory(State
,
5824 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5825 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5827 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5830 /* Exception occurred */
5834 /* Increment/decrement ESI */
5837 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5838 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5842 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5843 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5846 /* Return success */
5850 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5852 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5853 ULONG SecondValue
= 0;
5855 ULONG DataSize
, DataMask
, SignFlag
;
5856 BOOLEAN OperandSize
, AddressSize
;
5858 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5860 /* Make sure this is the right instruction */
5861 ASSERT((Opcode
& 0xFE) == 0xAE);
5863 TOGGLE_OPSIZE(OperandSize
);
5864 TOGGLE_ADSIZE(AddressSize
);
5866 /* Calculate the size */
5867 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5868 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5870 /* Calculate the mask and sign flag */
5871 DataMask
= (1 << (DataSize
* 8)) - 1;
5872 SignFlag
= 1 << ((DataSize
* 8) - 1);
5874 /* Read from the source operand */
5875 if (!Fast486ReadMemory(State
,
5877 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5878 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5883 /* Exception occurred */
5887 /* Calculate the result */
5888 FirstValue
&= DataMask
;
5889 SecondValue
&= DataMask
;
5890 Result
= (FirstValue
- SecondValue
) & DataMask
;
5892 /* Update the flags */
5893 State
->Flags
.Cf
= FirstValue
< SecondValue
;
5894 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5895 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5896 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5897 State
->Flags
.Zf
= (Result
== 0);
5898 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5899 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5901 /* Increment/decrement EDI */
5904 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5905 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5909 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5910 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5913 // FIXME: This method is slow!
5914 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5915 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5917 BOOLEAN Repeat
= TRUE
;
5921 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5929 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5936 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5937 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5939 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5945 /* Repeat the instruction */
5946 State
->InstPtr
= State
->SavedInstPtr
;
5950 /* Return success */
5954 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
5957 BOOLEAN OperandSize
, AddressSize
;
5959 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5961 /* Make sure this is the right instruction */
5962 ASSERT((Opcode
& 0xFE) == 0x6C);
5964 TOGGLE_OPSIZE(OperandSize
);
5965 TOGGLE_ADSIZE(AddressSize
);
5967 /* Calculate the size */
5968 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
5969 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5971 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5973 UCHAR Block
[STRING_BLOCK_SIZE
];
5974 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5975 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5977 /* Clear the memory block */
5978 RtlZeroMemory(Block
, sizeof(Block
));
5980 /* Transfer until finished */
5983 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5985 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5988 ULONG MaxBytes
= State
->Flags
.Df
5989 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5990 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5992 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5993 if (Processed
== 0) Processed
= 1;
5996 /* Read from the I/O port */
5997 State
->IoReadCallback(State
,
5998 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6000 Processed
* DataSize
);
6002 if (State
->Flags
.Df
)
6006 /* Reduce EDI by the number of bytes to transfer */
6007 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6008 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6010 /* Reverse the block data */
6011 for (i
= 0; i
< Processed
/ 2; i
++)
6013 /* Swap the values */
6014 for (j
= 0; j
< DataSize
; j
++)
6016 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6017 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6018 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6023 /* Write to memory */
6024 if (!Fast486WriteMemory(State
,
6026 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6027 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6029 Processed
* DataSize
))
6032 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6033 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6035 /* Exception occurred */
6039 if (!State
->Flags
.Df
)
6041 /* Increase EDI by the number of bytes transfered */
6042 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6043 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6046 /* Reduce the total count by the number processed in this run */
6051 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6052 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6058 /* Read from the I/O port */
6059 State
->IoReadCallback(State
,
6060 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6064 /* Write to the destination operand */
6065 if (!Fast486WriteMemory(State
,
6067 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6068 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6072 /* Exception occurred */
6076 /* Increment/decrement EDI */
6079 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6080 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6084 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6085 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6089 /* Return success */
6093 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6096 BOOLEAN OperandSize
, AddressSize
;
6098 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6100 /* Make sure this is the right instruction */
6101 ASSERT((Opcode
& 0xFE) == 0x6E);
6103 TOGGLE_OPSIZE(OperandSize
);
6104 TOGGLE_ADSIZE(AddressSize
);
6106 /* Calculate the size */
6107 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6108 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6110 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6112 UCHAR Block
[STRING_BLOCK_SIZE
];
6113 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6114 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6116 /* Clear the memory block */
6117 RtlZeroMemory(Block
, sizeof(Block
));
6119 /* Transfer until finished */
6122 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6124 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6127 ULONG MaxBytes
= State
->Flags
.Df
6128 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6129 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6131 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6132 if (Processed
== 0) Processed
= 1;
6135 /* Read from memory */
6136 if (!Fast486ReadMemory(State
,
6138 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6139 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6142 Processed
* DataSize
))
6145 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6146 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6148 /* Exception occurred */
6152 if (State
->Flags
.Df
)
6156 /* Reduce EDI by the number of bytes to transfer */
6157 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6158 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6160 /* Reverse the block data */
6161 for (i
= 0; i
< Processed
/ 2; i
++)
6163 /* Swap the values */
6164 for (j
= 0; j
< DataSize
; j
++)
6166 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6167 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6168 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6173 /* Write to the I/O port */
6174 State
->IoWriteCallback(State
,
6175 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6177 Processed
* DataSize
);
6179 if (!State
->Flags
.Df
)
6181 /* Increase EDI by the number of bytes transfered */
6182 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6183 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6186 /* Reduce the total count by the number processed in this run */
6191 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6192 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6198 /* Read from the source operand */
6199 if (!Fast486ReadMemory(State
,
6201 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6202 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6207 /* Exception occurred */
6211 /* Write to the I/O port */
6212 State
->IoWriteCallback(State
,
6213 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6217 /* Increment/decrement ESI */
6220 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6221 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6225 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6226 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6230 /* Return success */