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 *******************************************************************/
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
38 /* PUBLIC VARIABLES ***********************************************************/
40 FAST486_OPCODE_HANDLER_PROC
41 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
43 Fast486OpcodeAddByteModrm
,
44 Fast486OpcodeAddModrm
,
45 Fast486OpcodeAddByteModrm
,
46 Fast486OpcodeAddModrm
,
51 Fast486OpcodeOrByteModrm
,
53 Fast486OpcodeOrByteModrm
,
58 Fast486OpcodeExtended
,
59 Fast486OpcodeAdcByteModrm
,
60 Fast486OpcodeAdcModrm
,
61 Fast486OpcodeAdcByteModrm
,
62 Fast486OpcodeAdcModrm
,
67 Fast486OpcodeSbbByteModrm
,
68 Fast486OpcodeSbbModrm
,
69 Fast486OpcodeSbbByteModrm
,
70 Fast486OpcodeSbbModrm
,
75 Fast486OpcodeAndByteModrm
,
76 Fast486OpcodeAndModrm
,
77 Fast486OpcodeAndByteModrm
,
78 Fast486OpcodeAndModrm
,
83 Fast486OpcodeCmpSubByteModrm
,
84 Fast486OpcodeCmpSubModrm
,
85 Fast486OpcodeCmpSubByteModrm
,
86 Fast486OpcodeCmpSubModrm
,
87 Fast486OpcodeCmpSubAl
,
88 Fast486OpcodeCmpSubEax
,
91 Fast486OpcodeXorByteModrm
,
92 Fast486OpcodeXorModrm
,
93 Fast486OpcodeXorByteModrm
,
94 Fast486OpcodeXorModrm
,
99 Fast486OpcodeCmpSubByteModrm
,
100 Fast486OpcodeCmpSubModrm
,
101 Fast486OpcodeCmpSubByteModrm
,
102 Fast486OpcodeCmpSubModrm
,
103 Fast486OpcodeCmpSubAl
,
104 Fast486OpcodeCmpSubEax
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeIncrement
,
113 Fast486OpcodeIncrement
,
114 Fast486OpcodeIncrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodeDecrement
,
121 Fast486OpcodeDecrement
,
122 Fast486OpcodeDecrement
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
128 Fast486OpcodePushReg
,
129 Fast486OpcodePushReg
,
130 Fast486OpcodePushReg
,
139 Fast486OpcodePushAll
,
147 Fast486OpcodePushImm
,
148 Fast486OpcodeImulModrmImm
,
149 Fast486OpcodePushByteImm
,
150 Fast486OpcodeImulModrmImm
,
155 Fast486OpcodeShortConditionalJmp
,
156 Fast486OpcodeShortConditionalJmp
,
157 Fast486OpcodeShortConditionalJmp
,
158 Fast486OpcodeShortConditionalJmp
,
159 Fast486OpcodeShortConditionalJmp
,
160 Fast486OpcodeShortConditionalJmp
,
161 Fast486OpcodeShortConditionalJmp
,
162 Fast486OpcodeShortConditionalJmp
,
163 Fast486OpcodeShortConditionalJmp
,
164 Fast486OpcodeShortConditionalJmp
,
165 Fast486OpcodeShortConditionalJmp
,
166 Fast486OpcodeShortConditionalJmp
,
167 Fast486OpcodeShortConditionalJmp
,
168 Fast486OpcodeShortConditionalJmp
,
169 Fast486OpcodeShortConditionalJmp
,
170 Fast486OpcodeShortConditionalJmp
,
171 Fast486OpcodeGroup8082
,
172 Fast486OpcodeGroup81
,
173 Fast486OpcodeGroup8082
,
174 Fast486OpcodeGroup83
,
175 Fast486OpcodeTestByteModrm
,
176 Fast486OpcodeTestModrm
,
177 Fast486OpcodeXchgByteModrm
,
178 Fast486OpcodeXchgModrm
,
179 Fast486OpcodeMovByteModrm
,
180 Fast486OpcodeMovModrm
,
181 Fast486OpcodeMovByteModrm
,
182 Fast486OpcodeMovModrm
,
183 Fast486OpcodeMovStoreSeg
,
185 Fast486OpcodeMovLoadSeg
,
186 Fast486OpcodeGroup8F
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
192 Fast486OpcodeExchangeEax
,
193 Fast486OpcodeExchangeEax
,
194 Fast486OpcodeExchangeEax
,
197 Fast486OpcodeCallAbs
,
199 Fast486OpcodePushFlags
,
200 Fast486OpcodePopFlags
,
203 Fast486OpcodeMovAlOffset
,
204 Fast486OpcodeMovEaxOffset
,
205 Fast486OpcodeMovOffsetAl
,
206 Fast486OpcodeMovOffsetEax
,
212 Fast486OpcodeTestEax
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovByteRegImm
,
225 Fast486OpcodeMovByteRegImm
,
226 Fast486OpcodeMovByteRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeMovRegImm
,
233 Fast486OpcodeMovRegImm
,
234 Fast486OpcodeMovRegImm
,
235 Fast486OpcodeGroupC0
,
236 Fast486OpcodeGroupC1
,
241 Fast486OpcodeGroupC6
,
242 Fast486OpcodeGroupC7
,
251 Fast486OpcodeGroupD0
,
252 Fast486OpcodeGroupD1
,
253 Fast486OpcodeGroupD2
,
254 Fast486OpcodeGroupD3
,
259 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
260 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
261 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
262 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
263 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
264 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
265 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
266 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
273 Fast486OpcodeOutByte
,
278 Fast486OpcodeShortJump
,
281 Fast486OpcodeOutByte
,
288 Fast486OpcodeComplCarry
,
289 Fast486OpcodeGroupF6
,
290 Fast486OpcodeGroupF7
,
291 Fast486OpcodeClearCarry
,
292 Fast486OpcodeSetCarry
,
293 Fast486OpcodeClearInt
,
295 Fast486OpcodeClearDir
,
297 Fast486OpcodeGroupFE
,
298 Fast486OpcodeGroupFF
,
301 /* PUBLIC FUNCTIONS ***********************************************************/
303 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
305 BOOLEAN Valid
= FALSE
;
312 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
314 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
315 State
->SegmentOverride
= FAST486_REG_ES
;
325 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
327 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
328 State
->SegmentOverride
= FAST486_REG_CS
;
338 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
340 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
341 State
->SegmentOverride
= FAST486_REG_SS
;
351 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
353 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
354 State
->SegmentOverride
= FAST486_REG_DS
;
364 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
366 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
367 State
->SegmentOverride
= FAST486_REG_FS
;
377 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
379 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
380 State
->SegmentOverride
= FAST486_REG_GS
;
390 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
392 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
402 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
404 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
413 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
415 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
425 /* Mutually exclusive with REP */
426 if (!(State
->PrefixFlags
427 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
429 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
439 /* Mutually exclusive with REPNZ */
440 if (!(State
->PrefixFlags
441 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
443 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
453 /* Clear all prefixes */
454 State
->PrefixFlags
= 0;
456 /* Throw an exception */
457 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
464 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
467 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
472 /* Make sure this is the right instruction */
473 ASSERT((Opcode
& 0xF8) == 0x40);
477 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
479 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
480 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
484 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
486 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
487 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
490 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
491 State
->Flags
.Af
= ((Value
& 0x0F) == 0) ? TRUE
: FALSE
;
492 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
498 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
501 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
506 /* Make sure this is the right instruction */
507 ASSERT((Opcode
& 0xF8) == 0x48);
511 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
513 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1)) ? TRUE
: FALSE
;
514 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
518 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
520 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1)) ? TRUE
: FALSE
;
521 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
524 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
525 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F) ? TRUE
: FALSE
;
526 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
532 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
536 /* Make sure this is the right instruction */
537 ASSERT((Opcode
& 0xF8) == 0x50);
539 /* Call the internal function */
540 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
543 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
546 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_SS
].Size
;
551 /* Make sure this is the right instruction */
552 ASSERT((Opcode
& 0xF8) == 0x58);
554 /* Call the internal function */
555 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
557 /* Store the value */
558 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
559 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
565 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
567 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
570 State
->IdleCallback(State
);
576 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
578 INT Reg
= Opcode
& 0x07;
579 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
584 /* Make sure this is the right instruction */
585 ASSERT((Opcode
& 0xF8) == 0x90);
587 /* Exchange the values */
592 Value
= State
->GeneralRegs
[Reg
].Long
;
593 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
594 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
600 Value
= State
->GeneralRegs
[Reg
].LowWord
;
601 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
602 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
608 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
610 BOOLEAN Jump
= FALSE
;
613 /* Make sure this is the right instruction */
614 ASSERT((Opcode
& 0xF0) == 0x70);
616 /* Fetch the offset */
617 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
619 /* An exception occurred */
623 switch ((Opcode
& 0x0F) >> 1)
628 Jump
= State
->Flags
.Of
;
635 Jump
= State
->Flags
.Cf
;
642 Jump
= State
->Flags
.Zf
;
649 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
656 Jump
= State
->Flags
.Sf
;
663 Jump
= State
->Flags
.Pf
;
670 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
677 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
684 /* Invert the result */
690 /* Move the instruction pointer */
691 State
->InstPtr
.Long
+= Offset
;
698 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
700 /* Make sure this is the right instruction */
701 ASSERT(Opcode
== 0xF8);
703 /* No prefixes allowed */
704 if (State
->PrefixFlags
)
706 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
710 /* Clear CF and return success */
711 State
->Flags
.Cf
= FALSE
;
715 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
717 /* Make sure this is the right instruction */
718 ASSERT(Opcode
== 0xF9);
720 /* No prefixes allowed */
721 if (State
->PrefixFlags
)
723 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
727 /* Set CF and return success*/
728 State
->Flags
.Cf
= TRUE
;
732 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
734 /* Make sure this is the right instruction */
735 ASSERT(Opcode
== 0xF5);
737 /* No prefixes allowed */
738 if (State
->PrefixFlags
)
740 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
744 /* Toggle CF and return success */
745 State
->Flags
.Cf
= !State
->Flags
.Cf
;
749 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
751 /* Make sure this is the right instruction */
752 ASSERT(Opcode
== 0xFA);
754 /* No prefixes allowed */
755 if (State
->PrefixFlags
)
757 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
761 /* Check for protected mode */
762 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
765 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
767 /* Clear the interrupt flag */
768 State
->Flags
.If
= FALSE
;
772 /* General Protection Fault */
773 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
779 /* Just clear the interrupt flag */
780 State
->Flags
.If
= FALSE
;
787 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
789 /* Make sure this is the right instruction */
790 ASSERT(Opcode
== 0xFB);
792 /* No prefixes allowed */
793 if (State
->PrefixFlags
)
795 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
799 /* Check for protected mode */
800 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
803 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
805 /* Set the interrupt flag */
806 State
->Flags
.If
= TRUE
;
810 /* General Protection Fault */
811 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
817 /* Just set the interrupt flag */
818 State
->Flags
.If
= TRUE
;
825 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
827 /* Make sure this is the right instruction */
828 ASSERT(Opcode
== 0xFC);
830 /* No prefixes allowed */
831 if (State
->PrefixFlags
)
833 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
837 /* Clear DF and return success */
838 State
->Flags
.Df
= FALSE
;
842 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
844 /* Make sure this is the right instruction */
845 ASSERT(Opcode
== 0xFD);
847 /* No prefixes allowed */
848 if (State
->PrefixFlags
)
850 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
854 /* Set DF and return success*/
855 State
->Flags
.Df
= TRUE
;
859 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
861 /* Make sure this is the right instruction */
862 ASSERT(Opcode
== 0xF4);
864 /* No prefixes allowed */
865 if (State
->PrefixFlags
)
867 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
871 /* Privileged instructions can only be executed under CPL = 0 */
872 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
874 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
879 while (!State
->HardwareInt
) State
->IdleCallback(State
);
885 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
890 /* Make sure this is the right instruction */
891 ASSERT((Opcode
& 0xF7) == 0xE4);
895 /* Fetch the parameter */
896 if (!Fast486FetchByte(State
, &Data
))
898 /* Exception occurred */
902 /* Set the port number to the parameter */
907 /* The port number is in DX */
908 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
911 /* Read a byte from the I/O port */
912 State
->IoReadCallback(State
, Port
, &Data
, sizeof(UCHAR
));
914 /* Store the result in AL */
915 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
920 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
923 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
925 /* Make sure this is the right instruction */
926 ASSERT((Opcode
& 0xF7) == 0xE5);
935 /* Fetch the parameter */
936 if (!Fast486FetchByte(State
, &Data
))
938 /* Exception occurred */
942 /* Set the port number to the parameter */
947 /* The port number is in DX */
948 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
955 /* Read a dword from the I/O port */
956 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
958 /* Store the value in EAX */
959 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
965 /* Read a word from the I/O port */
966 State
->IoReadCallback(State
, Port
, &Data
, sizeof(USHORT
));
968 /* Store the value in AX */
969 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
975 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
980 /* Make sure this is the right instruction */
981 ASSERT((Opcode
& 0xF7) == 0xE6);
985 /* Fetch the parameter */
986 if (!Fast486FetchByte(State
, &Data
))
988 /* Exception occurred */
992 /* Set the port number to the parameter */
997 /* The port number is in DX */
998 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1001 /* Read the value from AL */
1002 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1004 /* Write the byte to the I/O port */
1005 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(UCHAR
));
1010 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1013 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1015 /* Make sure this is the right instruction */
1016 ASSERT((Opcode
& 0xF7) == 0xE7);
1018 TOGGLE_OPSIZE(Size
);
1025 /* Fetch the parameter */
1026 if (!Fast486FetchByte(State
, &Data
))
1028 /* Exception occurred */
1032 /* Set the port number to the parameter */
1037 /* The port number is in DX */
1038 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1043 /* Get the value from EAX */
1044 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1046 /* Write a dword to the I/O port */
1047 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1051 /* Get the value from AX */
1052 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1054 /* Write a word to the I/O port */
1055 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(USHORT
));
1061 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1065 /* Make sure this is the right instruction */
1066 ASSERT(Opcode
== 0xEB);
1068 /* Fetch the offset */
1069 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1071 /* An exception occurred */
1075 /* Move the instruction pointer */
1076 State
->InstPtr
.Long
+= Offset
;
1081 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1083 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1085 /* Make sure this is the right instruction */
1086 ASSERT((Opcode
& 0xF8) == 0xB8);
1088 TOGGLE_OPSIZE(Size
);
1095 /* Fetch the dword */
1096 if (!Fast486FetchDword(State
, &Value
))
1098 /* Exception occurred */
1102 /* Store the value in the register */
1103 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1109 /* Fetch the word */
1110 if (!Fast486FetchWord(State
, &Value
))
1112 /* Exception occurred */
1116 /* Store the value in the register */
1117 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1123 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1127 /* Make sure this is the right instruction */
1128 ASSERT((Opcode
& 0xF8) == 0xB0);
1130 if (State
->PrefixFlags
!= 0)
1132 /* Invalid prefix */
1133 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1137 /* Fetch the byte */
1138 if (!Fast486FetchByte(State
, &Value
))
1140 /* Exception occurred */
1146 /* AH, CH, DH or BH */
1147 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1151 /* AL, CL, DL or BL */
1152 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1158 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1160 UCHAR FirstValue
, SecondValue
, Result
;
1161 FAST486_MOD_REG_RM ModRegRm
;
1162 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1164 /* Make sure this is the right instruction */
1165 ASSERT((Opcode
& 0xFD) == 0x00);
1167 TOGGLE_ADSIZE(AddressSize
);
1169 /* Get the operands */
1170 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1172 /* Exception occurred */
1176 if (!Fast486ReadModrmByteOperands(State
,
1181 /* Exception occurred */
1185 /* Calculate the result */
1186 Result
= FirstValue
+ SecondValue
;
1188 /* Update the flags */
1189 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1190 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1191 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1192 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1193 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1194 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1195 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1197 /* Write back the result */
1198 return Fast486WriteModrmByteOperands(State
,
1200 Opcode
& FAST486_OPCODE_WRITE_REG
,
1204 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1206 FAST486_MOD_REG_RM ModRegRm
;
1207 BOOLEAN OperandSize
, AddressSize
;
1209 /* Make sure this is the right instruction */
1210 ASSERT((Opcode
& 0xFD) == 0x01);
1212 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1214 TOGGLE_ADSIZE(AddressSize
);
1215 TOGGLE_OPSIZE(OperandSize
);
1217 /* Get the operands */
1218 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1220 /* Exception occurred */
1224 /* Check the operand size */
1227 ULONG FirstValue
, SecondValue
, Result
;
1229 if (!Fast486ReadModrmDwordOperands(State
,
1234 /* Exception occurred */
1238 /* Calculate the result */
1239 Result
= FirstValue
+ SecondValue
;
1241 /* Update the flags */
1242 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1243 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1244 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1245 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1246 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1247 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1248 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1250 /* Write back the result */
1251 return Fast486WriteModrmDwordOperands(State
,
1253 Opcode
& FAST486_OPCODE_WRITE_REG
,
1258 USHORT FirstValue
, SecondValue
, Result
;
1260 if (!Fast486ReadModrmWordOperands(State
,
1265 /* Exception occurred */
1269 /* Calculate the result */
1270 Result
= FirstValue
+ SecondValue
;
1272 /* Update the flags */
1273 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1274 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1275 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1276 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1277 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1278 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1279 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1281 /* Write back the result */
1282 return Fast486WriteModrmWordOperands(State
,
1284 Opcode
& FAST486_OPCODE_WRITE_REG
,
1289 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1291 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1292 UCHAR SecondValue
, Result
;
1294 /* Make sure this is the right instruction */
1295 ASSERT(Opcode
== 0x04);
1297 if (State
->PrefixFlags
)
1299 /* This opcode doesn't take any prefixes */
1300 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1304 if (!Fast486FetchByte(State
, &SecondValue
))
1306 /* Exception occurred */
1310 /* Calculate the result */
1311 Result
= FirstValue
+ SecondValue
;
1313 /* Update the flags */
1314 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1315 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1316 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1317 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1318 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1319 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1320 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1322 /* Write back the result */
1323 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1328 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1330 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1332 /* Make sure this is the right instruction */
1333 ASSERT(Opcode
== 0x05);
1336 TOGGLE_OPSIZE(Size
);
1340 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1341 ULONG SecondValue
, Result
;
1343 if (!Fast486FetchDword(State
, &SecondValue
))
1345 /* Exception occurred */
1349 /* Calculate the result */
1350 Result
= FirstValue
+ SecondValue
;
1352 /* Update the flags */
1353 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1354 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1355 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1356 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1357 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1358 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1359 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1361 /* Write back the result */
1362 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1366 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1367 USHORT SecondValue
, Result
;
1369 if (!Fast486FetchWord(State
, &SecondValue
))
1371 /* Exception occurred */
1375 /* Calculate the result */
1376 Result
= FirstValue
+ SecondValue
;
1378 /* Update the flags */
1379 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1380 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1381 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1382 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1383 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1384 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1385 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1387 /* Write back the result */
1388 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1394 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1396 UCHAR FirstValue
, SecondValue
, Result
;
1397 FAST486_MOD_REG_RM ModRegRm
;
1398 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1400 /* Make sure this is the right instruction */
1401 ASSERT((Opcode
& 0xFD) == 0x08);
1403 TOGGLE_ADSIZE(AddressSize
);
1405 /* Get the operands */
1406 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1408 /* Exception occurred */
1412 if (!Fast486ReadModrmByteOperands(State
,
1417 /* Exception occurred */
1421 /* Calculate the result */
1422 Result
= FirstValue
| SecondValue
;
1424 /* Update the flags */
1425 State
->Flags
.Cf
= FALSE
;
1426 State
->Flags
.Of
= FALSE
;
1427 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1428 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1429 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1431 /* Write back the result */
1432 return Fast486WriteModrmByteOperands(State
,
1434 Opcode
& FAST486_OPCODE_WRITE_REG
,
1438 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1440 FAST486_MOD_REG_RM ModRegRm
;
1441 BOOLEAN OperandSize
, AddressSize
;
1443 /* Make sure this is the right instruction */
1444 ASSERT((Opcode
& 0xFD) == 0x09);
1446 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1448 TOGGLE_ADSIZE(AddressSize
);
1449 TOGGLE_OPSIZE(OperandSize
);
1451 /* Get the operands */
1452 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1454 /* Exception occurred */
1458 /* Check the operand size */
1461 ULONG FirstValue
, SecondValue
, Result
;
1463 if (!Fast486ReadModrmDwordOperands(State
,
1468 /* Exception occurred */
1472 /* Calculate the result */
1473 Result
= FirstValue
| SecondValue
;
1475 /* Update the flags */
1476 State
->Flags
.Cf
= FALSE
;
1477 State
->Flags
.Of
= FALSE
;
1478 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1479 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1480 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1482 /* Write back the result */
1483 return Fast486WriteModrmDwordOperands(State
,
1485 Opcode
& FAST486_OPCODE_WRITE_REG
,
1490 USHORT FirstValue
, SecondValue
, Result
;
1492 if (!Fast486ReadModrmWordOperands(State
,
1497 /* Exception occurred */
1501 /* Calculate the result */
1502 Result
= FirstValue
| SecondValue
;
1504 /* Update the flags */
1505 State
->Flags
.Cf
= FALSE
;
1506 State
->Flags
.Of
= FALSE
;
1507 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1508 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1509 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1511 /* Write back the result */
1512 return Fast486WriteModrmWordOperands(State
,
1514 Opcode
& FAST486_OPCODE_WRITE_REG
,
1519 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1521 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1522 UCHAR SecondValue
, Result
;
1524 /* Make sure this is the right instruction */
1525 ASSERT(Opcode
== 0x0C);
1527 if (State
->PrefixFlags
)
1529 /* This opcode doesn't take any prefixes */
1530 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1534 if (!Fast486FetchByte(State
, &SecondValue
))
1536 /* Exception occurred */
1540 /* Calculate the result */
1541 Result
= FirstValue
| SecondValue
;
1543 /* Update the flags */
1544 State
->Flags
.Cf
= FALSE
;
1545 State
->Flags
.Of
= FALSE
;
1546 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1547 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1548 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1550 /* Write back the result */
1551 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1556 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1558 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1560 /* Make sure this is the right instruction */
1561 ASSERT(Opcode
== 0x0D);
1564 TOGGLE_OPSIZE(Size
);
1568 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1569 ULONG SecondValue
, Result
;
1571 if (!Fast486FetchDword(State
, &SecondValue
))
1573 /* Exception occurred */
1577 /* Calculate the result */
1578 Result
= FirstValue
| SecondValue
;
1580 /* Update the flags */
1581 State
->Flags
.Cf
= FALSE
;
1582 State
->Flags
.Of
= FALSE
;
1583 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1584 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1585 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1587 /* Write back the result */
1588 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1592 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1593 USHORT SecondValue
, Result
;
1595 if (!Fast486FetchWord(State
, &SecondValue
))
1597 /* Exception occurred */
1601 /* Calculate the result */
1602 Result
= FirstValue
| SecondValue
;
1604 /* Update the flags */
1605 State
->Flags
.Cf
= FALSE
;
1606 State
->Flags
.Of
= FALSE
;
1607 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1608 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1609 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1611 /* Write back the result */
1612 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1618 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1620 UCHAR FirstValue
, SecondValue
, Result
;
1621 FAST486_MOD_REG_RM ModRegRm
;
1622 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1624 /* Make sure this is the right instruction */
1625 ASSERT((Opcode
& 0xFD) == 0x20);
1627 TOGGLE_ADSIZE(AddressSize
);
1629 /* Get the operands */
1630 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1632 /* Exception occurred */
1636 if (!Fast486ReadModrmByteOperands(State
,
1641 /* Exception occurred */
1645 /* Calculate the result */
1646 Result
= FirstValue
& SecondValue
;
1648 /* Update the flags */
1649 State
->Flags
.Cf
= FALSE
;
1650 State
->Flags
.Of
= FALSE
;
1651 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1652 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1653 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1655 /* Write back the result */
1656 return Fast486WriteModrmByteOperands(State
,
1658 Opcode
& FAST486_OPCODE_WRITE_REG
,
1662 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1664 FAST486_MOD_REG_RM ModRegRm
;
1665 BOOLEAN OperandSize
, AddressSize
;
1667 /* Make sure this is the right instruction */
1668 ASSERT((Opcode
& 0xFD) == 0x21);
1670 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1672 TOGGLE_ADSIZE(AddressSize
);
1673 TOGGLE_OPSIZE(OperandSize
);
1675 /* Get the operands */
1676 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1678 /* Exception occurred */
1682 /* Check the operand size */
1685 ULONG FirstValue
, SecondValue
, Result
;
1687 if (!Fast486ReadModrmDwordOperands(State
,
1692 /* Exception occurred */
1696 /* Calculate the result */
1697 Result
= FirstValue
& SecondValue
;
1699 /* Update the flags */
1700 State
->Flags
.Cf
= FALSE
;
1701 State
->Flags
.Of
= FALSE
;
1702 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1703 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1704 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1706 /* Write back the result */
1707 return Fast486WriteModrmDwordOperands(State
,
1709 Opcode
& FAST486_OPCODE_WRITE_REG
,
1714 USHORT FirstValue
, SecondValue
, Result
;
1716 if (!Fast486ReadModrmWordOperands(State
,
1721 /* Exception occurred */
1725 /* Calculate the result */
1726 Result
= FirstValue
& SecondValue
;
1728 /* Update the flags */
1729 State
->Flags
.Cf
= FALSE
;
1730 State
->Flags
.Of
= FALSE
;
1731 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1732 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1733 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1735 /* Write back the result */
1736 return Fast486WriteModrmWordOperands(State
,
1738 Opcode
& FAST486_OPCODE_WRITE_REG
,
1743 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1745 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1746 UCHAR SecondValue
, Result
;
1748 /* Make sure this is the right instruction */
1749 ASSERT(Opcode
== 0x24);
1753 if (!Fast486FetchByte(State
, &SecondValue
))
1755 /* Exception occurred */
1759 /* Calculate the result */
1760 Result
= FirstValue
& SecondValue
;
1762 /* Update the flags */
1763 State
->Flags
.Cf
= FALSE
;
1764 State
->Flags
.Of
= FALSE
;
1765 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1766 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1767 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1769 /* Write back the result */
1770 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1775 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1777 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1779 /* Make sure this is the right instruction */
1780 ASSERT(Opcode
== 0x25);
1783 TOGGLE_OPSIZE(Size
);
1787 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1788 ULONG SecondValue
, Result
;
1790 if (!Fast486FetchDword(State
, &SecondValue
))
1792 /* Exception occurred */
1796 /* Calculate the result */
1797 Result
= FirstValue
& SecondValue
;
1799 /* Update the flags */
1800 State
->Flags
.Cf
= FALSE
;
1801 State
->Flags
.Of
= FALSE
;
1802 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1803 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1804 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1806 /* Write back the result */
1807 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1811 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1812 USHORT SecondValue
, Result
;
1814 if (!Fast486FetchWord(State
, &SecondValue
))
1816 /* Exception occurred */
1820 /* Calculate the result */
1821 Result
= FirstValue
& SecondValue
;
1823 /* Update the flags */
1824 State
->Flags
.Cf
= FALSE
;
1825 State
->Flags
.Of
= FALSE
;
1826 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1827 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1828 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1830 /* Write back the result */
1831 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1837 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1839 UCHAR FirstValue
, SecondValue
, Result
;
1840 FAST486_MOD_REG_RM ModRegRm
;
1841 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1843 /* Make sure this is the right instruction */
1844 ASSERT((Opcode
& 0xFD) == 0x30);
1846 TOGGLE_ADSIZE(AddressSize
);
1848 /* Get the operands */
1849 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1851 /* Exception occurred */
1855 if (!Fast486ReadModrmByteOperands(State
,
1860 /* Exception occurred */
1864 /* Calculate the result */
1865 Result
= FirstValue
^ SecondValue
;
1867 /* Update the flags */
1868 State
->Flags
.Cf
= FALSE
;
1869 State
->Flags
.Of
= FALSE
;
1870 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1871 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1872 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1874 /* Write back the result */
1875 return Fast486WriteModrmByteOperands(State
,
1877 Opcode
& FAST486_OPCODE_WRITE_REG
,
1881 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1883 FAST486_MOD_REG_RM ModRegRm
;
1884 BOOLEAN OperandSize
, AddressSize
;
1886 /* Make sure this is the right instruction */
1887 ASSERT((Opcode
& 0xFD) == 0x31);
1889 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1891 TOGGLE_ADSIZE(AddressSize
);
1892 TOGGLE_OPSIZE(OperandSize
);
1894 /* Get the operands */
1895 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1897 /* Exception occurred */
1901 /* Check the operand size */
1904 ULONG FirstValue
, SecondValue
, Result
;
1906 if (!Fast486ReadModrmDwordOperands(State
,
1911 /* Exception occurred */
1915 /* Calculate the result */
1916 Result
= FirstValue
^ SecondValue
;
1918 /* Update the flags */
1919 State
->Flags
.Cf
= FALSE
;
1920 State
->Flags
.Of
= FALSE
;
1921 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1922 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1923 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1925 /* Write back the result */
1926 return Fast486WriteModrmDwordOperands(State
,
1928 Opcode
& FAST486_OPCODE_WRITE_REG
,
1933 USHORT FirstValue
, SecondValue
, Result
;
1935 if (!Fast486ReadModrmWordOperands(State
,
1940 /* Exception occurred */
1944 /* Calculate the result */
1945 Result
= FirstValue
^ SecondValue
;
1947 /* Update the flags */
1948 State
->Flags
.Cf
= FALSE
;
1949 State
->Flags
.Of
= FALSE
;
1950 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1951 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1952 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1954 /* Write back the result */
1955 return Fast486WriteModrmWordOperands(State
,
1957 Opcode
& FAST486_OPCODE_WRITE_REG
,
1962 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1964 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1965 UCHAR SecondValue
, Result
;
1967 /* Make sure this is the right instruction */
1968 ASSERT(Opcode
== 0x34);
1970 if (State
->PrefixFlags
)
1972 /* This opcode doesn't take any prefixes */
1973 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1977 if (!Fast486FetchByte(State
, &SecondValue
))
1979 /* Exception occurred */
1983 /* Calculate the result */
1984 Result
= FirstValue
^ SecondValue
;
1986 /* Update the flags */
1987 State
->Flags
.Cf
= FALSE
;
1988 State
->Flags
.Of
= FALSE
;
1989 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1990 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1991 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1993 /* Write back the result */
1994 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1999 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2001 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2003 /* Make sure this is the right instruction */
2004 ASSERT(Opcode
== 0x35);
2007 TOGGLE_OPSIZE(Size
);
2011 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2012 ULONG SecondValue
, Result
;
2014 if (!Fast486FetchDword(State
, &SecondValue
))
2016 /* Exception occurred */
2020 /* Calculate the result */
2021 Result
= FirstValue
^ SecondValue
;
2023 /* Update the flags */
2024 State
->Flags
.Cf
= FALSE
;
2025 State
->Flags
.Of
= FALSE
;
2026 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2027 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2028 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2030 /* Write back the result */
2031 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2035 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2036 USHORT SecondValue
, Result
;
2038 if (!Fast486FetchWord(State
, &SecondValue
))
2040 /* Exception occurred */
2044 /* Calculate the result */
2045 Result
= FirstValue
^ SecondValue
;
2047 /* Update the flags */
2048 State
->Flags
.Cf
= FALSE
;
2049 State
->Flags
.Of
= FALSE
;
2050 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2051 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2052 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2054 /* Write back the result */
2055 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2061 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2063 UCHAR FirstValue
, SecondValue
, Result
;
2064 FAST486_MOD_REG_RM ModRegRm
;
2065 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2067 /* Make sure this is the right instruction */
2068 ASSERT(Opcode
== 0x84);
2070 TOGGLE_ADSIZE(AddressSize
);
2072 /* Get the operands */
2073 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2075 /* Exception occurred */
2079 if (!Fast486ReadModrmByteOperands(State
,
2084 /* Exception occurred */
2087 /* Calculate the result */
2088 Result
= FirstValue
& SecondValue
;
2090 /* Update the flags */
2091 State
->Flags
.Cf
= FALSE
;
2092 State
->Flags
.Of
= FALSE
;
2093 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2094 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2095 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2097 /* The result is discarded */
2101 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2103 FAST486_MOD_REG_RM ModRegRm
;
2104 BOOLEAN OperandSize
, AddressSize
;
2106 /* Make sure this is the right instruction */
2107 ASSERT(Opcode
== 0x85);
2109 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2111 TOGGLE_ADSIZE(AddressSize
);
2112 TOGGLE_OPSIZE(OperandSize
);
2114 /* Get the operands */
2115 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2117 /* Exception occurred */
2121 /* Check the operand size */
2124 ULONG FirstValue
, SecondValue
, Result
;
2126 if (!Fast486ReadModrmDwordOperands(State
,
2131 /* Exception occurred */
2135 /* Calculate the result */
2136 Result
= FirstValue
& SecondValue
;
2138 /* Update the flags */
2139 State
->Flags
.Cf
= FALSE
;
2140 State
->Flags
.Of
= FALSE
;
2141 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2142 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2143 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2147 USHORT FirstValue
, SecondValue
, Result
;
2149 if (!Fast486ReadModrmWordOperands(State
,
2154 /* Exception occurred */
2158 /* Calculate the result */
2159 Result
= FirstValue
& SecondValue
;
2161 /* Update the flags */
2162 State
->Flags
.Cf
= FALSE
;
2163 State
->Flags
.Of
= FALSE
;
2164 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2165 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2166 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2169 /* The result is discarded */
2173 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2175 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2176 UCHAR SecondValue
, Result
;
2178 /* Make sure this is the right instruction */
2179 ASSERT(Opcode
== 0xA8);
2181 if (State
->PrefixFlags
)
2183 /* This opcode doesn't take any prefixes */
2184 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2188 if (!Fast486FetchByte(State
, &SecondValue
))
2190 /* Exception occurred */
2194 /* Calculate the result */
2195 Result
= FirstValue
& SecondValue
;
2197 /* Update the flags */
2198 State
->Flags
.Cf
= FALSE
;
2199 State
->Flags
.Of
= FALSE
;
2200 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2201 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2202 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2204 /* The result is discarded */
2208 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2210 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2212 /* Make sure this is the right instruction */
2213 ASSERT(Opcode
== 0xA9);
2216 TOGGLE_OPSIZE(Size
);
2220 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2221 ULONG SecondValue
, Result
;
2223 if (!Fast486FetchDword(State
, &SecondValue
))
2225 /* Exception occurred */
2229 /* Calculate the result */
2230 Result
= FirstValue
& SecondValue
;
2232 /* Update the flags */
2233 State
->Flags
.Cf
= FALSE
;
2234 State
->Flags
.Of
= FALSE
;
2235 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2236 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2237 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2241 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2242 USHORT SecondValue
, Result
;
2244 if (!Fast486FetchWord(State
, &SecondValue
))
2246 /* Exception occurred */
2250 /* Calculate the result */
2251 Result
= FirstValue
& SecondValue
;
2253 /* Update the flags */
2254 State
->Flags
.Cf
= FALSE
;
2255 State
->Flags
.Of
= FALSE
;
2256 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2257 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2258 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2261 /* The result is discarded */
2265 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2267 UCHAR FirstValue
, SecondValue
;
2268 FAST486_MOD_REG_RM ModRegRm
;
2269 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2271 /* Make sure this is the right instruction */
2272 ASSERT(Opcode
== 0x86);
2274 TOGGLE_ADSIZE(AddressSize
);
2276 /* Get the operands */
2277 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2279 /* Exception occurred */
2283 if (!Fast486ReadModrmByteOperands(State
,
2288 /* Exception occurred */
2292 /* Write the value from the register to the R/M */
2293 if (!Fast486WriteModrmByteOperands(State
,
2298 /* Exception occurred */
2302 /* Write the value from the R/M to the register */
2303 if (!Fast486WriteModrmByteOperands(State
,
2308 /* Exception occurred */
2315 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2317 FAST486_MOD_REG_RM ModRegRm
;
2318 BOOLEAN OperandSize
, AddressSize
;
2320 /* Make sure this is the right instruction */
2321 ASSERT(Opcode
== 0x87);
2323 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2325 TOGGLE_ADSIZE(AddressSize
);
2326 TOGGLE_OPSIZE(OperandSize
);
2328 /* Get the operands */
2329 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2331 /* Exception occurred */
2335 /* Check the operand size */
2338 ULONG FirstValue
, SecondValue
;
2340 if (!Fast486ReadModrmDwordOperands(State
,
2345 /* Exception occurred */
2349 /* Write the value from the register to the R/M */
2350 if (!Fast486WriteModrmDwordOperands(State
,
2355 /* Exception occurred */
2359 /* Write the value from the R/M to the register */
2360 if (!Fast486WriteModrmDwordOperands(State
,
2365 /* Exception occurred */
2371 USHORT FirstValue
, SecondValue
;
2373 if (!Fast486ReadModrmWordOperands(State
,
2378 /* Exception occurred */
2382 /* Write the value from the register to the R/M */
2383 if (!Fast486WriteModrmWordOperands(State
,
2388 /* Exception occurred */
2392 /* Write the value from the R/M to the register */
2393 if (!Fast486WriteModrmWordOperands(State
,
2398 /* Exception occurred */
2403 /* The result is discarded */
2407 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2409 /* Call the internal API */
2410 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2413 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2417 if (!Fast486StackPop(State
, &NewSelector
))
2419 /* Exception occurred */
2423 /* Call the internal API */
2424 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2427 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2429 /* Call the internal API */
2430 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2433 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2435 UCHAR FirstValue
, SecondValue
, Result
;
2436 FAST486_MOD_REG_RM ModRegRm
;
2437 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2439 /* Make sure this is the right instruction */
2440 ASSERT((Opcode
& 0xFD) == 0x10);
2442 TOGGLE_ADSIZE(AddressSize
);
2444 /* Get the operands */
2445 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2447 /* Exception occurred */
2451 if (!Fast486ReadModrmByteOperands(State
,
2456 /* Exception occurred */
2460 /* Calculate the result */
2461 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2463 /* Special exception for CF */
2464 State
->Flags
.Cf
= State
->Flags
.Cf
2465 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2467 /* Update the flags */
2468 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2469 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2470 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2471 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2472 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2473 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2474 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2476 /* Write back the result */
2477 return Fast486WriteModrmByteOperands(State
,
2479 Opcode
& FAST486_OPCODE_WRITE_REG
,
2483 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2485 FAST486_MOD_REG_RM ModRegRm
;
2486 BOOLEAN OperandSize
, AddressSize
;
2488 /* Make sure this is the right instruction */
2489 ASSERT((Opcode
& 0xFD) == 0x11);
2491 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2493 TOGGLE_ADSIZE(AddressSize
);
2494 TOGGLE_OPSIZE(OperandSize
);
2496 /* Get the operands */
2497 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2499 /* Exception occurred */
2503 /* Check the operand size */
2506 ULONG FirstValue
, SecondValue
, Result
;
2508 if (!Fast486ReadModrmDwordOperands(State
,
2513 /* Exception occurred */
2517 /* Calculate the result */
2518 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2520 /* Special exception for CF */
2521 State
->Flags
.Cf
= State
->Flags
.Cf
2522 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2524 /* Update the flags */
2525 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2526 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2527 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2528 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2529 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2530 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2531 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2533 /* Write back the result */
2534 return Fast486WriteModrmDwordOperands(State
,
2536 Opcode
& FAST486_OPCODE_WRITE_REG
,
2541 USHORT FirstValue
, SecondValue
, Result
;
2543 if (!Fast486ReadModrmWordOperands(State
,
2548 /* Exception occurred */
2552 /* Calculate the result */
2553 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2555 /* Special exception for CF */
2556 State
->Flags
.Cf
= State
->Flags
.Cf
2557 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2559 /* Update the flags */
2560 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2561 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2562 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2563 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2564 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2565 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2566 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2568 /* Write back the result */
2569 return Fast486WriteModrmWordOperands(State
,
2571 Opcode
& FAST486_OPCODE_WRITE_REG
,
2577 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2579 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2580 UCHAR SecondValue
, Result
;
2582 /* Make sure this is the right instruction */
2583 ASSERT(Opcode
== 0x14);
2585 if (State
->PrefixFlags
)
2587 /* This opcode doesn't take any prefixes */
2588 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2592 if (!Fast486FetchByte(State
, &SecondValue
))
2594 /* Exception occurred */
2598 /* Calculate the result */
2599 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2601 /* Special exception for CF */
2602 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2603 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2605 /* Update the flags */
2606 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2607 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2608 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2609 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2610 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2611 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2612 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2614 /* Write back the result */
2615 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2620 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2622 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2624 /* Make sure this is the right instruction */
2625 ASSERT(Opcode
== 0x15);
2628 TOGGLE_OPSIZE(Size
);
2632 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2633 ULONG SecondValue
, Result
;
2635 if (!Fast486FetchDword(State
, &SecondValue
))
2637 /* Exception occurred */
2641 /* Calculate the result */
2642 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2644 /* Special exception for CF */
2645 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2646 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2648 /* Update the flags */
2649 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2650 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2651 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2652 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2653 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2654 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2655 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2657 /* Write back the result */
2658 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2662 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2663 USHORT SecondValue
, Result
;
2665 if (!Fast486FetchWord(State
, &SecondValue
))
2667 /* Exception occurred */
2671 /* Calculate the result */
2672 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2674 /* Special exception for CF */
2675 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2676 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2678 /* Update the flags */
2679 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2680 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2681 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2682 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2683 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2684 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2685 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2687 /* Write back the result */
2688 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2694 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2696 /* Call the internal API */
2697 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2700 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2704 if (!Fast486StackPop(State
, &NewSelector
))
2706 /* Exception occurred */
2710 /* Call the internal API */
2711 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2714 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2716 UCHAR FirstValue
, SecondValue
, Result
;
2717 FAST486_MOD_REG_RM ModRegRm
;
2718 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2719 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2721 /* Make sure this is the right instruction */
2722 ASSERT((Opcode
& 0xFD) == 0x18);
2724 TOGGLE_ADSIZE(AddressSize
);
2726 /* Get the operands */
2727 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2729 /* Exception occurred */
2733 if (!Fast486ReadModrmByteOperands(State
,
2738 /* Exception occurred */
2742 /* Check if this is the instruction that writes to R/M */
2743 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2745 /* Swap the order */
2746 SWAP(FirstValue
, SecondValue
);
2749 /* Calculate the result */
2750 Result
= FirstValue
- SecondValue
- Carry
;
2752 /* Update the flags */
2753 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ 1);
2754 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2755 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2756 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2757 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2758 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2759 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2761 /* Write back the result */
2762 return Fast486WriteModrmByteOperands(State
,
2764 Opcode
& FAST486_OPCODE_WRITE_REG
,
2768 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2770 FAST486_MOD_REG_RM ModRegRm
;
2771 BOOLEAN OperandSize
, AddressSize
;
2772 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2774 /* Make sure this is the right instruction */
2775 ASSERT((Opcode
& 0xFD) == 0x19);
2777 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2779 TOGGLE_ADSIZE(AddressSize
);
2780 TOGGLE_OPSIZE(OperandSize
);
2782 /* Get the operands */
2783 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2785 /* Exception occurred */
2789 /* Check the operand size */
2792 ULONG FirstValue
, SecondValue
, Result
;
2794 if (!Fast486ReadModrmDwordOperands(State
,
2799 /* Exception occurred */
2803 /* Check if this is the instruction that writes to R/M */
2804 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2806 /* Swap the order */
2807 SWAP(FirstValue
, SecondValue
);
2810 /* Calculate the result */
2811 Result
= FirstValue
- SecondValue
- Carry
;
2813 /* Update the flags */
2814 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2815 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2816 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2817 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2818 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2819 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2820 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2822 /* Write back the result */
2823 return Fast486WriteModrmDwordOperands(State
,
2825 Opcode
& FAST486_OPCODE_WRITE_REG
,
2830 USHORT FirstValue
, SecondValue
, Result
;
2832 if (!Fast486ReadModrmWordOperands(State
,
2837 /* Exception occurred */
2841 /* Check if this is the instruction that writes to R/M */
2842 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2844 /* Swap the order */
2845 SWAP(FirstValue
, SecondValue
);
2848 /* Calculate the result */
2849 Result
= FirstValue
- SecondValue
- Carry
;
2851 /* Update the flags */
2852 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2853 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2854 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2855 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2856 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2857 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2858 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2860 /* Write back the result */
2861 return Fast486WriteModrmWordOperands(State
,
2863 Opcode
& FAST486_OPCODE_WRITE_REG
,
2868 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2870 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2871 UCHAR SecondValue
, Result
;
2872 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2874 /* Make sure this is the right instruction */
2875 ASSERT(Opcode
== 0x1C);
2877 if (State
->PrefixFlags
)
2879 /* This opcode doesn't take any prefixes */
2880 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2884 if (!Fast486FetchByte(State
, &SecondValue
))
2886 /* Exception occurred */
2890 /* Calculate the result */
2891 Result
= FirstValue
- SecondValue
- Carry
;
2893 /* Update the flags */
2894 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2895 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2896 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2897 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2898 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2899 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2900 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2902 /* Write back the result */
2903 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2909 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2911 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2912 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2914 /* Make sure this is the right instruction */
2915 ASSERT(Opcode
== 0x1D);
2918 TOGGLE_OPSIZE(Size
);
2922 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2923 ULONG SecondValue
, Result
;
2925 if (!Fast486FetchDword(State
, &SecondValue
))
2927 /* Exception occurred */
2931 /* Calculate the result */
2932 Result
= FirstValue
- SecondValue
- Carry
;
2934 /* Update the flags */
2935 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2936 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2937 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2938 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
2939 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2940 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2941 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2943 /* Write back the result */
2944 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2948 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2949 USHORT SecondValue
, Result
;
2951 if (!Fast486FetchWord(State
, &SecondValue
))
2953 /* Exception occurred */
2957 /* Calculate the result */
2958 Result
= FirstValue
- SecondValue
- Carry
;
2960 /* Update the flags */
2961 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2962 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2963 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2964 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
2965 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2966 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2967 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2969 /* Write back the result */
2970 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2977 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2979 /* Call the internal API */
2980 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2983 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
2987 if (!Fast486StackPop(State
, &NewSelector
))
2989 /* Exception occurred */
2993 /* Call the internal API */
2994 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
2997 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
2999 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3000 BOOLEAN Carry
= State
->Flags
.Cf
;
3002 /* Clear the carry flag */
3003 State
->Flags
.Cf
= FALSE
;
3005 /* Check if the first BCD digit is invalid or there was a carry from it */
3006 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3009 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3010 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3012 /* A carry occurred */
3013 State
->Flags
.Cf
= TRUE
;
3016 /* Set the adjust flag */
3017 State
->Flags
.Af
= TRUE
;
3020 /* Check if the second BCD digit is invalid or there was a carry from it */
3021 if ((Value
> 0x99) || Carry
)
3024 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3026 /* There was a carry */
3027 State
->Flags
.Cf
= TRUE
;
3033 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3035 UCHAR FirstValue
, SecondValue
, Result
;
3036 FAST486_MOD_REG_RM ModRegRm
;
3037 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3039 /* Make sure this is the right instruction */
3040 ASSERT((Opcode
& 0xED) == 0x28);
3042 TOGGLE_ADSIZE(AddressSize
);
3044 /* Get the operands */
3045 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3047 /* Exception occurred */
3051 if (!Fast486ReadModrmByteOperands(State
,
3056 /* Exception occurred */
3060 /* Check if this is the instruction that writes to R/M */
3061 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3063 /* Swap the order */
3064 SWAP(FirstValue
, SecondValue
);
3067 /* Calculate the result */
3068 Result
= FirstValue
- SecondValue
;
3070 /* Update the flags */
3071 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3072 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3073 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3074 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3075 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3076 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3077 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3079 /* Check if this is not a CMP */
3080 if (!(Opcode
& 0x10))
3082 /* Write back the result */
3083 return Fast486WriteModrmByteOperands(State
,
3085 Opcode
& FAST486_OPCODE_WRITE_REG
,
3090 /* Discard the result */
3095 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3097 FAST486_MOD_REG_RM ModRegRm
;
3098 BOOLEAN OperandSize
, AddressSize
;
3100 /* Make sure this is the right instruction */
3101 ASSERT((Opcode
& 0xED) == 0x29);
3103 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3105 TOGGLE_ADSIZE(AddressSize
);
3106 TOGGLE_OPSIZE(OperandSize
);
3108 /* Get the operands */
3109 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3111 /* Exception occurred */
3115 /* Check the operand size */
3118 ULONG FirstValue
, SecondValue
, Result
;
3120 if (!Fast486ReadModrmDwordOperands(State
,
3125 /* Exception occurred */
3129 /* Check if this is the instruction that writes to R/M */
3130 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3132 /* Swap the order */
3133 SWAP(FirstValue
, SecondValue
);
3136 /* Calculate the result */
3137 Result
= FirstValue
- SecondValue
;
3139 /* Update the flags */
3140 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3141 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3142 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3143 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3144 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3145 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3146 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3148 /* Check if this is not a CMP */
3149 if (!(Opcode
& 0x10))
3151 /* Write back the result */
3152 return Fast486WriteModrmDwordOperands(State
,
3154 Opcode
& FAST486_OPCODE_WRITE_REG
,
3159 /* Discard the result */
3165 USHORT FirstValue
, SecondValue
, Result
;
3167 if (!Fast486ReadModrmWordOperands(State
,
3172 /* Exception occurred */
3176 /* Check if this is the instruction that writes to R/M */
3177 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3179 /* Swap the order */
3180 SWAP(FirstValue
, SecondValue
);
3183 /* Calculate the result */
3184 Result
= FirstValue
- SecondValue
;
3186 /* Update the flags */
3187 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3188 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3189 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3190 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3191 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3192 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3193 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3195 /* Check if this is not a CMP */
3196 if (!(Opcode
& 0x10))
3198 /* Write back the result */
3199 return Fast486WriteModrmWordOperands(State
,
3201 Opcode
& FAST486_OPCODE_WRITE_REG
,
3206 /* Discard the result */
3212 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3214 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3215 UCHAR SecondValue
, Result
;
3217 /* Make sure this is the right instruction */
3218 ASSERT((Opcode
& 0xEF) == 0x2C);
3220 if (State
->PrefixFlags
)
3222 /* This opcode doesn't take any prefixes */
3223 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3227 if (!Fast486FetchByte(State
, &SecondValue
))
3229 /* Exception occurred */
3233 /* Calculate the result */
3234 Result
= FirstValue
- SecondValue
;
3236 /* Update the flags */
3237 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3238 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3239 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3240 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3241 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3242 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3243 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3245 /* Check if this is not a CMP */
3246 if (!(Opcode
& 0x10))
3248 /* Write back the result */
3249 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3255 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3257 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3259 /* Make sure this is the right instruction */
3260 ASSERT((Opcode
& 0xEF) == 0x2D);
3263 TOGGLE_OPSIZE(Size
);
3267 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3268 ULONG SecondValue
, Result
;
3270 if (!Fast486FetchDword(State
, &SecondValue
))
3272 /* Exception occurred */
3276 /* Calculate the result */
3277 Result
= FirstValue
- SecondValue
;
3279 /* Update the flags */
3280 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3281 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3282 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3283 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3284 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3285 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3286 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3288 /* Check if this is not a CMP */
3289 if (!(Opcode
& 0x10))
3291 /* Write back the result */
3292 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3297 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3298 USHORT SecondValue
, Result
;
3300 if (!Fast486FetchWord(State
, &SecondValue
))
3302 /* Exception occurred */
3306 /* Calculate the result */
3307 Result
= FirstValue
- SecondValue
;
3309 /* Update the flags */
3310 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3311 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3312 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3313 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3314 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3315 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3316 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3318 /* Check if this is not a CMP */
3319 if (!(Opcode
& 0x10))
3321 /* Write back the result */
3322 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3329 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3331 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3332 BOOLEAN Carry
= State
->Flags
.Cf
;
3334 /* Clear the carry flag */
3335 State
->Flags
.Cf
= FALSE
;
3337 /* Check if the first BCD digit is invalid or there was a borrow */
3338 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3341 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3342 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3344 /* A borrow occurred */
3345 State
->Flags
.Cf
= TRUE
;
3348 /* Set the adjust flag */
3349 State
->Flags
.Af
= TRUE
;
3352 /* Check if the second BCD digit is invalid or there was a borrow */
3353 if ((Value
> 0x99) || Carry
)
3356 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3358 /* There was a borrow */
3359 State
->Flags
.Cf
= TRUE
;
3365 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3367 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3370 * Check if the value in AL is not a valid BCD digit,
3371 * or there was a carry from the lowest 4 bits of AL
3373 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3376 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3377 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3380 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3384 /* Clear CF and AF */
3385 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3388 /* Keep only the lowest 4 bits of AL */
3389 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3394 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3396 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3399 * Check if the value in AL is not a valid BCD digit,
3400 * or there was a borrow from the lowest 4 bits of AL
3402 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3405 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3406 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3409 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3413 /* Clear CF and AF */
3414 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3417 /* Keep only the lowest 4 bits of AL */
3418 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3423 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3426 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3427 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3429 /* Make sure this is the right instruction */
3430 ASSERT(Opcode
== 0x60);
3432 TOGGLE_OPSIZE(Size
);
3435 /* Push all the registers in order */
3436 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3438 if (i
== FAST486_REG_ESP
)
3440 /* Use the saved ESP instead */
3441 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3443 /* Exception occurred */
3449 /* Push the register */
3450 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3451 : State
->GeneralRegs
[i
].LowWord
))
3453 /* Exception occurred */
3462 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3465 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3468 /* Make sure this is the right instruction */
3469 ASSERT(Opcode
== 0x61);
3471 TOGGLE_OPSIZE(Size
);
3474 /* Pop all the registers in reverse order */
3475 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3478 if (!Fast486StackPop(State
, &Value
))
3480 /* Exception occurred */
3484 /* Don't modify ESP */
3485 if (i
!= FAST486_REG_ESP
)
3487 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3488 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3495 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3497 // TODO: NOT IMPLEMENTED
3503 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3505 USHORT FirstValue
, SecondValue
;
3506 FAST486_MOD_REG_RM ModRegRm
;
3507 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3509 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3511 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3513 /* Cannot be used in real mode or with a LOCK prefix */
3514 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3518 TOGGLE_ADSIZE(AddressSize
);
3520 /* Get the operands */
3521 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3523 /* Exception occurred */
3527 /* Read the operands */
3528 if (!Fast486ReadModrmWordOperands(State
,
3533 /* Exception occurred */
3537 /* Check if the RPL needs adjusting */
3538 if ((SecondValue
& 3) < (FirstValue
& 3))
3540 /* Adjust the RPL */
3542 SecondValue
|= FirstValue
& 3;
3545 State
->Flags
.Zf
= TRUE
;
3547 /* Write back the result */
3548 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3553 State
->Flags
.Zf
= FALSE
;
3558 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3560 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3562 /* Make sure this is the right instruction */
3563 ASSERT(Opcode
== 0x68);
3566 TOGGLE_OPSIZE(Size
);
3572 if (!Fast486FetchDword(State
, &Data
))
3574 /* Exception occurred */
3578 /* Call the internal API */
3579 return Fast486StackPush(State
, Data
);
3585 if (!Fast486FetchWord(State
, &Data
))
3587 /* Exception occurred */
3591 /* Call the internal API */
3592 return Fast486StackPush(State
, Data
);
3596 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3598 BOOLEAN OperandSize
, AddressSize
;
3599 FAST486_MOD_REG_RM ModRegRm
;
3603 /* Make sure this is the right instruction */
3604 ASSERT((Opcode
& 0xFD) == 0x69);
3606 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3608 TOGGLE_ADSIZE(AddressSize
);
3609 TOGGLE_OPSIZE(OperandSize
);
3611 /* Fetch the parameters */
3612 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3614 /* Exception occurred */
3622 /* Fetch the immediate operand */
3623 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3625 /* Exception occurred */
3629 Multiplier
= (LONG
)Byte
;
3637 /* Fetch the immediate operand */
3638 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3640 /* Exception occurred */
3650 /* Fetch the immediate operand */
3651 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3653 /* Exception occurred */
3657 Multiplier
= (LONG
)Word
;
3663 LONG RegValue
, Multiplicand
;
3665 /* Read the operands */
3666 if (!Fast486ReadModrmDwordOperands(State
,
3669 (PULONG
)&Multiplicand
))
3671 /* Exception occurred */
3676 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3680 SHORT RegValue
, Multiplicand
;
3682 /* Read the operands */
3683 if (!Fast486ReadModrmWordOperands(State
,
3686 (PUSHORT
)&Multiplicand
))
3688 /* Exception occurred */
3693 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3696 /* Check for carry/overflow */
3697 if ((Product
< LONG_MIN
) || (Product
> LONG_MAX
))
3699 State
->Flags
.Cf
= State
->Flags
.Of
= TRUE
;
3701 else State
->Flags
.Cf
= State
->Flags
.Of
= FALSE
;
3703 /* Write-back the result */
3704 return Fast486WriteModrmDwordOperands(State
,
3707 (ULONG
)((LONG
)Product
));
3710 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3714 /* Make sure this is the right instruction */
3715 ASSERT(Opcode
== 0x6A);
3717 if (!Fast486FetchByte(State
, &Data
))
3719 /* Exception occurred */
3723 /* Call the internal API */
3724 return Fast486StackPush(State
, Data
);
3727 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3729 UCHAR FirstValue
, SecondValue
, Result
;
3730 FAST486_MOD_REG_RM ModRegRm
;
3731 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3733 /* Make sure this is the right instruction */
3734 ASSERT((Opcode
& 0xFD) == 0x88);
3736 TOGGLE_ADSIZE(AddressSize
);
3738 /* Get the operands */
3739 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3741 /* Exception occurred */
3745 if (!Fast486ReadModrmByteOperands(State
,
3750 /* Exception occurred */
3754 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3755 else Result
= FirstValue
;
3757 /* Write back the result */
3758 return Fast486WriteModrmByteOperands(State
,
3760 Opcode
& FAST486_OPCODE_WRITE_REG
,
3765 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3767 FAST486_MOD_REG_RM ModRegRm
;
3768 BOOLEAN OperandSize
, AddressSize
;
3770 /* Make sure this is the right instruction */
3771 ASSERT((Opcode
& 0xFD) == 0x89);
3773 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3775 TOGGLE_ADSIZE(AddressSize
);
3776 TOGGLE_OPSIZE(OperandSize
);
3778 /* Get the operands */
3779 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3781 /* Exception occurred */
3785 /* Check the operand size */
3788 ULONG FirstValue
, SecondValue
, Result
;
3790 if (!Fast486ReadModrmDwordOperands(State
,
3795 /* Exception occurred */
3799 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3800 else Result
= FirstValue
;
3802 /* Write back the result */
3803 return Fast486WriteModrmDwordOperands(State
,
3805 Opcode
& FAST486_OPCODE_WRITE_REG
,
3810 USHORT FirstValue
, SecondValue
, Result
;
3812 if (!Fast486ReadModrmWordOperands(State
,
3817 /* Exception occurred */
3821 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3822 else Result
= FirstValue
;
3824 /* Write back the result */
3825 return Fast486WriteModrmWordOperands(State
,
3827 Opcode
& FAST486_OPCODE_WRITE_REG
,
3832 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3834 BOOLEAN OperandSize
, AddressSize
;
3835 FAST486_MOD_REG_RM ModRegRm
;
3837 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3839 /* Make sure this is the right instruction */
3840 ASSERT(Opcode
== 0x8C);
3842 TOGGLE_ADSIZE(AddressSize
);
3843 TOGGLE_OPSIZE(OperandSize
);
3845 /* Get the operands */
3846 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3848 /* Exception occurred */
3852 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3855 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3861 return Fast486WriteModrmDwordOperands(State
,
3864 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3868 return Fast486WriteModrmWordOperands(State
,
3871 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3875 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3877 FAST486_MOD_REG_RM ModRegRm
;
3878 BOOLEAN OperandSize
, AddressSize
;
3880 /* Make sure this is the right instruction */
3881 ASSERT(Opcode
== 0x8D);
3883 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3885 TOGGLE_ADSIZE(AddressSize
);
3886 TOGGLE_OPSIZE(OperandSize
);
3888 /* Get the operands */
3889 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3891 /* Exception occurred */
3895 /* The second operand must be memory */
3896 if (!ModRegRm
.Memory
)
3899 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3903 /* Write the address to the register */
3906 return Fast486WriteModrmDwordOperands(State
,
3909 ModRegRm
.MemoryAddress
);
3913 return Fast486WriteModrmWordOperands(State
,
3916 ModRegRm
.MemoryAddress
);
3921 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3923 BOOLEAN OperandSize
, AddressSize
;
3924 FAST486_MOD_REG_RM ModRegRm
;
3926 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3928 /* Make sure this is the right instruction */
3929 ASSERT(Opcode
== 0x8E);
3931 TOGGLE_ADSIZE(AddressSize
);
3932 TOGGLE_OPSIZE(OperandSize
);
3934 /* Get the operands */
3935 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3937 /* Exception occurred */
3941 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3942 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3945 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3951 ULONG Dummy
, Selector
;
3953 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
3955 /* Exception occurred */
3959 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
3963 USHORT Dummy
, Selector
;
3965 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
3967 /* Exception occurred */
3971 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
3975 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
3977 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3979 /* Make sure this is the right instruction */
3980 ASSERT(Opcode
== 0x98);
3982 TOGGLE_OPSIZE(Size
);
3987 /* Sign extend AX to EAX */
3988 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
3990 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
3991 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
3997 /* Sign extend AL to AX */
3998 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
3999 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4006 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4008 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4010 /* Make sure this is the right instruction */
4011 ASSERT(Opcode
== 0x99);
4013 TOGGLE_OPSIZE(Size
);
4018 /* Sign extend EAX to EDX:EAX */
4019 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4020 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4021 ? 0xFFFFFFFF : 0x00000000;
4025 /* Sign extend AX to DX:AX */
4026 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4027 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4034 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4038 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4040 /* Make sure this is the right instruction */
4041 ASSERT(Opcode
== 0x9A);
4043 TOGGLE_OPSIZE(Size
);
4046 /* Fetch the offset */
4049 if (!Fast486FetchDword(State
, &Offset
))
4051 /* Exception occurred */
4057 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4059 /* Exception occurred */
4064 /* Fetch the segment */
4065 if (!Fast486FetchWord(State
, &Segment
))
4067 /* Exception occurred */
4071 /* Push the current code segment selector */
4072 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4074 /* Exception occurred */
4078 /* Push the current value of the instruction pointer */
4079 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4081 /* Exception occurred */
4085 /* Load the new CS */
4086 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4088 /* Exception occurred */
4092 /* Load new (E)IP */
4093 if (Size
) State
->InstPtr
.Long
= Offset
;
4094 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4099 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4101 // TODO: NOT IMPLEMENTED
4107 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4109 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4112 TOGGLE_OPSIZE(Size
);
4114 /* Check for VM86 mode when IOPL is not 3 */
4115 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4117 /* Call the VM86 monitor */
4118 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4122 /* Push the flags */
4123 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4124 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4127 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4129 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4130 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4134 TOGGLE_OPSIZE(Size
);
4136 /* Pop the new flags */
4137 if (!Fast486StackPop(State
, &NewFlags
))
4139 /* Exception occurred */
4143 if (!State
->Flags
.Vm
)
4145 /* Check the current privilege level */
4153 /* Memorize the old state of RF */
4154 BOOLEAN OldRf
= State
->Flags
.Rf
;
4156 State
->Flags
.Long
= NewFlags
;
4158 /* Restore VM and RF */
4159 State
->Flags
.Vm
= FALSE
;
4160 State
->Flags
.Rf
= OldRf
;
4162 /* Clear VIF and VIP */
4163 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4165 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4167 /* Restore the reserved bits */
4168 State
->Flags
.AlwaysSet
= TRUE
;
4169 State
->Flags
.Reserved0
= FALSE
;
4170 State
->Flags
.Reserved1
= FALSE
;
4176 /* Memorize the old state of IF and IOPL */
4177 BOOLEAN OldIf
= State
->Flags
.If
;
4178 UINT OldIopl
= State
->Flags
.Iopl
;
4183 /* Memorize the old state of RF */
4184 BOOLEAN OldRf
= State
->Flags
.Rf
;
4186 State
->Flags
.Long
= NewFlags
;
4188 /* Restore VM and RF */
4189 State
->Flags
.Vm
= FALSE
;
4190 State
->Flags
.Rf
= OldRf
;
4192 /* Clear VIF and VIP */
4193 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4195 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4197 /* Restore the reserved bits and IOPL */
4198 State
->Flags
.AlwaysSet
= TRUE
;
4199 State
->Flags
.Reserved0
= FALSE
;
4200 State
->Flags
.Reserved1
= FALSE
;
4201 State
->Flags
.Iopl
= OldIopl
;
4203 /* Check if the user doesn't have the privilege to change IF */
4204 if (Cpl
> State
->Flags
.Iopl
)
4207 State
->Flags
.If
= OldIf
;
4213 /* Check the IOPL */
4214 if (State
->Flags
.Iopl
== 3)
4218 /* Memorize the old state of RF, VIF and VIP */
4219 BOOLEAN OldRf
= State
->Flags
.Rf
;
4220 BOOLEAN OldVif
= State
->Flags
.Vif
;
4221 BOOLEAN OldVip
= State
->Flags
.Vip
;
4223 State
->Flags
.Long
= NewFlags
;
4225 /* Restore VM, RF, VIF and VIP */
4226 State
->Flags
.Vm
= TRUE
;
4227 State
->Flags
.Rf
= OldRf
;
4228 State
->Flags
.Vif
= OldVif
;
4229 State
->Flags
.Vip
= OldVip
;
4231 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4233 /* Restore the reserved bits and IOPL */
4234 State
->Flags
.AlwaysSet
= TRUE
;
4235 State
->Flags
.Reserved0
= FALSE
;
4236 State
->Flags
.Reserved1
= FALSE
;
4237 State
->Flags
.Iopl
= 3;
4241 /* Call the VM86 monitor */
4242 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4250 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4252 /* Make sure this is the right instruction */
4253 ASSERT(Opcode
== 0x9E);
4255 /* Set the low-order byte of FLAGS to AH */
4256 State
->Flags
.Long
&= 0xFFFFFF00;
4257 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4259 /* Restore the reserved bits of FLAGS */
4260 State
->Flags
.AlwaysSet
= TRUE
;
4261 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4266 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4268 /* Make sure this is the right instruction */
4269 ASSERT(Opcode
== 0x9F);
4271 /* Set AH to the low-order byte of FLAGS */
4272 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4277 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4279 ULONG ReturnAddress
;
4280 USHORT BytesToPop
= 0;
4281 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4283 /* Make sure this is the right instruction */
4284 ASSERT((Opcode
& 0xFE) == 0xC2);
4287 TOGGLE_OPSIZE(Size
);
4291 /* Fetch the number of bytes to pop after the return */
4292 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4295 /* Pop the return address */
4296 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4298 /* Return to the calling procedure, and if necessary, pop the parameters */
4301 State
->InstPtr
.Long
= ReturnAddress
;
4302 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4306 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4307 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4313 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4315 UCHAR FarPointer
[6];
4316 BOOLEAN OperandSize
, AddressSize
;
4317 FAST486_MOD_REG_RM ModRegRm
;
4319 /* Make sure this is the right instruction */
4320 ASSERT((Opcode
& 0xFE) == 0xC4);
4322 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4324 TOGGLE_ADSIZE(AddressSize
);
4326 /* Get the operands */
4327 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4329 /* Exception occurred */
4333 if (!ModRegRm
.Memory
)
4335 /* Check if this is a BOP and the host supports BOPs */
4336 if ((Opcode
== 0xC4)
4337 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4338 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4339 && (State
->BopCallback
!= NULL
))
4343 /* Fetch the BOP code */
4344 if (!Fast486FetchWord(State
, &BopCode
))
4346 /* Exception occurred */
4350 /* Call the BOP handler */
4351 State
->BopCallback(State
, BopCode
);
4353 /* Return success */
4358 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4362 if (!Fast486ReadMemory(State
,
4363 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4364 ? State
->SegmentOverride
: FAST486_REG_DS
,
4365 ModRegRm
.MemoryAddress
,
4368 OperandSize
? 6 : 4))
4370 /* Exception occurred */
4376 ULONG Offset
= *((PULONG
)FarPointer
);
4377 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4379 /* Set the register to the offset */
4380 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4382 /* Load the segment */
4383 return Fast486LoadSegment(State
,
4385 ? FAST486_REG_ES
: FAST486_REG_DS
,
4390 USHORT Offset
= *((PUSHORT
)FarPointer
);
4391 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4393 /* Set the register to the offset */
4394 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4396 /* Load the segment */
4397 return Fast486LoadSegment(State
,
4399 ? FAST486_REG_ES
: FAST486_REG_DS
,
4404 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4407 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4410 FAST486_REG FramePointer
;
4412 /* Make sure this is the right instruction */
4413 ASSERT(Opcode
== 0xC8);
4416 TOGGLE_OPSIZE(Size
);
4418 if (!Fast486FetchWord(State
, &FrameSize
))
4420 /* Exception occurred */
4424 if (!Fast486FetchByte(State
, &NestingLevel
))
4426 /* Exception occurred */
4431 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4433 /* Exception occurred */
4438 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4440 /* Set up the nested procedure stacks */
4441 for (i
= 1; i
< NestingLevel
; i
++)
4445 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4446 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4450 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4451 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4455 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4457 /* Set EBP to the frame pointer */
4458 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4460 /* Reserve space for the frame */
4461 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4462 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4467 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4469 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4471 /* Make sure this is the right instruction */
4472 ASSERT(Opcode
== 0xC9);
4475 TOGGLE_OPSIZE(Size
);
4479 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4480 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4482 /* Pop the saved base pointer from the stack */
4483 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4489 /* Set the stack pointer (SP) to the base pointer (BP) */
4490 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4492 /* Pop the saved base pointer from the stack */
4493 if (Fast486StackPop(State
, &Value
))
4495 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4502 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4506 USHORT BytesToPop
= 0;
4507 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4509 /* Make sure this is the right instruction */
4510 ASSERT((Opcode
& 0xFE) == 0xCA);
4512 TOGGLE_OPSIZE(Size
);
4517 /* Fetch the number of bytes to pop after the return */
4518 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4521 /* Pop the offset */
4522 if (!Fast486StackPop(State
, &Offset
))
4524 /* Exception occurred */
4528 /* Pop the segment */
4529 if (!Fast486StackPop(State
, &Segment
))
4531 /* Exception occurred */
4535 /* Load the new CS */
4536 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4538 /* Exception occurred */
4542 /* Load new (E)IP, and if necessary, pop the parameters */
4545 State
->InstPtr
.Long
= Offset
;
4546 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4550 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4551 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4557 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4560 FAST486_IDT_ENTRY IdtEntry
;
4566 /* This is the INT3 instruction */
4573 /* Fetch the interrupt number */
4574 if (!Fast486FetchByte(State
, &IntNum
))
4576 /* Exception occurred */
4585 /* Don't do anything if OF is cleared */
4586 if (!State
->Flags
.Of
) return TRUE
;
4589 IntNum
= FAST486_EXCEPTION_OF
;
4596 /* Should not happen */
4601 /* Get the interrupt vector */
4602 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4604 /* Exception occurred */
4608 /* Perform the interrupt */
4609 if (!Fast486InterruptInternal(State
,
4611 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4614 /* Exception occurred */
4621 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4624 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4625 FAST486_FLAGS_REG NewFlags
;
4626 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4628 /* Make sure this is the right instruction */
4629 ASSERT(Opcode
== 0xCF);
4632 TOGGLE_OPSIZE(Size
);
4635 if (!Fast486StackPop(State
, &InstPtr
))
4637 /* Exception occurred */
4642 if (!Fast486StackPop(State
, &CodeSel
))
4644 /* Exception occurred */
4649 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4651 /* Exception occurred */
4655 /* Check for protected mode */
4656 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4658 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4660 if (State
->Flags
.Vm
)
4662 /* Return from VM86 mode */
4664 /* Check the IOPL */
4665 if (State
->Flags
.Iopl
== 3)
4668 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4671 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4673 /* Exception occurred */
4677 /* Set the new flags */
4678 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4679 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4680 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4681 State
->Flags
.Iopl
= 3;
4685 /* Call the VM86 monitor */
4686 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4693 if (State
->Flags
.Nt
)
4695 /* Nested task return */
4703 /* Return to VM86 mode */
4704 ULONG Es
, Ds
, Fs
, Gs
;
4706 /* Pop ESP, SS, ES, FS, GS */
4707 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4708 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4709 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4710 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4711 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4712 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4714 /* Set the new IP */
4715 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4717 /* Set the new flags */
4718 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4719 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4720 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4722 /* Load the new segments */
4723 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4724 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4725 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4726 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4727 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4728 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4733 /* Load the new CS */
4734 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4736 /* Exception occurred */
4741 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4742 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4744 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4747 if (!Fast486StackPop(State
, &StackPtr
))
4754 if (!Fast486StackPop(State
, &StackSel
))
4761 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4768 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4769 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4772 /* Set the new flags */
4773 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4774 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4775 State
->Flags
.AlwaysSet
= TRUE
;
4777 /* Set additional flags */
4778 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4779 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4781 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4783 /* Update the CPL */
4784 Cpl
= Fast486GetCurrentPrivLevel(State
);
4786 /* Check segment security */
4787 for (i
= 0; i
<= FAST486_NUM_SEG_REGS
; i
++)
4789 /* Don't check CS or SS */
4790 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4792 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4793 && (!State
->SegmentRegs
[i
].Executable
4794 || !State
->SegmentRegs
[i
].DirConf
))
4796 /* Load the NULL descriptor in the segment */
4797 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4804 if (Size
&& (InstPtr
& 0xFFFF0000))
4807 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4812 State
->InstPtr
.Long
= InstPtr
;
4815 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4817 /* Exception occurred */
4821 /* Set the new flags */
4822 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4823 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4824 State
->Flags
.AlwaysSet
= TRUE
;
4830 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4833 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4837 /* Fetch the base */
4838 if (!Fast486FetchByte(State
, &Base
))
4840 /* Exception occurred */
4844 /* Check if the base is zero */
4848 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4853 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4854 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4857 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
4858 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
4859 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4864 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4867 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4871 /* Fetch the base */
4872 if (!Fast486FetchByte(State
, &Base
))
4874 /* Exception occurred */
4879 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4880 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4883 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
4884 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
4885 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4890 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4893 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4895 TOGGLE_ADSIZE(AddressSize
);
4897 /* Read a byte from DS:[(E)BX + AL] */
4898 if (!Fast486ReadMemory(State
,
4900 AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4901 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
4902 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4907 /* Exception occurred */
4911 /* Set AL to the result */
4912 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4914 /* Return success */
4918 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4921 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4924 /* Make sure this is the right instruction */
4925 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4928 TOGGLE_OPSIZE(Size
);
4930 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4931 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4935 /* Additional rule for LOOPNZ */
4936 if (State
->Flags
.Zf
) Condition
= FALSE
;
4941 /* Additional rule for LOOPZ */
4942 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4945 /* Fetch the offset */
4946 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4948 /* An exception occurred */
4954 /* Move the instruction pointer */
4955 State
->InstPtr
.Long
+= Offset
;
4961 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
4964 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4967 /* Make sure this is the right instruction */
4968 ASSERT(Opcode
== 0xE3);
4971 TOGGLE_OPSIZE(Size
);
4973 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
4974 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
4976 /* Fetch the offset */
4977 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4979 /* An exception occurred */
4985 /* Move the instruction pointer */
4986 State
->InstPtr
.Long
+= Offset
;
4992 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
4994 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4996 /* Make sure this is the right instruction */
4997 ASSERT(Opcode
== 0xE8);
4999 TOGGLE_OPSIZE(Size
);
5006 /* Fetch the offset */
5007 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5009 /* An exception occurred */
5013 /* Push the current value of the instruction pointer */
5014 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5016 /* Exception occurred */
5020 /* Move the instruction pointer */
5021 State
->InstPtr
.Long
+= Offset
;
5027 /* Fetch the offset */
5028 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5030 /* An exception occurred */
5034 /* Push the current value of the instruction pointer */
5035 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5037 /* Exception occurred */
5041 /* Move the instruction pointer */
5042 State
->InstPtr
.LowWord
+= Offset
;
5048 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5050 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5052 /* Make sure this is the right instruction */
5053 ASSERT(Opcode
== 0xE9);
5055 TOGGLE_OPSIZE(Size
);
5062 /* Fetch the offset */
5063 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5065 /* An exception occurred */
5069 /* Move the instruction pointer */
5070 State
->InstPtr
.Long
+= Offset
;
5076 /* Fetch the offset */
5077 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5079 /* An exception occurred */
5083 /* Move the instruction pointer */
5084 State
->InstPtr
.LowWord
+= Offset
;
5090 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5094 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5096 /* Make sure this is the right instruction */
5097 ASSERT(Opcode
== 0xEA);
5099 TOGGLE_OPSIZE(Size
);
5102 /* Fetch the offset */
5105 if (!Fast486FetchDword(State
, &Offset
))
5107 /* Exception occurred */
5113 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5115 /* Exception occurred */
5120 /* Fetch the segment */
5121 if (!Fast486FetchWord(State
, &Segment
))
5123 /* Exception occurred */
5127 /* Load the new CS */
5128 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5130 /* Exception occurred */
5134 /* Load new (E)IP */
5135 if (Size
) State
->InstPtr
.Long
= Offset
;
5136 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
5141 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5143 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5146 /* Make sure this is the right instruction */
5147 ASSERT(Opcode
== 0xA0);
5149 TOGGLE_OPSIZE(Size
);
5153 if (!Fast486FetchDword(State
, &Offset
))
5155 /* Exception occurred */
5163 if (!Fast486FetchWord(State
, &WordOffset
))
5165 /* Exception occurred */
5169 Offset
= (ULONG
)WordOffset
;
5172 /* Read from memory */
5173 return Fast486ReadMemory(State
,
5174 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5175 State
->SegmentOverride
: FAST486_REG_DS
,
5178 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5182 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5184 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5186 /* Make sure this is the right instruction */
5187 ASSERT(Opcode
== 0xA1);
5189 TOGGLE_OPSIZE(Size
);
5195 if (!Fast486FetchDword(State
, &Offset
))
5197 /* Exception occurred */
5201 /* Read from memory */
5202 return Fast486ReadMemory(State
,
5203 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5204 State
->SegmentOverride
: FAST486_REG_DS
,
5207 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5214 if (!Fast486FetchWord(State
, &Offset
))
5216 /* Exception occurred */
5220 /* Read from memory */
5221 return Fast486ReadMemory(State
,
5222 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5223 State
->SegmentOverride
: FAST486_REG_DS
,
5226 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5231 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5233 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5236 /* Make sure this is the right instruction */
5237 ASSERT(Opcode
== 0xA2);
5239 TOGGLE_OPSIZE(Size
);
5243 if (!Fast486FetchDword(State
, &Offset
))
5245 /* Exception occurred */
5253 if (!Fast486FetchWord(State
, &WordOffset
))
5255 /* Exception occurred */
5259 Offset
= (ULONG
)WordOffset
;
5262 /* Write to memory */
5263 return Fast486WriteMemory(State
,
5264 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5265 State
->SegmentOverride
: FAST486_REG_DS
,
5267 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5271 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5273 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5275 /* Make sure this is the right instruction */
5276 ASSERT(Opcode
== 0xA3);
5278 TOGGLE_OPSIZE(Size
);
5284 if (!Fast486FetchDword(State
, &Offset
))
5286 /* Exception occurred */
5290 /* Write to memory */
5291 return Fast486WriteMemory(State
,
5292 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5293 State
->SegmentOverride
: FAST486_REG_DS
,
5295 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5302 if (!Fast486FetchWord(State
, &Offset
))
5304 /* Exception occurred */
5308 /* Write to memory */
5309 return Fast486WriteMemory(State
,
5310 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5311 State
->SegmentOverride
: FAST486_REG_DS
,
5313 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5318 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5320 /* Make sure this is the right instruction */
5321 ASSERT(Opcode
== 0xD6);
5325 /* Set all the bits of AL to CF */
5326 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5331 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5333 ULONG Data
, DataSize
;
5334 BOOLEAN OperandSize
, AddressSize
;
5335 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5337 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5339 /* Make sure this is the right instruction */
5340 ASSERT((Opcode
& 0xFE) == 0xA4);
5342 TOGGLE_OPSIZE(OperandSize
);
5343 TOGGLE_ADSIZE(AddressSize
);
5345 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5347 /* Use the override segment instead of DS */
5348 Segment
= State
->SegmentOverride
;
5351 /* Calculate the size */
5352 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5353 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5355 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5357 UCHAR Block
[STRING_BLOCK_SIZE
];
5358 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5359 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5361 /* Clear the memory block */
5362 RtlZeroMemory(Block
, sizeof(Block
));
5364 /* Transfer until finished */
5367 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5369 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5372 ULONG MaxBytesSrc
= State
->Flags
.Df
5373 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
5374 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
5375 ULONG MaxBytesDest
= State
->Flags
.Df
5376 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5377 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5380 Processed
= min(Processed
, min(MaxBytesSrc
, MaxBytesDest
) / DataSize
);
5381 if (Processed
== 0) Processed
= 1;
5384 if (State
->Flags
.Df
)
5386 /* Reduce ESI and EDI by the number of bytes to transfer */
5389 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
5390 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5394 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
5395 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5399 /* Read from memory */
5400 if (!Fast486ReadMemory(State
,
5402 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5403 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5406 Processed
* DataSize
))
5409 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5410 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5412 /* Exception occurred */
5416 /* Write to memory */
5417 if (!Fast486WriteMemory(State
,
5419 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5420 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5422 Processed
* DataSize
))
5425 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5426 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5428 /* Exception occurred */
5432 if (!State
->Flags
.Df
)
5434 /* Increase ESI and EDI by the number of bytes transfered */
5437 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
5438 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5442 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
5443 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5447 /* Reduce the total count by the number processed in this run */
5452 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5453 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5457 /* Read from the source operand */
5458 if (!Fast486ReadMemory(State
,
5460 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5461 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5466 /* Exception occurred */
5470 /* Write to the destination operand */
5471 if (!Fast486WriteMemory(State
,
5473 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5474 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5478 /* Exception occurred */
5482 /* Increment/decrement ESI and EDI */
5485 if (!State
->Flags
.Df
)
5487 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5488 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5492 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5493 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5498 if (!State
->Flags
.Df
)
5500 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5501 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5505 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5506 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5511 /* Return success */
5515 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5517 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5518 ULONG DataSize
, DataMask
, SignFlag
;
5519 BOOLEAN OperandSize
, AddressSize
;
5520 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5522 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5524 /* Make sure this is the right instruction */
5525 ASSERT((Opcode
& 0xFE) == 0xA6);
5527 TOGGLE_OPSIZE(OperandSize
);
5528 TOGGLE_ADSIZE(AddressSize
);
5530 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5532 /* Use the override segment instead of DS */
5533 Segment
= State
->SegmentOverride
;
5536 /* Calculate the size */
5537 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5538 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5540 /* Calculate the mask and sign flag */
5541 DataMask
= (1 << (DataSize
* 8)) - 1;
5542 SignFlag
= 1 << ((DataSize
* 8) - 1);
5544 /* Read from the first source operand */
5545 if (!Fast486ReadMemory(State
,
5547 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5548 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5553 /* Exception occurred */
5557 /* Read from the second source operand */
5558 if (!Fast486ReadMemory(State
,
5560 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5561 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5566 /* Exception occurred */
5570 /* Calculate the result */
5571 FirstValue
&= DataMask
;
5572 SecondValue
&= DataMask
;
5573 Result
= (FirstValue
- SecondValue
) & DataMask
;
5575 /* Update the flags */
5576 State
->Flags
.Cf
= FirstValue
< SecondValue
;
5577 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5578 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5579 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5580 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
5581 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
5582 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5584 /* Increment/decrement ESI and EDI */
5587 if (!State
->Flags
.Df
)
5589 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5590 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5594 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5595 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5600 if (!State
->Flags
.Df
)
5602 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5603 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5607 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5608 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5612 // FIXME: This method is slow!
5613 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5614 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5616 BOOLEAN Repeat
= TRUE
;
5620 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5628 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5635 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5636 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5638 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5644 /* Repeat the instruction */
5645 State
->InstPtr
= State
->SavedInstPtr
;
5649 /* Return success */
5653 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5656 BOOLEAN OperandSize
, AddressSize
;
5658 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5660 /* Make sure this is the right instruction */
5661 ASSERT((Opcode
& 0xFE) == 0xAA);
5663 TOGGLE_OPSIZE(OperandSize
);
5664 TOGGLE_ADSIZE(AddressSize
);
5666 /* Calculate the size */
5667 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5668 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5670 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5672 UCHAR Block
[STRING_BLOCK_SIZE
];
5673 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5674 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5676 /* Fill the memory block with the data */
5677 if (DataSize
== sizeof(UCHAR
))
5679 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5685 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5687 if (DataSize
== sizeof(USHORT
))
5689 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5693 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5698 /* Transfer until finished */
5701 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5703 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5706 ULONG MaxBytes
= State
->Flags
.Df
5707 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5708 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5710 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5711 if (Processed
== 0) Processed
= 1;
5714 if (State
->Flags
.Df
)
5716 /* Reduce EDI by the number of bytes to transfer */
5717 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5718 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5721 /* Write to memory */
5722 if (!Fast486WriteMemory(State
,
5724 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5725 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5727 Processed
* DataSize
))
5730 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5731 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5733 /* Exception occurred */
5737 if (!State
->Flags
.Df
)
5739 /* Increase EDI by the number of bytes transfered */
5740 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5741 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5744 /* Reduce the total count by the number processed in this run */
5749 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5750 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5754 /* Write to the destination operand */
5755 if (!Fast486WriteMemory(State
,
5757 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5758 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5759 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5762 /* Exception occurred */
5766 /* Increment/decrement EDI */
5769 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5770 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5774 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5775 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5779 /* Return success */
5783 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5786 BOOLEAN OperandSize
, AddressSize
;
5787 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5789 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5791 /* Make sure this is the right instruction */
5792 ASSERT((Opcode
& 0xFE) == 0xAC);
5794 TOGGLE_OPSIZE(OperandSize
);
5795 TOGGLE_ADSIZE(AddressSize
);
5797 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5799 /* Use the override segment instead of DS */
5800 Segment
= State
->SegmentOverride
;
5803 /* Calculate the size */
5804 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5805 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5807 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5809 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5810 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5812 /* If the count is 0, do nothing */
5813 if (Count
== 0) return TRUE
;
5815 /* Only the last entry will be loaded */
5816 if (!State
->Flags
.Df
)
5818 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5819 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5823 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5824 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5828 /* Read from the source operand */
5829 if (!Fast486ReadMemory(State
,
5831 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5832 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5834 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5837 /* Exception occurred */
5841 /* Increment/decrement ESI */
5844 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5845 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5849 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5850 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5853 /* Return success */
5857 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5859 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5860 ULONG SecondValue
= 0;
5862 ULONG DataSize
, DataMask
, SignFlag
;
5863 BOOLEAN OperandSize
, AddressSize
;
5865 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5867 /* Make sure this is the right instruction */
5868 ASSERT((Opcode
& 0xFE) == 0xAE);
5870 TOGGLE_OPSIZE(OperandSize
);
5871 TOGGLE_ADSIZE(AddressSize
);
5873 /* Calculate the size */
5874 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5875 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5877 /* Calculate the mask and sign flag */
5878 DataMask
= (1 << (DataSize
* 8)) - 1;
5879 SignFlag
= 1 << ((DataSize
* 8) - 1);
5881 /* Read from the source operand */
5882 if (!Fast486ReadMemory(State
,
5884 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5885 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5890 /* Exception occurred */
5894 /* Calculate the result */
5895 FirstValue
&= DataMask
;
5896 SecondValue
&= DataMask
;
5897 Result
= (FirstValue
- SecondValue
) & DataMask
;
5899 /* Update the flags */
5900 State
->Flags
.Cf
= FirstValue
< SecondValue
;
5901 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5902 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5903 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5904 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
5905 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
5906 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5908 /* Increment/decrement EDI */
5911 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5912 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5916 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5917 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5920 // FIXME: This method is slow!
5921 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5922 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5924 BOOLEAN Repeat
= TRUE
;
5928 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5936 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5943 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5944 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5946 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5952 /* Repeat the instruction */
5953 State
->InstPtr
= State
->SavedInstPtr
;
5957 /* Return success */
5961 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
5964 BOOLEAN OperandSize
, AddressSize
;
5966 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5968 /* Make sure this is the right instruction */
5969 ASSERT((Opcode
& 0xFE) == 0x6C);
5971 TOGGLE_OPSIZE(OperandSize
);
5972 TOGGLE_ADSIZE(AddressSize
);
5974 /* Calculate the size */
5975 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
5976 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5978 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5980 UCHAR Block
[STRING_BLOCK_SIZE
];
5981 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5982 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5984 /* Clear the memory block */
5985 RtlZeroMemory(Block
, sizeof(Block
));
5987 /* Transfer until finished */
5990 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5992 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5995 ULONG MaxBytes
= State
->Flags
.Df
5996 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5997 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5999 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6000 if (Processed
== 0) Processed
= 1;
6003 /* Read from the I/O port */
6004 State
->IoReadCallback(State
,
6005 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6007 Processed
* DataSize
);
6009 if (State
->Flags
.Df
)
6013 /* Reduce EDI by the number of bytes to transfer */
6014 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6015 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6017 /* Reverse the block data */
6018 for (i
= 0; i
< Processed
/ 2; i
++)
6020 /* Swap the values */
6021 for (j
= 0; j
< DataSize
; j
++)
6023 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6024 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6025 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6030 /* Write to memory */
6031 if (!Fast486WriteMemory(State
,
6033 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6034 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6036 Processed
* DataSize
))
6039 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6040 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6042 /* Exception occurred */
6046 if (!State
->Flags
.Df
)
6048 /* Increase EDI by the number of bytes transfered */
6049 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6050 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6053 /* Reduce the total count by the number processed in this run */
6058 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6059 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6065 /* Read from the I/O port */
6066 State
->IoReadCallback(State
,
6067 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6071 /* Write to the destination operand */
6072 if (!Fast486WriteMemory(State
,
6074 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6075 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6079 /* Exception occurred */
6083 /* Increment/decrement EDI */
6086 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6087 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6091 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6092 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6096 /* Return success */
6100 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6103 BOOLEAN OperandSize
, AddressSize
;
6105 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6107 /* Make sure this is the right instruction */
6108 ASSERT((Opcode
& 0xFE) == 0x6E);
6110 TOGGLE_OPSIZE(OperandSize
);
6111 TOGGLE_ADSIZE(AddressSize
);
6113 /* Calculate the size */
6114 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6115 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6117 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6119 UCHAR Block
[STRING_BLOCK_SIZE
];
6120 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6121 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6123 /* Clear the memory block */
6124 RtlZeroMemory(Block
, sizeof(Block
));
6126 /* Transfer until finished */
6129 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6131 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6134 ULONG MaxBytes
= State
->Flags
.Df
6135 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6136 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6138 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6139 if (Processed
== 0) Processed
= 1;
6142 /* Read from memory */
6143 if (!Fast486ReadMemory(State
,
6145 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6146 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6149 Processed
* DataSize
))
6152 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6153 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6155 /* Exception occurred */
6159 if (State
->Flags
.Df
)
6163 /* Reduce EDI by the number of bytes to transfer */
6164 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6165 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6167 /* Reverse the block data */
6168 for (i
= 0; i
< Processed
/ 2; i
++)
6170 /* Swap the values */
6171 for (j
= 0; j
< DataSize
; j
++)
6173 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6174 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6175 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6180 /* Write to the I/O port */
6181 State
->IoWriteCallback(State
,
6182 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6184 Processed
* DataSize
);
6186 if (!State
->Flags
.Df
)
6188 /* Increase EDI by the number of bytes transfered */
6189 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6190 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6193 /* Reduce the total count by the number processed in this run */
6198 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6199 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6205 /* Read from the source operand */
6206 if (!Fast486ReadMemory(State
,
6208 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6209 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6214 /* Exception occurred */
6218 /* Write to the I/O port */
6219 State
->IoWriteCallback(State
,
6220 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6224 /* Increment/decrement ESI */
6227 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6228 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6232 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6233 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6237 /* Return success */