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
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
)
303 /* This is not a valid opcode */
304 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
308 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
310 BOOLEAN Valid
= FALSE
;
317 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
319 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
320 State
->SegmentOverride
= FAST486_REG_ES
;
330 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
332 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
333 State
->SegmentOverride
= FAST486_REG_CS
;
343 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
345 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
346 State
->SegmentOverride
= FAST486_REG_SS
;
356 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
358 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
359 State
->SegmentOverride
= FAST486_REG_DS
;
369 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
371 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
372 State
->SegmentOverride
= FAST486_REG_FS
;
382 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
384 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
385 State
->SegmentOverride
= FAST486_REG_GS
;
395 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
397 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
407 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
409 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
418 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
420 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
430 /* Mutually exclusive with REP */
431 if (!(State
->PrefixFlags
432 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
434 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
444 /* Mutually exclusive with REPNZ */
445 if (!(State
->PrefixFlags
446 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
448 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
458 /* Clear all prefixes */
459 State
->PrefixFlags
= 0;
461 /* Throw an exception */
462 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
469 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
472 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
477 /* Make sure this is the right instruction */
478 ASSERT((Opcode
& 0xF8) == 0x40);
482 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
484 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
485 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
489 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
491 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
492 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
495 State
->Flags
.Zf
= (Value
== 0);
496 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
497 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
503 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
506 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
511 /* Make sure this is the right instruction */
512 ASSERT((Opcode
& 0xF8) == 0x48);
516 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
518 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
519 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
523 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
525 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
526 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
529 State
->Flags
.Zf
= (Value
== 0);
530 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
531 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
537 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
541 /* Make sure this is the right instruction */
542 ASSERT((Opcode
& 0xF8) == 0x50);
544 /* Call the internal function */
545 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
548 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
551 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
556 /* Make sure this is the right instruction */
557 ASSERT((Opcode
& 0xF8) == 0x58);
559 /* Call the internal function */
560 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
562 /* Store the value */
563 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
564 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
570 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
572 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
575 State
->IdleCallback(State
);
581 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
583 INT Reg
= Opcode
& 0x07;
584 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
589 /* Make sure this is the right instruction */
590 ASSERT((Opcode
& 0xF8) == 0x90);
592 /* Exchange the values */
597 Value
= State
->GeneralRegs
[Reg
].Long
;
598 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
599 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
605 Value
= State
->GeneralRegs
[Reg
].LowWord
;
606 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
607 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
613 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
615 BOOLEAN Jump
= FALSE
;
617 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
619 /* Make sure this is the right instruction */
620 ASSERT((Opcode
& 0xF0) == 0x70);
624 /* Fetch the offset */
625 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
627 /* An exception occurred */
631 switch ((Opcode
& 0x0F) >> 1)
636 Jump
= State
->Flags
.Of
;
643 Jump
= State
->Flags
.Cf
;
650 Jump
= State
->Flags
.Zf
;
657 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
664 Jump
= State
->Flags
.Sf
;
671 Jump
= State
->Flags
.Pf
;
678 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
685 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
692 /* Invert the result */
698 /* Move the instruction pointer */
699 State
->InstPtr
.Long
+= Offset
;
703 /* Clear the top half of EIP */
704 State
->InstPtr
.Long
&= 0xFFFF;
712 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
714 /* Make sure this is the right instruction */
715 ASSERT(Opcode
== 0xF8);
717 /* No prefixes allowed */
718 if (State
->PrefixFlags
)
720 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
724 /* Clear CF and return success */
725 State
->Flags
.Cf
= FALSE
;
729 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
731 /* Make sure this is the right instruction */
732 ASSERT(Opcode
== 0xF9);
734 /* No prefixes allowed */
735 if (State
->PrefixFlags
)
737 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
741 /* Set CF and return success*/
742 State
->Flags
.Cf
= TRUE
;
746 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
748 /* Make sure this is the right instruction */
749 ASSERT(Opcode
== 0xF5);
751 /* No prefixes allowed */
752 if (State
->PrefixFlags
)
754 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
758 /* Toggle CF and return success */
759 State
->Flags
.Cf
= !State
->Flags
.Cf
;
763 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
765 /* Make sure this is the right instruction */
766 ASSERT(Opcode
== 0xFA);
768 /* No prefixes allowed */
769 if (State
->PrefixFlags
)
771 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
775 /* Check for protected mode */
776 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
779 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
781 /* Clear the interrupt flag */
782 State
->Flags
.If
= FALSE
;
786 /* General Protection Fault */
787 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
793 /* Just clear the interrupt flag */
794 State
->Flags
.If
= FALSE
;
801 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
803 /* Make sure this is the right instruction */
804 ASSERT(Opcode
== 0xFB);
806 /* No prefixes allowed */
807 if (State
->PrefixFlags
)
809 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
813 /* Check for protected mode */
814 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
817 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
819 /* Set the interrupt flag */
820 State
->Flags
.If
= TRUE
;
824 /* General Protection Fault */
825 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
831 /* Just set the interrupt flag */
832 State
->Flags
.If
= TRUE
;
839 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
841 /* Make sure this is the right instruction */
842 ASSERT(Opcode
== 0xFC);
844 /* No prefixes allowed */
845 if (State
->PrefixFlags
)
847 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
851 /* Clear DF and return success */
852 State
->Flags
.Df
= FALSE
;
856 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
858 /* Make sure this is the right instruction */
859 ASSERT(Opcode
== 0xFD);
861 /* No prefixes allowed */
862 if (State
->PrefixFlags
)
864 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
868 /* Set DF and return success*/
869 State
->Flags
.Df
= TRUE
;
873 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
875 /* Make sure this is the right instruction */
876 ASSERT(Opcode
== 0xF4);
878 /* No prefixes allowed */
879 if (State
->PrefixFlags
)
881 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
885 /* Privileged instructions can only be executed under CPL = 0 */
886 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
888 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
893 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
899 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
904 /* Make sure this is the right instruction */
905 ASSERT((Opcode
& 0xF7) == 0xE4);
909 /* Fetch the parameter */
910 if (!Fast486FetchByte(State
, &Data
))
912 /* Exception occurred */
916 /* Set the port number to the parameter */
921 /* The port number is in DX */
922 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
925 /* Read a byte from the I/O port */
926 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
928 /* Store the result in AL */
929 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
934 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
937 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
939 /* Make sure this is the right instruction */
940 ASSERT((Opcode
& 0xF7) == 0xE5);
949 /* Fetch the parameter */
950 if (!Fast486FetchByte(State
, &Data
))
952 /* Exception occurred */
956 /* Set the port number to the parameter */
961 /* The port number is in DX */
962 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
969 /* Read a dword from the I/O port */
970 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
972 /* Store the value in EAX */
973 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
979 /* Read a word from the I/O port */
980 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
982 /* Store the value in AX */
983 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
989 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
994 /* Make sure this is the right instruction */
995 ASSERT((Opcode
& 0xF7) == 0xE6);
999 /* Fetch the parameter */
1000 if (!Fast486FetchByte(State
, &Data
))
1002 /* Exception occurred */
1006 /* Set the port number to the parameter */
1011 /* The port number is in DX */
1012 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1015 /* Read the value from AL */
1016 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1018 /* Write the byte to the I/O port */
1019 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
1024 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1027 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1029 /* Make sure this is the right instruction */
1030 ASSERT((Opcode
& 0xF7) == 0xE7);
1032 TOGGLE_OPSIZE(Size
);
1039 /* Fetch the parameter */
1040 if (!Fast486FetchByte(State
, &Data
))
1042 /* Exception occurred */
1046 /* Set the port number to the parameter */
1051 /* The port number is in DX */
1052 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1057 /* Get the value from EAX */
1058 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1060 /* Write a dword to the I/O port */
1061 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1065 /* Get the value from AX */
1066 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1068 /* Write a word to the I/O port */
1069 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1075 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1078 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1080 TOGGLE_OPSIZE(Size
);
1082 /* Make sure this is the right instruction */
1083 ASSERT(Opcode
== 0xEB);
1085 /* Fetch the offset */
1086 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1088 /* An exception occurred */
1092 /* Move the instruction pointer */
1093 State
->InstPtr
.Long
+= Offset
;
1097 /* Clear the top half of EIP */
1098 State
->InstPtr
.Long
&= 0xFFFF;
1104 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1106 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1108 /* Make sure this is the right instruction */
1109 ASSERT((Opcode
& 0xF8) == 0xB8);
1111 TOGGLE_OPSIZE(Size
);
1118 /* Fetch the dword */
1119 if (!Fast486FetchDword(State
, &Value
))
1121 /* Exception occurred */
1125 /* Store the value in the register */
1126 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1132 /* Fetch the word */
1133 if (!Fast486FetchWord(State
, &Value
))
1135 /* Exception occurred */
1139 /* Store the value in the register */
1140 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1146 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1150 /* Make sure this is the right instruction */
1151 ASSERT((Opcode
& 0xF8) == 0xB0);
1153 if (State
->PrefixFlags
!= 0)
1155 /* Invalid prefix */
1156 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1160 /* Fetch the byte */
1161 if (!Fast486FetchByte(State
, &Value
))
1163 /* Exception occurred */
1169 /* AH, CH, DH or BH */
1170 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1174 /* AL, CL, DL or BL */
1175 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1181 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1183 UCHAR FirstValue
, SecondValue
, Result
;
1184 FAST486_MOD_REG_RM ModRegRm
;
1185 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1187 /* Make sure this is the right instruction */
1188 ASSERT((Opcode
& 0xFD) == 0x00);
1190 TOGGLE_ADSIZE(AddressSize
);
1192 /* Get the operands */
1193 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1195 /* Exception occurred */
1199 if (!Fast486ReadModrmByteOperands(State
,
1204 /* Exception occurred */
1208 /* Calculate the result */
1209 Result
= FirstValue
+ SecondValue
;
1211 /* Update the flags */
1212 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1213 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1214 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1215 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1216 State
->Flags
.Zf
= (Result
== 0);
1217 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1218 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1220 /* Write back the result */
1221 return Fast486WriteModrmByteOperands(State
,
1223 Opcode
& FAST486_OPCODE_WRITE_REG
,
1227 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1229 FAST486_MOD_REG_RM ModRegRm
;
1230 BOOLEAN OperandSize
, AddressSize
;
1232 /* Make sure this is the right instruction */
1233 ASSERT((Opcode
& 0xFD) == 0x01);
1235 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1237 TOGGLE_ADSIZE(AddressSize
);
1238 TOGGLE_OPSIZE(OperandSize
);
1240 /* Get the operands */
1241 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1243 /* Exception occurred */
1247 /* Check the operand size */
1250 ULONG FirstValue
, SecondValue
, Result
;
1252 if (!Fast486ReadModrmDwordOperands(State
,
1257 /* Exception occurred */
1261 /* Calculate the result */
1262 Result
= FirstValue
+ SecondValue
;
1264 /* Update the flags */
1265 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1266 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1267 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1268 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1269 State
->Flags
.Zf
= (Result
== 0);
1270 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1271 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1273 /* Write back the result */
1274 return Fast486WriteModrmDwordOperands(State
,
1276 Opcode
& FAST486_OPCODE_WRITE_REG
,
1281 USHORT FirstValue
, SecondValue
, Result
;
1283 if (!Fast486ReadModrmWordOperands(State
,
1288 /* Exception occurred */
1292 /* Calculate the result */
1293 Result
= FirstValue
+ SecondValue
;
1295 /* Update the flags */
1296 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1297 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1298 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1299 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1300 State
->Flags
.Zf
= (Result
== 0);
1301 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1302 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1304 /* Write back the result */
1305 return Fast486WriteModrmWordOperands(State
,
1307 Opcode
& FAST486_OPCODE_WRITE_REG
,
1312 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1314 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1315 UCHAR SecondValue
, Result
;
1317 /* Make sure this is the right instruction */
1318 ASSERT(Opcode
== 0x04);
1320 if (State
->PrefixFlags
)
1322 /* This opcode doesn't take any prefixes */
1323 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1327 if (!Fast486FetchByte(State
, &SecondValue
))
1329 /* Exception occurred */
1333 /* Calculate the result */
1334 Result
= FirstValue
+ SecondValue
;
1336 /* Update the flags */
1337 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1338 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1339 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1340 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1341 State
->Flags
.Zf
= (Result
== 0);
1342 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1343 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1345 /* Write back the result */
1346 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1351 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1353 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1355 /* Make sure this is the right instruction */
1356 ASSERT(Opcode
== 0x05);
1359 TOGGLE_OPSIZE(Size
);
1363 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1364 ULONG SecondValue
, Result
;
1366 if (!Fast486FetchDword(State
, &SecondValue
))
1368 /* Exception occurred */
1372 /* Calculate the result */
1373 Result
= FirstValue
+ SecondValue
;
1375 /* Update the flags */
1376 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1377 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1378 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1379 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1380 State
->Flags
.Zf
= (Result
== 0);
1381 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1382 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1384 /* Write back the result */
1385 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1389 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1390 USHORT SecondValue
, Result
;
1392 if (!Fast486FetchWord(State
, &SecondValue
))
1394 /* Exception occurred */
1398 /* Calculate the result */
1399 Result
= FirstValue
+ SecondValue
;
1401 /* Update the flags */
1402 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1403 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1404 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1405 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1406 State
->Flags
.Zf
= (Result
== 0);
1407 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1408 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1410 /* Write back the result */
1411 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1417 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1419 UCHAR FirstValue
, SecondValue
, Result
;
1420 FAST486_MOD_REG_RM ModRegRm
;
1421 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1423 /* Make sure this is the right instruction */
1424 ASSERT((Opcode
& 0xFD) == 0x08);
1426 TOGGLE_ADSIZE(AddressSize
);
1428 /* Get the operands */
1429 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1431 /* Exception occurred */
1435 if (!Fast486ReadModrmByteOperands(State
,
1440 /* Exception occurred */
1444 /* Calculate the result */
1445 Result
= FirstValue
| SecondValue
;
1447 /* Update the flags */
1448 State
->Flags
.Cf
= FALSE
;
1449 State
->Flags
.Of
= FALSE
;
1450 State
->Flags
.Zf
= (Result
== 0);
1451 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1452 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1454 /* Write back the result */
1455 return Fast486WriteModrmByteOperands(State
,
1457 Opcode
& FAST486_OPCODE_WRITE_REG
,
1461 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1463 FAST486_MOD_REG_RM ModRegRm
;
1464 BOOLEAN OperandSize
, AddressSize
;
1466 /* Make sure this is the right instruction */
1467 ASSERT((Opcode
& 0xFD) == 0x09);
1469 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1471 TOGGLE_ADSIZE(AddressSize
);
1472 TOGGLE_OPSIZE(OperandSize
);
1474 /* Get the operands */
1475 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1477 /* Exception occurred */
1481 /* Check the operand size */
1484 ULONG FirstValue
, SecondValue
, Result
;
1486 if (!Fast486ReadModrmDwordOperands(State
,
1491 /* Exception occurred */
1495 /* Calculate the result */
1496 Result
= FirstValue
| SecondValue
;
1498 /* Update the flags */
1499 State
->Flags
.Cf
= FALSE
;
1500 State
->Flags
.Of
= FALSE
;
1501 State
->Flags
.Zf
= (Result
== 0);
1502 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1503 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1505 /* Write back the result */
1506 return Fast486WriteModrmDwordOperands(State
,
1508 Opcode
& FAST486_OPCODE_WRITE_REG
,
1513 USHORT FirstValue
, SecondValue
, Result
;
1515 if (!Fast486ReadModrmWordOperands(State
,
1520 /* Exception occurred */
1524 /* Calculate the result */
1525 Result
= FirstValue
| SecondValue
;
1527 /* Update the flags */
1528 State
->Flags
.Cf
= FALSE
;
1529 State
->Flags
.Of
= FALSE
;
1530 State
->Flags
.Zf
= (Result
== 0);
1531 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1532 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1534 /* Write back the result */
1535 return Fast486WriteModrmWordOperands(State
,
1537 Opcode
& FAST486_OPCODE_WRITE_REG
,
1542 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1544 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1545 UCHAR SecondValue
, Result
;
1547 /* Make sure this is the right instruction */
1548 ASSERT(Opcode
== 0x0C);
1550 if (State
->PrefixFlags
)
1552 /* This opcode doesn't take any prefixes */
1553 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1557 if (!Fast486FetchByte(State
, &SecondValue
))
1559 /* Exception occurred */
1563 /* Calculate the result */
1564 Result
= FirstValue
| SecondValue
;
1566 /* Update the flags */
1567 State
->Flags
.Cf
= FALSE
;
1568 State
->Flags
.Of
= FALSE
;
1569 State
->Flags
.Zf
= (Result
== 0);
1570 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1571 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1573 /* Write back the result */
1574 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1579 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1581 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1583 /* Make sure this is the right instruction */
1584 ASSERT(Opcode
== 0x0D);
1587 TOGGLE_OPSIZE(Size
);
1591 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1592 ULONG SecondValue
, Result
;
1594 if (!Fast486FetchDword(State
, &SecondValue
))
1596 /* Exception occurred */
1600 /* Calculate the result */
1601 Result
= FirstValue
| SecondValue
;
1603 /* Update the flags */
1604 State
->Flags
.Cf
= FALSE
;
1605 State
->Flags
.Of
= FALSE
;
1606 State
->Flags
.Zf
= (Result
== 0);
1607 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1608 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1610 /* Write back the result */
1611 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1615 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1616 USHORT SecondValue
, Result
;
1618 if (!Fast486FetchWord(State
, &SecondValue
))
1620 /* Exception occurred */
1624 /* Calculate the result */
1625 Result
= FirstValue
| SecondValue
;
1627 /* Update the flags */
1628 State
->Flags
.Cf
= FALSE
;
1629 State
->Flags
.Of
= FALSE
;
1630 State
->Flags
.Zf
= (Result
== 0);
1631 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1632 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1634 /* Write back the result */
1635 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1641 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1643 UCHAR FirstValue
, SecondValue
, Result
;
1644 FAST486_MOD_REG_RM ModRegRm
;
1645 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1647 /* Make sure this is the right instruction */
1648 ASSERT((Opcode
& 0xFD) == 0x20);
1650 TOGGLE_ADSIZE(AddressSize
);
1652 /* Get the operands */
1653 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1655 /* Exception occurred */
1659 if (!Fast486ReadModrmByteOperands(State
,
1664 /* Exception occurred */
1668 /* Calculate the result */
1669 Result
= FirstValue
& SecondValue
;
1671 /* Update the flags */
1672 State
->Flags
.Cf
= FALSE
;
1673 State
->Flags
.Of
= FALSE
;
1674 State
->Flags
.Zf
= (Result
== 0);
1675 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1676 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1678 /* Write back the result */
1679 return Fast486WriteModrmByteOperands(State
,
1681 Opcode
& FAST486_OPCODE_WRITE_REG
,
1685 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1687 FAST486_MOD_REG_RM ModRegRm
;
1688 BOOLEAN OperandSize
, AddressSize
;
1690 /* Make sure this is the right instruction */
1691 ASSERT((Opcode
& 0xFD) == 0x21);
1693 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1695 TOGGLE_ADSIZE(AddressSize
);
1696 TOGGLE_OPSIZE(OperandSize
);
1698 /* Get the operands */
1699 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1701 /* Exception occurred */
1705 /* Check the operand size */
1708 ULONG FirstValue
, SecondValue
, Result
;
1710 if (!Fast486ReadModrmDwordOperands(State
,
1715 /* Exception occurred */
1719 /* Calculate the result */
1720 Result
= FirstValue
& SecondValue
;
1722 /* Update the flags */
1723 State
->Flags
.Cf
= FALSE
;
1724 State
->Flags
.Of
= FALSE
;
1725 State
->Flags
.Zf
= (Result
== 0);
1726 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1727 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1729 /* Write back the result */
1730 return Fast486WriteModrmDwordOperands(State
,
1732 Opcode
& FAST486_OPCODE_WRITE_REG
,
1737 USHORT FirstValue
, SecondValue
, Result
;
1739 if (!Fast486ReadModrmWordOperands(State
,
1744 /* Exception occurred */
1748 /* Calculate the result */
1749 Result
= FirstValue
& SecondValue
;
1751 /* Update the flags */
1752 State
->Flags
.Cf
= FALSE
;
1753 State
->Flags
.Of
= FALSE
;
1754 State
->Flags
.Zf
= (Result
== 0);
1755 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1756 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1758 /* Write back the result */
1759 return Fast486WriteModrmWordOperands(State
,
1761 Opcode
& FAST486_OPCODE_WRITE_REG
,
1766 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1768 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1769 UCHAR SecondValue
, Result
;
1771 /* Make sure this is the right instruction */
1772 ASSERT(Opcode
== 0x24);
1776 if (!Fast486FetchByte(State
, &SecondValue
))
1778 /* Exception occurred */
1782 /* Calculate the result */
1783 Result
= FirstValue
& SecondValue
;
1785 /* Update the flags */
1786 State
->Flags
.Cf
= FALSE
;
1787 State
->Flags
.Of
= FALSE
;
1788 State
->Flags
.Zf
= (Result
== 0);
1789 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1790 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1792 /* Write back the result */
1793 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1798 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1800 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1802 /* Make sure this is the right instruction */
1803 ASSERT(Opcode
== 0x25);
1806 TOGGLE_OPSIZE(Size
);
1810 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1811 ULONG SecondValue
, Result
;
1813 if (!Fast486FetchDword(State
, &SecondValue
))
1815 /* Exception occurred */
1819 /* Calculate the result */
1820 Result
= FirstValue
& SecondValue
;
1822 /* Update the flags */
1823 State
->Flags
.Cf
= FALSE
;
1824 State
->Flags
.Of
= FALSE
;
1825 State
->Flags
.Zf
= (Result
== 0);
1826 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1827 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1829 /* Write back the result */
1830 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1834 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1835 USHORT SecondValue
, Result
;
1837 if (!Fast486FetchWord(State
, &SecondValue
))
1839 /* Exception occurred */
1843 /* Calculate the result */
1844 Result
= FirstValue
& SecondValue
;
1846 /* Update the flags */
1847 State
->Flags
.Cf
= FALSE
;
1848 State
->Flags
.Of
= FALSE
;
1849 State
->Flags
.Zf
= (Result
== 0);
1850 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1851 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1853 /* Write back the result */
1854 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1860 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1862 UCHAR FirstValue
, SecondValue
, Result
;
1863 FAST486_MOD_REG_RM ModRegRm
;
1864 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1866 /* Make sure this is the right instruction */
1867 ASSERT((Opcode
& 0xFD) == 0x30);
1869 TOGGLE_ADSIZE(AddressSize
);
1871 /* Get the operands */
1872 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1874 /* Exception occurred */
1878 if (!Fast486ReadModrmByteOperands(State
,
1883 /* Exception occurred */
1887 /* Calculate the result */
1888 Result
= FirstValue
^ SecondValue
;
1890 /* Update the flags */
1891 State
->Flags
.Cf
= FALSE
;
1892 State
->Flags
.Of
= FALSE
;
1893 State
->Flags
.Zf
= (Result
== 0);
1894 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1895 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1897 /* Write back the result */
1898 return Fast486WriteModrmByteOperands(State
,
1900 Opcode
& FAST486_OPCODE_WRITE_REG
,
1904 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1906 FAST486_MOD_REG_RM ModRegRm
;
1907 BOOLEAN OperandSize
, AddressSize
;
1909 /* Make sure this is the right instruction */
1910 ASSERT((Opcode
& 0xFD) == 0x31);
1912 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1914 TOGGLE_ADSIZE(AddressSize
);
1915 TOGGLE_OPSIZE(OperandSize
);
1917 /* Get the operands */
1918 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1920 /* Exception occurred */
1924 /* Check the operand size */
1927 ULONG FirstValue
, SecondValue
, Result
;
1929 if (!Fast486ReadModrmDwordOperands(State
,
1934 /* Exception occurred */
1938 /* Calculate the result */
1939 Result
= FirstValue
^ SecondValue
;
1941 /* Update the flags */
1942 State
->Flags
.Cf
= FALSE
;
1943 State
->Flags
.Of
= FALSE
;
1944 State
->Flags
.Zf
= (Result
== 0);
1945 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1946 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1948 /* Write back the result */
1949 return Fast486WriteModrmDwordOperands(State
,
1951 Opcode
& FAST486_OPCODE_WRITE_REG
,
1956 USHORT FirstValue
, SecondValue
, Result
;
1958 if (!Fast486ReadModrmWordOperands(State
,
1963 /* Exception occurred */
1967 /* Calculate the result */
1968 Result
= FirstValue
^ SecondValue
;
1970 /* Update the flags */
1971 State
->Flags
.Cf
= FALSE
;
1972 State
->Flags
.Of
= FALSE
;
1973 State
->Flags
.Zf
= (Result
== 0);
1974 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1975 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1977 /* Write back the result */
1978 return Fast486WriteModrmWordOperands(State
,
1980 Opcode
& FAST486_OPCODE_WRITE_REG
,
1985 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1987 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1988 UCHAR SecondValue
, Result
;
1990 /* Make sure this is the right instruction */
1991 ASSERT(Opcode
== 0x34);
1993 if (State
->PrefixFlags
)
1995 /* This opcode doesn't take any prefixes */
1996 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2000 if (!Fast486FetchByte(State
, &SecondValue
))
2002 /* Exception occurred */
2006 /* Calculate the result */
2007 Result
= FirstValue
^ SecondValue
;
2009 /* Update the flags */
2010 State
->Flags
.Cf
= FALSE
;
2011 State
->Flags
.Of
= FALSE
;
2012 State
->Flags
.Zf
= (Result
== 0);
2013 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2014 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2016 /* Write back the result */
2017 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2022 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2024 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2026 /* Make sure this is the right instruction */
2027 ASSERT(Opcode
== 0x35);
2030 TOGGLE_OPSIZE(Size
);
2034 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2035 ULONG SecondValue
, Result
;
2037 if (!Fast486FetchDword(State
, &SecondValue
))
2039 /* Exception occurred */
2043 /* Calculate the result */
2044 Result
= FirstValue
^ SecondValue
;
2046 /* Update the flags */
2047 State
->Flags
.Cf
= FALSE
;
2048 State
->Flags
.Of
= FALSE
;
2049 State
->Flags
.Zf
= (Result
== 0);
2050 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2051 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2053 /* Write back the result */
2054 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2058 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2059 USHORT SecondValue
, Result
;
2061 if (!Fast486FetchWord(State
, &SecondValue
))
2063 /* Exception occurred */
2067 /* Calculate the result */
2068 Result
= FirstValue
^ SecondValue
;
2070 /* Update the flags */
2071 State
->Flags
.Cf
= FALSE
;
2072 State
->Flags
.Of
= FALSE
;
2073 State
->Flags
.Zf
= (Result
== 0);
2074 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2075 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2077 /* Write back the result */
2078 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2084 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2086 UCHAR FirstValue
, SecondValue
, Result
;
2087 FAST486_MOD_REG_RM ModRegRm
;
2088 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2090 /* Make sure this is the right instruction */
2091 ASSERT(Opcode
== 0x84);
2093 TOGGLE_ADSIZE(AddressSize
);
2095 /* Get the operands */
2096 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2098 /* Exception occurred */
2102 if (!Fast486ReadModrmByteOperands(State
,
2107 /* Exception occurred */
2110 /* Calculate the result */
2111 Result
= FirstValue
& SecondValue
;
2113 /* Update the flags */
2114 State
->Flags
.Cf
= FALSE
;
2115 State
->Flags
.Of
= FALSE
;
2116 State
->Flags
.Zf
= (Result
== 0);
2117 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2118 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2120 /* The result is discarded */
2124 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2126 FAST486_MOD_REG_RM ModRegRm
;
2127 BOOLEAN OperandSize
, AddressSize
;
2129 /* Make sure this is the right instruction */
2130 ASSERT(Opcode
== 0x85);
2132 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2134 TOGGLE_ADSIZE(AddressSize
);
2135 TOGGLE_OPSIZE(OperandSize
);
2137 /* Get the operands */
2138 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2140 /* Exception occurred */
2144 /* Check the operand size */
2147 ULONG FirstValue
, SecondValue
, Result
;
2149 if (!Fast486ReadModrmDwordOperands(State
,
2154 /* Exception occurred */
2158 /* Calculate the result */
2159 Result
= FirstValue
& SecondValue
;
2161 /* Update the flags */
2162 State
->Flags
.Cf
= FALSE
;
2163 State
->Flags
.Of
= FALSE
;
2164 State
->Flags
.Zf
= (Result
== 0);
2165 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2166 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2170 USHORT FirstValue
, SecondValue
, Result
;
2172 if (!Fast486ReadModrmWordOperands(State
,
2177 /* Exception occurred */
2181 /* Calculate the result */
2182 Result
= FirstValue
& SecondValue
;
2184 /* Update the flags */
2185 State
->Flags
.Cf
= FALSE
;
2186 State
->Flags
.Of
= FALSE
;
2187 State
->Flags
.Zf
= (Result
== 0);
2188 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2189 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2192 /* The result is discarded */
2196 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2198 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2199 UCHAR SecondValue
, Result
;
2201 /* Make sure this is the right instruction */
2202 ASSERT(Opcode
== 0xA8);
2204 if (State
->PrefixFlags
)
2206 /* This opcode doesn't take any prefixes */
2207 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2211 if (!Fast486FetchByte(State
, &SecondValue
))
2213 /* Exception occurred */
2217 /* Calculate the result */
2218 Result
= FirstValue
& SecondValue
;
2220 /* Update the flags */
2221 State
->Flags
.Cf
= FALSE
;
2222 State
->Flags
.Of
= FALSE
;
2223 State
->Flags
.Zf
= (Result
== 0);
2224 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2225 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2227 /* The result is discarded */
2231 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2233 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2235 /* Make sure this is the right instruction */
2236 ASSERT(Opcode
== 0xA9);
2239 TOGGLE_OPSIZE(Size
);
2243 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2244 ULONG SecondValue
, Result
;
2246 if (!Fast486FetchDword(State
, &SecondValue
))
2248 /* Exception occurred */
2252 /* Calculate the result */
2253 Result
= FirstValue
& SecondValue
;
2255 /* Update the flags */
2256 State
->Flags
.Cf
= FALSE
;
2257 State
->Flags
.Of
= FALSE
;
2258 State
->Flags
.Zf
= (Result
== 0);
2259 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2260 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2264 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2265 USHORT SecondValue
, Result
;
2267 if (!Fast486FetchWord(State
, &SecondValue
))
2269 /* Exception occurred */
2273 /* Calculate the result */
2274 Result
= FirstValue
& SecondValue
;
2276 /* Update the flags */
2277 State
->Flags
.Cf
= FALSE
;
2278 State
->Flags
.Of
= FALSE
;
2279 State
->Flags
.Zf
= (Result
== 0);
2280 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2281 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2284 /* The result is discarded */
2288 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2290 UCHAR FirstValue
, SecondValue
;
2291 FAST486_MOD_REG_RM ModRegRm
;
2292 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2294 /* Make sure this is the right instruction */
2295 ASSERT(Opcode
== 0x86);
2297 TOGGLE_ADSIZE(AddressSize
);
2299 /* Get the operands */
2300 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2302 /* Exception occurred */
2306 if (!Fast486ReadModrmByteOperands(State
,
2311 /* Exception occurred */
2315 /* Write the value from the register to the R/M */
2316 if (!Fast486WriteModrmByteOperands(State
,
2321 /* Exception occurred */
2325 /* Write the value from the R/M to the register */
2326 if (!Fast486WriteModrmByteOperands(State
,
2331 /* Exception occurred */
2338 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2340 FAST486_MOD_REG_RM ModRegRm
;
2341 BOOLEAN OperandSize
, AddressSize
;
2343 /* Make sure this is the right instruction */
2344 ASSERT(Opcode
== 0x87);
2346 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2348 TOGGLE_ADSIZE(AddressSize
);
2349 TOGGLE_OPSIZE(OperandSize
);
2351 /* Get the operands */
2352 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2354 /* Exception occurred */
2358 /* Check the operand size */
2361 ULONG FirstValue
, SecondValue
;
2363 if (!Fast486ReadModrmDwordOperands(State
,
2368 /* Exception occurred */
2372 /* Write the value from the register to the R/M */
2373 if (!Fast486WriteModrmDwordOperands(State
,
2378 /* Exception occurred */
2382 /* Write the value from the R/M to the register */
2383 if (!Fast486WriteModrmDwordOperands(State
,
2388 /* Exception occurred */
2394 USHORT FirstValue
, SecondValue
;
2396 if (!Fast486ReadModrmWordOperands(State
,
2401 /* Exception occurred */
2405 /* Write the value from the register to the R/M */
2406 if (!Fast486WriteModrmWordOperands(State
,
2411 /* Exception occurred */
2415 /* Write the value from the R/M to the register */
2416 if (!Fast486WriteModrmWordOperands(State
,
2421 /* Exception occurred */
2426 /* The result is discarded */
2430 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2432 /* Call the internal API */
2433 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2436 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2440 if (!Fast486StackPop(State
, &NewSelector
))
2442 /* Exception occurred */
2446 /* Call the internal API */
2447 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2450 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2452 /* Call the internal API */
2453 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2456 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2458 UCHAR FirstValue
, SecondValue
, Result
;
2459 FAST486_MOD_REG_RM ModRegRm
;
2460 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2462 /* Make sure this is the right instruction */
2463 ASSERT((Opcode
& 0xFD) == 0x10);
2465 TOGGLE_ADSIZE(AddressSize
);
2467 /* Get the operands */
2468 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2470 /* Exception occurred */
2474 if (!Fast486ReadModrmByteOperands(State
,
2479 /* Exception occurred */
2483 /* Calculate the result */
2484 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2486 /* Special exception for CF */
2487 State
->Flags
.Cf
= State
->Flags
.Cf
2488 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2490 /* Update the flags */
2491 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2492 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2493 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2494 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2495 State
->Flags
.Zf
= (Result
== 0);
2496 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2497 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2499 /* Write back the result */
2500 return Fast486WriteModrmByteOperands(State
,
2502 Opcode
& FAST486_OPCODE_WRITE_REG
,
2506 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2508 FAST486_MOD_REG_RM ModRegRm
;
2509 BOOLEAN OperandSize
, AddressSize
;
2511 /* Make sure this is the right instruction */
2512 ASSERT((Opcode
& 0xFD) == 0x11);
2514 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2516 TOGGLE_ADSIZE(AddressSize
);
2517 TOGGLE_OPSIZE(OperandSize
);
2519 /* Get the operands */
2520 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2522 /* Exception occurred */
2526 /* Check the operand size */
2529 ULONG FirstValue
, SecondValue
, Result
;
2531 if (!Fast486ReadModrmDwordOperands(State
,
2536 /* Exception occurred */
2540 /* Calculate the result */
2541 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2543 /* Special exception for CF */
2544 State
->Flags
.Cf
= State
->Flags
.Cf
2545 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2547 /* Update the flags */
2548 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2549 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2550 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2551 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2552 State
->Flags
.Zf
= (Result
== 0);
2553 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2554 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2556 /* Write back the result */
2557 return Fast486WriteModrmDwordOperands(State
,
2559 Opcode
& FAST486_OPCODE_WRITE_REG
,
2564 USHORT FirstValue
, SecondValue
, Result
;
2566 if (!Fast486ReadModrmWordOperands(State
,
2571 /* Exception occurred */
2575 /* Calculate the result */
2576 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2578 /* Special exception for CF */
2579 State
->Flags
.Cf
= State
->Flags
.Cf
2580 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2582 /* Update the flags */
2583 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2584 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2585 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2586 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2587 State
->Flags
.Zf
= (Result
== 0);
2588 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2589 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2591 /* Write back the result */
2592 return Fast486WriteModrmWordOperands(State
,
2594 Opcode
& FAST486_OPCODE_WRITE_REG
,
2600 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2602 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2603 UCHAR SecondValue
, Result
;
2605 /* Make sure this is the right instruction */
2606 ASSERT(Opcode
== 0x14);
2608 if (State
->PrefixFlags
)
2610 /* This opcode doesn't take any prefixes */
2611 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2615 if (!Fast486FetchByte(State
, &SecondValue
))
2617 /* Exception occurred */
2621 /* Calculate the result */
2622 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2624 /* Special exception for CF */
2625 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2626 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2628 /* Update the flags */
2629 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2630 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2631 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2632 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2633 State
->Flags
.Zf
= (Result
== 0);
2634 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2635 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2637 /* Write back the result */
2638 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2643 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2645 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2647 /* Make sure this is the right instruction */
2648 ASSERT(Opcode
== 0x15);
2651 TOGGLE_OPSIZE(Size
);
2655 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2656 ULONG SecondValue
, Result
;
2658 if (!Fast486FetchDword(State
, &SecondValue
))
2660 /* Exception occurred */
2664 /* Calculate the result */
2665 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2667 /* Special exception for CF */
2668 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2669 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2671 /* Update the flags */
2672 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2673 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2674 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2675 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2676 State
->Flags
.Zf
= (Result
== 0);
2677 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2678 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2680 /* Write back the result */
2681 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2685 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2686 USHORT SecondValue
, Result
;
2688 if (!Fast486FetchWord(State
, &SecondValue
))
2690 /* Exception occurred */
2694 /* Calculate the result */
2695 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2697 /* Special exception for CF */
2698 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2699 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2701 /* Update the flags */
2702 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2703 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2704 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2705 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2706 State
->Flags
.Zf
= (Result
== 0);
2707 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2708 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2710 /* Write back the result */
2711 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2717 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2719 /* Call the internal API */
2720 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2723 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2727 if (!Fast486StackPop(State
, &NewSelector
))
2729 /* Exception occurred */
2733 /* Call the internal API */
2734 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2737 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2739 UCHAR FirstValue
, SecondValue
, Result
;
2740 FAST486_MOD_REG_RM ModRegRm
;
2741 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2742 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2744 /* Make sure this is the right instruction */
2745 ASSERT((Opcode
& 0xFD) == 0x18);
2747 TOGGLE_ADSIZE(AddressSize
);
2749 /* Get the operands */
2750 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2752 /* Exception occurred */
2756 if (!Fast486ReadModrmByteOperands(State
,
2761 /* Exception occurred */
2765 /* Check if this is the instruction that writes to R/M */
2766 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2768 /* Swap the order */
2769 SWAP(FirstValue
, SecondValue
);
2772 /* Calculate the result */
2773 Result
= FirstValue
- SecondValue
- Carry
;
2775 /* Update the flags */
2776 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2777 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2778 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2779 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2780 State
->Flags
.Zf
= (Result
== 0);
2781 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2782 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2784 /* Write back the result */
2785 return Fast486WriteModrmByteOperands(State
,
2787 Opcode
& FAST486_OPCODE_WRITE_REG
,
2791 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2793 FAST486_MOD_REG_RM ModRegRm
;
2794 BOOLEAN OperandSize
, AddressSize
;
2795 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2797 /* Make sure this is the right instruction */
2798 ASSERT((Opcode
& 0xFD) == 0x19);
2800 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2802 TOGGLE_ADSIZE(AddressSize
);
2803 TOGGLE_OPSIZE(OperandSize
);
2805 /* Get the operands */
2806 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2808 /* Exception occurred */
2812 /* Check the operand size */
2815 ULONG FirstValue
, SecondValue
, Result
;
2817 if (!Fast486ReadModrmDwordOperands(State
,
2822 /* Exception occurred */
2826 /* Check if this is the instruction that writes to R/M */
2827 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2829 /* Swap the order */
2830 SWAP(FirstValue
, SecondValue
);
2833 /* Calculate the result */
2834 Result
= FirstValue
- SecondValue
- Carry
;
2836 /* Update the flags */
2837 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2838 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2839 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2840 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2841 State
->Flags
.Zf
= (Result
== 0);
2842 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2843 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2845 /* Write back the result */
2846 return Fast486WriteModrmDwordOperands(State
,
2848 Opcode
& FAST486_OPCODE_WRITE_REG
,
2853 USHORT FirstValue
, SecondValue
, Result
;
2855 if (!Fast486ReadModrmWordOperands(State
,
2860 /* Exception occurred */
2864 /* Check if this is the instruction that writes to R/M */
2865 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2867 /* Swap the order */
2868 SWAP(FirstValue
, SecondValue
);
2871 /* Calculate the result */
2872 Result
= FirstValue
- SecondValue
- Carry
;
2874 /* Update the flags */
2875 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2876 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2877 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2878 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2879 State
->Flags
.Zf
= (Result
== 0);
2880 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2881 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2883 /* Write back the result */
2884 return Fast486WriteModrmWordOperands(State
,
2886 Opcode
& FAST486_OPCODE_WRITE_REG
,
2891 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2893 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2894 UCHAR SecondValue
, Result
;
2895 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2897 /* Make sure this is the right instruction */
2898 ASSERT(Opcode
== 0x1C);
2900 if (State
->PrefixFlags
)
2902 /* This opcode doesn't take any prefixes */
2903 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2907 if (!Fast486FetchByte(State
, &SecondValue
))
2909 /* Exception occurred */
2913 /* Calculate the result */
2914 Result
= FirstValue
- SecondValue
- Carry
;
2916 /* Update the flags */
2917 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2918 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2919 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2920 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2921 State
->Flags
.Zf
= (Result
== 0);
2922 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2923 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2925 /* Write back the result */
2926 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2932 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2934 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2935 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2937 /* Make sure this is the right instruction */
2938 ASSERT(Opcode
== 0x1D);
2941 TOGGLE_OPSIZE(Size
);
2945 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2946 ULONG SecondValue
, Result
;
2948 if (!Fast486FetchDword(State
, &SecondValue
))
2950 /* Exception occurred */
2954 /* Calculate the result */
2955 Result
= FirstValue
- SecondValue
- Carry
;
2957 /* Update the flags */
2958 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2959 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2960 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2961 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2962 State
->Flags
.Zf
= (Result
== 0);
2963 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2964 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2966 /* Write back the result */
2967 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2971 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2972 USHORT SecondValue
, Result
;
2974 if (!Fast486FetchWord(State
, &SecondValue
))
2976 /* Exception occurred */
2980 /* Calculate the result */
2981 Result
= FirstValue
- SecondValue
- Carry
;
2983 /* Update the flags */
2984 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2985 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2986 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2987 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2988 State
->Flags
.Zf
= (Result
== 0);
2989 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2990 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2992 /* Write back the result */
2993 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3000 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
3002 /* Call the internal API */
3003 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
3006 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3010 if (!Fast486StackPop(State
, &NewSelector
))
3012 /* Exception occurred */
3016 /* Call the internal API */
3017 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3020 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3022 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3023 BOOLEAN Carry
= State
->Flags
.Cf
;
3025 /* Clear the carry flag */
3026 State
->Flags
.Cf
= FALSE
;
3028 /* Check if the first BCD digit is invalid or there was a carry from it */
3029 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3032 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3033 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3035 /* A carry occurred */
3036 State
->Flags
.Cf
= TRUE
;
3039 /* Set the adjust flag */
3040 State
->Flags
.Af
= TRUE
;
3043 /* Check if the second BCD digit is invalid or there was a carry from it */
3044 if ((Value
> 0x99) || Carry
)
3047 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3049 /* There was a carry */
3050 State
->Flags
.Cf
= TRUE
;
3053 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3055 /* Update the flags */
3056 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3057 State
->Flags
.Zf
= (Value
== 0);
3058 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3063 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3065 UCHAR FirstValue
, SecondValue
, Result
;
3066 FAST486_MOD_REG_RM ModRegRm
;
3067 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3069 /* Make sure this is the right instruction */
3070 ASSERT((Opcode
& 0xED) == 0x28);
3072 TOGGLE_ADSIZE(AddressSize
);
3074 /* Get the operands */
3075 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3077 /* Exception occurred */
3081 if (!Fast486ReadModrmByteOperands(State
,
3086 /* Exception occurred */
3090 /* Check if this is the instruction that writes to R/M */
3091 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3093 /* Swap the order */
3094 SWAP(FirstValue
, SecondValue
);
3097 /* Calculate the result */
3098 Result
= FirstValue
- SecondValue
;
3100 /* Update the flags */
3101 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3102 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3103 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3104 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3105 State
->Flags
.Zf
= (Result
== 0);
3106 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3107 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3109 /* Check if this is not a CMP */
3110 if (!(Opcode
& 0x10))
3112 /* Write back the result */
3113 return Fast486WriteModrmByteOperands(State
,
3115 Opcode
& FAST486_OPCODE_WRITE_REG
,
3120 /* Discard the result */
3125 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3127 FAST486_MOD_REG_RM ModRegRm
;
3128 BOOLEAN OperandSize
, AddressSize
;
3130 /* Make sure this is the right instruction */
3131 ASSERT((Opcode
& 0xED) == 0x29);
3133 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3135 TOGGLE_ADSIZE(AddressSize
);
3136 TOGGLE_OPSIZE(OperandSize
);
3138 /* Get the operands */
3139 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3141 /* Exception occurred */
3145 /* Check the operand size */
3148 ULONG FirstValue
, SecondValue
, Result
;
3150 if (!Fast486ReadModrmDwordOperands(State
,
3155 /* Exception occurred */
3159 /* Check if this is the instruction that writes to R/M */
3160 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3162 /* Swap the order */
3163 SWAP(FirstValue
, SecondValue
);
3166 /* Calculate the result */
3167 Result
= FirstValue
- SecondValue
;
3169 /* Update the flags */
3170 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3171 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3172 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3173 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3174 State
->Flags
.Zf
= (Result
== 0);
3175 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3176 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3178 /* Check if this is not a CMP */
3179 if (!(Opcode
& 0x10))
3181 /* Write back the result */
3182 return Fast486WriteModrmDwordOperands(State
,
3184 Opcode
& FAST486_OPCODE_WRITE_REG
,
3189 /* Discard the result */
3195 USHORT FirstValue
, SecondValue
, Result
;
3197 if (!Fast486ReadModrmWordOperands(State
,
3202 /* Exception occurred */
3206 /* Check if this is the instruction that writes to R/M */
3207 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3209 /* Swap the order */
3210 SWAP(FirstValue
, SecondValue
);
3213 /* Calculate the result */
3214 Result
= FirstValue
- SecondValue
;
3216 /* Update the flags */
3217 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3218 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3219 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3220 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3221 State
->Flags
.Zf
= (Result
== 0);
3222 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3223 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3225 /* Check if this is not a CMP */
3226 if (!(Opcode
& 0x10))
3228 /* Write back the result */
3229 return Fast486WriteModrmWordOperands(State
,
3231 Opcode
& FAST486_OPCODE_WRITE_REG
,
3236 /* Discard the result */
3242 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3244 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3245 UCHAR SecondValue
, Result
;
3247 /* Make sure this is the right instruction */
3248 ASSERT((Opcode
& 0xEF) == 0x2C);
3250 if (State
->PrefixFlags
)
3252 /* This opcode doesn't take any prefixes */
3253 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3257 if (!Fast486FetchByte(State
, &SecondValue
))
3259 /* Exception occurred */
3263 /* Calculate the result */
3264 Result
= FirstValue
- SecondValue
;
3266 /* Update the flags */
3267 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3268 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3269 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3270 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3271 State
->Flags
.Zf
= (Result
== 0);
3272 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3273 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3275 /* Check if this is not a CMP */
3276 if (!(Opcode
& 0x10))
3278 /* Write back the result */
3279 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3285 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3287 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3289 /* Make sure this is the right instruction */
3290 ASSERT((Opcode
& 0xEF) == 0x2D);
3293 TOGGLE_OPSIZE(Size
);
3297 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3298 ULONG SecondValue
, Result
;
3300 if (!Fast486FetchDword(State
, &SecondValue
))
3302 /* Exception occurred */
3306 /* Calculate the result */
3307 Result
= FirstValue
- SecondValue
;
3309 /* Update the flags */
3310 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3311 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3312 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3313 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3314 State
->Flags
.Zf
= (Result
== 0);
3315 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3316 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3318 /* Check if this is not a CMP */
3319 if (!(Opcode
& 0x10))
3321 /* Write back the result */
3322 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3327 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3328 USHORT SecondValue
, Result
;
3330 if (!Fast486FetchWord(State
, &SecondValue
))
3332 /* Exception occurred */
3336 /* Calculate the result */
3337 Result
= FirstValue
- SecondValue
;
3339 /* Update the flags */
3340 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3341 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3342 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3343 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3344 State
->Flags
.Zf
= (Result
== 0);
3345 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3346 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3348 /* Check if this is not a CMP */
3349 if (!(Opcode
& 0x10))
3351 /* Write back the result */
3352 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3359 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3361 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3362 BOOLEAN Carry
= State
->Flags
.Cf
;
3364 /* Clear the carry flag */
3365 State
->Flags
.Cf
= FALSE
;
3367 /* Check if the first BCD digit is invalid or there was a borrow */
3368 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3371 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3372 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3374 /* A borrow occurred */
3375 State
->Flags
.Cf
= TRUE
;
3378 /* Set the adjust flag */
3379 State
->Flags
.Af
= TRUE
;
3382 /* Check if the second BCD digit is invalid or there was a borrow */
3383 if ((Value
> 0x99) || Carry
)
3386 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3388 /* There was a borrow */
3389 State
->Flags
.Cf
= TRUE
;
3392 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3394 /* Update the flags */
3395 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3396 State
->Flags
.Zf
= (Value
== 0);
3397 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3402 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3404 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3407 * Check if the value in AL is not a valid BCD digit,
3408 * or there was a carry from the lowest 4 bits of AL
3410 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3413 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3414 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3417 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3421 /* Clear CF and AF */
3422 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3425 /* Keep only the lowest 4 bits of AL */
3426 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3431 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3433 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3436 * Check if the value in AL is not a valid BCD digit,
3437 * or there was a borrow from the lowest 4 bits of AL
3439 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3442 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3443 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3446 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3450 /* Clear CF and AF */
3451 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3454 /* Keep only the lowest 4 bits of AL */
3455 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3460 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3463 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3464 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3466 /* Make sure this is the right instruction */
3467 ASSERT(Opcode
== 0x60);
3469 TOGGLE_OPSIZE(Size
);
3472 /* Push all the registers in order */
3473 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3475 if (i
== FAST486_REG_ESP
)
3477 /* Use the saved ESP instead */
3478 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3480 /* Exception occurred */
3486 /* Push the register */
3487 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3488 : State
->GeneralRegs
[i
].LowWord
))
3490 /* Exception occurred */
3499 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3502 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3505 /* Make sure this is the right instruction */
3506 ASSERT(Opcode
== 0x61);
3508 TOGGLE_OPSIZE(Size
);
3511 /* Pop all the registers in reverse order */
3512 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3515 if (!Fast486StackPop(State
, &Value
))
3517 /* Exception occurred */
3521 /* Don't modify ESP */
3522 if (i
!= FAST486_REG_ESP
)
3524 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3525 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3532 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3534 BOOLEAN OperandSize
, AddressSize
;
3535 FAST486_MOD_REG_RM ModRegRm
;
3536 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3538 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3541 TOGGLE_OPSIZE(OperandSize
);
3542 TOGGLE_ADSIZE(AddressSize
);
3544 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3546 /* Exception occurred */
3550 if (!ModRegRm
.Memory
)
3553 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3557 /* Check for the segment override */
3558 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3560 /* Use the override segment instead */
3561 Segment
= State
->SegmentOverride
;
3566 LONG Index
, LowerBound
, UpperBound
;
3568 /* Read the operands */
3569 if (!Fast486ReadModrmDwordOperands(State
,
3572 (PULONG
)&LowerBound
))
3574 /* Exception occurred */
3578 if (!Fast486ReadMemory(State
,
3580 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3585 /* Exception occurred */
3589 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3592 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3598 SHORT Index
, LowerBound
, UpperBound
;
3600 /* Read the operands */
3601 if (!Fast486ReadModrmWordOperands(State
,
3604 (PUSHORT
)&LowerBound
))
3606 /* Exception occurred */
3610 if (!Fast486ReadMemory(State
,
3612 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3617 /* Exception occurred */
3621 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3624 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3632 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3634 USHORT FirstValue
, SecondValue
;
3635 FAST486_MOD_REG_RM ModRegRm
;
3636 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3638 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3640 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3642 /* Cannot be used in real mode or with a LOCK prefix */
3643 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3647 TOGGLE_ADSIZE(AddressSize
);
3649 /* Get the operands */
3650 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3652 /* Exception occurred */
3656 /* Read the operands */
3657 if (!Fast486ReadModrmWordOperands(State
,
3662 /* Exception occurred */
3666 /* Check if the RPL needs adjusting */
3667 if ((SecondValue
& 3) < (FirstValue
& 3))
3669 /* Adjust the RPL */
3671 SecondValue
|= FirstValue
& 3;
3674 State
->Flags
.Zf
= TRUE
;
3676 /* Write back the result */
3677 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3682 State
->Flags
.Zf
= FALSE
;
3687 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3689 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3691 /* Make sure this is the right instruction */
3692 ASSERT(Opcode
== 0x68);
3695 TOGGLE_OPSIZE(Size
);
3701 if (!Fast486FetchDword(State
, &Data
))
3703 /* Exception occurred */
3707 /* Call the internal API */
3708 return Fast486StackPush(State
, Data
);
3714 if (!Fast486FetchWord(State
, (PUSHORT
)&Data
))
3716 /* Exception occurred */
3720 /* Call the internal API */
3721 return Fast486StackPush(State
, Data
);
3725 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3727 BOOLEAN OperandSize
, AddressSize
;
3728 FAST486_MOD_REG_RM ModRegRm
;
3731 /* Make sure this is the right instruction */
3732 ASSERT((Opcode
& 0xFD) == 0x69);
3734 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3736 TOGGLE_ADSIZE(AddressSize
);
3737 TOGGLE_OPSIZE(OperandSize
);
3739 /* Fetch the parameters */
3740 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3742 /* Exception occurred */
3750 /* Fetch the immediate operand */
3751 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3753 /* Exception occurred */
3757 Multiplier
= (LONG
)Byte
;
3765 /* Fetch the immediate operand */
3766 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3768 /* Exception occurred */
3778 /* Fetch the immediate operand */
3779 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3781 /* Exception occurred */
3785 Multiplier
= (LONG
)Word
;
3791 LONG RegValue
, Multiplicand
;
3794 /* Read the operands */
3795 if (!Fast486ReadModrmDwordOperands(State
,
3798 (PULONG
)&Multiplicand
))
3800 /* Exception occurred */
3805 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3807 /* Check for carry/overflow */
3808 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3810 /* Write-back the result */
3811 return Fast486WriteModrmDwordOperands(State
,
3814 (ULONG
)((LONG
)Product
));
3818 SHORT RegValue
, Multiplicand
;
3821 /* Read the operands */
3822 if (!Fast486ReadModrmWordOperands(State
,
3825 (PUSHORT
)&Multiplicand
))
3827 /* Exception occurred */
3832 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3834 /* Check for carry/overflow */
3835 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3837 /* Write-back the result */
3838 return Fast486WriteModrmWordOperands(State
,
3841 (USHORT
)((SHORT
)Product
));
3845 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3849 /* Make sure this is the right instruction */
3850 ASSERT(Opcode
== 0x6A);
3852 if (!Fast486FetchByte(State
, (PUCHAR
)&Data
))
3854 /* Exception occurred */
3858 /* Call the internal API */
3859 return Fast486StackPush(State
, Data
);
3862 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3864 UCHAR FirstValue
, SecondValue
, Result
;
3865 FAST486_MOD_REG_RM ModRegRm
;
3866 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3868 /* Make sure this is the right instruction */
3869 ASSERT((Opcode
& 0xFD) == 0x88);
3871 TOGGLE_ADSIZE(AddressSize
);
3873 /* Get the operands */
3874 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3876 /* Exception occurred */
3880 if (!Fast486ReadModrmByteOperands(State
,
3885 /* Exception occurred */
3889 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3890 else Result
= FirstValue
;
3892 /* Write back the result */
3893 return Fast486WriteModrmByteOperands(State
,
3895 Opcode
& FAST486_OPCODE_WRITE_REG
,
3900 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3902 FAST486_MOD_REG_RM ModRegRm
;
3903 BOOLEAN OperandSize
, AddressSize
;
3905 /* Make sure this is the right instruction */
3906 ASSERT((Opcode
& 0xFD) == 0x89);
3908 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3910 TOGGLE_ADSIZE(AddressSize
);
3911 TOGGLE_OPSIZE(OperandSize
);
3913 /* Get the operands */
3914 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3916 /* Exception occurred */
3920 /* Check the operand size */
3923 ULONG FirstValue
, SecondValue
, Result
;
3925 if (!Fast486ReadModrmDwordOperands(State
,
3930 /* Exception occurred */
3934 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3935 else Result
= FirstValue
;
3937 /* Write back the result */
3938 return Fast486WriteModrmDwordOperands(State
,
3940 Opcode
& FAST486_OPCODE_WRITE_REG
,
3945 USHORT FirstValue
, SecondValue
, Result
;
3947 if (!Fast486ReadModrmWordOperands(State
,
3952 /* Exception occurred */
3956 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3957 else Result
= FirstValue
;
3959 /* Write back the result */
3960 return Fast486WriteModrmWordOperands(State
,
3962 Opcode
& FAST486_OPCODE_WRITE_REG
,
3967 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3969 BOOLEAN OperandSize
, AddressSize
;
3970 FAST486_MOD_REG_RM ModRegRm
;
3972 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3974 /* Make sure this is the right instruction */
3975 ASSERT(Opcode
== 0x8C);
3977 TOGGLE_ADSIZE(AddressSize
);
3978 TOGGLE_OPSIZE(OperandSize
);
3980 /* Get the operands */
3981 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3983 /* Exception occurred */
3987 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3990 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3996 return Fast486WriteModrmDwordOperands(State
,
3999 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4003 return Fast486WriteModrmWordOperands(State
,
4006 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4010 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
4012 FAST486_MOD_REG_RM ModRegRm
;
4013 BOOLEAN OperandSize
, AddressSize
;
4015 /* Make sure this is the right instruction */
4016 ASSERT(Opcode
== 0x8D);
4018 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4020 TOGGLE_ADSIZE(AddressSize
);
4021 TOGGLE_OPSIZE(OperandSize
);
4023 /* Get the operands */
4024 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4026 /* Exception occurred */
4030 /* The second operand must be memory */
4031 if (!ModRegRm
.Memory
)
4034 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4038 /* Write the address to the register */
4041 return Fast486WriteModrmDwordOperands(State
,
4044 ModRegRm
.MemoryAddress
);
4048 return Fast486WriteModrmWordOperands(State
,
4051 ModRegRm
.MemoryAddress
);
4056 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
4058 BOOLEAN OperandSize
, AddressSize
;
4059 FAST486_MOD_REG_RM ModRegRm
;
4061 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4063 /* Make sure this is the right instruction */
4064 ASSERT(Opcode
== 0x8E);
4066 TOGGLE_ADSIZE(AddressSize
);
4067 TOGGLE_OPSIZE(OperandSize
);
4069 /* Get the operands */
4070 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4072 /* Exception occurred */
4076 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4077 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
4080 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4088 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4090 /* Exception occurred */
4094 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4100 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4102 /* Exception occurred */
4106 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4110 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4112 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4114 /* Make sure this is the right instruction */
4115 ASSERT(Opcode
== 0x98);
4117 TOGGLE_OPSIZE(Size
);
4122 /* Sign extend AX to EAX */
4123 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4125 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4126 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4132 /* Sign extend AL to AX */
4133 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4134 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4141 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4143 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4145 /* Make sure this is the right instruction */
4146 ASSERT(Opcode
== 0x99);
4148 TOGGLE_OPSIZE(Size
);
4153 /* Sign extend EAX to EDX:EAX */
4154 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4155 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4156 ? 0xFFFFFFFF : 0x00000000;
4160 /* Sign extend AX to DX:AX */
4161 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4162 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4169 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4173 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4175 /* Make sure this is the right instruction */
4176 ASSERT(Opcode
== 0x9A);
4178 TOGGLE_OPSIZE(Size
);
4181 /* Fetch the offset */
4184 if (!Fast486FetchDword(State
, &Offset
))
4186 /* Exception occurred */
4192 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4194 /* Exception occurred */
4199 /* Fetch the segment */
4200 if (!Fast486FetchWord(State
, &Segment
))
4202 /* Exception occurred */
4206 /* Push the current code segment selector */
4207 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4209 /* Exception occurred */
4213 /* Push the current value of the instruction pointer */
4214 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4216 /* Exception occurred */
4220 /* Load the new CS */
4221 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4223 /* Exception occurred */
4227 /* Load new (E)IP */
4228 if (Size
) State
->InstPtr
.Long
= Offset
;
4229 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4234 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4236 // TODO: NOT IMPLEMENTED
4242 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4244 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4247 TOGGLE_OPSIZE(Size
);
4249 /* Check for VM86 mode when IOPL is not 3 */
4250 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4252 /* Call the VM86 monitor */
4253 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4257 /* Push the flags */
4258 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4259 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4262 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4264 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4265 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4266 FAST486_FLAGS_REG NewFlags
;
4269 TOGGLE_OPSIZE(Size
);
4271 /* Pop the new flags */
4272 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4274 /* Exception occurred */
4278 /* Check for VM86 mode when IOPL is not 3 */
4279 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4281 /* Call the VM86 monitor */
4282 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4286 State
->Flags
.Cf
= NewFlags
.Cf
;
4287 State
->Flags
.Pf
= NewFlags
.Pf
;
4288 State
->Flags
.Af
= NewFlags
.Af
;
4289 State
->Flags
.Zf
= NewFlags
.Zf
;
4290 State
->Flags
.Sf
= NewFlags
.Sf
;
4291 State
->Flags
.Tf
= NewFlags
.Tf
;
4292 State
->Flags
.Df
= NewFlags
.Df
;
4293 State
->Flags
.Of
= NewFlags
.Of
;
4294 State
->Flags
.Nt
= NewFlags
.Nt
;
4295 State
->Flags
.Ac
= NewFlags
.Ac
;
4297 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4298 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4303 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4305 /* Make sure this is the right instruction */
4306 ASSERT(Opcode
== 0x9E);
4308 /* Set the low-order byte of FLAGS to AH */
4309 State
->Flags
.Long
&= 0xFFFFFF00;
4310 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4312 /* Restore the reserved bits of FLAGS */
4313 State
->Flags
.AlwaysSet
= TRUE
;
4314 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4319 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4321 /* Make sure this is the right instruction */
4322 ASSERT(Opcode
== 0x9F);
4324 /* Set AH to the low-order byte of FLAGS */
4325 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4330 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4332 ULONG ReturnAddress
;
4333 USHORT BytesToPop
= 0;
4334 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4336 /* Make sure this is the right instruction */
4337 ASSERT((Opcode
& 0xFE) == 0xC2);
4340 TOGGLE_OPSIZE(Size
);
4344 /* Fetch the number of bytes to pop after the return */
4345 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4348 /* Pop the return address */
4349 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4351 /* Return to the calling procedure, and if necessary, pop the parameters */
4354 State
->InstPtr
.Long
= ReturnAddress
;
4355 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4359 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4360 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4366 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4368 UCHAR FarPointer
[6];
4369 BOOLEAN OperandSize
, AddressSize
;
4370 FAST486_MOD_REG_RM ModRegRm
;
4372 /* Make sure this is the right instruction */
4373 ASSERT((Opcode
& 0xFE) == 0xC4);
4375 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4377 TOGGLE_OPSIZE(OperandSize
);
4378 TOGGLE_ADSIZE(AddressSize
);
4380 /* Get the operands */
4381 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4383 /* Exception occurred */
4387 if (!ModRegRm
.Memory
)
4389 /* Check if this is a BOP and the host supports BOPs */
4390 if ((Opcode
== 0xC4)
4391 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4392 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4393 && (State
->BopCallback
!= NULL
))
4397 /* Fetch the BOP code */
4398 if (!Fast486FetchByte(State
, &BopCode
))
4400 /* Exception occurred */
4404 /* Call the BOP handler */
4405 State
->BopCallback(State
, BopCode
);
4408 * If an interrupt should occur at this time, delay it.
4409 * We must do this because if an interrupt begins and the BOP callback
4410 * changes the CS:IP, the interrupt handler won't execute and the
4411 * stack pointer will never be restored.
4413 if (State
->IntStatus
== FAST486_INT_EXECUTE
)
4415 State
->IntStatus
= FAST486_INT_DELAYED
;
4418 /* Return success */
4423 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4427 if (!Fast486ReadMemory(State
,
4428 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4429 ? State
->SegmentOverride
: FAST486_REG_DS
,
4430 ModRegRm
.MemoryAddress
,
4433 OperandSize
? 6 : 4))
4435 /* Exception occurred */
4441 ULONG Offset
= *((PULONG
)FarPointer
);
4442 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4444 /* Set the register to the offset */
4445 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4447 /* Load the segment */
4448 return Fast486LoadSegment(State
,
4450 ? FAST486_REG_ES
: FAST486_REG_DS
,
4455 USHORT Offset
= *((PUSHORT
)FarPointer
);
4456 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4458 /* Set the register to the offset */
4459 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4461 /* Load the segment */
4462 return Fast486LoadSegment(State
,
4464 ? FAST486_REG_ES
: FAST486_REG_DS
,
4469 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4472 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4475 FAST486_REG FramePointer
;
4477 /* Make sure this is the right instruction */
4478 ASSERT(Opcode
== 0xC8);
4481 TOGGLE_OPSIZE(Size
);
4483 if (!Fast486FetchWord(State
, &FrameSize
))
4485 /* Exception occurred */
4489 if (!Fast486FetchByte(State
, &NestingLevel
))
4491 /* Exception occurred */
4496 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4498 /* Exception occurred */
4503 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4505 /* Set up the nested procedure stacks */
4506 for (i
= 1; i
< NestingLevel
; i
++)
4510 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4511 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4515 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4516 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4520 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4522 /* Set EBP to the frame pointer */
4523 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4525 /* Reserve space for the frame */
4526 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4527 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4532 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4534 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4536 /* Make sure this is the right instruction */
4537 ASSERT(Opcode
== 0xC9);
4540 TOGGLE_OPSIZE(Size
);
4544 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4545 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4547 /* Pop the saved base pointer from the stack */
4548 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4554 /* Set the stack pointer (SP) to the base pointer (BP) */
4555 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4557 /* Pop the saved base pointer from the stack */
4558 if (Fast486StackPop(State
, &Value
))
4560 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4567 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4571 USHORT BytesToPop
= 0;
4572 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4574 /* Make sure this is the right instruction */
4575 ASSERT((Opcode
& 0xFE) == 0xCA);
4577 TOGGLE_OPSIZE(Size
);
4582 /* Fetch the number of bytes to pop after the return */
4583 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4586 /* Pop the offset */
4587 if (!Fast486StackPop(State
, &Offset
))
4589 /* Exception occurred */
4593 /* Pop the segment */
4594 if (!Fast486StackPop(State
, &Segment
))
4596 /* Exception occurred */
4600 /* Load the new CS */
4601 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4603 /* Exception occurred */
4607 /* Load new (E)IP, and if necessary, pop the parameters */
4610 State
->InstPtr
.Long
= Offset
;
4611 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4615 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4616 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4622 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4630 /* This is the INT3 instruction */
4637 /* Fetch the interrupt number */
4638 if (!Fast486FetchByte(State
, &IntNum
))
4640 /* Exception occurred */
4649 /* Don't do anything if OF is cleared */
4650 if (!State
->Flags
.Of
) return TRUE
;
4653 IntNum
= FAST486_EXCEPTION_OF
;
4660 /* Should not happen */
4665 /* Perform the interrupt */
4666 return Fast486PerformInterrupt(State
, IntNum
);
4669 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4672 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4673 FAST486_FLAGS_REG NewFlags
;
4674 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4676 /* Make sure this is the right instruction */
4677 ASSERT(Opcode
== 0xCF);
4680 TOGGLE_OPSIZE(Size
);
4683 if (!Fast486StackPop(State
, &InstPtr
))
4685 /* Exception occurred */
4690 if (!Fast486StackPop(State
, &CodeSel
))
4692 /* Exception occurred */
4697 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4699 /* Exception occurred */
4703 /* Check for protected mode */
4704 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4706 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4708 if (State
->Flags
.Vm
)
4710 /* Return from VM86 mode */
4712 /* Check the IOPL */
4713 if (State
->Flags
.Iopl
== 3)
4716 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4719 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4721 /* Exception occurred */
4725 /* Set the new flags */
4726 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4727 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4728 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4729 State
->Flags
.Iopl
= 3;
4733 /* Call the VM86 monitor */
4734 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4741 if (State
->Flags
.Nt
)
4743 /* Nested task return */
4751 /* Return to VM86 mode */
4752 ULONG Es
, Ds
, Fs
, Gs
;
4754 /* Pop ESP, SS, ES, FS, GS */
4755 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4756 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4757 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4758 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4759 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4760 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4762 /* Set the new IP */
4763 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4765 /* Set the new flags */
4766 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4767 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4768 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4770 /* Load the new segments */
4771 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4772 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4773 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4774 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4775 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4776 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4781 /* Load the new CS */
4782 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4784 /* Exception occurred */
4789 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4790 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4792 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4795 if (!Fast486StackPop(State
, &StackPtr
))
4802 if (!Fast486StackPop(State
, &StackSel
))
4809 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4816 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4817 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4820 /* Set the new flags */
4821 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4822 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4823 State
->Flags
.AlwaysSet
= TRUE
;
4825 /* Set additional flags */
4826 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4827 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4829 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4831 /* Update the CPL */
4832 Cpl
= Fast486GetCurrentPrivLevel(State
);
4834 /* Check segment security */
4835 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4837 /* Don't check CS or SS */
4838 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4840 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4841 && (!State
->SegmentRegs
[i
].Executable
4842 || !State
->SegmentRegs
[i
].DirConf
))
4844 /* Load the NULL descriptor in the segment */
4845 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4852 if (Size
&& (InstPtr
& 0xFFFF0000))
4855 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4860 State
->InstPtr
.Long
= InstPtr
;
4863 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4865 /* Exception occurred */
4869 /* Set the new flags */
4870 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4871 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4872 State
->Flags
.AlwaysSet
= TRUE
;
4878 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4881 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4885 /* Fetch the base */
4886 if (!Fast486FetchByte(State
, &Base
))
4888 /* Exception occurred */
4892 /* Check if the base is zero */
4896 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4901 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4902 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4905 State
->Flags
.Af
= FALSE
;
4906 State
->Flags
.Zf
= (Value
== 0);
4907 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4908 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4913 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4916 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4920 /* Fetch the base */
4921 if (!Fast486FetchByte(State
, &Base
))
4923 /* Exception occurred */
4928 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4929 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4932 State
->Flags
.Af
= FALSE
;
4933 State
->Flags
.Zf
= (Value
== 0);
4934 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4935 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4940 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4943 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4945 TOGGLE_ADSIZE(AddressSize
);
4947 /* Read a byte from DS:[(E)BX + AL] */
4948 if (!Fast486ReadMemory(State
,
4949 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4950 ? State
->SegmentOverride
: FAST486_REG_DS
,
4951 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4952 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4953 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4958 /* Exception occurred */
4962 /* Set AL to the result */
4963 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4965 /* Return success */
4969 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4972 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4975 /* Make sure this is the right instruction */
4976 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4979 TOGGLE_ADSIZE(Size
);
4981 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4982 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4986 /* Additional rule for LOOPNZ */
4987 if (State
->Flags
.Zf
) Condition
= FALSE
;
4992 /* Additional rule for LOOPZ */
4993 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4996 /* Fetch the offset */
4997 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4999 /* An exception occurred */
5005 /* Move the instruction pointer */
5006 if (Size
) State
->InstPtr
.Long
+= Offset
;
5007 else State
->InstPtr
.LowWord
+= Offset
;
5013 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5016 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5019 /* Make sure this is the right instruction */
5020 ASSERT(Opcode
== 0xE3);
5023 TOGGLE_ADSIZE(Size
);
5025 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5026 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5028 /* Fetch the offset */
5029 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5031 /* An exception occurred */
5037 /* Move the instruction pointer */
5038 if (Size
) State
->InstPtr
.Long
+= Offset
;
5039 else State
->InstPtr
.LowWord
+= Offset
;
5045 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5047 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5049 /* Make sure this is the right instruction */
5050 ASSERT(Opcode
== 0xE8);
5052 TOGGLE_OPSIZE(Size
);
5059 /* Fetch the offset */
5060 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5062 /* An exception occurred */
5066 /* Push the current value of the instruction pointer */
5067 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5069 /* Exception occurred */
5073 /* Move the instruction pointer */
5074 State
->InstPtr
.Long
+= Offset
;
5080 /* Fetch the offset */
5081 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5083 /* An exception occurred */
5087 /* Push the current value of the instruction pointer */
5088 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5090 /* Exception occurred */
5094 /* Move the instruction pointer */
5095 State
->InstPtr
.LowWord
+= Offset
;
5101 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5103 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5105 /* Make sure this is the right instruction */
5106 ASSERT(Opcode
== 0xE9);
5108 TOGGLE_OPSIZE(Size
);
5115 /* Fetch the offset */
5116 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5118 /* An exception occurred */
5122 /* Move the instruction pointer */
5123 State
->InstPtr
.Long
+= Offset
;
5129 /* Fetch the offset */
5130 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5132 /* An exception occurred */
5136 /* Move the instruction pointer */
5137 State
->InstPtr
.Long
+= Offset
;
5139 /* Clear the top half of EIP */
5140 State
->InstPtr
.Long
&= 0xFFFF;
5146 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5150 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5152 /* Make sure this is the right instruction */
5153 ASSERT(Opcode
== 0xEA);
5155 TOGGLE_OPSIZE(Size
);
5158 /* Fetch the offset */
5161 if (!Fast486FetchDword(State
, &Offset
))
5163 /* Exception occurred */
5169 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5171 /* Exception occurred */
5176 /* Fetch the segment */
5177 if (!Fast486FetchWord(State
, &Segment
))
5179 /* Exception occurred */
5183 /* Load the new CS */
5184 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5186 /* Exception occurred */
5191 State
->InstPtr
.Long
= Offset
;
5196 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5198 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5201 /* Make sure this is the right instruction */
5202 ASSERT(Opcode
== 0xA0);
5204 TOGGLE_ADSIZE(AddressSize
);
5208 if (!Fast486FetchDword(State
, &Offset
))
5210 /* Exception occurred */
5218 if (!Fast486FetchWord(State
, &WordOffset
))
5220 /* Exception occurred */
5224 Offset
= (ULONG
)WordOffset
;
5227 /* Read from memory */
5228 return Fast486ReadMemory(State
,
5229 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5230 State
->SegmentOverride
: FAST486_REG_DS
,
5233 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5237 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5239 BOOLEAN OperandSize
, AddressSize
;
5241 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5243 /* Make sure this is the right instruction */
5244 ASSERT(Opcode
== 0xA1);
5246 TOGGLE_OPSIZE(OperandSize
);
5247 TOGGLE_ADSIZE(AddressSize
);
5253 if (!Fast486FetchDword(State
, &Offset
))
5255 /* Exception occurred */
5259 /* Read from memory */
5262 return Fast486ReadMemory(State
,
5263 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5264 State
->SegmentOverride
: FAST486_REG_DS
,
5267 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5272 return Fast486ReadMemory(State
,
5273 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5274 State
->SegmentOverride
: FAST486_REG_DS
,
5277 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5285 if (!Fast486FetchWord(State
, &Offset
))
5287 /* Exception occurred */
5291 /* Read from memory */
5294 return Fast486ReadMemory(State
,
5295 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5296 State
->SegmentOverride
: FAST486_REG_DS
,
5299 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5304 return Fast486ReadMemory(State
,
5305 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5306 State
->SegmentOverride
: FAST486_REG_DS
,
5309 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5315 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5317 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5320 /* Make sure this is the right instruction */
5321 ASSERT(Opcode
== 0xA2);
5323 TOGGLE_ADSIZE(AddressSize
);
5327 if (!Fast486FetchDword(State
, &Offset
))
5329 /* Exception occurred */
5337 if (!Fast486FetchWord(State
, &WordOffset
))
5339 /* Exception occurred */
5343 Offset
= (ULONG
)WordOffset
;
5346 /* Write to memory */
5347 return Fast486WriteMemory(State
,
5348 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5349 State
->SegmentOverride
: FAST486_REG_DS
,
5351 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5355 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5357 BOOLEAN OperandSize
, AddressSize
;
5359 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5361 /* Make sure this is the right instruction */
5362 ASSERT(Opcode
== 0xA3);
5364 TOGGLE_OPSIZE(OperandSize
);
5365 TOGGLE_ADSIZE(AddressSize
);
5371 if (!Fast486FetchDword(State
, &Offset
))
5373 /* Exception occurred */
5377 /* Write to memory */
5380 return Fast486WriteMemory(State
,
5381 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5382 State
->SegmentOverride
: FAST486_REG_DS
,
5384 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5389 return Fast486WriteMemory(State
,
5390 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5391 State
->SegmentOverride
: FAST486_REG_DS
,
5393 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5401 if (!Fast486FetchWord(State
, &Offset
))
5403 /* Exception occurred */
5407 /* Write to memory */
5410 return Fast486WriteMemory(State
,
5411 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5412 State
->SegmentOverride
: FAST486_REG_DS
,
5414 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5419 return Fast486WriteMemory(State
,
5420 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5421 State
->SegmentOverride
: FAST486_REG_DS
,
5423 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5429 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5431 /* Make sure this is the right instruction */
5432 ASSERT(Opcode
== 0xD6);
5436 /* Set all the bits of AL to CF */
5437 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5442 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5444 ULONG Data
, DataSize
;
5445 BOOLEAN OperandSize
, AddressSize
;
5446 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5448 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5450 /* Make sure this is the right instruction */
5451 ASSERT((Opcode
& 0xFE) == 0xA4);
5453 TOGGLE_OPSIZE(OperandSize
);
5454 TOGGLE_ADSIZE(AddressSize
);
5456 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5458 /* Use the override segment instead of DS */
5459 Segment
= State
->SegmentOverride
;
5462 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5464 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5465 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5472 /* Calculate the size */
5473 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5474 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5476 /* Read from the source operand */
5477 if (!Fast486ReadMemory(State
,
5479 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5480 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5485 /* Exception occurred */
5489 /* Write to the destination operand */
5490 if (!Fast486WriteMemory(State
,
5492 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5493 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5497 /* Exception occurred */
5501 /* Increment/decrement ESI and EDI */
5504 if (!State
->Flags
.Df
)
5506 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5507 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5511 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5512 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5517 if (!State
->Flags
.Df
)
5519 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5520 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5524 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5525 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5529 // FIXME: This method is slow!
5530 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5534 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5536 /* Repeat the instruction */
5537 State
->InstPtr
= State
->SavedInstPtr
;
5542 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5544 /* Repeat the instruction */
5545 State
->InstPtr
= State
->SavedInstPtr
;
5550 /* Return success */
5554 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5556 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5557 ULONG DataSize
, DataMask
, SignFlag
;
5558 BOOLEAN OperandSize
, AddressSize
;
5559 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5561 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5563 /* Make sure this is the right instruction */
5564 ASSERT((Opcode
& 0xFE) == 0xA6);
5566 TOGGLE_OPSIZE(OperandSize
);
5567 TOGGLE_ADSIZE(AddressSize
);
5569 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5571 /* Use the override segment instead of DS */
5572 Segment
= State
->SegmentOverride
;
5575 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5576 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5578 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5579 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5586 /* Calculate the size */
5587 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5588 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5590 /* Calculate the mask and sign flag */
5591 SignFlag
= 1 << ((DataSize
* 8) - 1);
5592 DataMask
= SignFlag
| (SignFlag
- 1);
5594 /* Read from the first source operand */
5595 if (!Fast486ReadMemory(State
,
5597 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5598 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5603 /* Exception occurred */
5607 /* Read from the second source operand */
5608 if (!Fast486ReadMemory(State
,
5610 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5611 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5616 /* Exception occurred */
5620 /* Calculate the result */
5621 FirstValue
&= DataMask
;
5622 SecondValue
&= DataMask
;
5623 Result
= (FirstValue
- SecondValue
) & DataMask
;
5625 /* Update the flags */
5626 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5627 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5628 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5629 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5630 State
->Flags
.Zf
= (Result
== 0);
5631 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5632 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5634 /* Increment/decrement ESI and EDI */
5637 if (!State
->Flags
.Df
)
5639 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5640 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5644 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5645 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5650 if (!State
->Flags
.Df
)
5652 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5653 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5657 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5658 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5662 // FIXME: This method is slow!
5663 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5664 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5666 BOOLEAN Repeat
= TRUE
;
5670 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5678 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5685 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5686 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5688 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5694 /* Repeat the instruction */
5695 State
->InstPtr
= State
->SavedInstPtr
;
5699 /* Return success */
5703 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5706 BOOLEAN OperandSize
, AddressSize
;
5708 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5710 /* Make sure this is the right instruction */
5711 ASSERT((Opcode
& 0xFE) == 0xAA);
5713 TOGGLE_OPSIZE(OperandSize
);
5714 TOGGLE_ADSIZE(AddressSize
);
5716 /* Calculate the size */
5717 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5718 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5720 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5722 UCHAR Block
[STRING_BLOCK_SIZE
];
5723 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5724 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5726 /* Fill the memory block with the data */
5727 if (DataSize
== sizeof(UCHAR
))
5729 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5735 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5737 if (DataSize
== sizeof(USHORT
))
5739 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5743 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5748 /* Transfer until finished */
5751 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5753 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5756 ULONG MaxBytes
= State
->Flags
.Df
5757 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5758 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5760 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5761 if (Processed
== 0) Processed
= 1;
5764 if (State
->Flags
.Df
)
5766 /* Set EDI to the starting location */
5767 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5768 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5771 /* Write to memory */
5772 if (!Fast486WriteMemory(State
,
5774 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5775 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5777 Processed
* DataSize
))
5780 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5781 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5783 /* Exception occurred */
5787 if (!State
->Flags
.Df
)
5789 /* Increase EDI by the number of bytes transfered */
5790 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5791 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5796 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5797 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5800 /* Reduce the total count by the number processed in this run */
5805 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5806 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5810 /* Write to the destination operand */
5811 if (!Fast486WriteMemory(State
,
5813 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5814 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5815 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5818 /* Exception occurred */
5822 /* Increment/decrement EDI */
5825 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5826 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5830 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5831 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5835 /* Return success */
5839 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5842 BOOLEAN OperandSize
, AddressSize
;
5843 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5845 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5847 /* Make sure this is the right instruction */
5848 ASSERT((Opcode
& 0xFE) == 0xAC);
5850 TOGGLE_OPSIZE(OperandSize
);
5851 TOGGLE_ADSIZE(AddressSize
);
5853 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5855 /* Use the override segment instead of DS */
5856 Segment
= State
->SegmentOverride
;
5859 /* Calculate the size */
5860 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5861 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5863 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5865 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5866 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5868 /* If the count is 0, do nothing */
5869 if (Count
== 0) return TRUE
;
5871 /* Only the last entry will be loaded */
5872 if (!State
->Flags
.Df
)
5874 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5875 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5879 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5880 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5884 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5885 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5888 /* Read from the source operand */
5889 if (!Fast486ReadMemory(State
,
5891 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5892 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5894 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5897 /* Exception occurred */
5901 /* Increment/decrement ESI */
5904 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5905 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5909 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5910 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5913 /* Return success */
5917 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5919 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5920 ULONG SecondValue
= 0;
5922 ULONG DataSize
, DataMask
, SignFlag
;
5923 BOOLEAN OperandSize
, AddressSize
;
5925 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5927 /* Make sure this is the right instruction */
5928 ASSERT((Opcode
& 0xFE) == 0xAE);
5930 TOGGLE_OPSIZE(OperandSize
);
5931 TOGGLE_ADSIZE(AddressSize
);
5933 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5934 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5936 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5937 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5944 /* Calculate the size */
5945 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5946 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5948 /* Calculate the mask and sign flag */
5949 SignFlag
= 1 << ((DataSize
* 8) - 1);
5950 DataMask
= SignFlag
| (SignFlag
- 1);
5952 /* Read from the source operand */
5953 if (!Fast486ReadMemory(State
,
5955 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5956 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5961 /* Exception occurred */
5965 /* Calculate the result */
5966 FirstValue
&= DataMask
;
5967 SecondValue
&= DataMask
;
5968 Result
= (FirstValue
- SecondValue
) & DataMask
;
5970 /* Update the flags */
5971 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5972 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5973 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5974 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5975 State
->Flags
.Zf
= (Result
== 0);
5976 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5977 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5979 /* Increment/decrement EDI */
5982 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5983 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5987 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5988 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5991 // FIXME: This method is slow!
5992 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5993 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5995 BOOLEAN Repeat
= TRUE
;
5999 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6007 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6014 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6015 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6017 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6023 /* Repeat the instruction */
6024 State
->InstPtr
= State
->SavedInstPtr
;
6028 /* Return success */
6032 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6035 BOOLEAN OperandSize
, AddressSize
;
6037 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6039 /* Make sure this is the right instruction */
6040 ASSERT((Opcode
& 0xFE) == 0x6C);
6042 TOGGLE_OPSIZE(OperandSize
);
6043 TOGGLE_ADSIZE(AddressSize
);
6045 /* Calculate the size */
6046 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6047 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6049 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6051 UCHAR Block
[STRING_BLOCK_SIZE
];
6052 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6053 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6055 /* Clear the memory block */
6056 RtlZeroMemory(Block
, sizeof(Block
));
6058 /* Transfer until finished */
6061 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6063 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6066 ULONG MaxBytes
= State
->Flags
.Df
6067 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6068 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6070 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6071 if (Processed
== 0) Processed
= 1;
6074 /* Read from the I/O port */
6075 State
->IoReadCallback(State
,
6076 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6081 if (State
->Flags
.Df
)
6085 /* Reduce EDI by the number of bytes to transfer */
6086 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6087 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6089 /* Reverse the block data */
6090 for (i
= 0; i
< Processed
/ 2; i
++)
6092 /* Swap the values */
6093 for (j
= 0; j
< DataSize
; j
++)
6095 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6096 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6097 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6102 /* Write to memory */
6103 if (!Fast486WriteMemory(State
,
6105 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6106 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6108 Processed
* DataSize
))
6111 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6112 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6114 /* Exception occurred */
6118 if (!State
->Flags
.Df
)
6120 /* Increase EDI by the number of bytes transfered */
6121 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6122 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6125 /* Reduce the total count by the number processed in this run */
6130 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6131 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6137 /* Read from the I/O port */
6138 State
->IoReadCallback(State
,
6139 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6144 /* Write to the destination operand */
6145 if (!Fast486WriteMemory(State
,
6147 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6148 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6152 /* Exception occurred */
6156 /* Increment/decrement EDI */
6159 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6160 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6164 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6165 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6169 /* Return success */
6173 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6176 BOOLEAN OperandSize
, AddressSize
;
6178 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6180 /* Make sure this is the right instruction */
6181 ASSERT((Opcode
& 0xFE) == 0x6E);
6183 TOGGLE_OPSIZE(OperandSize
);
6184 TOGGLE_ADSIZE(AddressSize
);
6186 /* Calculate the size */
6187 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6188 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6190 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6192 UCHAR Block
[STRING_BLOCK_SIZE
];
6193 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6194 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6196 /* Clear the memory block */
6197 RtlZeroMemory(Block
, sizeof(Block
));
6199 /* Transfer until finished */
6202 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6204 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6207 ULONG MaxBytes
= State
->Flags
.Df
6208 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
6209 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
6211 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6212 if (Processed
== 0) Processed
= 1;
6215 /* Read from memory */
6216 if (!Fast486ReadMemory(State
,
6217 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6218 ? State
->SegmentOverride
: FAST486_REG_DS
,
6219 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6220 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6223 Processed
* DataSize
))
6226 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6227 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6229 /* Exception occurred */
6233 if (State
->Flags
.Df
)
6237 /* Reduce ESI by the number of bytes to transfer */
6238 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
6239 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
6241 /* Reverse the block data */
6242 for (i
= 0; i
< Processed
/ 2; i
++)
6244 /* Swap the values */
6245 for (j
= 0; j
< DataSize
; j
++)
6247 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6248 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6249 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6254 /* Write to the I/O port */
6255 State
->IoWriteCallback(State
,
6256 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6261 if (!State
->Flags
.Df
)
6263 /* Increase ESI by the number of bytes transfered */
6264 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
6265 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
6268 /* Reduce the total count by the number processed in this run */
6273 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6274 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6280 /* Read from the source operand */
6281 if (!Fast486ReadMemory(State
,
6282 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6283 ? State
->SegmentOverride
: FAST486_REG_DS
,
6284 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6285 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6290 /* Exception occurred */
6294 /* Write to the I/O port */
6295 State
->IoWriteCallback(State
,
6296 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6301 /* Increment/decrement ESI */
6304 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6305 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6309 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6310 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6314 /* Return success */