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
, 1, 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
, 1, 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
, 1, 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
, 1, 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
->IoWriteCallback(State
, Port
, &Data
, 1, 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
, 1, 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
;
3599 /* Make sure this is the right instruction */
3600 ASSERT((Opcode
& 0xFD) == 0x69);
3602 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3604 TOGGLE_ADSIZE(AddressSize
);
3605 TOGGLE_OPSIZE(OperandSize
);
3607 /* Fetch the parameters */
3608 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3610 /* Exception occurred */
3618 /* Fetch the immediate operand */
3619 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3621 /* Exception occurred */
3625 Multiplier
= (LONG
)Byte
;
3633 /* Fetch the immediate operand */
3634 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3636 /* Exception occurred */
3646 /* Fetch the immediate operand */
3647 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3649 /* Exception occurred */
3653 Multiplier
= (LONG
)Word
;
3659 LONG RegValue
, Multiplicand
;
3662 /* Read the operands */
3663 if (!Fast486ReadModrmDwordOperands(State
,
3666 (PULONG
)&Multiplicand
))
3668 /* Exception occurred */
3673 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3675 /* Check for carry/overflow */
3676 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3678 /* Write-back the result */
3679 return Fast486WriteModrmDwordOperands(State
,
3682 (ULONG
)((LONG
)Product
));
3686 SHORT RegValue
, Multiplicand
;
3689 /* Read the operands */
3690 if (!Fast486ReadModrmWordOperands(State
,
3693 (PUSHORT
)&Multiplicand
))
3695 /* Exception occurred */
3700 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3702 /* Check for carry/overflow */
3703 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3705 /* Write-back the result */
3706 return Fast486WriteModrmWordOperands(State
,
3709 (USHORT
)((SHORT
)Product
));
3713 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3717 /* Make sure this is the right instruction */
3718 ASSERT(Opcode
== 0x6A);
3720 if (!Fast486FetchByte(State
, &Data
))
3722 /* Exception occurred */
3726 /* Call the internal API */
3727 return Fast486StackPush(State
, Data
);
3730 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3732 UCHAR FirstValue
, SecondValue
, Result
;
3733 FAST486_MOD_REG_RM ModRegRm
;
3734 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3736 /* Make sure this is the right instruction */
3737 ASSERT((Opcode
& 0xFD) == 0x88);
3739 TOGGLE_ADSIZE(AddressSize
);
3741 /* Get the operands */
3742 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3744 /* Exception occurred */
3748 if (!Fast486ReadModrmByteOperands(State
,
3753 /* Exception occurred */
3757 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3758 else Result
= FirstValue
;
3760 /* Write back the result */
3761 return Fast486WriteModrmByteOperands(State
,
3763 Opcode
& FAST486_OPCODE_WRITE_REG
,
3768 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3770 FAST486_MOD_REG_RM ModRegRm
;
3771 BOOLEAN OperandSize
, AddressSize
;
3773 /* Make sure this is the right instruction */
3774 ASSERT((Opcode
& 0xFD) == 0x89);
3776 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3778 TOGGLE_ADSIZE(AddressSize
);
3779 TOGGLE_OPSIZE(OperandSize
);
3781 /* Get the operands */
3782 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3784 /* Exception occurred */
3788 /* Check the operand size */
3791 ULONG FirstValue
, SecondValue
, Result
;
3793 if (!Fast486ReadModrmDwordOperands(State
,
3798 /* Exception occurred */
3802 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3803 else Result
= FirstValue
;
3805 /* Write back the result */
3806 return Fast486WriteModrmDwordOperands(State
,
3808 Opcode
& FAST486_OPCODE_WRITE_REG
,
3813 USHORT FirstValue
, SecondValue
, Result
;
3815 if (!Fast486ReadModrmWordOperands(State
,
3820 /* Exception occurred */
3824 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3825 else Result
= FirstValue
;
3827 /* Write back the result */
3828 return Fast486WriteModrmWordOperands(State
,
3830 Opcode
& FAST486_OPCODE_WRITE_REG
,
3835 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3837 BOOLEAN OperandSize
, AddressSize
;
3838 FAST486_MOD_REG_RM ModRegRm
;
3840 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3842 /* Make sure this is the right instruction */
3843 ASSERT(Opcode
== 0x8C);
3845 TOGGLE_ADSIZE(AddressSize
);
3846 TOGGLE_OPSIZE(OperandSize
);
3848 /* Get the operands */
3849 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3851 /* Exception occurred */
3855 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3858 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3864 return Fast486WriteModrmDwordOperands(State
,
3867 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3871 return Fast486WriteModrmWordOperands(State
,
3874 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3878 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3880 FAST486_MOD_REG_RM ModRegRm
;
3881 BOOLEAN OperandSize
, AddressSize
;
3883 /* Make sure this is the right instruction */
3884 ASSERT(Opcode
== 0x8D);
3886 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3888 TOGGLE_ADSIZE(AddressSize
);
3889 TOGGLE_OPSIZE(OperandSize
);
3891 /* Get the operands */
3892 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3894 /* Exception occurred */
3898 /* The second operand must be memory */
3899 if (!ModRegRm
.Memory
)
3902 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3906 /* Write the address to the register */
3909 return Fast486WriteModrmDwordOperands(State
,
3912 ModRegRm
.MemoryAddress
);
3916 return Fast486WriteModrmWordOperands(State
,
3919 ModRegRm
.MemoryAddress
);
3924 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3926 BOOLEAN OperandSize
, AddressSize
;
3927 FAST486_MOD_REG_RM ModRegRm
;
3929 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3931 /* Make sure this is the right instruction */
3932 ASSERT(Opcode
== 0x8E);
3934 TOGGLE_ADSIZE(AddressSize
);
3935 TOGGLE_OPSIZE(OperandSize
);
3937 /* Get the operands */
3938 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3940 /* Exception occurred */
3944 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3945 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3948 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3954 ULONG Dummy
, Selector
;
3956 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
3958 /* Exception occurred */
3962 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
3966 USHORT Dummy
, Selector
;
3968 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
3970 /* Exception occurred */
3974 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
3978 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
3980 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3982 /* Make sure this is the right instruction */
3983 ASSERT(Opcode
== 0x98);
3985 TOGGLE_OPSIZE(Size
);
3990 /* Sign extend AX to EAX */
3991 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
3993 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
3994 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4000 /* Sign extend AL to AX */
4001 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4002 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4009 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4011 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4013 /* Make sure this is the right instruction */
4014 ASSERT(Opcode
== 0x99);
4016 TOGGLE_OPSIZE(Size
);
4021 /* Sign extend EAX to EDX:EAX */
4022 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4023 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4024 ? 0xFFFFFFFF : 0x00000000;
4028 /* Sign extend AX to DX:AX */
4029 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4030 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4037 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4041 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4043 /* Make sure this is the right instruction */
4044 ASSERT(Opcode
== 0x9A);
4046 TOGGLE_OPSIZE(Size
);
4049 /* Fetch the offset */
4052 if (!Fast486FetchDword(State
, &Offset
))
4054 /* Exception occurred */
4060 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4062 /* Exception occurred */
4067 /* Fetch the segment */
4068 if (!Fast486FetchWord(State
, &Segment
))
4070 /* Exception occurred */
4074 /* Push the current code segment selector */
4075 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4077 /* Exception occurred */
4081 /* Push the current value of the instruction pointer */
4082 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4084 /* Exception occurred */
4088 /* Load the new CS */
4089 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4091 /* Exception occurred */
4095 /* Load new (E)IP */
4096 if (Size
) State
->InstPtr
.Long
= Offset
;
4097 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4102 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4104 // TODO: NOT IMPLEMENTED
4110 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4112 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4115 TOGGLE_OPSIZE(Size
);
4117 /* Check for VM86 mode when IOPL is not 3 */
4118 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4120 /* Call the VM86 monitor */
4121 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4125 /* Push the flags */
4126 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4127 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4130 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4132 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4133 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4137 TOGGLE_OPSIZE(Size
);
4139 /* Pop the new flags */
4140 if (!Fast486StackPop(State
, &NewFlags
))
4142 /* Exception occurred */
4146 if (!State
->Flags
.Vm
)
4148 /* Check the current privilege level */
4156 /* Memorize the old state of RF */
4157 BOOLEAN OldRf
= State
->Flags
.Rf
;
4159 State
->Flags
.Long
= NewFlags
;
4161 /* Restore VM and RF */
4162 State
->Flags
.Vm
= FALSE
;
4163 State
->Flags
.Rf
= OldRf
;
4165 /* Clear VIF and VIP */
4166 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4168 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4170 /* Restore the reserved bits */
4171 State
->Flags
.AlwaysSet
= TRUE
;
4172 State
->Flags
.Reserved0
= FALSE
;
4173 State
->Flags
.Reserved1
= FALSE
;
4179 /* Memorize the old state of IF and IOPL */
4180 BOOLEAN OldIf
= State
->Flags
.If
;
4181 UINT OldIopl
= State
->Flags
.Iopl
;
4186 /* Memorize the old state of RF */
4187 BOOLEAN OldRf
= State
->Flags
.Rf
;
4189 State
->Flags
.Long
= NewFlags
;
4191 /* Restore VM and RF */
4192 State
->Flags
.Vm
= FALSE
;
4193 State
->Flags
.Rf
= OldRf
;
4195 /* Clear VIF and VIP */
4196 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4198 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4200 /* Restore the reserved bits and IOPL */
4201 State
->Flags
.AlwaysSet
= TRUE
;
4202 State
->Flags
.Reserved0
= FALSE
;
4203 State
->Flags
.Reserved1
= FALSE
;
4204 State
->Flags
.Iopl
= OldIopl
;
4206 /* Check if the user doesn't have the privilege to change IF */
4207 if (Cpl
> State
->Flags
.Iopl
)
4210 State
->Flags
.If
= OldIf
;
4216 /* Check the IOPL */
4217 if (State
->Flags
.Iopl
== 3)
4221 /* Memorize the old state of RF, VIF and VIP */
4222 BOOLEAN OldRf
= State
->Flags
.Rf
;
4223 BOOLEAN OldVif
= State
->Flags
.Vif
;
4224 BOOLEAN OldVip
= State
->Flags
.Vip
;
4226 State
->Flags
.Long
= NewFlags
;
4228 /* Restore VM, RF, VIF and VIP */
4229 State
->Flags
.Vm
= TRUE
;
4230 State
->Flags
.Rf
= OldRf
;
4231 State
->Flags
.Vif
= OldVif
;
4232 State
->Flags
.Vip
= OldVip
;
4234 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4236 /* Restore the reserved bits and IOPL */
4237 State
->Flags
.AlwaysSet
= TRUE
;
4238 State
->Flags
.Reserved0
= FALSE
;
4239 State
->Flags
.Reserved1
= FALSE
;
4240 State
->Flags
.Iopl
= 3;
4244 /* Call the VM86 monitor */
4245 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4253 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4255 /* Make sure this is the right instruction */
4256 ASSERT(Opcode
== 0x9E);
4258 /* Set the low-order byte of FLAGS to AH */
4259 State
->Flags
.Long
&= 0xFFFFFF00;
4260 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4262 /* Restore the reserved bits of FLAGS */
4263 State
->Flags
.AlwaysSet
= TRUE
;
4264 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4269 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4271 /* Make sure this is the right instruction */
4272 ASSERT(Opcode
== 0x9F);
4274 /* Set AH to the low-order byte of FLAGS */
4275 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4280 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4282 ULONG ReturnAddress
;
4283 USHORT BytesToPop
= 0;
4284 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4286 /* Make sure this is the right instruction */
4287 ASSERT((Opcode
& 0xFE) == 0xC2);
4290 TOGGLE_OPSIZE(Size
);
4294 /* Fetch the number of bytes to pop after the return */
4295 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4298 /* Pop the return address */
4299 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4301 /* Return to the calling procedure, and if necessary, pop the parameters */
4304 State
->InstPtr
.Long
= ReturnAddress
;
4305 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4309 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4310 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4316 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4318 UCHAR FarPointer
[6];
4319 BOOLEAN OperandSize
, AddressSize
;
4320 FAST486_MOD_REG_RM ModRegRm
;
4322 /* Make sure this is the right instruction */
4323 ASSERT((Opcode
& 0xFE) == 0xC4);
4325 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4327 TOGGLE_OPSIZE(OperandSize
);
4328 TOGGLE_ADSIZE(AddressSize
);
4330 /* Get the operands */
4331 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4333 /* Exception occurred */
4337 if (!ModRegRm
.Memory
)
4339 /* Check if this is a BOP and the host supports BOPs */
4340 if ((Opcode
== 0xC4)
4341 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4342 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4343 && (State
->BopCallback
!= NULL
))
4347 /* Fetch the BOP code */
4348 if (!Fast486FetchByte(State
, &BopCode
))
4350 /* Exception occurred */
4354 /* Call the BOP handler */
4355 State
->BopCallback(State
, BopCode
);
4357 /* Return success */
4362 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4366 if (!Fast486ReadMemory(State
,
4367 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4368 ? State
->SegmentOverride
: FAST486_REG_DS
,
4369 ModRegRm
.MemoryAddress
,
4372 OperandSize
? 6 : 4))
4374 /* Exception occurred */
4380 ULONG Offset
= *((PULONG
)FarPointer
);
4381 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4383 /* Set the register to the offset */
4384 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4386 /* Load the segment */
4387 return Fast486LoadSegment(State
,
4389 ? FAST486_REG_ES
: FAST486_REG_DS
,
4394 USHORT Offset
= *((PUSHORT
)FarPointer
);
4395 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4397 /* Set the register to the offset */
4398 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4400 /* Load the segment */
4401 return Fast486LoadSegment(State
,
4403 ? FAST486_REG_ES
: FAST486_REG_DS
,
4408 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4411 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4414 FAST486_REG FramePointer
;
4416 /* Make sure this is the right instruction */
4417 ASSERT(Opcode
== 0xC8);
4420 TOGGLE_OPSIZE(Size
);
4422 if (!Fast486FetchWord(State
, &FrameSize
))
4424 /* Exception occurred */
4428 if (!Fast486FetchByte(State
, &NestingLevel
))
4430 /* Exception occurred */
4435 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4437 /* Exception occurred */
4442 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4444 /* Set up the nested procedure stacks */
4445 for (i
= 1; i
< NestingLevel
; i
++)
4449 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4450 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4454 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4455 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4459 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4461 /* Set EBP to the frame pointer */
4462 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4464 /* Reserve space for the frame */
4465 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4466 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4471 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4473 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4475 /* Make sure this is the right instruction */
4476 ASSERT(Opcode
== 0xC9);
4479 TOGGLE_OPSIZE(Size
);
4483 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4484 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4486 /* Pop the saved base pointer from the stack */
4487 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4493 /* Set the stack pointer (SP) to the base pointer (BP) */
4494 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4496 /* Pop the saved base pointer from the stack */
4497 if (Fast486StackPop(State
, &Value
))
4499 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4506 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4510 USHORT BytesToPop
= 0;
4511 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4513 /* Make sure this is the right instruction */
4514 ASSERT((Opcode
& 0xFE) == 0xCA);
4516 TOGGLE_OPSIZE(Size
);
4521 /* Fetch the number of bytes to pop after the return */
4522 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4525 /* Pop the offset */
4526 if (!Fast486StackPop(State
, &Offset
))
4528 /* Exception occurred */
4532 /* Pop the segment */
4533 if (!Fast486StackPop(State
, &Segment
))
4535 /* Exception occurred */
4539 /* Load the new CS */
4540 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4542 /* Exception occurred */
4546 /* Load new (E)IP, and if necessary, pop the parameters */
4549 State
->InstPtr
.Long
= Offset
;
4550 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4554 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4555 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4561 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4564 FAST486_IDT_ENTRY IdtEntry
;
4570 /* This is the INT3 instruction */
4577 /* Fetch the interrupt number */
4578 if (!Fast486FetchByte(State
, &IntNum
))
4580 /* Exception occurred */
4589 /* Don't do anything if OF is cleared */
4590 if (!State
->Flags
.Of
) return TRUE
;
4593 IntNum
= FAST486_EXCEPTION_OF
;
4600 /* Should not happen */
4605 /* Get the interrupt vector */
4606 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4608 /* Exception occurred */
4612 /* Perform the interrupt */
4613 if (!Fast486InterruptInternal(State
,
4615 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4618 /* Exception occurred */
4625 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4628 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4629 FAST486_FLAGS_REG NewFlags
;
4630 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4632 /* Make sure this is the right instruction */
4633 ASSERT(Opcode
== 0xCF);
4636 TOGGLE_OPSIZE(Size
);
4639 if (!Fast486StackPop(State
, &InstPtr
))
4641 /* Exception occurred */
4646 if (!Fast486StackPop(State
, &CodeSel
))
4648 /* Exception occurred */
4653 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4655 /* Exception occurred */
4659 /* Check for protected mode */
4660 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4662 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4664 if (State
->Flags
.Vm
)
4666 /* Return from VM86 mode */
4668 /* Check the IOPL */
4669 if (State
->Flags
.Iopl
== 3)
4672 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4675 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4677 /* Exception occurred */
4681 /* Set the new flags */
4682 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4683 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4684 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4685 State
->Flags
.Iopl
= 3;
4689 /* Call the VM86 monitor */
4690 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4697 if (State
->Flags
.Nt
)
4699 /* Nested task return */
4707 /* Return to VM86 mode */
4708 ULONG Es
, Ds
, Fs
, Gs
;
4710 /* Pop ESP, SS, ES, FS, GS */
4711 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4712 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4713 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4714 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4715 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4716 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4718 /* Set the new IP */
4719 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4721 /* Set the new flags */
4722 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4723 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4724 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4726 /* Load the new segments */
4727 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4728 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4729 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4730 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4731 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4732 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4737 /* Load the new CS */
4738 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4740 /* Exception occurred */
4745 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4746 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4748 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4751 if (!Fast486StackPop(State
, &StackPtr
))
4758 if (!Fast486StackPop(State
, &StackSel
))
4765 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4772 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4773 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4776 /* Set the new flags */
4777 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4778 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4779 State
->Flags
.AlwaysSet
= TRUE
;
4781 /* Set additional flags */
4782 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4783 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4785 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4787 /* Update the CPL */
4788 Cpl
= Fast486GetCurrentPrivLevel(State
);
4790 /* Check segment security */
4791 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4793 /* Don't check CS or SS */
4794 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4796 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4797 && (!State
->SegmentRegs
[i
].Executable
4798 || !State
->SegmentRegs
[i
].DirConf
))
4800 /* Load the NULL descriptor in the segment */
4801 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4808 if (Size
&& (InstPtr
& 0xFFFF0000))
4811 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4816 State
->InstPtr
.Long
= InstPtr
;
4819 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4821 /* Exception occurred */
4825 /* Set the new flags */
4826 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4827 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4828 State
->Flags
.AlwaysSet
= TRUE
;
4834 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4837 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4841 /* Fetch the base */
4842 if (!Fast486FetchByte(State
, &Base
))
4844 /* Exception occurred */
4848 /* Check if the base is zero */
4852 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4857 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4858 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4861 State
->Flags
.Zf
= (Value
== 0);
4862 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4863 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4868 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4871 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4875 /* Fetch the base */
4876 if (!Fast486FetchByte(State
, &Base
))
4878 /* Exception occurred */
4883 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4884 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4887 State
->Flags
.Zf
= (Value
== 0);
4888 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4889 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4894 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4897 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4899 TOGGLE_ADSIZE(AddressSize
);
4901 /* Read a byte from DS:[(E)BX + AL] */
4902 if (!Fast486ReadMemory(State
,
4904 AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4905 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
4906 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4911 /* Exception occurred */
4915 /* Set AL to the result */
4916 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4918 /* Return success */
4922 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4925 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4928 /* Make sure this is the right instruction */
4929 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4932 TOGGLE_ADSIZE(Size
);
4934 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4935 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4939 /* Additional rule for LOOPNZ */
4940 if (State
->Flags
.Zf
) Condition
= FALSE
;
4945 /* Additional rule for LOOPZ */
4946 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4949 /* Fetch the offset */
4950 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4952 /* An exception occurred */
4958 /* Move the instruction pointer */
4959 if (Size
) State
->InstPtr
.Long
+= Offset
;
4960 else State
->InstPtr
.LowWord
+= Offset
;
4966 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
4969 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4972 /* Make sure this is the right instruction */
4973 ASSERT(Opcode
== 0xE3);
4976 TOGGLE_ADSIZE(Size
);
4978 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
4979 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
4981 /* Fetch the offset */
4982 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4984 /* An exception occurred */
4990 /* Move the instruction pointer */
4991 if (Size
) State
->InstPtr
.Long
+= Offset
;
4992 else State
->InstPtr
.LowWord
+= Offset
;
4998 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5000 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5002 /* Make sure this is the right instruction */
5003 ASSERT(Opcode
== 0xE8);
5005 TOGGLE_OPSIZE(Size
);
5012 /* Fetch the offset */
5013 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5015 /* An exception occurred */
5019 /* Push the current value of the instruction pointer */
5020 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5022 /* Exception occurred */
5026 /* Move the instruction pointer */
5027 State
->InstPtr
.Long
+= Offset
;
5033 /* Fetch the offset */
5034 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5036 /* An exception occurred */
5040 /* Push the current value of the instruction pointer */
5041 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5043 /* Exception occurred */
5047 /* Move the instruction pointer */
5048 State
->InstPtr
.LowWord
+= Offset
;
5054 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5056 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5058 /* Make sure this is the right instruction */
5059 ASSERT(Opcode
== 0xE9);
5061 TOGGLE_OPSIZE(Size
);
5068 /* Fetch the offset */
5069 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5071 /* An exception occurred */
5075 /* Move the instruction pointer */
5076 State
->InstPtr
.Long
+= Offset
;
5082 /* Fetch the offset */
5083 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5085 /* An exception occurred */
5089 /* Move the instruction pointer */
5090 State
->InstPtr
.LowWord
+= Offset
;
5096 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5100 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5102 /* Make sure this is the right instruction */
5103 ASSERT(Opcode
== 0xEA);
5105 TOGGLE_OPSIZE(Size
);
5108 /* Fetch the offset */
5111 if (!Fast486FetchDword(State
, &Offset
))
5113 /* Exception occurred */
5119 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5121 /* Exception occurred */
5126 /* Fetch the segment */
5127 if (!Fast486FetchWord(State
, &Segment
))
5129 /* Exception occurred */
5133 /* Load the new CS */
5134 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5136 /* Exception occurred */
5140 /* Load new (E)IP */
5141 if (Size
) State
->InstPtr
.Long
= Offset
;
5142 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
5147 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5149 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5152 /* Make sure this is the right instruction */
5153 ASSERT(Opcode
== 0xA0);
5155 TOGGLE_ADSIZE(AddressSize
);
5159 if (!Fast486FetchDword(State
, &Offset
))
5161 /* Exception occurred */
5169 if (!Fast486FetchWord(State
, &WordOffset
))
5171 /* Exception occurred */
5175 Offset
= (ULONG
)WordOffset
;
5178 /* Read from memory */
5179 return Fast486ReadMemory(State
,
5180 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5181 State
->SegmentOverride
: FAST486_REG_DS
,
5184 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5188 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5190 BOOLEAN OperandSize
, AddressSize
;
5192 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5194 /* Make sure this is the right instruction */
5195 ASSERT(Opcode
== 0xA1);
5197 TOGGLE_OPSIZE(OperandSize
);
5198 TOGGLE_ADSIZE(AddressSize
);
5204 if (!Fast486FetchDword(State
, &Offset
))
5206 /* Exception occurred */
5210 /* Read from memory */
5213 return Fast486ReadMemory(State
,
5214 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5215 State
->SegmentOverride
: FAST486_REG_DS
,
5218 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5223 return Fast486ReadMemory(State
,
5224 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5225 State
->SegmentOverride
: FAST486_REG_DS
,
5228 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5236 if (!Fast486FetchWord(State
, &Offset
))
5238 /* Exception occurred */
5242 /* Read from memory */
5245 return Fast486ReadMemory(State
,
5246 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5247 State
->SegmentOverride
: FAST486_REG_DS
,
5250 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5255 return Fast486ReadMemory(State
,
5256 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5257 State
->SegmentOverride
: FAST486_REG_DS
,
5260 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5266 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5268 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5271 /* Make sure this is the right instruction */
5272 ASSERT(Opcode
== 0xA2);
5274 TOGGLE_ADSIZE(AddressSize
);
5278 if (!Fast486FetchDword(State
, &Offset
))
5280 /* Exception occurred */
5288 if (!Fast486FetchWord(State
, &WordOffset
))
5290 /* Exception occurred */
5294 Offset
= (ULONG
)WordOffset
;
5297 /* Write to memory */
5298 return Fast486WriteMemory(State
,
5299 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5300 State
->SegmentOverride
: FAST486_REG_DS
,
5302 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5306 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5308 BOOLEAN OperandSize
, AddressSize
;
5310 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5312 /* Make sure this is the right instruction */
5313 ASSERT(Opcode
== 0xA3);
5315 TOGGLE_OPSIZE(OperandSize
);
5316 TOGGLE_ADSIZE(AddressSize
);
5322 if (!Fast486FetchDword(State
, &Offset
))
5324 /* Exception occurred */
5328 /* Write to memory */
5331 return Fast486WriteMemory(State
,
5332 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5333 State
->SegmentOverride
: FAST486_REG_DS
,
5335 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5340 return Fast486WriteMemory(State
,
5341 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5342 State
->SegmentOverride
: FAST486_REG_DS
,
5344 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5352 if (!Fast486FetchWord(State
, &Offset
))
5354 /* Exception occurred */
5358 /* Write to memory */
5361 return Fast486WriteMemory(State
,
5362 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5363 State
->SegmentOverride
: FAST486_REG_DS
,
5365 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5370 return Fast486WriteMemory(State
,
5371 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5372 State
->SegmentOverride
: FAST486_REG_DS
,
5374 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5380 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5382 /* Make sure this is the right instruction */
5383 ASSERT(Opcode
== 0xD6);
5387 /* Set all the bits of AL to CF */
5388 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5393 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5395 ULONG Data
, DataSize
;
5396 BOOLEAN OperandSize
, AddressSize
;
5397 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5399 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5401 /* Make sure this is the right instruction */
5402 ASSERT((Opcode
& 0xFE) == 0xA4);
5404 TOGGLE_OPSIZE(OperandSize
);
5405 TOGGLE_ADSIZE(AddressSize
);
5407 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5409 /* Use the override segment instead of DS */
5410 Segment
= State
->SegmentOverride
;
5413 /* Calculate the size */
5414 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5415 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5417 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5419 UCHAR Block
[STRING_BLOCK_SIZE
];
5420 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5421 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5423 /* Clear the memory block */
5424 RtlZeroMemory(Block
, sizeof(Block
));
5426 /* Transfer until finished */
5429 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5431 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5434 ULONG MaxBytesSrc
= State
->Flags
.Df
5435 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
5436 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
5437 ULONG MaxBytesDest
= State
->Flags
.Df
5438 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5439 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5442 Processed
= min(Processed
, min(MaxBytesSrc
, MaxBytesDest
) / DataSize
);
5443 if (Processed
== 0) Processed
= 1;
5446 if (State
->Flags
.Df
)
5448 /* Reduce ESI and EDI by the number of bytes to transfer */
5451 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
5452 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5456 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
5457 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5461 /* Read from memory */
5462 if (!Fast486ReadMemory(State
,
5464 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5465 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5468 Processed
* DataSize
))
5471 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5472 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5474 /* Exception occurred */
5478 /* Write to memory */
5479 if (!Fast486WriteMemory(State
,
5481 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5482 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5484 Processed
* DataSize
))
5487 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5488 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5490 /* Exception occurred */
5494 if (!State
->Flags
.Df
)
5496 /* Increase ESI and EDI by the number of bytes transfered */
5499 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
5500 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5504 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
5505 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5509 /* Reduce the total count by the number processed in this run */
5514 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5515 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5519 /* Read from the source operand */
5520 if (!Fast486ReadMemory(State
,
5522 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5523 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5528 /* Exception occurred */
5532 /* Write to the destination operand */
5533 if (!Fast486WriteMemory(State
,
5535 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5536 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5540 /* Exception occurred */
5544 /* Increment/decrement ESI and EDI */
5547 if (!State
->Flags
.Df
)
5549 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5550 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5554 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5555 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5560 if (!State
->Flags
.Df
)
5562 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5563 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5567 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5568 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5573 /* Return success */
5577 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5579 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5580 ULONG DataSize
, DataMask
, SignFlag
;
5581 BOOLEAN OperandSize
, AddressSize
;
5582 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5584 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5586 /* Make sure this is the right instruction */
5587 ASSERT((Opcode
& 0xFE) == 0xA6);
5589 TOGGLE_OPSIZE(OperandSize
);
5590 TOGGLE_ADSIZE(AddressSize
);
5592 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5594 /* Use the override segment instead of DS */
5595 Segment
= State
->SegmentOverride
;
5598 /* Calculate the size */
5599 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5600 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5602 /* Calculate the mask and sign flag */
5603 DataMask
= (1 << (DataSize
* 8)) - 1;
5604 SignFlag
= 1 << ((DataSize
* 8) - 1);
5606 /* Read from the first source operand */
5607 if (!Fast486ReadMemory(State
,
5609 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5610 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5615 /* Exception occurred */
5619 /* Read from the second source operand */
5620 if (!Fast486ReadMemory(State
,
5622 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5623 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5628 /* Exception occurred */
5632 /* Calculate the result */
5633 FirstValue
&= DataMask
;
5634 SecondValue
&= DataMask
;
5635 Result
= (FirstValue
- SecondValue
) & DataMask
;
5637 /* Update the flags */
5638 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5639 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5640 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5641 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5642 State
->Flags
.Zf
= (Result
== 0);
5643 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5644 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5646 /* Increment/decrement ESI and EDI */
5649 if (!State
->Flags
.Df
)
5651 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5652 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5656 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5657 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5662 if (!State
->Flags
.Df
)
5664 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5665 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5669 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5670 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5674 // FIXME: This method is slow!
5675 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5676 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5678 BOOLEAN Repeat
= TRUE
;
5682 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5690 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5697 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5698 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5700 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5706 /* Repeat the instruction */
5707 State
->InstPtr
= State
->SavedInstPtr
;
5711 /* Return success */
5715 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5718 BOOLEAN OperandSize
, AddressSize
;
5720 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5722 /* Make sure this is the right instruction */
5723 ASSERT((Opcode
& 0xFE) == 0xAA);
5725 TOGGLE_OPSIZE(OperandSize
);
5726 TOGGLE_ADSIZE(AddressSize
);
5728 /* Calculate the size */
5729 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5730 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5732 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5734 UCHAR Block
[STRING_BLOCK_SIZE
];
5735 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5736 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5738 /* Fill the memory block with the data */
5739 if (DataSize
== sizeof(UCHAR
))
5741 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5747 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5749 if (DataSize
== sizeof(USHORT
))
5751 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5755 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5760 /* Transfer until finished */
5763 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5765 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5768 ULONG MaxBytes
= State
->Flags
.Df
5769 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5770 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5772 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5773 if (Processed
== 0) Processed
= 1;
5776 if (State
->Flags
.Df
)
5778 /* Reduce EDI by the number of bytes to transfer */
5779 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5780 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5783 /* Write to memory */
5784 if (!Fast486WriteMemory(State
,
5786 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5787 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5789 Processed
* DataSize
))
5792 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5793 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5795 /* Exception occurred */
5799 if (!State
->Flags
.Df
)
5801 /* Increase EDI by the number of bytes transfered */
5802 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5803 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5806 /* Reduce the total count by the number processed in this run */
5811 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5812 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5816 /* Write to the destination operand */
5817 if (!Fast486WriteMemory(State
,
5819 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5820 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5821 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5824 /* Exception occurred */
5828 /* Increment/decrement EDI */
5831 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5832 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5836 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5837 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5841 /* Return success */
5845 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5848 BOOLEAN OperandSize
, AddressSize
;
5849 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5851 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5853 /* Make sure this is the right instruction */
5854 ASSERT((Opcode
& 0xFE) == 0xAC);
5856 TOGGLE_OPSIZE(OperandSize
);
5857 TOGGLE_ADSIZE(AddressSize
);
5859 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5861 /* Use the override segment instead of DS */
5862 Segment
= State
->SegmentOverride
;
5865 /* Calculate the size */
5866 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5867 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5869 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5871 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5872 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5874 /* If the count is 0, do nothing */
5875 if (Count
== 0) return TRUE
;
5877 /* Only the last entry will be loaded */
5878 if (!State
->Flags
.Df
)
5880 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5881 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5885 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5886 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5889 /* Update registers */
5892 State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5893 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5897 State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5898 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5902 /* Read from the source operand */
5903 if (!Fast486ReadMemory(State
,
5905 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5906 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5908 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5911 /* Exception occurred */
5915 /* Increment/decrement ESI */
5918 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5919 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5923 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5924 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5927 /* Return success */
5931 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5933 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5934 ULONG SecondValue
= 0;
5936 ULONG DataSize
, DataMask
, SignFlag
;
5937 BOOLEAN OperandSize
, AddressSize
;
5939 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5941 /* Make sure this is the right instruction */
5942 ASSERT((Opcode
& 0xFE) == 0xAE);
5944 TOGGLE_OPSIZE(OperandSize
);
5945 TOGGLE_ADSIZE(AddressSize
);
5947 /* Calculate the size */
5948 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5949 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5951 /* Calculate the mask and sign flag */
5952 DataMask
= (1 << (DataSize
* 8)) - 1;
5953 SignFlag
= 1 << ((DataSize
* 8) - 1);
5955 /* Read from the source operand */
5956 if (!Fast486ReadMemory(State
,
5958 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5959 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5964 /* Exception occurred */
5968 /* Calculate the result */
5969 FirstValue
&= DataMask
;
5970 SecondValue
&= DataMask
;
5971 Result
= (FirstValue
- SecondValue
) & DataMask
;
5973 /* Update the flags */
5974 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5975 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5976 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5977 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5978 State
->Flags
.Zf
= (Result
== 0);
5979 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5980 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5982 /* Increment/decrement EDI */
5985 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5986 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5990 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5991 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5994 // FIXME: This method is slow!
5995 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5996 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5998 BOOLEAN Repeat
= TRUE
;
6002 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6010 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6017 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6018 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6020 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6026 /* Repeat the instruction */
6027 State
->InstPtr
= State
->SavedInstPtr
;
6031 /* Return success */
6035 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6038 BOOLEAN OperandSize
, AddressSize
;
6040 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6042 /* Make sure this is the right instruction */
6043 ASSERT((Opcode
& 0xFE) == 0x6C);
6045 TOGGLE_OPSIZE(OperandSize
);
6046 TOGGLE_ADSIZE(AddressSize
);
6048 /* Calculate the size */
6049 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6050 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6052 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6054 UCHAR Block
[STRING_BLOCK_SIZE
];
6055 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6056 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6058 /* Clear the memory block */
6059 RtlZeroMemory(Block
, sizeof(Block
));
6061 /* Transfer until finished */
6064 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6066 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6069 ULONG MaxBytes
= State
->Flags
.Df
6070 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6071 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6073 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6074 if (Processed
== 0) Processed
= 1;
6077 /* Read from the I/O port */
6078 State
->IoReadCallback(State
,
6079 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6084 if (State
->Flags
.Df
)
6088 /* Reduce EDI by the number of bytes to transfer */
6089 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6090 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6092 /* Reverse the block data */
6093 for (i
= 0; i
< Processed
/ 2; i
++)
6095 /* Swap the values */
6096 for (j
= 0; j
< DataSize
; j
++)
6098 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6099 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6100 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6105 /* Write to memory */
6106 if (!Fast486WriteMemory(State
,
6108 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6109 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6111 Processed
* DataSize
))
6114 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6115 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6117 /* Exception occurred */
6121 if (!State
->Flags
.Df
)
6123 /* Increase EDI by the number of bytes transfered */
6124 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6125 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6128 /* Reduce the total count by the number processed in this run */
6133 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6134 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6140 /* Read from the I/O port */
6141 State
->IoReadCallback(State
,
6142 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6147 /* Write to the destination operand */
6148 if (!Fast486WriteMemory(State
,
6150 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6151 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6155 /* Exception occurred */
6159 /* Increment/decrement EDI */
6162 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6163 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6167 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6168 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6172 /* Return success */
6176 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6179 BOOLEAN OperandSize
, AddressSize
;
6181 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6183 /* Make sure this is the right instruction */
6184 ASSERT((Opcode
& 0xFE) == 0x6E);
6186 TOGGLE_OPSIZE(OperandSize
);
6187 TOGGLE_ADSIZE(AddressSize
);
6189 /* Calculate the size */
6190 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6191 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6193 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6195 UCHAR Block
[STRING_BLOCK_SIZE
];
6196 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6197 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6199 /* Clear the memory block */
6200 RtlZeroMemory(Block
, sizeof(Block
));
6202 /* Transfer until finished */
6205 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6207 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6210 ULONG MaxBytes
= State
->Flags
.Df
6211 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6212 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6214 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6215 if (Processed
== 0) Processed
= 1;
6218 /* Read from memory */
6219 if (!Fast486ReadMemory(State
,
6221 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6222 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6225 Processed
* DataSize
))
6228 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6229 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6231 /* Exception occurred */
6235 if (State
->Flags
.Df
)
6239 /* Reduce EDI by the number of bytes to transfer */
6240 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6241 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6243 /* Reverse the block data */
6244 for (i
= 0; i
< Processed
/ 2; i
++)
6246 /* Swap the values */
6247 for (j
= 0; j
< DataSize
; j
++)
6249 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6250 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6251 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6256 /* Write to the I/O port */
6257 State
->IoWriteCallback(State
,
6258 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6263 if (!State
->Flags
.Df
)
6265 /* Increase EDI by the number of bytes transfered */
6266 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6267 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6270 /* Reduce the total count by the number processed in this run */
6275 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6276 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6282 /* Read from the source operand */
6283 if (!Fast486ReadMemory(State
,
6285 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6286 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6291 /* Exception occurred */
6295 /* Write to the I/O port */
6296 State
->IoWriteCallback(State
,
6297 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6302 /* Increment/decrement ESI */
6305 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6306 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6310 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6311 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6315 /* Return success */