2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /* INCLUDES *******************************************************************/
36 /* PUBLIC VARIABLES ***********************************************************/
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
41 Fast486OpcodeAddByteModrm
, /* 0x00 - 0x03 */
42 Fast486OpcodeAddModrm
,
43 Fast486OpcodeAddByteModrm
,
44 Fast486OpcodeAddModrm
,
45 Fast486OpcodeAddAl
, /* 0x04 */
46 Fast486OpcodeAddEax
, /* 0x05 */
47 Fast486OpcodePushEs
, /* 0x06 */
48 Fast486OpcodePopEs
, /* 0x07 */
49 Fast486OpcodeOrByteModrm
, /* 0x08 - 0x0B */
51 Fast486OpcodeOrByteModrm
,
53 Fast486OpcodeOrAl
, /* 0x0C */
54 Fast486OpcodeOrEax
, /* 0x0D */
55 Fast486OpcodePushCs
, /* 0x0E */
56 Fast486OpcodeExtended
, /* 0x0F */
57 Fast486OpcodeAdcByteModrm
, /* 0x10 - 0x13 */
58 Fast486OpcodeAdcModrm
,
59 Fast486OpcodeAdcByteModrm
,
60 Fast486OpcodeAdcModrm
,
61 Fast486OpcodeAdcAl
, /* 0x14 */
62 Fast486OpcodeAdcEax
, /* 0x15 */
63 Fast486OpcodePushSs
, /* 0x16 */
64 Fast486OpcodePopSs
, /* 0x17 */
65 Fast486OpcodeSbbByteModrm
, /* 0x18 - 0x1B */
66 Fast486OpcodeSbbModrm
,
67 Fast486OpcodeSbbByteModrm
,
68 Fast486OpcodeSbbModrm
,
69 Fast486OpcodeSbbAl
, /* 0x1C */
70 Fast486OpcodeSbbEax
, /* 0x1D */
71 Fast486OpcodePushDs
, /* 0x1E */
72 Fast486OpcodePopDs
, /* 0x1F */
73 Fast486OpcodeAndByteModrm
, /* 0x20 - 0x23 */
74 Fast486OpcodeAndModrm
,
75 Fast486OpcodeAndByteModrm
,
76 Fast486OpcodeAndModrm
,
77 Fast486OpcodeAndAl
, /* 0x24 */
78 Fast486OpcodeAndEax
, /* 0x25 */
79 Fast486OpcodePrefix
, /* 0x26 */
80 Fast486OpcodeDaa
, /* 0x27 */
81 Fast486OpcodeCmpSubByteModrm
, /* 0x28 - 0x2B */
82 Fast486OpcodeCmpSubModrm
,
83 Fast486OpcodeCmpSubByteModrm
,
84 Fast486OpcodeCmpSubModrm
,
85 Fast486OpcodeCmpSubAl
, /* 0x2C */
86 Fast486OpcodeCmpSubEax
, /* 0x2D */
87 Fast486OpcodePrefix
, /* 0x2E */
88 Fast486OpcodeDas
, /* 0x2F */
89 Fast486OpcodeXorByteModrm
, /* 0x30 - 0x33 */
90 Fast486OpcodeXorModrm
,
91 Fast486OpcodeXorByteModrm
,
92 Fast486OpcodeXorModrm
,
93 Fast486OpcodeXorAl
, /* 0x34 */
94 Fast486OpcodeXorEax
, /* 0x35 */
95 Fast486OpcodePrefix
, /* 0x36 */
96 Fast486OpcodeAaa
, /* 0x37 */
97 Fast486OpcodeCmpSubByteModrm
, /* 0x38 - 0x3B */
98 Fast486OpcodeCmpSubModrm
,
99 Fast486OpcodeCmpSubByteModrm
,
100 Fast486OpcodeCmpSubModrm
,
101 Fast486OpcodeCmpSubAl
, /* 0x3C */
102 Fast486OpcodeCmpSubEax
, /* 0x3D */
103 Fast486OpcodePrefix
, /* 0x3E */
104 Fast486OpcodeAas
, /* 0x3F */
105 Fast486OpcodeIncrement
, /* 0x40 - 0x47 */
106 Fast486OpcodeIncrement
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeIncrement
,
113 Fast486OpcodeDecrement
, /* 0x48 - 0x4F */
114 Fast486OpcodeDecrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodeDecrement
,
121 Fast486OpcodePushReg
, /* 0x50 - 0x57 */
122 Fast486OpcodePushReg
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
128 Fast486OpcodePushReg
,
129 Fast486OpcodePopReg
, /* 0x58 - 0x5F */
137 Fast486OpcodePushAll
, /* 0x60 */
138 Fast486OpcodePopAll
, /* 0x61 */
139 Fast486OpcodeBound
, /* 0x62 */
140 Fast486OpcodeArpl
, /* 0x63 */
141 Fast486OpcodePrefix
, /* 0x64 - 0x67 */
145 Fast486OpcodePushImm
, /* 0x68 */
146 Fast486OpcodeImulModrmImm
, /* 0x69 */
147 Fast486OpcodePushByteImm
, /* 0x6A */
148 Fast486OpcodeImulModrmImm
, /* 0x6B */
149 Fast486OpcodeIns
, /* 0x6C */
150 Fast486OpcodeIns
, /* 0x6D */
151 Fast486OpcodeOuts
, /* 0x6E */
152 Fast486OpcodeOuts
, /* 0x6F */
153 Fast486OpcodeShortConditionalJmp
, /* 0x70 - 0x7F */
154 Fast486OpcodeShortConditionalJmp
,
155 Fast486OpcodeShortConditionalJmp
,
156 Fast486OpcodeShortConditionalJmp
,
157 Fast486OpcodeShortConditionalJmp
,
158 Fast486OpcodeShortConditionalJmp
,
159 Fast486OpcodeShortConditionalJmp
,
160 Fast486OpcodeShortConditionalJmp
,
161 Fast486OpcodeShortConditionalJmp
,
162 Fast486OpcodeShortConditionalJmp
,
163 Fast486OpcodeShortConditionalJmp
,
164 Fast486OpcodeShortConditionalJmp
,
165 Fast486OpcodeShortConditionalJmp
,
166 Fast486OpcodeShortConditionalJmp
,
167 Fast486OpcodeShortConditionalJmp
,
168 Fast486OpcodeShortConditionalJmp
,
169 Fast486OpcodeGroup8082
, /* 0x80 */
170 Fast486OpcodeGroup81
, /* 0x81 */
171 Fast486OpcodeGroup8082
, /* 0x82 */
172 Fast486OpcodeGroup83
, /* 0x83 */
173 Fast486OpcodeTestByteModrm
, /* 0x84 */
174 Fast486OpcodeTestModrm
, /* 0x85 */
175 Fast486OpcodeXchgByteModrm
, /* 0x86 */
176 Fast486OpcodeXchgModrm
, /* 0x87 */
177 Fast486OpcodeMovByteModrm
, /* 0x88 */
178 Fast486OpcodeMovModrm
, /* 0x89 */
179 Fast486OpcodeMovByteModrm
, /* 0x8A */
180 Fast486OpcodeMovModrm
, /* 0x8B */
181 Fast486OpcodeMovStoreSeg
, /* 0x8C */
182 Fast486OpcodeLea
, /* 0x8D */
183 Fast486OpcodeMovLoadSeg
, /* 0x8E */
184 Fast486OpcodeGroup8F
, /* 0x8F */
185 Fast486OpcodeNop
, /* 0x90 */
186 Fast486OpcodeExchangeEax
, /* 0x91 - 0x97 */
187 Fast486OpcodeExchangeEax
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
192 Fast486OpcodeExchangeEax
,
193 Fast486OpcodeCwde
, /* 0x98 */
194 Fast486OpcodeCdq
, /* 0x99 */
195 Fast486OpcodeCallAbs
, /* 0x9A */
196 Fast486OpcodeWait
, /* 0x9B */
197 Fast486OpcodePushFlags
, /* 0x9C */
198 Fast486OpcodePopFlags
, /* 0x9D */
199 Fast486OpcodeSahf
, /* 0x9E */
200 Fast486OpcodeLahf
, /* 0x9F */
201 Fast486OpcodeMovAlOffset
, /* 0xA0 */
202 Fast486OpcodeMovEaxOffset
, /* 0xA1 */
203 Fast486OpcodeMovOffsetAl
, /* 0xA2 */
204 Fast486OpcodeMovOffsetEax
, /* 0xA3 */
205 Fast486OpcodeMovs
, /* 0xA4 */
206 Fast486OpcodeMovs
, /* 0xA5 */
207 Fast486OpcodeCmps
, /* 0xA6 */
208 Fast486OpcodeCmps
, /* 0xA7 */
209 Fast486OpcodeTestAl
, /* 0xA8 */
210 Fast486OpcodeTestEax
, /* 0xA9 */
211 Fast486OpcodeStos
, /* 0xAA */
212 Fast486OpcodeStos
, /* 0xAB */
213 Fast486OpcodeLods
, /* 0xAC */
214 Fast486OpcodeLods
, /* 0xAD */
215 Fast486OpcodeScas
, /* 0xAE */
216 Fast486OpcodeScas
, /* 0xAF */
217 Fast486OpcodeMovByteRegImm
, /* 0xB0 - 0xB7 */
218 Fast486OpcodeMovByteRegImm
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovByteRegImm
,
225 Fast486OpcodeMovRegImm
, /* 0xB8 - 0xBF */
226 Fast486OpcodeMovRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeMovRegImm
,
233 Fast486OpcodeGroupC0
, /* 0xC0 */
234 Fast486OpcodeGroupC1
, /* 0xC1 */
235 Fast486OpcodeRet
, /* 0xC2 */
236 Fast486OpcodeRet
, /* 0xC3 */
237 Fast486OpcodeLdsLes
, /* 0xC4 */
238 Fast486OpcodeLdsLes
, /* 0xC5 */
239 Fast486OpcodeGroupC6
, /* 0xC6 */
240 Fast486OpcodeGroupC7
, /* 0xC7 */
241 Fast486OpcodeEnter
, /* 0xC8 */
242 Fast486OpcodeLeave
, /* 0xC9 */
243 Fast486OpcodeRetFar
, /* 0xCA */
244 Fast486OpcodeRetFar
, /* 0xCB */
245 Fast486OpcodeInt
, /* 0xCC */
246 Fast486OpcodeInt
, /* 0xCD */
247 Fast486OpcodeInt
, /* 0xCE */
248 Fast486OpcodeIret
, /* 0xCF */
249 Fast486OpcodeGroupD0
, /* 0xD0 - 0xD3 */
250 Fast486OpcodeGroupD1
,
251 Fast486OpcodeGroupD2
,
252 Fast486OpcodeGroupD3
,
253 Fast486OpcodeAam
, /* 0xD4 */
254 Fast486OpcodeAad
, /* 0xD5 */
255 Fast486OpcodeSalc
, /* 0xD6 */
256 Fast486OpcodeXlat
, /* 0xD7 */
257 Fast486FpuOpcodeD8DC
, /* 0xD8 - 0xDF */
261 Fast486FpuOpcodeD8DC
,
265 Fast486OpcodeLoop
, /* 0xE0 - 0xE2 */
268 Fast486OpcodeJecxz
, /* 0xE3 */
269 Fast486OpcodeInByte
, /* 0xE4 */
270 Fast486OpcodeIn
, /* 0xE5 */
271 Fast486OpcodeOutByte
, /* 0xE6 */
272 Fast486OpcodeOut
, /* 0xE7 */
273 Fast486OpcodeCall
, /* 0xE8 */
274 Fast486OpcodeJmp
, /* 0xE9 */
275 Fast486OpcodeJmpAbs
, /* 0xEA */
276 Fast486OpcodeShortJump
, /* 0xEB */
277 Fast486OpcodeInByte
, /* 0xEC */
278 Fast486OpcodeIn
, /* 0xED */
279 Fast486OpcodeOutByte
, /* 0xEE */
280 Fast486OpcodeOut
, /* 0xEF */
281 Fast486OpcodePrefix
, /* 0xF0 */
282 Fast486OpcodeInvalid
, /* 0xF1 */ // Invalid opcode -- ICEBP/INT01 opcode
283 Fast486OpcodePrefix
, /* 0xF2 */
284 Fast486OpcodePrefix
, /* 0xF3 */
285 Fast486OpcodeHalt
, /* 0xF4 */
286 Fast486OpcodeComplCarry
, /* 0xF5 */
287 Fast486OpcodeGroupF6
, /* 0xF6 */
288 Fast486OpcodeGroupF7
, /* 0xF7 */
289 Fast486OpcodeClearCarry
, /* 0xF8 */
290 Fast486OpcodeSetCarry
, /* 0xF9 */
291 Fast486OpcodeClearInt
, /* 0xFA */
292 Fast486OpcodeSetInt
, /* 0xFB */
293 Fast486OpcodeClearDir
, /* 0xFC */
294 Fast486OpcodeSetDir
, /* 0xFD */
295 Fast486OpcodeGroupFE
, /* 0xFE */
296 Fast486OpcodeGroupFF
, /* 0xFF */
299 /* PUBLIC FUNCTIONS ***********************************************************/
301 FAST486_OPCODE_HANDLER(Fast486OpcodeInvalid
)
304 * This is not a valid opcode.
305 * Well, not totally: see http://www.rcollins.org/secrets/opcodes/ICEBP.html
308 DPRINT1("FAST486 -- Calling ICEBP opcode\n");
309 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
313 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
315 BOOLEAN Valid
= FALSE
;
322 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
324 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
325 State
->SegmentOverride
= FAST486_REG_ES
;
335 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
337 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
338 State
->SegmentOverride
= FAST486_REG_CS
;
348 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
350 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
351 State
->SegmentOverride
= FAST486_REG_SS
;
361 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
363 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
364 State
->SegmentOverride
= FAST486_REG_DS
;
374 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
376 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
377 State
->SegmentOverride
= FAST486_REG_FS
;
387 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
389 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
390 State
->SegmentOverride
= FAST486_REG_GS
;
400 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
402 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
412 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
414 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
423 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
425 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
435 /* Mutually exclusive with REP */
436 if (!(State
->PrefixFlags
437 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
439 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
449 /* Mutually exclusive with REPNZ */
450 if (!(State
->PrefixFlags
451 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
453 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
463 /* Clear all prefixes */
464 State
->PrefixFlags
= 0;
466 /* Throw an exception */
467 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
474 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
477 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
482 /* Make sure this is the right instruction */
483 ASSERT((Opcode
& 0xF8) == 0x40);
487 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
489 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
490 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
494 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
496 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
497 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
500 State
->Flags
.Zf
= (Value
== 0);
501 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
502 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
508 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
511 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
516 /* Make sure this is the right instruction */
517 ASSERT((Opcode
& 0xF8) == 0x48);
521 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
523 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
524 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
528 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
530 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
531 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
534 State
->Flags
.Zf
= (Value
== 0);
535 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
536 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
542 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
546 /* Make sure this is the right instruction */
547 ASSERT((Opcode
& 0xF8) == 0x50);
549 /* Call the internal function */
550 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
553 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
556 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
561 /* Make sure this is the right instruction */
562 ASSERT((Opcode
& 0xF8) == 0x58);
564 /* Call the internal function */
565 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
567 /* Store the value */
568 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
569 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
575 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
580 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
582 INT Reg
= Opcode
& 0x07;
583 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
588 /* Make sure this is the right instruction */
589 ASSERT((Opcode
& 0xF8) == 0x90);
591 /* Exchange the values */
596 Value
= State
->GeneralRegs
[Reg
].Long
;
597 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
598 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
604 Value
= State
->GeneralRegs
[Reg
].LowWord
;
605 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
606 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
612 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
614 BOOLEAN Jump
= FALSE
;
616 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
618 /* Make sure this is the right instruction */
619 ASSERT((Opcode
& 0xF0) == 0x70);
623 /* Fetch the offset */
624 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
626 /* An exception occurred */
630 switch ((Opcode
& 0x0F) >> 1)
635 Jump
= State
->Flags
.Of
;
642 Jump
= State
->Flags
.Cf
;
649 Jump
= State
->Flags
.Zf
;
656 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
663 Jump
= State
->Flags
.Sf
;
670 Jump
= State
->Flags
.Pf
;
677 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
684 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
691 /* Invert the result */
697 /* Move the instruction pointer */
698 State
->InstPtr
.Long
+= Offset
;
702 /* Clear the top half of EIP */
703 State
->InstPtr
.Long
&= 0xFFFF;
711 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
713 /* Make sure this is the right instruction */
714 ASSERT(Opcode
== 0xF8);
716 /* No prefixes allowed */
717 if (State
->PrefixFlags
)
719 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
723 /* Clear CF and return success */
724 State
->Flags
.Cf
= FALSE
;
728 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
730 /* Make sure this is the right instruction */
731 ASSERT(Opcode
== 0xF9);
733 /* No prefixes allowed */
734 if (State
->PrefixFlags
)
736 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
740 /* Set CF and return success*/
741 State
->Flags
.Cf
= TRUE
;
745 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
747 /* Make sure this is the right instruction */
748 ASSERT(Opcode
== 0xF5);
750 /* No prefixes allowed */
751 if (State
->PrefixFlags
)
753 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
757 /* Toggle CF and return success */
758 State
->Flags
.Cf
= !State
->Flags
.Cf
;
762 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
764 /* Make sure this is the right instruction */
765 ASSERT(Opcode
== 0xFA);
767 /* No prefixes allowed */
768 if (State
->PrefixFlags
)
770 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
774 /* Check for protected mode */
775 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
778 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
780 /* Clear the interrupt flag */
781 State
->Flags
.If
= FALSE
;
785 /* General Protection Fault */
786 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
792 /* Just clear the interrupt flag */
793 State
->Flags
.If
= FALSE
;
800 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
802 /* Make sure this is the right instruction */
803 ASSERT(Opcode
== 0xFB);
805 /* No prefixes allowed */
806 if (State
->PrefixFlags
)
808 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
812 /* Check for protected mode */
813 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
816 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
818 /* Set the interrupt flag */
819 State
->Flags
.If
= TRUE
;
823 /* General Protection Fault */
824 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
830 /* Just set the interrupt flag */
831 State
->Flags
.If
= TRUE
;
838 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
840 /* Make sure this is the right instruction */
841 ASSERT(Opcode
== 0xFC);
843 /* No prefixes allowed */
844 if (State
->PrefixFlags
)
846 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
850 /* Clear DF and return success */
851 State
->Flags
.Df
= FALSE
;
855 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
857 /* Make sure this is the right instruction */
858 ASSERT(Opcode
== 0xFD);
860 /* No prefixes allowed */
861 if (State
->PrefixFlags
)
863 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
867 /* Set DF and return success*/
868 State
->Flags
.Df
= TRUE
;
872 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
874 /* Make sure this is the right instruction */
875 ASSERT(Opcode
== 0xF4);
877 /* No prefixes allowed */
878 if (State
->PrefixFlags
)
880 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
884 /* Privileged instructions can only be executed under CPL = 0 */
885 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
887 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
892 State
->Halted
= TRUE
;
898 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
903 /* Make sure this is the right instruction */
904 ASSERT((Opcode
& 0xF7) == 0xE4);
908 /* Fetch the parameter */
909 if (!Fast486FetchByte(State
, &Data
))
911 /* Exception occurred */
915 /* Set the port number to the parameter */
920 /* The port number is in DX */
921 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
924 /* Read a byte from the I/O port */
925 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
927 /* Store the result in AL */
928 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
933 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
936 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
938 /* Make sure this is the right instruction */
939 ASSERT((Opcode
& 0xF7) == 0xE5);
948 /* Fetch the parameter */
949 if (!Fast486FetchByte(State
, &Data
))
951 /* Exception occurred */
955 /* Set the port number to the parameter */
960 /* The port number is in DX */
961 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
968 /* Read a dword from the I/O port */
969 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
971 /* Store the value in EAX */
972 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
978 /* Read a word from the I/O port */
979 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
981 /* Store the value in AX */
982 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
988 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
993 /* Make sure this is the right instruction */
994 ASSERT((Opcode
& 0xF7) == 0xE6);
998 /* Fetch the parameter */
999 if (!Fast486FetchByte(State
, &Data
))
1001 /* Exception occurred */
1005 /* Set the port number to the parameter */
1010 /* The port number is in DX */
1011 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1014 /* Read the value from AL */
1015 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1017 /* Write the byte to the I/O port */
1018 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
1023 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1026 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1028 /* Make sure this is the right instruction */
1029 ASSERT((Opcode
& 0xF7) == 0xE7);
1031 TOGGLE_OPSIZE(Size
);
1038 /* Fetch the parameter */
1039 if (!Fast486FetchByte(State
, &Data
))
1041 /* Exception occurred */
1045 /* Set the port number to the parameter */
1050 /* The port number is in DX */
1051 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1056 /* Get the value from EAX */
1057 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1059 /* Write a dword to the I/O port */
1060 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1064 /* Get the value from AX */
1065 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1067 /* Write a word to the I/O port */
1068 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1074 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1077 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1079 TOGGLE_OPSIZE(Size
);
1081 /* Make sure this is the right instruction */
1082 ASSERT(Opcode
== 0xEB);
1084 /* Fetch the offset */
1085 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1087 /* An exception occurred */
1091 /* Move the instruction pointer */
1092 State
->InstPtr
.Long
+= Offset
;
1096 /* Clear the top half of EIP */
1097 State
->InstPtr
.Long
&= 0xFFFF;
1103 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1105 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1107 /* Make sure this is the right instruction */
1108 ASSERT((Opcode
& 0xF8) == 0xB8);
1110 TOGGLE_OPSIZE(Size
);
1117 /* Fetch the dword */
1118 if (!Fast486FetchDword(State
, &Value
))
1120 /* Exception occurred */
1124 /* Store the value in the register */
1125 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1131 /* Fetch the word */
1132 if (!Fast486FetchWord(State
, &Value
))
1134 /* Exception occurred */
1138 /* Store the value in the register */
1139 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1145 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1149 /* Make sure this is the right instruction */
1150 ASSERT((Opcode
& 0xF8) == 0xB0);
1152 if (State
->PrefixFlags
!= 0)
1154 /* Invalid prefix */
1155 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1159 /* Fetch the byte */
1160 if (!Fast486FetchByte(State
, &Value
))
1162 /* Exception occurred */
1168 /* AH, CH, DH or BH */
1169 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1173 /* AL, CL, DL or BL */
1174 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1180 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1182 UCHAR FirstValue
, SecondValue
, Result
;
1183 FAST486_MOD_REG_RM ModRegRm
;
1184 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1186 /* Make sure this is the right instruction */
1187 ASSERT((Opcode
& 0xFD) == 0x00);
1189 TOGGLE_ADSIZE(AddressSize
);
1191 /* Get the operands */
1192 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1194 /* Exception occurred */
1198 if (!Fast486ReadModrmByteOperands(State
,
1203 /* Exception occurred */
1207 /* Calculate the result */
1208 Result
= FirstValue
+ SecondValue
;
1210 /* Update the flags */
1211 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1212 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1213 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1214 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1215 State
->Flags
.Zf
= (Result
== 0);
1216 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1217 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1219 /* Write back the result */
1220 return Fast486WriteModrmByteOperands(State
,
1222 Opcode
& FAST486_OPCODE_WRITE_REG
,
1226 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1228 FAST486_MOD_REG_RM ModRegRm
;
1229 BOOLEAN OperandSize
, AddressSize
;
1231 /* Make sure this is the right instruction */
1232 ASSERT((Opcode
& 0xFD) == 0x01);
1234 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1236 TOGGLE_ADSIZE(AddressSize
);
1237 TOGGLE_OPSIZE(OperandSize
);
1239 /* Get the operands */
1240 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1242 /* Exception occurred */
1246 /* Check the operand size */
1249 ULONG FirstValue
, SecondValue
, Result
;
1251 if (!Fast486ReadModrmDwordOperands(State
,
1256 /* Exception occurred */
1260 /* Calculate the result */
1261 Result
= FirstValue
+ SecondValue
;
1263 /* Update the flags */
1264 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1265 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1266 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1267 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1268 State
->Flags
.Zf
= (Result
== 0);
1269 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1270 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1272 /* Write back the result */
1273 return Fast486WriteModrmDwordOperands(State
,
1275 Opcode
& FAST486_OPCODE_WRITE_REG
,
1280 USHORT FirstValue
, SecondValue
, Result
;
1282 if (!Fast486ReadModrmWordOperands(State
,
1287 /* Exception occurred */
1291 /* Calculate the result */
1292 Result
= FirstValue
+ SecondValue
;
1294 /* Update the flags */
1295 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1296 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1297 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1298 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1299 State
->Flags
.Zf
= (Result
== 0);
1300 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1301 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1303 /* Write back the result */
1304 return Fast486WriteModrmWordOperands(State
,
1306 Opcode
& FAST486_OPCODE_WRITE_REG
,
1311 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1313 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1314 UCHAR SecondValue
, Result
;
1316 /* Make sure this is the right instruction */
1317 ASSERT(Opcode
== 0x04);
1319 if (State
->PrefixFlags
)
1321 /* This opcode doesn't take any prefixes */
1322 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1326 if (!Fast486FetchByte(State
, &SecondValue
))
1328 /* Exception occurred */
1332 /* Calculate the result */
1333 Result
= FirstValue
+ SecondValue
;
1335 /* Update the flags */
1336 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1337 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1338 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1339 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1340 State
->Flags
.Zf
= (Result
== 0);
1341 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1342 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1344 /* Write back the result */
1345 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1350 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1352 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1354 /* Make sure this is the right instruction */
1355 ASSERT(Opcode
== 0x05);
1358 TOGGLE_OPSIZE(Size
);
1362 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1363 ULONG SecondValue
, Result
;
1365 if (!Fast486FetchDword(State
, &SecondValue
))
1367 /* Exception occurred */
1371 /* Calculate the result */
1372 Result
= FirstValue
+ SecondValue
;
1374 /* Update the flags */
1375 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1376 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1377 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1378 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1379 State
->Flags
.Zf
= (Result
== 0);
1380 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1381 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1383 /* Write back the result */
1384 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1388 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1389 USHORT SecondValue
, Result
;
1391 if (!Fast486FetchWord(State
, &SecondValue
))
1393 /* Exception occurred */
1397 /* Calculate the result */
1398 Result
= FirstValue
+ SecondValue
;
1400 /* Update the flags */
1401 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1402 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1403 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1404 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1405 State
->Flags
.Zf
= (Result
== 0);
1406 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1407 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1409 /* Write back the result */
1410 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1416 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1418 UCHAR FirstValue
, SecondValue
, Result
;
1419 FAST486_MOD_REG_RM ModRegRm
;
1420 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1422 /* Make sure this is the right instruction */
1423 ASSERT((Opcode
& 0xFD) == 0x08);
1425 TOGGLE_ADSIZE(AddressSize
);
1427 /* Get the operands */
1428 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1430 /* Exception occurred */
1434 if (!Fast486ReadModrmByteOperands(State
,
1439 /* Exception occurred */
1443 /* Calculate the result */
1444 Result
= FirstValue
| SecondValue
;
1446 /* Update the flags */
1447 State
->Flags
.Cf
= FALSE
;
1448 State
->Flags
.Of
= FALSE
;
1449 State
->Flags
.Zf
= (Result
== 0);
1450 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1451 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1453 /* Write back the result */
1454 return Fast486WriteModrmByteOperands(State
,
1456 Opcode
& FAST486_OPCODE_WRITE_REG
,
1460 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1462 FAST486_MOD_REG_RM ModRegRm
;
1463 BOOLEAN OperandSize
, AddressSize
;
1465 /* Make sure this is the right instruction */
1466 ASSERT((Opcode
& 0xFD) == 0x09);
1468 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1470 TOGGLE_ADSIZE(AddressSize
);
1471 TOGGLE_OPSIZE(OperandSize
);
1473 /* Get the operands */
1474 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1476 /* Exception occurred */
1480 /* Check the operand size */
1483 ULONG FirstValue
, SecondValue
, Result
;
1485 if (!Fast486ReadModrmDwordOperands(State
,
1490 /* Exception occurred */
1494 /* Calculate the result */
1495 Result
= FirstValue
| SecondValue
;
1497 /* Update the flags */
1498 State
->Flags
.Cf
= FALSE
;
1499 State
->Flags
.Of
= FALSE
;
1500 State
->Flags
.Zf
= (Result
== 0);
1501 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1502 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1504 /* Write back the result */
1505 return Fast486WriteModrmDwordOperands(State
,
1507 Opcode
& FAST486_OPCODE_WRITE_REG
,
1512 USHORT FirstValue
, SecondValue
, Result
;
1514 if (!Fast486ReadModrmWordOperands(State
,
1519 /* Exception occurred */
1523 /* Calculate the result */
1524 Result
= FirstValue
| SecondValue
;
1526 /* Update the flags */
1527 State
->Flags
.Cf
= FALSE
;
1528 State
->Flags
.Of
= FALSE
;
1529 State
->Flags
.Zf
= (Result
== 0);
1530 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1531 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1533 /* Write back the result */
1534 return Fast486WriteModrmWordOperands(State
,
1536 Opcode
& FAST486_OPCODE_WRITE_REG
,
1541 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1543 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1544 UCHAR SecondValue
, Result
;
1546 /* Make sure this is the right instruction */
1547 ASSERT(Opcode
== 0x0C);
1549 if (State
->PrefixFlags
)
1551 /* This opcode doesn't take any prefixes */
1552 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1556 if (!Fast486FetchByte(State
, &SecondValue
))
1558 /* Exception occurred */
1562 /* Calculate the result */
1563 Result
= FirstValue
| SecondValue
;
1565 /* Update the flags */
1566 State
->Flags
.Cf
= FALSE
;
1567 State
->Flags
.Of
= FALSE
;
1568 State
->Flags
.Zf
= (Result
== 0);
1569 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1570 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1572 /* Write back the result */
1573 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1578 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1580 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1582 /* Make sure this is the right instruction */
1583 ASSERT(Opcode
== 0x0D);
1586 TOGGLE_OPSIZE(Size
);
1590 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1591 ULONG SecondValue
, Result
;
1593 if (!Fast486FetchDword(State
, &SecondValue
))
1595 /* Exception occurred */
1599 /* Calculate the result */
1600 Result
= FirstValue
| SecondValue
;
1602 /* Update the flags */
1603 State
->Flags
.Cf
= FALSE
;
1604 State
->Flags
.Of
= FALSE
;
1605 State
->Flags
.Zf
= (Result
== 0);
1606 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1607 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1609 /* Write back the result */
1610 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1614 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1615 USHORT SecondValue
, Result
;
1617 if (!Fast486FetchWord(State
, &SecondValue
))
1619 /* Exception occurred */
1623 /* Calculate the result */
1624 Result
= FirstValue
| SecondValue
;
1626 /* Update the flags */
1627 State
->Flags
.Cf
= FALSE
;
1628 State
->Flags
.Of
= FALSE
;
1629 State
->Flags
.Zf
= (Result
== 0);
1630 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1631 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1633 /* Write back the result */
1634 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1640 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1642 UCHAR FirstValue
, SecondValue
, Result
;
1643 FAST486_MOD_REG_RM ModRegRm
;
1644 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1646 /* Make sure this is the right instruction */
1647 ASSERT((Opcode
& 0xFD) == 0x20);
1649 TOGGLE_ADSIZE(AddressSize
);
1651 /* Get the operands */
1652 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1654 /* Exception occurred */
1658 if (!Fast486ReadModrmByteOperands(State
,
1663 /* Exception occurred */
1667 /* Calculate the result */
1668 Result
= FirstValue
& SecondValue
;
1670 /* Update the flags */
1671 State
->Flags
.Cf
= FALSE
;
1672 State
->Flags
.Of
= FALSE
;
1673 State
->Flags
.Zf
= (Result
== 0);
1674 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1675 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1677 /* Write back the result */
1678 return Fast486WriteModrmByteOperands(State
,
1680 Opcode
& FAST486_OPCODE_WRITE_REG
,
1684 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1686 FAST486_MOD_REG_RM ModRegRm
;
1687 BOOLEAN OperandSize
, AddressSize
;
1689 /* Make sure this is the right instruction */
1690 ASSERT((Opcode
& 0xFD) == 0x21);
1692 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1694 TOGGLE_ADSIZE(AddressSize
);
1695 TOGGLE_OPSIZE(OperandSize
);
1697 /* Get the operands */
1698 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1700 /* Exception occurred */
1704 /* Check the operand size */
1707 ULONG FirstValue
, SecondValue
, Result
;
1709 if (!Fast486ReadModrmDwordOperands(State
,
1714 /* Exception occurred */
1718 /* Calculate the result */
1719 Result
= FirstValue
& SecondValue
;
1721 /* Update the flags */
1722 State
->Flags
.Cf
= FALSE
;
1723 State
->Flags
.Of
= FALSE
;
1724 State
->Flags
.Zf
= (Result
== 0);
1725 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1726 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1728 /* Write back the result */
1729 return Fast486WriteModrmDwordOperands(State
,
1731 Opcode
& FAST486_OPCODE_WRITE_REG
,
1736 USHORT FirstValue
, SecondValue
, Result
;
1738 if (!Fast486ReadModrmWordOperands(State
,
1743 /* Exception occurred */
1747 /* Calculate the result */
1748 Result
= FirstValue
& SecondValue
;
1750 /* Update the flags */
1751 State
->Flags
.Cf
= FALSE
;
1752 State
->Flags
.Of
= FALSE
;
1753 State
->Flags
.Zf
= (Result
== 0);
1754 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1755 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1757 /* Write back the result */
1758 return Fast486WriteModrmWordOperands(State
,
1760 Opcode
& FAST486_OPCODE_WRITE_REG
,
1765 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1767 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1768 UCHAR SecondValue
, Result
;
1770 /* Make sure this is the right instruction */
1771 ASSERT(Opcode
== 0x24);
1775 if (!Fast486FetchByte(State
, &SecondValue
))
1777 /* Exception occurred */
1781 /* Calculate the result */
1782 Result
= FirstValue
& SecondValue
;
1784 /* Update the flags */
1785 State
->Flags
.Cf
= FALSE
;
1786 State
->Flags
.Of
= FALSE
;
1787 State
->Flags
.Zf
= (Result
== 0);
1788 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1789 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1791 /* Write back the result */
1792 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1797 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1799 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1801 /* Make sure this is the right instruction */
1802 ASSERT(Opcode
== 0x25);
1805 TOGGLE_OPSIZE(Size
);
1809 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1810 ULONG SecondValue
, Result
;
1812 if (!Fast486FetchDword(State
, &SecondValue
))
1814 /* Exception occurred */
1818 /* Calculate the result */
1819 Result
= FirstValue
& SecondValue
;
1821 /* Update the flags */
1822 State
->Flags
.Cf
= FALSE
;
1823 State
->Flags
.Of
= FALSE
;
1824 State
->Flags
.Zf
= (Result
== 0);
1825 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1826 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1828 /* Write back the result */
1829 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1833 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1834 USHORT SecondValue
, Result
;
1836 if (!Fast486FetchWord(State
, &SecondValue
))
1838 /* Exception occurred */
1842 /* Calculate the result */
1843 Result
= FirstValue
& SecondValue
;
1845 /* Update the flags */
1846 State
->Flags
.Cf
= FALSE
;
1847 State
->Flags
.Of
= FALSE
;
1848 State
->Flags
.Zf
= (Result
== 0);
1849 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1850 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1852 /* Write back the result */
1853 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1859 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1861 UCHAR FirstValue
, SecondValue
, Result
;
1862 FAST486_MOD_REG_RM ModRegRm
;
1863 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1865 /* Make sure this is the right instruction */
1866 ASSERT((Opcode
& 0xFD) == 0x30);
1868 TOGGLE_ADSIZE(AddressSize
);
1870 /* Get the operands */
1871 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1873 /* Exception occurred */
1877 if (!Fast486ReadModrmByteOperands(State
,
1882 /* Exception occurred */
1886 /* Calculate the result */
1887 Result
= FirstValue
^ SecondValue
;
1889 /* Update the flags */
1890 State
->Flags
.Cf
= FALSE
;
1891 State
->Flags
.Of
= FALSE
;
1892 State
->Flags
.Zf
= (Result
== 0);
1893 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1894 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1896 /* Write back the result */
1897 return Fast486WriteModrmByteOperands(State
,
1899 Opcode
& FAST486_OPCODE_WRITE_REG
,
1903 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1905 FAST486_MOD_REG_RM ModRegRm
;
1906 BOOLEAN OperandSize
, AddressSize
;
1908 /* Make sure this is the right instruction */
1909 ASSERT((Opcode
& 0xFD) == 0x31);
1911 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1913 TOGGLE_ADSIZE(AddressSize
);
1914 TOGGLE_OPSIZE(OperandSize
);
1916 /* Get the operands */
1917 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1919 /* Exception occurred */
1923 /* Check the operand size */
1926 ULONG FirstValue
, SecondValue
, Result
;
1928 if (!Fast486ReadModrmDwordOperands(State
,
1933 /* Exception occurred */
1937 /* Calculate the result */
1938 Result
= FirstValue
^ SecondValue
;
1940 /* Update the flags */
1941 State
->Flags
.Cf
= FALSE
;
1942 State
->Flags
.Of
= FALSE
;
1943 State
->Flags
.Zf
= (Result
== 0);
1944 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1945 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1947 /* Write back the result */
1948 return Fast486WriteModrmDwordOperands(State
,
1950 Opcode
& FAST486_OPCODE_WRITE_REG
,
1955 USHORT FirstValue
, SecondValue
, Result
;
1957 if (!Fast486ReadModrmWordOperands(State
,
1962 /* Exception occurred */
1966 /* Calculate the result */
1967 Result
= FirstValue
^ SecondValue
;
1969 /* Update the flags */
1970 State
->Flags
.Cf
= FALSE
;
1971 State
->Flags
.Of
= FALSE
;
1972 State
->Flags
.Zf
= (Result
== 0);
1973 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1974 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1976 /* Write back the result */
1977 return Fast486WriteModrmWordOperands(State
,
1979 Opcode
& FAST486_OPCODE_WRITE_REG
,
1984 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1986 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1987 UCHAR SecondValue
, Result
;
1989 /* Make sure this is the right instruction */
1990 ASSERT(Opcode
== 0x34);
1992 if (State
->PrefixFlags
)
1994 /* This opcode doesn't take any prefixes */
1995 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1999 if (!Fast486FetchByte(State
, &SecondValue
))
2001 /* Exception occurred */
2005 /* Calculate the result */
2006 Result
= FirstValue
^ SecondValue
;
2008 /* Update the flags */
2009 State
->Flags
.Cf
= FALSE
;
2010 State
->Flags
.Of
= FALSE
;
2011 State
->Flags
.Zf
= (Result
== 0);
2012 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2013 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2015 /* Write back the result */
2016 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2021 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2023 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2025 /* Make sure this is the right instruction */
2026 ASSERT(Opcode
== 0x35);
2029 TOGGLE_OPSIZE(Size
);
2033 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2034 ULONG SecondValue
, Result
;
2036 if (!Fast486FetchDword(State
, &SecondValue
))
2038 /* Exception occurred */
2042 /* Calculate the result */
2043 Result
= FirstValue
^ SecondValue
;
2045 /* Update the flags */
2046 State
->Flags
.Cf
= FALSE
;
2047 State
->Flags
.Of
= FALSE
;
2048 State
->Flags
.Zf
= (Result
== 0);
2049 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2050 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2052 /* Write back the result */
2053 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2057 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2058 USHORT SecondValue
, Result
;
2060 if (!Fast486FetchWord(State
, &SecondValue
))
2062 /* Exception occurred */
2066 /* Calculate the result */
2067 Result
= FirstValue
^ SecondValue
;
2069 /* Update the flags */
2070 State
->Flags
.Cf
= FALSE
;
2071 State
->Flags
.Of
= FALSE
;
2072 State
->Flags
.Zf
= (Result
== 0);
2073 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2074 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2076 /* Write back the result */
2077 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2083 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2085 UCHAR FirstValue
, SecondValue
, Result
;
2086 FAST486_MOD_REG_RM ModRegRm
;
2087 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2089 /* Make sure this is the right instruction */
2090 ASSERT(Opcode
== 0x84);
2092 TOGGLE_ADSIZE(AddressSize
);
2094 /* Get the operands */
2095 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2097 /* Exception occurred */
2101 if (!Fast486ReadModrmByteOperands(State
,
2106 /* Exception occurred */
2109 /* Calculate the result */
2110 Result
= FirstValue
& SecondValue
;
2112 /* Update the flags */
2113 State
->Flags
.Cf
= FALSE
;
2114 State
->Flags
.Of
= FALSE
;
2115 State
->Flags
.Zf
= (Result
== 0);
2116 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2117 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2119 /* The result is discarded */
2123 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2125 FAST486_MOD_REG_RM ModRegRm
;
2126 BOOLEAN OperandSize
, AddressSize
;
2128 /* Make sure this is the right instruction */
2129 ASSERT(Opcode
== 0x85);
2131 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2133 TOGGLE_ADSIZE(AddressSize
);
2134 TOGGLE_OPSIZE(OperandSize
);
2136 /* Get the operands */
2137 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2139 /* Exception occurred */
2143 /* Check the operand size */
2146 ULONG FirstValue
, SecondValue
, Result
;
2148 if (!Fast486ReadModrmDwordOperands(State
,
2153 /* Exception occurred */
2157 /* Calculate the result */
2158 Result
= FirstValue
& SecondValue
;
2160 /* Update the flags */
2161 State
->Flags
.Cf
= FALSE
;
2162 State
->Flags
.Of
= FALSE
;
2163 State
->Flags
.Zf
= (Result
== 0);
2164 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2165 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2169 USHORT FirstValue
, SecondValue
, Result
;
2171 if (!Fast486ReadModrmWordOperands(State
,
2176 /* Exception occurred */
2180 /* Calculate the result */
2181 Result
= FirstValue
& SecondValue
;
2183 /* Update the flags */
2184 State
->Flags
.Cf
= FALSE
;
2185 State
->Flags
.Of
= FALSE
;
2186 State
->Flags
.Zf
= (Result
== 0);
2187 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2188 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2191 /* The result is discarded */
2195 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2197 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2198 UCHAR SecondValue
, Result
;
2200 /* Make sure this is the right instruction */
2201 ASSERT(Opcode
== 0xA8);
2203 if (State
->PrefixFlags
)
2205 /* This opcode doesn't take any prefixes */
2206 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2210 if (!Fast486FetchByte(State
, &SecondValue
))
2212 /* Exception occurred */
2216 /* Calculate the result */
2217 Result
= FirstValue
& SecondValue
;
2219 /* Update the flags */
2220 State
->Flags
.Cf
= FALSE
;
2221 State
->Flags
.Of
= FALSE
;
2222 State
->Flags
.Zf
= (Result
== 0);
2223 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2224 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2226 /* The result is discarded */
2230 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2232 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2234 /* Make sure this is the right instruction */
2235 ASSERT(Opcode
== 0xA9);
2238 TOGGLE_OPSIZE(Size
);
2242 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2243 ULONG SecondValue
, Result
;
2245 if (!Fast486FetchDword(State
, &SecondValue
))
2247 /* Exception occurred */
2251 /* Calculate the result */
2252 Result
= FirstValue
& SecondValue
;
2254 /* Update the flags */
2255 State
->Flags
.Cf
= FALSE
;
2256 State
->Flags
.Of
= FALSE
;
2257 State
->Flags
.Zf
= (Result
== 0);
2258 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2259 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2263 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2264 USHORT SecondValue
, Result
;
2266 if (!Fast486FetchWord(State
, &SecondValue
))
2268 /* Exception occurred */
2272 /* Calculate the result */
2273 Result
= FirstValue
& SecondValue
;
2275 /* Update the flags */
2276 State
->Flags
.Cf
= FALSE
;
2277 State
->Flags
.Of
= FALSE
;
2278 State
->Flags
.Zf
= (Result
== 0);
2279 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2280 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2283 /* The result is discarded */
2287 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2289 UCHAR FirstValue
, SecondValue
;
2290 FAST486_MOD_REG_RM ModRegRm
;
2291 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2293 /* Make sure this is the right instruction */
2294 ASSERT(Opcode
== 0x86);
2296 TOGGLE_ADSIZE(AddressSize
);
2298 /* Get the operands */
2299 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2301 /* Exception occurred */
2305 if (!Fast486ReadModrmByteOperands(State
,
2310 /* Exception occurred */
2314 /* Write the value from the register to the R/M */
2315 if (!Fast486WriteModrmByteOperands(State
,
2320 /* Exception occurred */
2324 /* Write the value from the R/M to the register */
2325 if (!Fast486WriteModrmByteOperands(State
,
2330 /* Exception occurred */
2337 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2339 FAST486_MOD_REG_RM ModRegRm
;
2340 BOOLEAN OperandSize
, AddressSize
;
2342 /* Make sure this is the right instruction */
2343 ASSERT(Opcode
== 0x87);
2345 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2347 TOGGLE_ADSIZE(AddressSize
);
2348 TOGGLE_OPSIZE(OperandSize
);
2350 /* Get the operands */
2351 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2353 /* Exception occurred */
2357 /* Check the operand size */
2360 ULONG FirstValue
, SecondValue
;
2362 if (!Fast486ReadModrmDwordOperands(State
,
2367 /* Exception occurred */
2371 /* Write the value from the register to the R/M */
2372 if (!Fast486WriteModrmDwordOperands(State
,
2377 /* Exception occurred */
2381 /* Write the value from the R/M to the register */
2382 if (!Fast486WriteModrmDwordOperands(State
,
2387 /* Exception occurred */
2393 USHORT FirstValue
, SecondValue
;
2395 if (!Fast486ReadModrmWordOperands(State
,
2400 /* Exception occurred */
2404 /* Write the value from the register to the R/M */
2405 if (!Fast486WriteModrmWordOperands(State
,
2410 /* Exception occurred */
2414 /* Write the value from the R/M to the register */
2415 if (!Fast486WriteModrmWordOperands(State
,
2420 /* Exception occurred */
2425 /* The result is discarded */
2429 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2431 /* Call the internal API */
2432 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2435 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2439 if (!Fast486StackPop(State
, &NewSelector
))
2441 /* Exception occurred */
2445 /* Call the internal API */
2446 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2449 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2451 /* Call the internal API */
2452 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2455 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2457 UCHAR FirstValue
, SecondValue
, Result
;
2458 FAST486_MOD_REG_RM ModRegRm
;
2459 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2461 /* Make sure this is the right instruction */
2462 ASSERT((Opcode
& 0xFD) == 0x10);
2464 TOGGLE_ADSIZE(AddressSize
);
2466 /* Get the operands */
2467 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2469 /* Exception occurred */
2473 if (!Fast486ReadModrmByteOperands(State
,
2478 /* Exception occurred */
2482 /* Calculate the result */
2483 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2485 /* Special exception for CF */
2486 State
->Flags
.Cf
= State
->Flags
.Cf
2487 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2489 /* Update the flags */
2490 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2491 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2492 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2493 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2494 State
->Flags
.Zf
= (Result
== 0);
2495 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2496 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2498 /* Write back the result */
2499 return Fast486WriteModrmByteOperands(State
,
2501 Opcode
& FAST486_OPCODE_WRITE_REG
,
2505 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2507 FAST486_MOD_REG_RM ModRegRm
;
2508 BOOLEAN OperandSize
, AddressSize
;
2510 /* Make sure this is the right instruction */
2511 ASSERT((Opcode
& 0xFD) == 0x11);
2513 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2515 TOGGLE_ADSIZE(AddressSize
);
2516 TOGGLE_OPSIZE(OperandSize
);
2518 /* Get the operands */
2519 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2521 /* Exception occurred */
2525 /* Check the operand size */
2528 ULONG FirstValue
, SecondValue
, Result
;
2530 if (!Fast486ReadModrmDwordOperands(State
,
2535 /* Exception occurred */
2539 /* Calculate the result */
2540 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2542 /* Special exception for CF */
2543 State
->Flags
.Cf
= State
->Flags
.Cf
2544 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2546 /* Update the flags */
2547 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2548 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2549 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2550 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2551 State
->Flags
.Zf
= (Result
== 0);
2552 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2553 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2555 /* Write back the result */
2556 return Fast486WriteModrmDwordOperands(State
,
2558 Opcode
& FAST486_OPCODE_WRITE_REG
,
2563 USHORT FirstValue
, SecondValue
, Result
;
2565 if (!Fast486ReadModrmWordOperands(State
,
2570 /* Exception occurred */
2574 /* Calculate the result */
2575 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2577 /* Special exception for CF */
2578 State
->Flags
.Cf
= State
->Flags
.Cf
2579 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2581 /* Update the flags */
2582 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2583 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2584 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2585 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2586 State
->Flags
.Zf
= (Result
== 0);
2587 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2588 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2590 /* Write back the result */
2591 return Fast486WriteModrmWordOperands(State
,
2593 Opcode
& FAST486_OPCODE_WRITE_REG
,
2599 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2601 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2602 UCHAR SecondValue
, Result
;
2604 /* Make sure this is the right instruction */
2605 ASSERT(Opcode
== 0x14);
2607 if (State
->PrefixFlags
)
2609 /* This opcode doesn't take any prefixes */
2610 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2614 if (!Fast486FetchByte(State
, &SecondValue
))
2616 /* Exception occurred */
2620 /* Calculate the result */
2621 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2623 /* Special exception for CF */
2624 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2625 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2627 /* Update the flags */
2628 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2629 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2630 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2631 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2632 State
->Flags
.Zf
= (Result
== 0);
2633 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2634 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2636 /* Write back the result */
2637 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2642 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2644 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2646 /* Make sure this is the right instruction */
2647 ASSERT(Opcode
== 0x15);
2650 TOGGLE_OPSIZE(Size
);
2654 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2655 ULONG SecondValue
, Result
;
2657 if (!Fast486FetchDword(State
, &SecondValue
))
2659 /* Exception occurred */
2663 /* Calculate the result */
2664 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2666 /* Special exception for CF */
2667 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2668 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2670 /* Update the flags */
2671 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2672 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2673 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2674 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2675 State
->Flags
.Zf
= (Result
== 0);
2676 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2677 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2679 /* Write back the result */
2680 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2684 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2685 USHORT SecondValue
, Result
;
2687 if (!Fast486FetchWord(State
, &SecondValue
))
2689 /* Exception occurred */
2693 /* Calculate the result */
2694 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2696 /* Special exception for CF */
2697 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2698 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2700 /* Update the flags */
2701 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2702 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2703 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2704 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2705 State
->Flags
.Zf
= (Result
== 0);
2706 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2707 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2709 /* Write back the result */
2710 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2716 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2718 /* Call the internal API */
2719 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2722 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2726 if (!Fast486StackPop(State
, &NewSelector
))
2728 /* Exception occurred */
2732 /* Call the internal API */
2733 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2736 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2738 UCHAR FirstValue
, SecondValue
, Result
;
2739 FAST486_MOD_REG_RM ModRegRm
;
2740 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2741 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2743 /* Make sure this is the right instruction */
2744 ASSERT((Opcode
& 0xFD) == 0x18);
2746 TOGGLE_ADSIZE(AddressSize
);
2748 /* Get the operands */
2749 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2751 /* Exception occurred */
2755 if (!Fast486ReadModrmByteOperands(State
,
2760 /* Exception occurred */
2764 /* Check if this is the instruction that writes to R/M */
2765 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2767 /* Swap the order */
2768 SWAP(FirstValue
, SecondValue
);
2771 /* Calculate the result */
2772 Result
= FirstValue
- SecondValue
- Carry
;
2774 /* Update the flags */
2775 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2776 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2777 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2778 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2779 State
->Flags
.Zf
= (Result
== 0);
2780 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2781 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2783 /* Write back the result */
2784 return Fast486WriteModrmByteOperands(State
,
2786 Opcode
& FAST486_OPCODE_WRITE_REG
,
2790 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2792 FAST486_MOD_REG_RM ModRegRm
;
2793 BOOLEAN OperandSize
, AddressSize
;
2794 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2796 /* Make sure this is the right instruction */
2797 ASSERT((Opcode
& 0xFD) == 0x19);
2799 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2801 TOGGLE_ADSIZE(AddressSize
);
2802 TOGGLE_OPSIZE(OperandSize
);
2804 /* Get the operands */
2805 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2807 /* Exception occurred */
2811 /* Check the operand size */
2814 ULONG FirstValue
, SecondValue
, Result
;
2816 if (!Fast486ReadModrmDwordOperands(State
,
2821 /* Exception occurred */
2825 /* Check if this is the instruction that writes to R/M */
2826 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2828 /* Swap the order */
2829 SWAP(FirstValue
, SecondValue
);
2832 /* Calculate the result */
2833 Result
= FirstValue
- SecondValue
- Carry
;
2835 /* Update the flags */
2836 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2837 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2838 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2839 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2840 State
->Flags
.Zf
= (Result
== 0);
2841 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2842 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2844 /* Write back the result */
2845 return Fast486WriteModrmDwordOperands(State
,
2847 Opcode
& FAST486_OPCODE_WRITE_REG
,
2852 USHORT FirstValue
, SecondValue
, Result
;
2854 if (!Fast486ReadModrmWordOperands(State
,
2859 /* Exception occurred */
2863 /* Check if this is the instruction that writes to R/M */
2864 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2866 /* Swap the order */
2867 SWAP(FirstValue
, SecondValue
);
2870 /* Calculate the result */
2871 Result
= FirstValue
- SecondValue
- Carry
;
2873 /* Update the flags */
2874 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2875 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2876 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2877 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2878 State
->Flags
.Zf
= (Result
== 0);
2879 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2880 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2882 /* Write back the result */
2883 return Fast486WriteModrmWordOperands(State
,
2885 Opcode
& FAST486_OPCODE_WRITE_REG
,
2890 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2892 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2893 UCHAR SecondValue
, Result
;
2894 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2896 /* Make sure this is the right instruction */
2897 ASSERT(Opcode
== 0x1C);
2899 if (State
->PrefixFlags
)
2901 /* This opcode doesn't take any prefixes */
2902 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2906 if (!Fast486FetchByte(State
, &SecondValue
))
2908 /* Exception occurred */
2912 /* Calculate the result */
2913 Result
= FirstValue
- SecondValue
- Carry
;
2915 /* Update the flags */
2916 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2917 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2918 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2919 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2920 State
->Flags
.Zf
= (Result
== 0);
2921 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2922 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2924 /* Write back the result */
2925 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2931 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2933 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2934 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2936 /* Make sure this is the right instruction */
2937 ASSERT(Opcode
== 0x1D);
2940 TOGGLE_OPSIZE(Size
);
2944 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2945 ULONG SecondValue
, Result
;
2947 if (!Fast486FetchDword(State
, &SecondValue
))
2949 /* Exception occurred */
2953 /* Calculate the result */
2954 Result
= FirstValue
- SecondValue
- Carry
;
2956 /* Update the flags */
2957 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2958 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2959 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2960 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2961 State
->Flags
.Zf
= (Result
== 0);
2962 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2963 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2965 /* Write back the result */
2966 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2970 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2971 USHORT SecondValue
, Result
;
2973 if (!Fast486FetchWord(State
, &SecondValue
))
2975 /* Exception occurred */
2979 /* Calculate the result */
2980 Result
= FirstValue
- SecondValue
- Carry
;
2982 /* Update the flags */
2983 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2984 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2985 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2986 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2987 State
->Flags
.Zf
= (Result
== 0);
2988 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2989 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2991 /* Write back the result */
2992 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2999 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
3001 /* Call the internal API */
3002 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
3005 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3009 if (!Fast486StackPop(State
, &NewSelector
))
3011 /* Exception occurred */
3015 /* Call the internal API */
3016 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3019 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3021 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3022 BOOLEAN Carry
= State
->Flags
.Cf
;
3024 /* Clear the carry flag */
3025 State
->Flags
.Cf
= FALSE
;
3027 /* Check if the first BCD digit is invalid or there was a carry from it */
3028 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3031 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3032 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3034 /* A carry occurred */
3035 State
->Flags
.Cf
= TRUE
;
3038 /* Set the adjust flag */
3039 State
->Flags
.Af
= TRUE
;
3042 /* Check if the second BCD digit is invalid or there was a carry from it */
3043 if ((Value
> 0x99) || Carry
)
3046 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3048 /* There was a carry */
3049 State
->Flags
.Cf
= TRUE
;
3052 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3054 /* Update the flags */
3055 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3056 State
->Flags
.Zf
= (Value
== 0);
3057 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3062 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3064 UCHAR FirstValue
, SecondValue
, Result
;
3065 FAST486_MOD_REG_RM ModRegRm
;
3066 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3068 /* Make sure this is the right instruction */
3069 ASSERT((Opcode
& 0xED) == 0x28);
3071 TOGGLE_ADSIZE(AddressSize
);
3073 /* Get the operands */
3074 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3076 /* Exception occurred */
3080 if (!Fast486ReadModrmByteOperands(State
,
3085 /* Exception occurred */
3089 /* Check if this is the instruction that writes to R/M */
3090 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3092 /* Swap the order */
3093 SWAP(FirstValue
, SecondValue
);
3096 /* Calculate the result */
3097 Result
= FirstValue
- SecondValue
;
3099 /* Update the flags */
3100 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3101 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3102 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3103 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3104 State
->Flags
.Zf
= (Result
== 0);
3105 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3106 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3108 /* Check if this is not a CMP */
3109 if (!(Opcode
& 0x10))
3111 /* Write back the result */
3112 return Fast486WriteModrmByteOperands(State
,
3114 Opcode
& FAST486_OPCODE_WRITE_REG
,
3119 /* Discard the result */
3124 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3126 FAST486_MOD_REG_RM ModRegRm
;
3127 BOOLEAN OperandSize
, AddressSize
;
3129 /* Make sure this is the right instruction */
3130 ASSERT((Opcode
& 0xED) == 0x29);
3132 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3134 TOGGLE_ADSIZE(AddressSize
);
3135 TOGGLE_OPSIZE(OperandSize
);
3137 /* Get the operands */
3138 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3140 /* Exception occurred */
3144 /* Check the operand size */
3147 ULONG FirstValue
, SecondValue
, Result
;
3149 if (!Fast486ReadModrmDwordOperands(State
,
3154 /* Exception occurred */
3158 /* Check if this is the instruction that writes to R/M */
3159 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3161 /* Swap the order */
3162 SWAP(FirstValue
, SecondValue
);
3165 /* Calculate the result */
3166 Result
= FirstValue
- SecondValue
;
3168 /* Update the flags */
3169 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3170 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3171 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3172 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3173 State
->Flags
.Zf
= (Result
== 0);
3174 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3175 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3177 /* Check if this is not a CMP */
3178 if (!(Opcode
& 0x10))
3180 /* Write back the result */
3181 return Fast486WriteModrmDwordOperands(State
,
3183 Opcode
& FAST486_OPCODE_WRITE_REG
,
3188 /* Discard the result */
3194 USHORT FirstValue
, SecondValue
, Result
;
3196 if (!Fast486ReadModrmWordOperands(State
,
3201 /* Exception occurred */
3205 /* Check if this is the instruction that writes to R/M */
3206 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3208 /* Swap the order */
3209 SWAP(FirstValue
, SecondValue
);
3212 /* Calculate the result */
3213 Result
= FirstValue
- SecondValue
;
3215 /* Update the flags */
3216 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3217 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3218 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3219 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3220 State
->Flags
.Zf
= (Result
== 0);
3221 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3222 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3224 /* Check if this is not a CMP */
3225 if (!(Opcode
& 0x10))
3227 /* Write back the result */
3228 return Fast486WriteModrmWordOperands(State
,
3230 Opcode
& FAST486_OPCODE_WRITE_REG
,
3235 /* Discard the result */
3241 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3243 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3244 UCHAR SecondValue
, Result
;
3246 /* Make sure this is the right instruction */
3247 ASSERT((Opcode
& 0xEF) == 0x2C);
3249 if (State
->PrefixFlags
)
3251 /* This opcode doesn't take any prefixes */
3252 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3256 if (!Fast486FetchByte(State
, &SecondValue
))
3258 /* Exception occurred */
3262 /* Calculate the result */
3263 Result
= FirstValue
- SecondValue
;
3265 /* Update the flags */
3266 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3267 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3268 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3269 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3270 State
->Flags
.Zf
= (Result
== 0);
3271 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3272 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3274 /* Check if this is not a CMP */
3275 if (!(Opcode
& 0x10))
3277 /* Write back the result */
3278 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3284 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3286 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3288 /* Make sure this is the right instruction */
3289 ASSERT((Opcode
& 0xEF) == 0x2D);
3292 TOGGLE_OPSIZE(Size
);
3296 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3297 ULONG SecondValue
, Result
;
3299 if (!Fast486FetchDword(State
, &SecondValue
))
3301 /* Exception occurred */
3305 /* Calculate the result */
3306 Result
= FirstValue
- SecondValue
;
3308 /* Update the flags */
3309 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3310 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3311 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3312 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3313 State
->Flags
.Zf
= (Result
== 0);
3314 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3315 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3317 /* Check if this is not a CMP */
3318 if (!(Opcode
& 0x10))
3320 /* Write back the result */
3321 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3326 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3327 USHORT SecondValue
, Result
;
3329 if (!Fast486FetchWord(State
, &SecondValue
))
3331 /* Exception occurred */
3335 /* Calculate the result */
3336 Result
= FirstValue
- SecondValue
;
3338 /* Update the flags */
3339 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3340 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3341 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3342 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3343 State
->Flags
.Zf
= (Result
== 0);
3344 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3345 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3347 /* Check if this is not a CMP */
3348 if (!(Opcode
& 0x10))
3350 /* Write back the result */
3351 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3358 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3360 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3361 BOOLEAN Carry
= State
->Flags
.Cf
;
3363 /* Clear the carry flag */
3364 State
->Flags
.Cf
= FALSE
;
3366 /* Check if the first BCD digit is invalid or there was a borrow */
3367 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3370 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3371 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3373 /* A borrow occurred */
3374 State
->Flags
.Cf
= TRUE
;
3377 /* Set the adjust flag */
3378 State
->Flags
.Af
= TRUE
;
3381 /* Check if the second BCD digit is invalid or there was a borrow */
3382 if ((Value
> 0x99) || Carry
)
3385 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3387 /* There was a borrow */
3388 State
->Flags
.Cf
= TRUE
;
3391 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3393 /* Update the flags */
3394 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3395 State
->Flags
.Zf
= (Value
== 0);
3396 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3401 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3403 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3406 * Check if the value in AL is not a valid BCD digit,
3407 * or there was a carry from the lowest 4 bits of AL
3409 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3412 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3413 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3416 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3420 /* Clear CF and AF */
3421 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3424 /* Keep only the lowest 4 bits of AL */
3425 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3430 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3432 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3435 * Check if the value in AL is not a valid BCD digit,
3436 * or there was a borrow from the lowest 4 bits of AL
3438 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3441 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3442 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3445 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3449 /* Clear CF and AF */
3450 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3453 /* Keep only the lowest 4 bits of AL */
3454 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3459 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3462 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3463 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3465 /* Make sure this is the right instruction */
3466 ASSERT(Opcode
== 0x60);
3468 TOGGLE_OPSIZE(Size
);
3471 /* Push all the registers in order */
3472 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3474 if (i
== FAST486_REG_ESP
)
3476 /* Use the saved ESP instead */
3477 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3479 /* Exception occurred */
3485 /* Push the register */
3486 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3487 : State
->GeneralRegs
[i
].LowWord
))
3489 /* Exception occurred */
3498 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3501 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3504 /* Make sure this is the right instruction */
3505 ASSERT(Opcode
== 0x61);
3507 TOGGLE_OPSIZE(Size
);
3510 /* Pop all the registers in reverse order */
3511 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3514 if (!Fast486StackPop(State
, &Value
))
3516 /* Exception occurred */
3520 /* Don't modify ESP */
3521 if (i
!= FAST486_REG_ESP
)
3523 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3524 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3531 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3533 BOOLEAN OperandSize
, AddressSize
;
3534 FAST486_MOD_REG_RM ModRegRm
;
3535 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3537 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3540 TOGGLE_OPSIZE(OperandSize
);
3541 TOGGLE_ADSIZE(AddressSize
);
3543 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3545 /* Exception occurred */
3549 if (!ModRegRm
.Memory
)
3552 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3556 /* Check for the segment override */
3557 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3559 /* Use the override segment instead */
3560 Segment
= State
->SegmentOverride
;
3565 LONG Index
, LowerBound
, UpperBound
;
3567 /* Read the operands */
3568 if (!Fast486ReadModrmDwordOperands(State
,
3571 (PULONG
)&LowerBound
))
3573 /* Exception occurred */
3577 if (!Fast486ReadMemory(State
,
3579 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3584 /* Exception occurred */
3588 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3591 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3597 SHORT Index
, LowerBound
, UpperBound
;
3599 /* Read the operands */
3600 if (!Fast486ReadModrmWordOperands(State
,
3603 (PUSHORT
)&LowerBound
))
3605 /* Exception occurred */
3609 if (!Fast486ReadMemory(State
,
3611 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3616 /* Exception occurred */
3620 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3623 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3631 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3633 USHORT FirstValue
, SecondValue
;
3634 FAST486_MOD_REG_RM ModRegRm
;
3635 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3637 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3639 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3641 /* Cannot be used in real mode or with a LOCK prefix */
3642 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3646 TOGGLE_ADSIZE(AddressSize
);
3648 /* Get the operands */
3649 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3651 /* Exception occurred */
3655 /* Read the operands */
3656 if (!Fast486ReadModrmWordOperands(State
,
3661 /* Exception occurred */
3665 /* Check if the RPL needs adjusting */
3666 if ((SecondValue
& 3) < (FirstValue
& 3))
3668 /* Adjust the RPL */
3670 SecondValue
|= FirstValue
& 3;
3673 State
->Flags
.Zf
= TRUE
;
3675 /* Write back the result */
3676 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3681 State
->Flags
.Zf
= FALSE
;
3686 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3688 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3690 /* Make sure this is the right instruction */
3691 ASSERT(Opcode
== 0x68);
3694 TOGGLE_OPSIZE(Size
);
3700 if (!Fast486FetchDword(State
, &Data
))
3702 /* Exception occurred */
3706 /* Call the internal API */
3707 return Fast486StackPush(State
, Data
);
3713 if (!Fast486FetchWord(State
, (PUSHORT
)&Data
))
3715 /* Exception occurred */
3719 /* Call the internal API */
3720 return Fast486StackPush(State
, Data
);
3724 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3726 BOOLEAN OperandSize
, AddressSize
;
3727 FAST486_MOD_REG_RM ModRegRm
;
3730 /* Make sure this is the right instruction */
3731 ASSERT((Opcode
& 0xFD) == 0x69);
3733 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3735 TOGGLE_ADSIZE(AddressSize
);
3736 TOGGLE_OPSIZE(OperandSize
);
3738 /* Fetch the parameters */
3739 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3741 /* Exception occurred */
3749 /* Fetch the immediate operand */
3750 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3752 /* Exception occurred */
3756 Multiplier
= (LONG
)Byte
;
3764 /* Fetch the immediate operand */
3765 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3767 /* Exception occurred */
3777 /* Fetch the immediate operand */
3778 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3780 /* Exception occurred */
3784 Multiplier
= (LONG
)Word
;
3790 LONG RegValue
, Multiplicand
;
3793 /* Read the operands */
3794 if (!Fast486ReadModrmDwordOperands(State
,
3797 (PULONG
)&Multiplicand
))
3799 /* Exception occurred */
3804 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3806 /* Check for carry/overflow */
3807 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3809 /* Write-back the result */
3810 return Fast486WriteModrmDwordOperands(State
,
3813 (ULONG
)((LONG
)Product
));
3817 SHORT RegValue
, Multiplicand
;
3820 /* Read the operands */
3821 if (!Fast486ReadModrmWordOperands(State
,
3824 (PUSHORT
)&Multiplicand
))
3826 /* Exception occurred */
3831 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3833 /* Check for carry/overflow */
3834 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3836 /* Write-back the result */
3837 return Fast486WriteModrmWordOperands(State
,
3840 (USHORT
)((SHORT
)Product
));
3844 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3848 /* Make sure this is the right instruction */
3849 ASSERT(Opcode
== 0x6A);
3851 if (!Fast486FetchByte(State
, (PUCHAR
)&Data
))
3853 /* Exception occurred */
3857 /* Call the internal API */
3858 return Fast486StackPush(State
, Data
);
3861 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3863 UCHAR FirstValue
, SecondValue
, Result
;
3864 FAST486_MOD_REG_RM ModRegRm
;
3865 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3867 /* Make sure this is the right instruction */
3868 ASSERT((Opcode
& 0xFD) == 0x88);
3870 TOGGLE_ADSIZE(AddressSize
);
3872 /* Get the operands */
3873 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3875 /* Exception occurred */
3879 if (!Fast486ReadModrmByteOperands(State
,
3884 /* Exception occurred */
3888 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3889 else Result
= FirstValue
;
3891 /* Write back the result */
3892 return Fast486WriteModrmByteOperands(State
,
3894 Opcode
& FAST486_OPCODE_WRITE_REG
,
3899 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3901 FAST486_MOD_REG_RM ModRegRm
;
3902 BOOLEAN OperandSize
, AddressSize
;
3904 /* Make sure this is the right instruction */
3905 ASSERT((Opcode
& 0xFD) == 0x89);
3907 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3909 TOGGLE_ADSIZE(AddressSize
);
3910 TOGGLE_OPSIZE(OperandSize
);
3912 /* Get the operands */
3913 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3915 /* Exception occurred */
3919 /* Check the operand size */
3922 ULONG FirstValue
, SecondValue
, Result
;
3924 if (!Fast486ReadModrmDwordOperands(State
,
3929 /* Exception occurred */
3933 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3934 else Result
= FirstValue
;
3936 /* Write back the result */
3937 return Fast486WriteModrmDwordOperands(State
,
3939 Opcode
& FAST486_OPCODE_WRITE_REG
,
3944 USHORT FirstValue
, SecondValue
, Result
;
3946 if (!Fast486ReadModrmWordOperands(State
,
3951 /* Exception occurred */
3955 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3956 else Result
= FirstValue
;
3958 /* Write back the result */
3959 return Fast486WriteModrmWordOperands(State
,
3961 Opcode
& FAST486_OPCODE_WRITE_REG
,
3966 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3968 BOOLEAN OperandSize
, AddressSize
;
3969 FAST486_MOD_REG_RM ModRegRm
;
3971 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3973 /* Make sure this is the right instruction */
3974 ASSERT(Opcode
== 0x8C);
3976 TOGGLE_ADSIZE(AddressSize
);
3977 TOGGLE_OPSIZE(OperandSize
);
3979 /* Get the operands */
3980 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3982 /* Exception occurred */
3986 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3989 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3995 return Fast486WriteModrmDwordOperands(State
,
3998 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4002 return Fast486WriteModrmWordOperands(State
,
4005 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4009 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
4011 FAST486_MOD_REG_RM ModRegRm
;
4012 BOOLEAN OperandSize
, AddressSize
;
4014 /* Make sure this is the right instruction */
4015 ASSERT(Opcode
== 0x8D);
4017 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4019 TOGGLE_ADSIZE(AddressSize
);
4020 TOGGLE_OPSIZE(OperandSize
);
4022 /* Get the operands */
4023 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4025 /* Exception occurred */
4029 /* The second operand must be memory */
4030 if (!ModRegRm
.Memory
)
4033 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4037 /* Write the address to the register */
4040 return Fast486WriteModrmDwordOperands(State
,
4043 ModRegRm
.MemoryAddress
);
4047 return Fast486WriteModrmWordOperands(State
,
4050 ModRegRm
.MemoryAddress
);
4055 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
4057 BOOLEAN OperandSize
, AddressSize
;
4058 FAST486_MOD_REG_RM ModRegRm
;
4060 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4062 /* Make sure this is the right instruction */
4063 ASSERT(Opcode
== 0x8E);
4065 TOGGLE_ADSIZE(AddressSize
);
4066 TOGGLE_OPSIZE(OperandSize
);
4068 /* Get the operands */
4069 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4071 /* Exception occurred */
4075 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4076 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
4079 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4087 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4089 /* Exception occurred */
4093 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4099 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4101 /* Exception occurred */
4105 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4109 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4111 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4113 /* Make sure this is the right instruction */
4114 ASSERT(Opcode
== 0x98);
4116 TOGGLE_OPSIZE(Size
);
4121 /* Sign extend AX to EAX */
4122 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4124 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4125 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4131 /* Sign extend AL to AX */
4132 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4133 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4140 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4142 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4144 /* Make sure this is the right instruction */
4145 ASSERT(Opcode
== 0x99);
4147 TOGGLE_OPSIZE(Size
);
4152 /* Sign extend EAX to EDX:EAX */
4153 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4154 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4155 ? 0xFFFFFFFF : 0x00000000;
4159 /* Sign extend AX to DX:AX */
4160 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4161 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4168 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4172 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4174 /* Make sure this is the right instruction */
4175 ASSERT(Opcode
== 0x9A);
4177 TOGGLE_OPSIZE(Size
);
4180 /* Fetch the offset */
4183 if (!Fast486FetchDword(State
, &Offset
))
4185 /* Exception occurred */
4191 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4193 /* Exception occurred */
4198 /* Fetch the segment */
4199 if (!Fast486FetchWord(State
, &Segment
))
4201 /* Exception occurred */
4205 /* Push the current code segment selector */
4206 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4208 /* Exception occurred */
4212 /* Push the current value of the instruction pointer */
4213 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4215 /* Exception occurred */
4219 /* Load the new CS */
4220 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4222 /* Exception occurred */
4226 /* Load new (E)IP */
4227 if (Size
) State
->InstPtr
.Long
= Offset
;
4228 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4233 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4235 // TODO: NOT IMPLEMENTED
4241 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4243 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4246 TOGGLE_OPSIZE(Size
);
4248 /* Check for VM86 mode when IOPL is not 3 */
4249 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4251 /* Call the VM86 monitor */
4252 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4256 /* Push the flags */
4257 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4258 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4261 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4263 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4264 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4265 FAST486_FLAGS_REG NewFlags
;
4268 TOGGLE_OPSIZE(Size
);
4270 /* Pop the new flags */
4271 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4273 /* Exception occurred */
4277 /* Check for VM86 mode when IOPL is not 3 */
4278 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4280 /* Call the VM86 monitor */
4281 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4285 State
->Flags
.Cf
= NewFlags
.Cf
;
4286 State
->Flags
.Pf
= NewFlags
.Pf
;
4287 State
->Flags
.Af
= NewFlags
.Af
;
4288 State
->Flags
.Zf
= NewFlags
.Zf
;
4289 State
->Flags
.Sf
= NewFlags
.Sf
;
4290 State
->Flags
.Tf
= NewFlags
.Tf
;
4291 State
->Flags
.Df
= NewFlags
.Df
;
4292 State
->Flags
.Of
= NewFlags
.Of
;
4293 State
->Flags
.Nt
= NewFlags
.Nt
;
4294 State
->Flags
.Ac
= NewFlags
.Ac
;
4296 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4297 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4302 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4304 /* Make sure this is the right instruction */
4305 ASSERT(Opcode
== 0x9E);
4307 /* Set the low-order byte of FLAGS to AH */
4308 State
->Flags
.Long
&= 0xFFFFFF00;
4309 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4311 /* Restore the reserved bits of FLAGS */
4312 State
->Flags
.AlwaysSet
= TRUE
;
4313 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4318 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4320 /* Make sure this is the right instruction */
4321 ASSERT(Opcode
== 0x9F);
4323 /* Set AH to the low-order byte of FLAGS */
4324 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4329 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4331 ULONG ReturnAddress
;
4332 USHORT BytesToPop
= 0;
4333 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4335 /* Make sure this is the right instruction */
4336 ASSERT((Opcode
& 0xFE) == 0xC2);
4339 TOGGLE_OPSIZE(Size
);
4343 /* Fetch the number of bytes to pop after the return */
4344 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4347 /* Pop the return address */
4348 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4350 /* Return to the calling procedure, and if necessary, pop the parameters */
4353 State
->InstPtr
.Long
= ReturnAddress
;
4354 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4358 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4359 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4365 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4367 UCHAR FarPointer
[6];
4368 BOOLEAN OperandSize
, AddressSize
;
4369 FAST486_MOD_REG_RM ModRegRm
;
4371 /* Make sure this is the right instruction */
4372 ASSERT((Opcode
& 0xFE) == 0xC4);
4374 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4376 TOGGLE_OPSIZE(OperandSize
);
4377 TOGGLE_ADSIZE(AddressSize
);
4379 /* Get the operands */
4380 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4382 /* Exception occurred */
4386 if (!ModRegRm
.Memory
)
4388 /* Check if this is a BOP and the host supports BOPs */
4389 if ((Opcode
== 0xC4)
4390 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4391 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4392 && (State
->BopCallback
!= NULL
))
4396 /* Fetch the BOP code */
4397 if (!Fast486FetchByte(State
, &BopCode
))
4399 /* Exception occurred */
4403 /* Call the BOP handler */
4404 State
->BopCallback(State
, BopCode
);
4407 * If an interrupt should occur at this time, delay it.
4408 * We must do this because if an interrupt begins and the BOP callback
4409 * changes the CS:IP, the interrupt handler won't execute and the
4410 * stack pointer will never be restored.
4412 if (State
->IntStatus
== FAST486_INT_EXECUTE
)
4414 State
->IntStatus
= FAST486_INT_DELAYED
;
4417 /* Return success */
4422 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4426 if (!Fast486ReadMemory(State
,
4427 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4428 ? State
->SegmentOverride
: FAST486_REG_DS
,
4429 ModRegRm
.MemoryAddress
,
4432 OperandSize
? 6 : 4))
4434 /* Exception occurred */
4440 ULONG Offset
= *((PULONG
)FarPointer
);
4441 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4443 /* Set the register to the offset */
4444 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4446 /* Load the segment */
4447 return Fast486LoadSegment(State
,
4449 ? FAST486_REG_ES
: FAST486_REG_DS
,
4454 USHORT Offset
= *((PUSHORT
)FarPointer
);
4455 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4457 /* Set the register to the offset */
4458 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4460 /* Load the segment */
4461 return Fast486LoadSegment(State
,
4463 ? FAST486_REG_ES
: FAST486_REG_DS
,
4468 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4471 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4474 FAST486_REG FramePointer
;
4476 /* Make sure this is the right instruction */
4477 ASSERT(Opcode
== 0xC8);
4480 TOGGLE_OPSIZE(Size
);
4482 if (!Fast486FetchWord(State
, &FrameSize
))
4484 /* Exception occurred */
4488 if (!Fast486FetchByte(State
, &NestingLevel
))
4490 /* Exception occurred */
4495 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4497 /* Exception occurred */
4502 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4504 /* Set up the nested procedure stacks */
4505 for (i
= 1; i
< NestingLevel
; i
++)
4509 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4510 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4514 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4515 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4519 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4521 /* Set EBP to the frame pointer */
4522 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4524 /* Reserve space for the frame */
4525 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4526 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4531 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4533 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4535 /* Make sure this is the right instruction */
4536 ASSERT(Opcode
== 0xC9);
4539 TOGGLE_OPSIZE(Size
);
4543 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4544 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4546 /* Pop the saved base pointer from the stack */
4547 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4553 /* Set the stack pointer (SP) to the base pointer (BP) */
4554 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4556 /* Pop the saved base pointer from the stack */
4557 if (Fast486StackPop(State
, &Value
))
4559 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4566 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4570 USHORT BytesToPop
= 0;
4571 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4573 /* Make sure this is the right instruction */
4574 ASSERT((Opcode
& 0xFE) == 0xCA);
4576 TOGGLE_OPSIZE(Size
);
4581 /* Fetch the number of bytes to pop after the return */
4582 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4585 /* Pop the offset */
4586 if (!Fast486StackPop(State
, &Offset
))
4588 /* Exception occurred */
4592 /* Pop the segment */
4593 if (!Fast486StackPop(State
, &Segment
))
4595 /* Exception occurred */
4599 /* Load the new CS */
4600 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4602 /* Exception occurred */
4606 /* Load new (E)IP, and if necessary, pop the parameters */
4609 State
->InstPtr
.Long
= Offset
;
4610 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4614 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4615 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4621 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4629 /* This is the INT3 instruction */
4634 case 0xCD: // INT xx
4636 /* Fetch the interrupt number */
4637 if (!Fast486FetchByte(State
, &IntNum
))
4639 /* Exception occurred */
4648 /* Don't do anything if OF is cleared */
4649 if (!State
->Flags
.Of
) return TRUE
;
4652 IntNum
= FAST486_EXCEPTION_OF
;
4659 /* Should not happen */
4664 /* Perform the interrupt */
4665 return Fast486PerformInterrupt(State
, IntNum
);
4668 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4671 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4672 FAST486_FLAGS_REG NewFlags
;
4673 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4675 /* Make sure this is the right instruction */
4676 ASSERT(Opcode
== 0xCF);
4679 TOGGLE_OPSIZE(Size
);
4682 if (!Fast486StackPop(State
, &InstPtr
))
4684 /* Exception occurred */
4689 if (!Fast486StackPop(State
, &CodeSel
))
4691 /* Exception occurred */
4696 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4698 /* Exception occurred */
4702 /* Check for protected mode */
4703 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4705 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4707 if (State
->Flags
.Vm
)
4709 /* Return from VM86 mode */
4711 /* Check the IOPL */
4712 if (State
->Flags
.Iopl
== 3)
4715 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4718 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4720 /* Exception occurred */
4724 /* Set the new flags */
4725 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4726 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4727 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4728 State
->Flags
.Iopl
= 3;
4732 /* Call the VM86 monitor */
4733 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4740 if (State
->Flags
.Nt
)
4742 /* Nested task return */
4750 /* Return to VM86 mode */
4751 ULONG Es
, Ds
, Fs
, Gs
;
4753 /* Pop ESP, SS, ES, FS, GS */
4754 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4755 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4756 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4757 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4758 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4759 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4761 /* Set the new IP */
4762 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4764 /* Set the new flags */
4765 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4766 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4767 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4769 /* Load the new segments */
4770 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4771 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4772 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4773 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4774 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4775 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4780 /* Load the new CS */
4781 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4783 /* Exception occurred */
4788 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4789 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4791 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4794 if (!Fast486StackPop(State
, &StackPtr
))
4801 if (!Fast486StackPop(State
, &StackSel
))
4808 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4815 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4816 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4819 /* Set the new flags */
4820 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4821 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4822 State
->Flags
.AlwaysSet
= TRUE
;
4824 /* Set additional flags */
4825 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4826 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4828 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4830 /* Update the CPL */
4831 Cpl
= Fast486GetCurrentPrivLevel(State
);
4833 /* Check segment security */
4834 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4836 /* Don't check CS or SS */
4837 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4839 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4840 && (!State
->SegmentRegs
[i
].Executable
4841 || !State
->SegmentRegs
[i
].DirConf
))
4843 /* Load the NULL descriptor in the segment */
4844 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4851 if (Size
&& (InstPtr
& 0xFFFF0000))
4854 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4859 State
->InstPtr
.Long
= InstPtr
;
4862 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4864 /* Exception occurred */
4868 /* Set the new flags */
4869 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4870 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4871 State
->Flags
.AlwaysSet
= TRUE
;
4877 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4880 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4884 /* Fetch the base */
4885 if (!Fast486FetchByte(State
, &Base
))
4887 /* Exception occurred */
4891 /* Check if the base is zero */
4895 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4900 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4901 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4904 State
->Flags
.Af
= FALSE
;
4905 State
->Flags
.Zf
= (Value
== 0);
4906 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4907 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4912 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4915 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4919 /* Fetch the base */
4920 if (!Fast486FetchByte(State
, &Base
))
4922 /* Exception occurred */
4927 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4928 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4931 State
->Flags
.Af
= FALSE
;
4932 State
->Flags
.Zf
= (Value
== 0);
4933 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4934 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4939 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4942 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4944 TOGGLE_ADSIZE(AddressSize
);
4946 /* Read a byte from DS:[(E)BX + AL] */
4947 if (!Fast486ReadMemory(State
,
4948 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4949 ? State
->SegmentOverride
: FAST486_REG_DS
,
4950 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4951 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4952 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4957 /* Exception occurred */
4961 /* Set AL to the result */
4962 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4964 /* Return success */
4968 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4971 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4974 /* Make sure this is the right instruction */
4975 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4978 TOGGLE_ADSIZE(Size
);
4980 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4981 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4985 /* Additional rule for LOOPNZ */
4986 if (State
->Flags
.Zf
) Condition
= FALSE
;
4991 /* Additional rule for LOOPZ */
4992 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4995 /* Fetch the offset */
4996 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4998 /* An exception occurred */
5004 /* Move the instruction pointer */
5005 if (Size
) State
->InstPtr
.Long
+= Offset
;
5006 else State
->InstPtr
.LowWord
+= Offset
;
5012 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5015 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5018 /* Make sure this is the right instruction */
5019 ASSERT(Opcode
== 0xE3);
5022 TOGGLE_ADSIZE(Size
);
5024 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5025 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5027 /* Fetch the offset */
5028 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5030 /* An exception occurred */
5036 /* Move the instruction pointer */
5037 if (Size
) State
->InstPtr
.Long
+= Offset
;
5038 else State
->InstPtr
.LowWord
+= Offset
;
5044 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5046 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5048 /* Make sure this is the right instruction */
5049 ASSERT(Opcode
== 0xE8);
5051 TOGGLE_OPSIZE(Size
);
5058 /* Fetch the offset */
5059 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5061 /* An exception occurred */
5065 /* Push the current value of the instruction pointer */
5066 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5068 /* Exception occurred */
5072 /* Move the instruction pointer */
5073 State
->InstPtr
.Long
+= Offset
;
5079 /* Fetch the offset */
5080 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5082 /* An exception occurred */
5086 /* Push the current value of the instruction pointer */
5087 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5089 /* Exception occurred */
5093 /* Move the instruction pointer */
5094 State
->InstPtr
.LowWord
+= Offset
;
5100 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5102 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5104 /* Make sure this is the right instruction */
5105 ASSERT(Opcode
== 0xE9);
5107 TOGGLE_OPSIZE(Size
);
5114 /* Fetch the offset */
5115 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5117 /* An exception occurred */
5121 /* Move the instruction pointer */
5122 State
->InstPtr
.Long
+= Offset
;
5128 /* Fetch the offset */
5129 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5131 /* An exception occurred */
5135 /* Move the instruction pointer */
5136 State
->InstPtr
.Long
+= Offset
;
5138 /* Clear the top half of EIP */
5139 State
->InstPtr
.Long
&= 0xFFFF;
5145 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5149 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5151 /* Make sure this is the right instruction */
5152 ASSERT(Opcode
== 0xEA);
5154 TOGGLE_OPSIZE(Size
);
5157 /* Fetch the offset */
5160 if (!Fast486FetchDword(State
, &Offset
))
5162 /* Exception occurred */
5168 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5170 /* Exception occurred */
5175 /* Fetch the segment */
5176 if (!Fast486FetchWord(State
, &Segment
))
5178 /* Exception occurred */
5182 /* Load the new CS */
5183 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5185 /* Exception occurred */
5190 State
->InstPtr
.Long
= Offset
;
5195 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5197 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5200 /* Make sure this is the right instruction */
5201 ASSERT(Opcode
== 0xA0);
5203 TOGGLE_ADSIZE(AddressSize
);
5207 if (!Fast486FetchDword(State
, &Offset
))
5209 /* Exception occurred */
5217 if (!Fast486FetchWord(State
, &WordOffset
))
5219 /* Exception occurred */
5223 Offset
= (ULONG
)WordOffset
;
5226 /* Read from memory */
5227 return Fast486ReadMemory(State
,
5228 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5229 State
->SegmentOverride
: FAST486_REG_DS
,
5232 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5236 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5238 BOOLEAN OperandSize
, AddressSize
;
5240 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5242 /* Make sure this is the right instruction */
5243 ASSERT(Opcode
== 0xA1);
5245 TOGGLE_OPSIZE(OperandSize
);
5246 TOGGLE_ADSIZE(AddressSize
);
5252 if (!Fast486FetchDword(State
, &Offset
))
5254 /* Exception occurred */
5258 /* Read from memory */
5261 return Fast486ReadMemory(State
,
5262 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5263 State
->SegmentOverride
: FAST486_REG_DS
,
5266 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5271 return Fast486ReadMemory(State
,
5272 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5273 State
->SegmentOverride
: FAST486_REG_DS
,
5276 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5284 if (!Fast486FetchWord(State
, &Offset
))
5286 /* Exception occurred */
5290 /* Read from memory */
5293 return Fast486ReadMemory(State
,
5294 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5295 State
->SegmentOverride
: FAST486_REG_DS
,
5298 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5303 return Fast486ReadMemory(State
,
5304 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5305 State
->SegmentOverride
: FAST486_REG_DS
,
5308 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5314 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5316 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5319 /* Make sure this is the right instruction */
5320 ASSERT(Opcode
== 0xA2);
5322 TOGGLE_ADSIZE(AddressSize
);
5326 if (!Fast486FetchDword(State
, &Offset
))
5328 /* Exception occurred */
5336 if (!Fast486FetchWord(State
, &WordOffset
))
5338 /* Exception occurred */
5342 Offset
= (ULONG
)WordOffset
;
5345 /* Write to memory */
5346 return Fast486WriteMemory(State
,
5347 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5348 State
->SegmentOverride
: FAST486_REG_DS
,
5350 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5354 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5356 BOOLEAN OperandSize
, AddressSize
;
5358 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5360 /* Make sure this is the right instruction */
5361 ASSERT(Opcode
== 0xA3);
5363 TOGGLE_OPSIZE(OperandSize
);
5364 TOGGLE_ADSIZE(AddressSize
);
5370 if (!Fast486FetchDword(State
, &Offset
))
5372 /* Exception occurred */
5376 /* Write to memory */
5379 return Fast486WriteMemory(State
,
5380 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5381 State
->SegmentOverride
: FAST486_REG_DS
,
5383 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5388 return Fast486WriteMemory(State
,
5389 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5390 State
->SegmentOverride
: FAST486_REG_DS
,
5392 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5400 if (!Fast486FetchWord(State
, &Offset
))
5402 /* Exception occurred */
5406 /* Write to memory */
5409 return Fast486WriteMemory(State
,
5410 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5411 State
->SegmentOverride
: FAST486_REG_DS
,
5413 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5418 return Fast486WriteMemory(State
,
5419 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5420 State
->SegmentOverride
: FAST486_REG_DS
,
5422 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5428 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5431 * See: http://www.rcollins.org/secrets/opcodes/SALC.html
5432 * for more information.
5435 /* Make sure this is the right instruction */
5436 ASSERT(Opcode
== 0xD6);
5440 /* Set all the bits of AL to CF */
5441 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5446 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5448 ULONG Data
, DataSize
;
5449 BOOLEAN OperandSize
, AddressSize
;
5450 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5452 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5454 /* Make sure this is the right instruction */
5455 ASSERT((Opcode
& 0xFE) == 0xA4);
5457 TOGGLE_OPSIZE(OperandSize
);
5458 TOGGLE_ADSIZE(AddressSize
);
5460 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5462 /* Use the override segment instead of DS */
5463 Segment
= State
->SegmentOverride
;
5466 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5468 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5469 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5476 /* Calculate the size */
5477 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5478 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5480 /* Read from the source operand */
5481 if (!Fast486ReadMemory(State
,
5483 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5484 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5489 /* Exception occurred */
5493 /* Write to the destination operand */
5494 if (!Fast486WriteMemory(State
,
5496 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5497 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5501 /* Exception occurred */
5505 /* Increment/decrement ESI and EDI */
5508 if (!State
->Flags
.Df
)
5510 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5511 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5515 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5516 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5521 if (!State
->Flags
.Df
)
5523 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5524 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5528 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5529 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5533 // FIXME: This method is slow!
5534 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5538 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5540 /* Repeat the instruction */
5541 State
->InstPtr
= State
->SavedInstPtr
;
5546 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5548 /* Repeat the instruction */
5549 State
->InstPtr
= State
->SavedInstPtr
;
5554 /* Return success */
5558 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5560 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5561 ULONG DataSize
, DataMask
, SignFlag
;
5562 BOOLEAN OperandSize
, AddressSize
;
5563 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5565 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5567 /* Make sure this is the right instruction */
5568 ASSERT((Opcode
& 0xFE) == 0xA6);
5570 TOGGLE_OPSIZE(OperandSize
);
5571 TOGGLE_ADSIZE(AddressSize
);
5573 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5575 /* Use the override segment instead of DS */
5576 Segment
= State
->SegmentOverride
;
5579 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5580 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5582 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5583 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5590 /* Calculate the size */
5591 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5592 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5594 /* Calculate the mask and sign flag */
5595 SignFlag
= 1 << ((DataSize
* 8) - 1);
5596 DataMask
= SignFlag
| (SignFlag
- 1);
5598 /* Read from the first source operand */
5599 if (!Fast486ReadMemory(State
,
5601 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5602 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5607 /* Exception occurred */
5611 /* Read from the second source operand */
5612 if (!Fast486ReadMemory(State
,
5614 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5615 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5620 /* Exception occurred */
5624 /* Calculate the result */
5625 FirstValue
&= DataMask
;
5626 SecondValue
&= DataMask
;
5627 Result
= (FirstValue
- SecondValue
) & DataMask
;
5629 /* Update the flags */
5630 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5631 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5632 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5633 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5634 State
->Flags
.Zf
= (Result
== 0);
5635 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5636 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5638 /* Increment/decrement ESI and EDI */
5641 if (!State
->Flags
.Df
)
5643 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5644 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5648 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5649 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5654 if (!State
->Flags
.Df
)
5656 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5657 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5661 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5662 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5666 // FIXME: This method is slow!
5667 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5668 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5670 BOOLEAN Repeat
= TRUE
;
5674 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5682 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5689 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5690 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5692 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5698 /* Repeat the instruction */
5699 State
->InstPtr
= State
->SavedInstPtr
;
5703 /* Return success */
5707 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5710 BOOLEAN OperandSize
, AddressSize
;
5712 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5714 /* Make sure this is the right instruction */
5715 ASSERT((Opcode
& 0xFE) == 0xAA);
5717 TOGGLE_OPSIZE(OperandSize
);
5718 TOGGLE_ADSIZE(AddressSize
);
5720 /* Calculate the size */
5721 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5722 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5724 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5726 UCHAR Block
[STRING_BLOCK_SIZE
];
5727 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5728 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5730 /* Fill the memory block with the data */
5731 if (DataSize
== sizeof(UCHAR
))
5733 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5739 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5741 if (DataSize
== sizeof(USHORT
))
5743 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5747 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5752 /* Transfer until finished */
5755 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5757 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5760 ULONG MaxBytes
= State
->Flags
.Df
5761 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5762 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5764 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5765 if (Processed
== 0) Processed
= 1;
5768 if (State
->Flags
.Df
)
5770 /* Set EDI to the starting location */
5771 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5772 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5775 /* Write to memory */
5776 if (!Fast486WriteMemory(State
,
5778 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5779 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5781 Processed
* DataSize
))
5784 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5785 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5787 /* Exception occurred */
5791 if (!State
->Flags
.Df
)
5793 /* Increase EDI by the number of bytes transfered */
5794 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5795 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5800 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5801 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5804 /* Reduce the total count by the number processed in this run */
5809 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5810 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5814 /* Write to the destination operand */
5815 if (!Fast486WriteMemory(State
,
5817 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5818 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5819 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5822 /* Exception occurred */
5826 /* Increment/decrement EDI */
5829 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5830 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5834 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5835 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5839 /* Return success */
5843 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5846 BOOLEAN OperandSize
, AddressSize
;
5847 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5849 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5851 /* Make sure this is the right instruction */
5852 ASSERT((Opcode
& 0xFE) == 0xAC);
5854 TOGGLE_OPSIZE(OperandSize
);
5855 TOGGLE_ADSIZE(AddressSize
);
5857 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5859 /* Use the override segment instead of DS */
5860 Segment
= State
->SegmentOverride
;
5863 /* Calculate the size */
5864 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5865 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5867 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5869 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5870 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5872 /* If the count is 0, do nothing */
5873 if (Count
== 0) return TRUE
;
5875 /* Only the last entry will be loaded */
5876 if (!State
->Flags
.Df
)
5878 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5879 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5883 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5884 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5888 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5889 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5892 /* Read from the source operand */
5893 if (!Fast486ReadMemory(State
,
5895 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5896 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5898 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5901 /* Exception occurred */
5905 /* Increment/decrement ESI */
5908 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5909 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5913 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5914 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5917 /* Return success */
5921 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5923 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5924 ULONG SecondValue
= 0;
5926 ULONG DataSize
, DataMask
, SignFlag
;
5927 BOOLEAN OperandSize
, AddressSize
;
5929 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5931 /* Make sure this is the right instruction */
5932 ASSERT((Opcode
& 0xFE) == 0xAE);
5934 TOGGLE_OPSIZE(OperandSize
);
5935 TOGGLE_ADSIZE(AddressSize
);
5937 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5938 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5940 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5941 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5948 /* Calculate the size */
5949 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5950 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5952 /* Calculate the mask and sign flag */
5953 SignFlag
= 1 << ((DataSize
* 8) - 1);
5954 DataMask
= SignFlag
| (SignFlag
- 1);
5956 /* Read from the source operand */
5957 if (!Fast486ReadMemory(State
,
5959 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5960 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5965 /* Exception occurred */
5969 /* Calculate the result */
5970 FirstValue
&= DataMask
;
5971 SecondValue
&= DataMask
;
5972 Result
= (FirstValue
- SecondValue
) & DataMask
;
5974 /* Update the flags */
5975 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5976 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5977 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5978 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5979 State
->Flags
.Zf
= (Result
== 0);
5980 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5981 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5983 /* Increment/decrement EDI */
5986 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5987 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5991 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5992 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5995 // FIXME: This method is slow!
5996 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5997 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5999 BOOLEAN Repeat
= TRUE
;
6003 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6011 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6018 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6019 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6021 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6027 /* Repeat the instruction */
6028 State
->InstPtr
= State
->SavedInstPtr
;
6032 /* Return success */
6036 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6039 BOOLEAN OperandSize
, AddressSize
;
6041 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6043 /* Make sure this is the right instruction */
6044 ASSERT((Opcode
& 0xFE) == 0x6C);
6046 TOGGLE_OPSIZE(OperandSize
);
6047 TOGGLE_ADSIZE(AddressSize
);
6049 /* Calculate the size */
6050 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6051 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6053 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6055 UCHAR Block
[STRING_BLOCK_SIZE
];
6056 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6057 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6059 /* Clear the memory block */
6060 RtlZeroMemory(Block
, sizeof(Block
));
6062 /* Transfer until finished */
6065 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6067 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6070 ULONG MaxBytes
= State
->Flags
.Df
6071 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6072 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6074 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6075 if (Processed
== 0) Processed
= 1;
6078 /* Read from the I/O port */
6079 State
->IoReadCallback(State
,
6080 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6085 if (State
->Flags
.Df
)
6089 /* Reduce EDI by the number of bytes to transfer */
6090 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6091 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6093 /* Reverse the block data */
6094 for (i
= 0; i
< Processed
/ 2; i
++)
6096 /* Swap the values */
6097 for (j
= 0; j
< DataSize
; j
++)
6099 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6100 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6101 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6106 /* Write to memory */
6107 if (!Fast486WriteMemory(State
,
6109 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6110 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6112 Processed
* DataSize
))
6115 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6116 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6118 /* Exception occurred */
6122 if (!State
->Flags
.Df
)
6124 /* Increase EDI by the number of bytes transfered */
6125 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6126 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6129 /* Reduce the total count by the number processed in this run */
6134 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6135 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6141 /* Read from the I/O port */
6142 State
->IoReadCallback(State
,
6143 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6148 /* Write to the destination operand */
6149 if (!Fast486WriteMemory(State
,
6151 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6152 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6156 /* Exception occurred */
6160 /* Increment/decrement EDI */
6163 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6164 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6168 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6169 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6173 /* Return success */
6177 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6180 BOOLEAN OperandSize
, AddressSize
;
6182 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6184 /* Make sure this is the right instruction */
6185 ASSERT((Opcode
& 0xFE) == 0x6E);
6187 TOGGLE_OPSIZE(OperandSize
);
6188 TOGGLE_ADSIZE(AddressSize
);
6190 /* Calculate the size */
6191 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6192 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6194 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6196 UCHAR Block
[STRING_BLOCK_SIZE
];
6197 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6198 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6200 /* Clear the memory block */
6201 RtlZeroMemory(Block
, sizeof(Block
));
6203 /* Transfer until finished */
6206 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6208 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6211 ULONG MaxBytes
= State
->Flags
.Df
6212 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
6213 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
6215 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6216 if (Processed
== 0) Processed
= 1;
6219 /* Read from memory */
6220 if (!Fast486ReadMemory(State
,
6221 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6222 ? State
->SegmentOverride
: FAST486_REG_DS
,
6223 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6224 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6227 Processed
* DataSize
))
6230 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6231 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6233 /* Exception occurred */
6237 if (State
->Flags
.Df
)
6241 /* Reduce ESI by the number of bytes to transfer */
6242 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
6243 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
6245 /* Reverse the block data */
6246 for (i
= 0; i
< Processed
/ 2; i
++)
6248 /* Swap the values */
6249 for (j
= 0; j
< DataSize
; j
++)
6251 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6252 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6253 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6258 /* Write to the I/O port */
6259 State
->IoWriteCallback(State
,
6260 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6265 if (!State
->Flags
.Df
)
6267 /* Increase ESI by the number of bytes transfered */
6268 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
6269 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
6272 /* Reduce the total count by the number processed in this run */
6277 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6278 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6284 /* Read from the source operand */
6285 if (!Fast486ReadMemory(State
,
6286 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6287 ? State
->SegmentOverride
: FAST486_REG_DS
,
6288 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6289 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6294 /* Exception occurred */
6298 /* Write to the I/O port */
6299 State
->IoWriteCallback(State
,
6300 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6305 /* Increment/decrement ESI */
6308 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6309 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6313 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6314 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6318 /* Return success */