2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /* INCLUDES *******************************************************************/
36 /* PUBLIC VARIABLES ***********************************************************/
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
41 Fast486OpcodeAddByteModrm
, /* 0x00 - 0x03 */
42 Fast486OpcodeAddModrm
,
43 Fast486OpcodeAddByteModrm
,
44 Fast486OpcodeAddModrm
,
45 Fast486OpcodeAddAl
, /* 0x04 */
46 Fast486OpcodeAddEax
, /* 0x05 */
47 Fast486OpcodePushEs
, /* 0x06 */
48 Fast486OpcodePopEs
, /* 0x07 */
49 Fast486OpcodeOrByteModrm
, /* 0x08 - 0x0B */
51 Fast486OpcodeOrByteModrm
,
53 Fast486OpcodeOrAl
, /* 0x0C */
54 Fast486OpcodeOrEax
, /* 0x0D */
55 Fast486OpcodePushCs
, /* 0x0E */
56 Fast486OpcodeExtended
, /* 0x0F */
57 Fast486OpcodeAdcByteModrm
, /* 0x10 - 0x13 */
58 Fast486OpcodeAdcModrm
,
59 Fast486OpcodeAdcByteModrm
,
60 Fast486OpcodeAdcModrm
,
61 Fast486OpcodeAdcAl
, /* 0x14 */
62 Fast486OpcodeAdcEax
, /* 0x15 */
63 Fast486OpcodePushSs
, /* 0x16 */
64 Fast486OpcodePopSs
, /* 0x17 */
65 Fast486OpcodeSbbByteModrm
, /* 0x18 - 0x1B */
66 Fast486OpcodeSbbModrm
,
67 Fast486OpcodeSbbByteModrm
,
68 Fast486OpcodeSbbModrm
,
69 Fast486OpcodeSbbAl
, /* 0x1C */
70 Fast486OpcodeSbbEax
, /* 0x1D */
71 Fast486OpcodePushDs
, /* 0x1E */
72 Fast486OpcodePopDs
, /* 0x1F */
73 Fast486OpcodeAndByteModrm
, /* 0x20 - 0x23 */
74 Fast486OpcodeAndModrm
,
75 Fast486OpcodeAndByteModrm
,
76 Fast486OpcodeAndModrm
,
77 Fast486OpcodeAndAl
, /* 0x24 */
78 Fast486OpcodeAndEax
, /* 0x25 */
79 Fast486OpcodePrefix
, /* 0x26 */
80 Fast486OpcodeDaa
, /* 0x27 */
81 Fast486OpcodeCmpSubByteModrm
, /* 0x28 - 0x2B */
82 Fast486OpcodeCmpSubModrm
,
83 Fast486OpcodeCmpSubByteModrm
,
84 Fast486OpcodeCmpSubModrm
,
85 Fast486OpcodeCmpSubAl
, /* 0x2C */
86 Fast486OpcodeCmpSubEax
, /* 0x2D */
87 Fast486OpcodePrefix
, /* 0x2E */
88 Fast486OpcodeDas
, /* 0x2F */
89 Fast486OpcodeXorByteModrm
, /* 0x30 - 0x33 */
90 Fast486OpcodeXorModrm
,
91 Fast486OpcodeXorByteModrm
,
92 Fast486OpcodeXorModrm
,
93 Fast486OpcodeXorAl
, /* 0x34 */
94 Fast486OpcodeXorEax
, /* 0x35 */
95 Fast486OpcodePrefix
, /* 0x36 */
96 Fast486OpcodeAaa
, /* 0x37 */
97 Fast486OpcodeCmpSubByteModrm
, /* 0x38 - 0x3B */
98 Fast486OpcodeCmpSubModrm
,
99 Fast486OpcodeCmpSubByteModrm
,
100 Fast486OpcodeCmpSubModrm
,
101 Fast486OpcodeCmpSubAl
, /* 0x3C */
102 Fast486OpcodeCmpSubEax
, /* 0x3D */
103 Fast486OpcodePrefix
, /* 0x3E */
104 Fast486OpcodeAas
, /* 0x3F */
105 Fast486OpcodeIncrement
, /* 0x40 - 0x47 */
106 Fast486OpcodeIncrement
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeIncrement
,
113 Fast486OpcodeDecrement
, /* 0x48 - 0x4F */
114 Fast486OpcodeDecrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodeDecrement
,
121 Fast486OpcodePushReg
, /* 0x50 - 0x57 */
122 Fast486OpcodePushReg
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
128 Fast486OpcodePushReg
,
129 Fast486OpcodePopReg
, /* 0x58 - 0x5F */
137 Fast486OpcodePushAll
, /* 0x60 */
138 Fast486OpcodePopAll
, /* 0x61 */
139 Fast486OpcodeBound
, /* 0x62 */
140 Fast486OpcodeArpl
, /* 0x63 */
141 Fast486OpcodePrefix
, /* 0x64 - 0x67 */
145 Fast486OpcodePushImm
, /* 0x68 */
146 Fast486OpcodeImulModrmImm
, /* 0x69 */
147 Fast486OpcodePushByteImm
, /* 0x6A */
148 Fast486OpcodeImulModrmImm
, /* 0x6B */
149 Fast486OpcodeIns
, /* 0x6C */
150 Fast486OpcodeIns
, /* 0x6D */
151 Fast486OpcodeOuts
, /* 0x6E */
152 Fast486OpcodeOuts
, /* 0x6F */
153 Fast486OpcodeShortConditionalJmp
, /* 0x70 - 0x7F */
154 Fast486OpcodeShortConditionalJmp
,
155 Fast486OpcodeShortConditionalJmp
,
156 Fast486OpcodeShortConditionalJmp
,
157 Fast486OpcodeShortConditionalJmp
,
158 Fast486OpcodeShortConditionalJmp
,
159 Fast486OpcodeShortConditionalJmp
,
160 Fast486OpcodeShortConditionalJmp
,
161 Fast486OpcodeShortConditionalJmp
,
162 Fast486OpcodeShortConditionalJmp
,
163 Fast486OpcodeShortConditionalJmp
,
164 Fast486OpcodeShortConditionalJmp
,
165 Fast486OpcodeShortConditionalJmp
,
166 Fast486OpcodeShortConditionalJmp
,
167 Fast486OpcodeShortConditionalJmp
,
168 Fast486OpcodeShortConditionalJmp
,
169 Fast486OpcodeGroup8082
, /* 0x80 */
170 Fast486OpcodeGroup81
, /* 0x81 */
171 Fast486OpcodeGroup8082
, /* 0x82 */
172 Fast486OpcodeGroup83
, /* 0x83 */
173 Fast486OpcodeTestByteModrm
, /* 0x84 */
174 Fast486OpcodeTestModrm
, /* 0x85 */
175 Fast486OpcodeXchgByteModrm
, /* 0x86 */
176 Fast486OpcodeXchgModrm
, /* 0x87 */
177 Fast486OpcodeMovByteModrm
, /* 0x88 */
178 Fast486OpcodeMovModrm
, /* 0x89 */
179 Fast486OpcodeMovByteModrm
, /* 0x8A */
180 Fast486OpcodeMovModrm
, /* 0x8B */
181 Fast486OpcodeMovStoreSeg
, /* 0x8C */
182 Fast486OpcodeLea
, /* 0x8D */
183 Fast486OpcodeMovLoadSeg
, /* 0x8E */
184 Fast486OpcodeGroup8F
, /* 0x8F */
185 Fast486OpcodeNop
, /* 0x90 */
186 Fast486OpcodeExchangeEax
, /* 0x91 - 0x97 */
187 Fast486OpcodeExchangeEax
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
192 Fast486OpcodeExchangeEax
,
193 Fast486OpcodeCwde
, /* 0x98 */
194 Fast486OpcodeCdq
, /* 0x99 */
195 Fast486OpcodeCallAbs
, /* 0x9A */
196 Fast486OpcodeWait
, /* 0x9B */
197 Fast486OpcodePushFlags
, /* 0x9C */
198 Fast486OpcodePopFlags
, /* 0x9D */
199 Fast486OpcodeSahf
, /* 0x9E */
200 Fast486OpcodeLahf
, /* 0x9F */
201 Fast486OpcodeMovAlOffset
, /* 0xA0 */
202 Fast486OpcodeMovEaxOffset
, /* 0xA1 */
203 Fast486OpcodeMovOffsetAl
, /* 0xA2 */
204 Fast486OpcodeMovOffsetEax
, /* 0xA3 */
205 Fast486OpcodeMovs
, /* 0xA4 */
206 Fast486OpcodeMovs
, /* 0xA5 */
207 Fast486OpcodeCmps
, /* 0xA6 */
208 Fast486OpcodeCmps
, /* 0xA7 */
209 Fast486OpcodeTestAl
, /* 0xA8 */
210 Fast486OpcodeTestEax
, /* 0xA9 */
211 Fast486OpcodeStos
, /* 0xAA */
212 Fast486OpcodeStos
, /* 0xAB */
213 Fast486OpcodeLods
, /* 0xAC */
214 Fast486OpcodeLods
, /* 0xAD */
215 Fast486OpcodeScas
, /* 0xAE */
216 Fast486OpcodeScas
, /* 0xAF */
217 Fast486OpcodeMovByteRegImm
, /* 0xB0 - 0xB7 */
218 Fast486OpcodeMovByteRegImm
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovByteRegImm
,
225 Fast486OpcodeMovRegImm
, /* 0xB8 - 0xBF */
226 Fast486OpcodeMovRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeMovRegImm
,
233 Fast486OpcodeGroupC0
, /* 0xC0 */
234 Fast486OpcodeGroupC1
, /* 0xC1 */
235 Fast486OpcodeRet
, /* 0xC2 */
236 Fast486OpcodeRet
, /* 0xC3 */
237 Fast486OpcodeLdsLes
, /* 0xC4 */
238 Fast486OpcodeLdsLes
, /* 0xC5 */
239 Fast486OpcodeGroupC6
, /* 0xC6 */
240 Fast486OpcodeGroupC7
, /* 0xC7 */
241 Fast486OpcodeEnter
, /* 0xC8 */
242 Fast486OpcodeLeave
, /* 0xC9 */
243 Fast486OpcodeRetFar
, /* 0xCA */
244 Fast486OpcodeRetFar
, /* 0xCB */
245 Fast486OpcodeInt
, /* 0xCC */
246 Fast486OpcodeInt
, /* 0xCD */
247 Fast486OpcodeInt
, /* 0xCE */
248 Fast486OpcodeIret
, /* 0xCF */
249 Fast486OpcodeGroupD0
, /* 0xD0 - 0xD3 */
250 Fast486OpcodeGroupD1
,
251 Fast486OpcodeGroupD2
,
252 Fast486OpcodeGroupD3
,
253 Fast486OpcodeAam
, /* 0xD4 */
254 Fast486OpcodeAad
, /* 0xD5 */
255 Fast486OpcodeSalc
, /* 0xD6 */
256 Fast486OpcodeXlat
, /* 0xD7 */
257 Fast486FpuOpcodeD8DC
, /* 0xD8 - 0xDF */
261 Fast486FpuOpcodeD8DC
,
265 Fast486OpcodeLoop
, /* 0xE0 - 0xE2 */
268 Fast486OpcodeJecxz
, /* 0xE3 */
269 Fast486OpcodeInByte
, /* 0xE4 */
270 Fast486OpcodeIn
, /* 0xE5 */
271 Fast486OpcodeOutByte
, /* 0xE6 */
272 Fast486OpcodeOut
, /* 0xE7 */
273 Fast486OpcodeCall
, /* 0xE8 */
274 Fast486OpcodeJmp
, /* 0xE9 */
275 Fast486OpcodeJmpAbs
, /* 0xEA */
276 Fast486OpcodeShortJump
, /* 0xEB */
277 Fast486OpcodeInByte
, /* 0xEC */
278 Fast486OpcodeIn
, /* 0xED */
279 Fast486OpcodeOutByte
, /* 0xEE */
280 Fast486OpcodeOut
, /* 0xEF */
281 Fast486OpcodePrefix
, /* 0xF0 */
282 Fast486OpcodeInvalid
, /* 0xF1 */ // Invalid opcode -- ICEBP/INT01 opcode
283 Fast486OpcodePrefix
, /* 0xF2 */
284 Fast486OpcodePrefix
, /* 0xF3 */
285 Fast486OpcodeHalt
, /* 0xF4 */
286 Fast486OpcodeComplCarry
, /* 0xF5 */
287 Fast486OpcodeGroupF6
, /* 0xF6 */
288 Fast486OpcodeGroupF7
, /* 0xF7 */
289 Fast486OpcodeClearCarry
, /* 0xF8 */
290 Fast486OpcodeSetCarry
, /* 0xF9 */
291 Fast486OpcodeClearInt
, /* 0xFA */
292 Fast486OpcodeSetInt
, /* 0xFB */
293 Fast486OpcodeClearDir
, /* 0xFC */
294 Fast486OpcodeSetDir
, /* 0xFD */
295 Fast486OpcodeGroupFE
, /* 0xFE */
296 Fast486OpcodeGroupFF
, /* 0xFF */
299 /* PUBLIC FUNCTIONS ***********************************************************/
301 FAST486_OPCODE_HANDLER(Fast486OpcodeInvalid
)
304 * This is not a valid opcode.
305 * Well, not totally: see http://www.rcollins.org/secrets/opcodes/ICEBP.html
308 DPRINT1("FAST486 -- Calling ICEBP opcode\n");
309 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
313 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
315 BOOLEAN Valid
= FALSE
;
322 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
324 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
325 State
->SegmentOverride
= FAST486_REG_ES
;
335 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
337 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
338 State
->SegmentOverride
= FAST486_REG_CS
;
348 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
350 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
351 State
->SegmentOverride
= FAST486_REG_SS
;
361 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
363 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
364 State
->SegmentOverride
= FAST486_REG_DS
;
374 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
376 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
377 State
->SegmentOverride
= FAST486_REG_FS
;
387 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
389 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
390 State
->SegmentOverride
= FAST486_REG_GS
;
400 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
402 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
412 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
414 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
423 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
425 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
435 /* Mutually exclusive with REP */
436 if (!(State
->PrefixFlags
437 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
439 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
449 /* Mutually exclusive with REPNZ */
450 if (!(State
->PrefixFlags
451 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
453 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
463 /* Clear all prefixes */
464 State
->PrefixFlags
= 0;
466 /* Throw an exception */
467 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
474 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
477 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
482 /* Make sure this is the right instruction */
483 ASSERT((Opcode
& 0xF8) == 0x40);
487 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
489 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
490 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
494 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
496 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
497 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
500 State
->Flags
.Zf
= (Value
== 0);
501 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
502 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
508 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
511 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
516 /* Make sure this is the right instruction */
517 ASSERT((Opcode
& 0xF8) == 0x48);
521 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
523 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
524 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
528 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
530 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
531 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
534 State
->Flags
.Zf
= (Value
== 0);
535 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
536 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
542 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
546 /* Make sure this is the right instruction */
547 ASSERT((Opcode
& 0xF8) == 0x50);
549 /* Call the internal function */
550 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
553 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
556 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
561 /* Make sure this is the right instruction */
562 ASSERT((Opcode
& 0xF8) == 0x58);
564 /* Call the internal function */
565 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
567 /* Store the value */
568 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
569 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
575 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
577 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
580 State
->IdleCallback(State
);
586 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
588 INT Reg
= Opcode
& 0x07;
589 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
594 /* Make sure this is the right instruction */
595 ASSERT((Opcode
& 0xF8) == 0x90);
597 /* Exchange the values */
602 Value
= State
->GeneralRegs
[Reg
].Long
;
603 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
604 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
610 Value
= State
->GeneralRegs
[Reg
].LowWord
;
611 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
612 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
618 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
620 BOOLEAN Jump
= FALSE
;
622 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
624 /* Make sure this is the right instruction */
625 ASSERT((Opcode
& 0xF0) == 0x70);
629 /* Fetch the offset */
630 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
632 /* An exception occurred */
636 switch ((Opcode
& 0x0F) >> 1)
641 Jump
= State
->Flags
.Of
;
648 Jump
= State
->Flags
.Cf
;
655 Jump
= State
->Flags
.Zf
;
662 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
669 Jump
= State
->Flags
.Sf
;
676 Jump
= State
->Flags
.Pf
;
683 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
690 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
697 /* Invert the result */
703 /* Move the instruction pointer */
704 State
->InstPtr
.Long
+= Offset
;
708 /* Clear the top half of EIP */
709 State
->InstPtr
.Long
&= 0xFFFF;
717 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
719 /* Make sure this is the right instruction */
720 ASSERT(Opcode
== 0xF8);
722 /* No prefixes allowed */
723 if (State
->PrefixFlags
)
725 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
729 /* Clear CF and return success */
730 State
->Flags
.Cf
= FALSE
;
734 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
736 /* Make sure this is the right instruction */
737 ASSERT(Opcode
== 0xF9);
739 /* No prefixes allowed */
740 if (State
->PrefixFlags
)
742 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
746 /* Set CF and return success*/
747 State
->Flags
.Cf
= TRUE
;
751 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
753 /* Make sure this is the right instruction */
754 ASSERT(Opcode
== 0xF5);
756 /* No prefixes allowed */
757 if (State
->PrefixFlags
)
759 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
763 /* Toggle CF and return success */
764 State
->Flags
.Cf
= !State
->Flags
.Cf
;
768 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
770 /* Make sure this is the right instruction */
771 ASSERT(Opcode
== 0xFA);
773 /* No prefixes allowed */
774 if (State
->PrefixFlags
)
776 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
780 /* Check for protected mode */
781 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
784 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
786 /* Clear the interrupt flag */
787 State
->Flags
.If
= FALSE
;
791 /* General Protection Fault */
792 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
798 /* Just clear the interrupt flag */
799 State
->Flags
.If
= FALSE
;
806 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
808 /* Make sure this is the right instruction */
809 ASSERT(Opcode
== 0xFB);
811 /* No prefixes allowed */
812 if (State
->PrefixFlags
)
814 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
818 /* Check for protected mode */
819 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
822 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
824 /* Set the interrupt flag */
825 State
->Flags
.If
= TRUE
;
829 /* General Protection Fault */
830 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
836 /* Just set the interrupt flag */
837 State
->Flags
.If
= TRUE
;
844 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
846 /* Make sure this is the right instruction */
847 ASSERT(Opcode
== 0xFC);
849 /* No prefixes allowed */
850 if (State
->PrefixFlags
)
852 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
856 /* Clear DF and return success */
857 State
->Flags
.Df
= FALSE
;
861 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
863 /* Make sure this is the right instruction */
864 ASSERT(Opcode
== 0xFD);
866 /* No prefixes allowed */
867 if (State
->PrefixFlags
)
869 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
873 /* Set DF and return success*/
874 State
->Flags
.Df
= TRUE
;
878 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
880 /* Make sure this is the right instruction */
881 ASSERT(Opcode
== 0xF4);
883 /* No prefixes allowed */
884 if (State
->PrefixFlags
)
886 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
890 /* Privileged instructions can only be executed under CPL = 0 */
891 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
893 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
898 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
904 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
909 /* Make sure this is the right instruction */
910 ASSERT((Opcode
& 0xF7) == 0xE4);
914 /* Fetch the parameter */
915 if (!Fast486FetchByte(State
, &Data
))
917 /* Exception occurred */
921 /* Set the port number to the parameter */
926 /* The port number is in DX */
927 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
930 /* Read a byte from the I/O port */
931 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
933 /* Store the result in AL */
934 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
939 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
942 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
944 /* Make sure this is the right instruction */
945 ASSERT((Opcode
& 0xF7) == 0xE5);
954 /* Fetch the parameter */
955 if (!Fast486FetchByte(State
, &Data
))
957 /* Exception occurred */
961 /* Set the port number to the parameter */
966 /* The port number is in DX */
967 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
974 /* Read a dword from the I/O port */
975 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
977 /* Store the value in EAX */
978 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
984 /* Read a word from the I/O port */
985 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
987 /* Store the value in AX */
988 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
994 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
999 /* Make sure this is the right instruction */
1000 ASSERT((Opcode
& 0xF7) == 0xE6);
1004 /* Fetch the parameter */
1005 if (!Fast486FetchByte(State
, &Data
))
1007 /* Exception occurred */
1011 /* Set the port number to the parameter */
1016 /* The port number is in DX */
1017 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1020 /* Read the value from AL */
1021 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1023 /* Write the byte to the I/O port */
1024 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
1029 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1032 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1034 /* Make sure this is the right instruction */
1035 ASSERT((Opcode
& 0xF7) == 0xE7);
1037 TOGGLE_OPSIZE(Size
);
1044 /* Fetch the parameter */
1045 if (!Fast486FetchByte(State
, &Data
))
1047 /* Exception occurred */
1051 /* Set the port number to the parameter */
1056 /* The port number is in DX */
1057 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1062 /* Get the value from EAX */
1063 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1065 /* Write a dword to the I/O port */
1066 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1070 /* Get the value from AX */
1071 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1073 /* Write a word to the I/O port */
1074 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1080 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1083 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1085 TOGGLE_OPSIZE(Size
);
1087 /* Make sure this is the right instruction */
1088 ASSERT(Opcode
== 0xEB);
1090 /* Fetch the offset */
1091 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1093 /* An exception occurred */
1097 /* Move the instruction pointer */
1098 State
->InstPtr
.Long
+= Offset
;
1102 /* Clear the top half of EIP */
1103 State
->InstPtr
.Long
&= 0xFFFF;
1109 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1111 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1113 /* Make sure this is the right instruction */
1114 ASSERT((Opcode
& 0xF8) == 0xB8);
1116 TOGGLE_OPSIZE(Size
);
1123 /* Fetch the dword */
1124 if (!Fast486FetchDword(State
, &Value
))
1126 /* Exception occurred */
1130 /* Store the value in the register */
1131 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1137 /* Fetch the word */
1138 if (!Fast486FetchWord(State
, &Value
))
1140 /* Exception occurred */
1144 /* Store the value in the register */
1145 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1151 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1155 /* Make sure this is the right instruction */
1156 ASSERT((Opcode
& 0xF8) == 0xB0);
1158 if (State
->PrefixFlags
!= 0)
1160 /* Invalid prefix */
1161 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1165 /* Fetch the byte */
1166 if (!Fast486FetchByte(State
, &Value
))
1168 /* Exception occurred */
1174 /* AH, CH, DH or BH */
1175 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1179 /* AL, CL, DL or BL */
1180 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1186 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1188 UCHAR FirstValue
, SecondValue
, Result
;
1189 FAST486_MOD_REG_RM ModRegRm
;
1190 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1192 /* Make sure this is the right instruction */
1193 ASSERT((Opcode
& 0xFD) == 0x00);
1195 TOGGLE_ADSIZE(AddressSize
);
1197 /* Get the operands */
1198 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1200 /* Exception occurred */
1204 if (!Fast486ReadModrmByteOperands(State
,
1209 /* Exception occurred */
1213 /* Calculate the result */
1214 Result
= FirstValue
+ SecondValue
;
1216 /* Update the flags */
1217 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1218 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1219 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1220 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1221 State
->Flags
.Zf
= (Result
== 0);
1222 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1223 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1225 /* Write back the result */
1226 return Fast486WriteModrmByteOperands(State
,
1228 Opcode
& FAST486_OPCODE_WRITE_REG
,
1232 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1234 FAST486_MOD_REG_RM ModRegRm
;
1235 BOOLEAN OperandSize
, AddressSize
;
1237 /* Make sure this is the right instruction */
1238 ASSERT((Opcode
& 0xFD) == 0x01);
1240 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1242 TOGGLE_ADSIZE(AddressSize
);
1243 TOGGLE_OPSIZE(OperandSize
);
1245 /* Get the operands */
1246 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1248 /* Exception occurred */
1252 /* Check the operand size */
1255 ULONG FirstValue
, SecondValue
, Result
;
1257 if (!Fast486ReadModrmDwordOperands(State
,
1262 /* Exception occurred */
1266 /* Calculate the result */
1267 Result
= FirstValue
+ SecondValue
;
1269 /* Update the flags */
1270 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1271 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1272 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1273 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1274 State
->Flags
.Zf
= (Result
== 0);
1275 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1276 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1278 /* Write back the result */
1279 return Fast486WriteModrmDwordOperands(State
,
1281 Opcode
& FAST486_OPCODE_WRITE_REG
,
1286 USHORT FirstValue
, SecondValue
, Result
;
1288 if (!Fast486ReadModrmWordOperands(State
,
1293 /* Exception occurred */
1297 /* Calculate the result */
1298 Result
= FirstValue
+ SecondValue
;
1300 /* Update the flags */
1301 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1302 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1303 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1304 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1305 State
->Flags
.Zf
= (Result
== 0);
1306 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1307 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1309 /* Write back the result */
1310 return Fast486WriteModrmWordOperands(State
,
1312 Opcode
& FAST486_OPCODE_WRITE_REG
,
1317 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1319 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1320 UCHAR SecondValue
, Result
;
1322 /* Make sure this is the right instruction */
1323 ASSERT(Opcode
== 0x04);
1325 if (State
->PrefixFlags
)
1327 /* This opcode doesn't take any prefixes */
1328 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1332 if (!Fast486FetchByte(State
, &SecondValue
))
1334 /* Exception occurred */
1338 /* Calculate the result */
1339 Result
= FirstValue
+ SecondValue
;
1341 /* Update the flags */
1342 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1343 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1344 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1345 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1346 State
->Flags
.Zf
= (Result
== 0);
1347 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1348 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1350 /* Write back the result */
1351 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1356 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1358 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1360 /* Make sure this is the right instruction */
1361 ASSERT(Opcode
== 0x05);
1364 TOGGLE_OPSIZE(Size
);
1368 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1369 ULONG SecondValue
, Result
;
1371 if (!Fast486FetchDword(State
, &SecondValue
))
1373 /* Exception occurred */
1377 /* Calculate the result */
1378 Result
= FirstValue
+ SecondValue
;
1380 /* Update the flags */
1381 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1382 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1383 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1384 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1385 State
->Flags
.Zf
= (Result
== 0);
1386 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1387 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1389 /* Write back the result */
1390 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1394 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1395 USHORT SecondValue
, Result
;
1397 if (!Fast486FetchWord(State
, &SecondValue
))
1399 /* Exception occurred */
1403 /* Calculate the result */
1404 Result
= FirstValue
+ SecondValue
;
1406 /* Update the flags */
1407 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1408 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1409 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1410 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1411 State
->Flags
.Zf
= (Result
== 0);
1412 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1413 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1415 /* Write back the result */
1416 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1422 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1424 UCHAR FirstValue
, SecondValue
, Result
;
1425 FAST486_MOD_REG_RM ModRegRm
;
1426 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1428 /* Make sure this is the right instruction */
1429 ASSERT((Opcode
& 0xFD) == 0x08);
1431 TOGGLE_ADSIZE(AddressSize
);
1433 /* Get the operands */
1434 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1436 /* Exception occurred */
1440 if (!Fast486ReadModrmByteOperands(State
,
1445 /* Exception occurred */
1449 /* Calculate the result */
1450 Result
= FirstValue
| SecondValue
;
1452 /* Update the flags */
1453 State
->Flags
.Cf
= FALSE
;
1454 State
->Flags
.Of
= FALSE
;
1455 State
->Flags
.Zf
= (Result
== 0);
1456 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1457 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1459 /* Write back the result */
1460 return Fast486WriteModrmByteOperands(State
,
1462 Opcode
& FAST486_OPCODE_WRITE_REG
,
1466 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1468 FAST486_MOD_REG_RM ModRegRm
;
1469 BOOLEAN OperandSize
, AddressSize
;
1471 /* Make sure this is the right instruction */
1472 ASSERT((Opcode
& 0xFD) == 0x09);
1474 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1476 TOGGLE_ADSIZE(AddressSize
);
1477 TOGGLE_OPSIZE(OperandSize
);
1479 /* Get the operands */
1480 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1482 /* Exception occurred */
1486 /* Check the operand size */
1489 ULONG FirstValue
, SecondValue
, Result
;
1491 if (!Fast486ReadModrmDwordOperands(State
,
1496 /* Exception occurred */
1500 /* Calculate the result */
1501 Result
= FirstValue
| SecondValue
;
1503 /* Update the flags */
1504 State
->Flags
.Cf
= FALSE
;
1505 State
->Flags
.Of
= FALSE
;
1506 State
->Flags
.Zf
= (Result
== 0);
1507 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1508 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1510 /* Write back the result */
1511 return Fast486WriteModrmDwordOperands(State
,
1513 Opcode
& FAST486_OPCODE_WRITE_REG
,
1518 USHORT FirstValue
, SecondValue
, Result
;
1520 if (!Fast486ReadModrmWordOperands(State
,
1525 /* Exception occurred */
1529 /* Calculate the result */
1530 Result
= FirstValue
| SecondValue
;
1532 /* Update the flags */
1533 State
->Flags
.Cf
= FALSE
;
1534 State
->Flags
.Of
= FALSE
;
1535 State
->Flags
.Zf
= (Result
== 0);
1536 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1537 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1539 /* Write back the result */
1540 return Fast486WriteModrmWordOperands(State
,
1542 Opcode
& FAST486_OPCODE_WRITE_REG
,
1547 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1549 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1550 UCHAR SecondValue
, Result
;
1552 /* Make sure this is the right instruction */
1553 ASSERT(Opcode
== 0x0C);
1555 if (State
->PrefixFlags
)
1557 /* This opcode doesn't take any prefixes */
1558 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1562 if (!Fast486FetchByte(State
, &SecondValue
))
1564 /* Exception occurred */
1568 /* Calculate the result */
1569 Result
= FirstValue
| SecondValue
;
1571 /* Update the flags */
1572 State
->Flags
.Cf
= FALSE
;
1573 State
->Flags
.Of
= FALSE
;
1574 State
->Flags
.Zf
= (Result
== 0);
1575 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1576 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1578 /* Write back the result */
1579 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1584 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1586 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1588 /* Make sure this is the right instruction */
1589 ASSERT(Opcode
== 0x0D);
1592 TOGGLE_OPSIZE(Size
);
1596 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1597 ULONG SecondValue
, Result
;
1599 if (!Fast486FetchDword(State
, &SecondValue
))
1601 /* Exception occurred */
1605 /* Calculate the result */
1606 Result
= FirstValue
| SecondValue
;
1608 /* Update the flags */
1609 State
->Flags
.Cf
= FALSE
;
1610 State
->Flags
.Of
= FALSE
;
1611 State
->Flags
.Zf
= (Result
== 0);
1612 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1613 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1615 /* Write back the result */
1616 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1620 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1621 USHORT SecondValue
, Result
;
1623 if (!Fast486FetchWord(State
, &SecondValue
))
1625 /* Exception occurred */
1629 /* Calculate the result */
1630 Result
= FirstValue
| SecondValue
;
1632 /* Update the flags */
1633 State
->Flags
.Cf
= FALSE
;
1634 State
->Flags
.Of
= FALSE
;
1635 State
->Flags
.Zf
= (Result
== 0);
1636 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1637 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1639 /* Write back the result */
1640 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1646 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1648 UCHAR FirstValue
, SecondValue
, Result
;
1649 FAST486_MOD_REG_RM ModRegRm
;
1650 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1652 /* Make sure this is the right instruction */
1653 ASSERT((Opcode
& 0xFD) == 0x20);
1655 TOGGLE_ADSIZE(AddressSize
);
1657 /* Get the operands */
1658 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1660 /* Exception occurred */
1664 if (!Fast486ReadModrmByteOperands(State
,
1669 /* Exception occurred */
1673 /* Calculate the result */
1674 Result
= FirstValue
& SecondValue
;
1676 /* Update the flags */
1677 State
->Flags
.Cf
= FALSE
;
1678 State
->Flags
.Of
= FALSE
;
1679 State
->Flags
.Zf
= (Result
== 0);
1680 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1681 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1683 /* Write back the result */
1684 return Fast486WriteModrmByteOperands(State
,
1686 Opcode
& FAST486_OPCODE_WRITE_REG
,
1690 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1692 FAST486_MOD_REG_RM ModRegRm
;
1693 BOOLEAN OperandSize
, AddressSize
;
1695 /* Make sure this is the right instruction */
1696 ASSERT((Opcode
& 0xFD) == 0x21);
1698 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1700 TOGGLE_ADSIZE(AddressSize
);
1701 TOGGLE_OPSIZE(OperandSize
);
1703 /* Get the operands */
1704 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1706 /* Exception occurred */
1710 /* Check the operand size */
1713 ULONG FirstValue
, SecondValue
, Result
;
1715 if (!Fast486ReadModrmDwordOperands(State
,
1720 /* Exception occurred */
1724 /* Calculate the result */
1725 Result
= FirstValue
& SecondValue
;
1727 /* Update the flags */
1728 State
->Flags
.Cf
= FALSE
;
1729 State
->Flags
.Of
= FALSE
;
1730 State
->Flags
.Zf
= (Result
== 0);
1731 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1732 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1734 /* Write back the result */
1735 return Fast486WriteModrmDwordOperands(State
,
1737 Opcode
& FAST486_OPCODE_WRITE_REG
,
1742 USHORT FirstValue
, SecondValue
, Result
;
1744 if (!Fast486ReadModrmWordOperands(State
,
1749 /* Exception occurred */
1753 /* Calculate the result */
1754 Result
= FirstValue
& SecondValue
;
1756 /* Update the flags */
1757 State
->Flags
.Cf
= FALSE
;
1758 State
->Flags
.Of
= FALSE
;
1759 State
->Flags
.Zf
= (Result
== 0);
1760 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1761 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1763 /* Write back the result */
1764 return Fast486WriteModrmWordOperands(State
,
1766 Opcode
& FAST486_OPCODE_WRITE_REG
,
1771 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1773 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1774 UCHAR SecondValue
, Result
;
1776 /* Make sure this is the right instruction */
1777 ASSERT(Opcode
== 0x24);
1781 if (!Fast486FetchByte(State
, &SecondValue
))
1783 /* Exception occurred */
1787 /* Calculate the result */
1788 Result
= FirstValue
& SecondValue
;
1790 /* Update the flags */
1791 State
->Flags
.Cf
= FALSE
;
1792 State
->Flags
.Of
= FALSE
;
1793 State
->Flags
.Zf
= (Result
== 0);
1794 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1795 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1797 /* Write back the result */
1798 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1803 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1805 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1807 /* Make sure this is the right instruction */
1808 ASSERT(Opcode
== 0x25);
1811 TOGGLE_OPSIZE(Size
);
1815 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1816 ULONG SecondValue
, Result
;
1818 if (!Fast486FetchDword(State
, &SecondValue
))
1820 /* Exception occurred */
1824 /* Calculate the result */
1825 Result
= FirstValue
& SecondValue
;
1827 /* Update the flags */
1828 State
->Flags
.Cf
= FALSE
;
1829 State
->Flags
.Of
= FALSE
;
1830 State
->Flags
.Zf
= (Result
== 0);
1831 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1832 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1834 /* Write back the result */
1835 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1839 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1840 USHORT SecondValue
, Result
;
1842 if (!Fast486FetchWord(State
, &SecondValue
))
1844 /* Exception occurred */
1848 /* Calculate the result */
1849 Result
= FirstValue
& SecondValue
;
1851 /* Update the flags */
1852 State
->Flags
.Cf
= FALSE
;
1853 State
->Flags
.Of
= FALSE
;
1854 State
->Flags
.Zf
= (Result
== 0);
1855 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1856 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1858 /* Write back the result */
1859 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1865 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1867 UCHAR FirstValue
, SecondValue
, Result
;
1868 FAST486_MOD_REG_RM ModRegRm
;
1869 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1871 /* Make sure this is the right instruction */
1872 ASSERT((Opcode
& 0xFD) == 0x30);
1874 TOGGLE_ADSIZE(AddressSize
);
1876 /* Get the operands */
1877 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1879 /* Exception occurred */
1883 if (!Fast486ReadModrmByteOperands(State
,
1888 /* Exception occurred */
1892 /* Calculate the result */
1893 Result
= FirstValue
^ SecondValue
;
1895 /* Update the flags */
1896 State
->Flags
.Cf
= FALSE
;
1897 State
->Flags
.Of
= FALSE
;
1898 State
->Flags
.Zf
= (Result
== 0);
1899 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1900 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1902 /* Write back the result */
1903 return Fast486WriteModrmByteOperands(State
,
1905 Opcode
& FAST486_OPCODE_WRITE_REG
,
1909 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1911 FAST486_MOD_REG_RM ModRegRm
;
1912 BOOLEAN OperandSize
, AddressSize
;
1914 /* Make sure this is the right instruction */
1915 ASSERT((Opcode
& 0xFD) == 0x31);
1917 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1919 TOGGLE_ADSIZE(AddressSize
);
1920 TOGGLE_OPSIZE(OperandSize
);
1922 /* Get the operands */
1923 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1925 /* Exception occurred */
1929 /* Check the operand size */
1932 ULONG FirstValue
, SecondValue
, Result
;
1934 if (!Fast486ReadModrmDwordOperands(State
,
1939 /* Exception occurred */
1943 /* Calculate the result */
1944 Result
= FirstValue
^ SecondValue
;
1946 /* Update the flags */
1947 State
->Flags
.Cf
= FALSE
;
1948 State
->Flags
.Of
= FALSE
;
1949 State
->Flags
.Zf
= (Result
== 0);
1950 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1951 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1953 /* Write back the result */
1954 return Fast486WriteModrmDwordOperands(State
,
1956 Opcode
& FAST486_OPCODE_WRITE_REG
,
1961 USHORT FirstValue
, SecondValue
, Result
;
1963 if (!Fast486ReadModrmWordOperands(State
,
1968 /* Exception occurred */
1972 /* Calculate the result */
1973 Result
= FirstValue
^ SecondValue
;
1975 /* Update the flags */
1976 State
->Flags
.Cf
= FALSE
;
1977 State
->Flags
.Of
= FALSE
;
1978 State
->Flags
.Zf
= (Result
== 0);
1979 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1980 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1982 /* Write back the result */
1983 return Fast486WriteModrmWordOperands(State
,
1985 Opcode
& FAST486_OPCODE_WRITE_REG
,
1990 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1992 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1993 UCHAR SecondValue
, Result
;
1995 /* Make sure this is the right instruction */
1996 ASSERT(Opcode
== 0x34);
1998 if (State
->PrefixFlags
)
2000 /* This opcode doesn't take any prefixes */
2001 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2005 if (!Fast486FetchByte(State
, &SecondValue
))
2007 /* Exception occurred */
2011 /* Calculate the result */
2012 Result
= FirstValue
^ SecondValue
;
2014 /* Update the flags */
2015 State
->Flags
.Cf
= FALSE
;
2016 State
->Flags
.Of
= FALSE
;
2017 State
->Flags
.Zf
= (Result
== 0);
2018 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2019 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2021 /* Write back the result */
2022 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2027 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2029 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2031 /* Make sure this is the right instruction */
2032 ASSERT(Opcode
== 0x35);
2035 TOGGLE_OPSIZE(Size
);
2039 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2040 ULONG SecondValue
, Result
;
2042 if (!Fast486FetchDword(State
, &SecondValue
))
2044 /* Exception occurred */
2048 /* Calculate the result */
2049 Result
= FirstValue
^ SecondValue
;
2051 /* Update the flags */
2052 State
->Flags
.Cf
= FALSE
;
2053 State
->Flags
.Of
= FALSE
;
2054 State
->Flags
.Zf
= (Result
== 0);
2055 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2056 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2058 /* Write back the result */
2059 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2063 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2064 USHORT SecondValue
, Result
;
2066 if (!Fast486FetchWord(State
, &SecondValue
))
2068 /* Exception occurred */
2072 /* Calculate the result */
2073 Result
= FirstValue
^ SecondValue
;
2075 /* Update the flags */
2076 State
->Flags
.Cf
= FALSE
;
2077 State
->Flags
.Of
= FALSE
;
2078 State
->Flags
.Zf
= (Result
== 0);
2079 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2080 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2082 /* Write back the result */
2083 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2089 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2091 UCHAR FirstValue
, SecondValue
, Result
;
2092 FAST486_MOD_REG_RM ModRegRm
;
2093 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2095 /* Make sure this is the right instruction */
2096 ASSERT(Opcode
== 0x84);
2098 TOGGLE_ADSIZE(AddressSize
);
2100 /* Get the operands */
2101 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2103 /* Exception occurred */
2107 if (!Fast486ReadModrmByteOperands(State
,
2112 /* Exception occurred */
2115 /* Calculate the result */
2116 Result
= FirstValue
& SecondValue
;
2118 /* Update the flags */
2119 State
->Flags
.Cf
= FALSE
;
2120 State
->Flags
.Of
= FALSE
;
2121 State
->Flags
.Zf
= (Result
== 0);
2122 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2123 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2125 /* The result is discarded */
2129 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2131 FAST486_MOD_REG_RM ModRegRm
;
2132 BOOLEAN OperandSize
, AddressSize
;
2134 /* Make sure this is the right instruction */
2135 ASSERT(Opcode
== 0x85);
2137 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2139 TOGGLE_ADSIZE(AddressSize
);
2140 TOGGLE_OPSIZE(OperandSize
);
2142 /* Get the operands */
2143 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2145 /* Exception occurred */
2149 /* Check the operand size */
2152 ULONG FirstValue
, SecondValue
, Result
;
2154 if (!Fast486ReadModrmDwordOperands(State
,
2159 /* Exception occurred */
2163 /* Calculate the result */
2164 Result
= FirstValue
& SecondValue
;
2166 /* Update the flags */
2167 State
->Flags
.Cf
= FALSE
;
2168 State
->Flags
.Of
= FALSE
;
2169 State
->Flags
.Zf
= (Result
== 0);
2170 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2171 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2175 USHORT FirstValue
, SecondValue
, Result
;
2177 if (!Fast486ReadModrmWordOperands(State
,
2182 /* Exception occurred */
2186 /* Calculate the result */
2187 Result
= FirstValue
& SecondValue
;
2189 /* Update the flags */
2190 State
->Flags
.Cf
= FALSE
;
2191 State
->Flags
.Of
= FALSE
;
2192 State
->Flags
.Zf
= (Result
== 0);
2193 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2194 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2197 /* The result is discarded */
2201 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2203 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2204 UCHAR SecondValue
, Result
;
2206 /* Make sure this is the right instruction */
2207 ASSERT(Opcode
== 0xA8);
2209 if (State
->PrefixFlags
)
2211 /* This opcode doesn't take any prefixes */
2212 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2216 if (!Fast486FetchByte(State
, &SecondValue
))
2218 /* Exception occurred */
2222 /* Calculate the result */
2223 Result
= FirstValue
& SecondValue
;
2225 /* Update the flags */
2226 State
->Flags
.Cf
= FALSE
;
2227 State
->Flags
.Of
= FALSE
;
2228 State
->Flags
.Zf
= (Result
== 0);
2229 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2230 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2232 /* The result is discarded */
2236 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2238 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2240 /* Make sure this is the right instruction */
2241 ASSERT(Opcode
== 0xA9);
2244 TOGGLE_OPSIZE(Size
);
2248 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2249 ULONG SecondValue
, Result
;
2251 if (!Fast486FetchDword(State
, &SecondValue
))
2253 /* Exception occurred */
2257 /* Calculate the result */
2258 Result
= FirstValue
& SecondValue
;
2260 /* Update the flags */
2261 State
->Flags
.Cf
= FALSE
;
2262 State
->Flags
.Of
= FALSE
;
2263 State
->Flags
.Zf
= (Result
== 0);
2264 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2265 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2269 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2270 USHORT SecondValue
, Result
;
2272 if (!Fast486FetchWord(State
, &SecondValue
))
2274 /* Exception occurred */
2278 /* Calculate the result */
2279 Result
= FirstValue
& SecondValue
;
2281 /* Update the flags */
2282 State
->Flags
.Cf
= FALSE
;
2283 State
->Flags
.Of
= FALSE
;
2284 State
->Flags
.Zf
= (Result
== 0);
2285 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2286 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2289 /* The result is discarded */
2293 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2295 UCHAR FirstValue
, SecondValue
;
2296 FAST486_MOD_REG_RM ModRegRm
;
2297 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2299 /* Make sure this is the right instruction */
2300 ASSERT(Opcode
== 0x86);
2302 TOGGLE_ADSIZE(AddressSize
);
2304 /* Get the operands */
2305 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2307 /* Exception occurred */
2311 if (!Fast486ReadModrmByteOperands(State
,
2316 /* Exception occurred */
2320 /* Write the value from the register to the R/M */
2321 if (!Fast486WriteModrmByteOperands(State
,
2326 /* Exception occurred */
2330 /* Write the value from the R/M to the register */
2331 if (!Fast486WriteModrmByteOperands(State
,
2336 /* Exception occurred */
2343 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2345 FAST486_MOD_REG_RM ModRegRm
;
2346 BOOLEAN OperandSize
, AddressSize
;
2348 /* Make sure this is the right instruction */
2349 ASSERT(Opcode
== 0x87);
2351 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2353 TOGGLE_ADSIZE(AddressSize
);
2354 TOGGLE_OPSIZE(OperandSize
);
2356 /* Get the operands */
2357 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2359 /* Exception occurred */
2363 /* Check the operand size */
2366 ULONG FirstValue
, SecondValue
;
2368 if (!Fast486ReadModrmDwordOperands(State
,
2373 /* Exception occurred */
2377 /* Write the value from the register to the R/M */
2378 if (!Fast486WriteModrmDwordOperands(State
,
2383 /* Exception occurred */
2387 /* Write the value from the R/M to the register */
2388 if (!Fast486WriteModrmDwordOperands(State
,
2393 /* Exception occurred */
2399 USHORT FirstValue
, SecondValue
;
2401 if (!Fast486ReadModrmWordOperands(State
,
2406 /* Exception occurred */
2410 /* Write the value from the register to the R/M */
2411 if (!Fast486WriteModrmWordOperands(State
,
2416 /* Exception occurred */
2420 /* Write the value from the R/M to the register */
2421 if (!Fast486WriteModrmWordOperands(State
,
2426 /* Exception occurred */
2431 /* The result is discarded */
2435 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2437 /* Call the internal API */
2438 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2441 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2445 if (!Fast486StackPop(State
, &NewSelector
))
2447 /* Exception occurred */
2451 /* Call the internal API */
2452 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2455 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2457 /* Call the internal API */
2458 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2461 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2463 UCHAR FirstValue
, SecondValue
, Result
;
2464 FAST486_MOD_REG_RM ModRegRm
;
2465 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2467 /* Make sure this is the right instruction */
2468 ASSERT((Opcode
& 0xFD) == 0x10);
2470 TOGGLE_ADSIZE(AddressSize
);
2472 /* Get the operands */
2473 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2475 /* Exception occurred */
2479 if (!Fast486ReadModrmByteOperands(State
,
2484 /* Exception occurred */
2488 /* Calculate the result */
2489 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2491 /* Special exception for CF */
2492 State
->Flags
.Cf
= State
->Flags
.Cf
2493 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2495 /* Update the flags */
2496 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2497 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2498 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2499 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2500 State
->Flags
.Zf
= (Result
== 0);
2501 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2502 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2504 /* Write back the result */
2505 return Fast486WriteModrmByteOperands(State
,
2507 Opcode
& FAST486_OPCODE_WRITE_REG
,
2511 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2513 FAST486_MOD_REG_RM ModRegRm
;
2514 BOOLEAN OperandSize
, AddressSize
;
2516 /* Make sure this is the right instruction */
2517 ASSERT((Opcode
& 0xFD) == 0x11);
2519 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2521 TOGGLE_ADSIZE(AddressSize
);
2522 TOGGLE_OPSIZE(OperandSize
);
2524 /* Get the operands */
2525 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2527 /* Exception occurred */
2531 /* Check the operand size */
2534 ULONG FirstValue
, SecondValue
, Result
;
2536 if (!Fast486ReadModrmDwordOperands(State
,
2541 /* Exception occurred */
2545 /* Calculate the result */
2546 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2548 /* Special exception for CF */
2549 State
->Flags
.Cf
= State
->Flags
.Cf
2550 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2552 /* Update the flags */
2553 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2554 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2555 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2556 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2557 State
->Flags
.Zf
= (Result
== 0);
2558 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2559 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2561 /* Write back the result */
2562 return Fast486WriteModrmDwordOperands(State
,
2564 Opcode
& FAST486_OPCODE_WRITE_REG
,
2569 USHORT FirstValue
, SecondValue
, Result
;
2571 if (!Fast486ReadModrmWordOperands(State
,
2576 /* Exception occurred */
2580 /* Calculate the result */
2581 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2583 /* Special exception for CF */
2584 State
->Flags
.Cf
= State
->Flags
.Cf
2585 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2587 /* Update the flags */
2588 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2589 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2590 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2591 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2592 State
->Flags
.Zf
= (Result
== 0);
2593 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2594 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2596 /* Write back the result */
2597 return Fast486WriteModrmWordOperands(State
,
2599 Opcode
& FAST486_OPCODE_WRITE_REG
,
2605 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2607 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2608 UCHAR SecondValue
, Result
;
2610 /* Make sure this is the right instruction */
2611 ASSERT(Opcode
== 0x14);
2613 if (State
->PrefixFlags
)
2615 /* This opcode doesn't take any prefixes */
2616 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2620 if (!Fast486FetchByte(State
, &SecondValue
))
2622 /* Exception occurred */
2626 /* Calculate the result */
2627 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2629 /* Special exception for CF */
2630 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2631 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2633 /* Update the flags */
2634 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2635 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2636 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2637 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2638 State
->Flags
.Zf
= (Result
== 0);
2639 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2640 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2642 /* Write back the result */
2643 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2648 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2650 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2652 /* Make sure this is the right instruction */
2653 ASSERT(Opcode
== 0x15);
2656 TOGGLE_OPSIZE(Size
);
2660 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2661 ULONG SecondValue
, Result
;
2663 if (!Fast486FetchDword(State
, &SecondValue
))
2665 /* Exception occurred */
2669 /* Calculate the result */
2670 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2672 /* Special exception for CF */
2673 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2674 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2676 /* Update the flags */
2677 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2678 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2679 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2680 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2681 State
->Flags
.Zf
= (Result
== 0);
2682 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2683 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2685 /* Write back the result */
2686 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2690 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2691 USHORT SecondValue
, Result
;
2693 if (!Fast486FetchWord(State
, &SecondValue
))
2695 /* Exception occurred */
2699 /* Calculate the result */
2700 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2702 /* Special exception for CF */
2703 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2704 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2706 /* Update the flags */
2707 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2708 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2709 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2710 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2711 State
->Flags
.Zf
= (Result
== 0);
2712 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2713 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2715 /* Write back the result */
2716 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2722 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2724 /* Call the internal API */
2725 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2728 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2732 if (!Fast486StackPop(State
, &NewSelector
))
2734 /* Exception occurred */
2738 /* Call the internal API */
2739 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2742 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2744 UCHAR FirstValue
, SecondValue
, Result
;
2745 FAST486_MOD_REG_RM ModRegRm
;
2746 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2747 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2749 /* Make sure this is the right instruction */
2750 ASSERT((Opcode
& 0xFD) == 0x18);
2752 TOGGLE_ADSIZE(AddressSize
);
2754 /* Get the operands */
2755 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2757 /* Exception occurred */
2761 if (!Fast486ReadModrmByteOperands(State
,
2766 /* Exception occurred */
2770 /* Check if this is the instruction that writes to R/M */
2771 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2773 /* Swap the order */
2774 SWAP(FirstValue
, SecondValue
);
2777 /* Calculate the result */
2778 Result
= FirstValue
- SecondValue
- Carry
;
2780 /* Update the flags */
2781 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2782 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2783 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2784 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2785 State
->Flags
.Zf
= (Result
== 0);
2786 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2787 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2789 /* Write back the result */
2790 return Fast486WriteModrmByteOperands(State
,
2792 Opcode
& FAST486_OPCODE_WRITE_REG
,
2796 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2798 FAST486_MOD_REG_RM ModRegRm
;
2799 BOOLEAN OperandSize
, AddressSize
;
2800 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2802 /* Make sure this is the right instruction */
2803 ASSERT((Opcode
& 0xFD) == 0x19);
2805 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2807 TOGGLE_ADSIZE(AddressSize
);
2808 TOGGLE_OPSIZE(OperandSize
);
2810 /* Get the operands */
2811 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2813 /* Exception occurred */
2817 /* Check the operand size */
2820 ULONG FirstValue
, SecondValue
, Result
;
2822 if (!Fast486ReadModrmDwordOperands(State
,
2827 /* Exception occurred */
2831 /* Check if this is the instruction that writes to R/M */
2832 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2834 /* Swap the order */
2835 SWAP(FirstValue
, SecondValue
);
2838 /* Calculate the result */
2839 Result
= FirstValue
- SecondValue
- Carry
;
2841 /* Update the flags */
2842 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2843 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2844 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2845 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2846 State
->Flags
.Zf
= (Result
== 0);
2847 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2848 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2850 /* Write back the result */
2851 return Fast486WriteModrmDwordOperands(State
,
2853 Opcode
& FAST486_OPCODE_WRITE_REG
,
2858 USHORT FirstValue
, SecondValue
, Result
;
2860 if (!Fast486ReadModrmWordOperands(State
,
2865 /* Exception occurred */
2869 /* Check if this is the instruction that writes to R/M */
2870 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2872 /* Swap the order */
2873 SWAP(FirstValue
, SecondValue
);
2876 /* Calculate the result */
2877 Result
= FirstValue
- SecondValue
- Carry
;
2879 /* Update the flags */
2880 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2881 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2882 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2883 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2884 State
->Flags
.Zf
= (Result
== 0);
2885 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2886 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2888 /* Write back the result */
2889 return Fast486WriteModrmWordOperands(State
,
2891 Opcode
& FAST486_OPCODE_WRITE_REG
,
2896 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2898 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2899 UCHAR SecondValue
, Result
;
2900 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2902 /* Make sure this is the right instruction */
2903 ASSERT(Opcode
== 0x1C);
2905 if (State
->PrefixFlags
)
2907 /* This opcode doesn't take any prefixes */
2908 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2912 if (!Fast486FetchByte(State
, &SecondValue
))
2914 /* Exception occurred */
2918 /* Calculate the result */
2919 Result
= FirstValue
- SecondValue
- Carry
;
2921 /* Update the flags */
2922 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2923 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2924 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2925 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2926 State
->Flags
.Zf
= (Result
== 0);
2927 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2928 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2930 /* Write back the result */
2931 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2937 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2939 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2940 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2942 /* Make sure this is the right instruction */
2943 ASSERT(Opcode
== 0x1D);
2946 TOGGLE_OPSIZE(Size
);
2950 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2951 ULONG SecondValue
, Result
;
2953 if (!Fast486FetchDword(State
, &SecondValue
))
2955 /* Exception occurred */
2959 /* Calculate the result */
2960 Result
= FirstValue
- SecondValue
- Carry
;
2962 /* Update the flags */
2963 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2964 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2965 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2966 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2967 State
->Flags
.Zf
= (Result
== 0);
2968 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2969 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2971 /* Write back the result */
2972 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2976 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2977 USHORT SecondValue
, Result
;
2979 if (!Fast486FetchWord(State
, &SecondValue
))
2981 /* Exception occurred */
2985 /* Calculate the result */
2986 Result
= FirstValue
- SecondValue
- Carry
;
2988 /* Update the flags */
2989 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2990 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2991 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2992 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2993 State
->Flags
.Zf
= (Result
== 0);
2994 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2995 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2997 /* Write back the result */
2998 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3005 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
3007 /* Call the internal API */
3008 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
3011 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3015 if (!Fast486StackPop(State
, &NewSelector
))
3017 /* Exception occurred */
3021 /* Call the internal API */
3022 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3025 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3027 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3028 BOOLEAN Carry
= State
->Flags
.Cf
;
3030 /* Clear the carry flag */
3031 State
->Flags
.Cf
= FALSE
;
3033 /* Check if the first BCD digit is invalid or there was a carry from it */
3034 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3037 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3038 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3040 /* A carry occurred */
3041 State
->Flags
.Cf
= TRUE
;
3044 /* Set the adjust flag */
3045 State
->Flags
.Af
= TRUE
;
3048 /* Check if the second BCD digit is invalid or there was a carry from it */
3049 if ((Value
> 0x99) || Carry
)
3052 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3054 /* There was a carry */
3055 State
->Flags
.Cf
= TRUE
;
3058 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3060 /* Update the flags */
3061 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3062 State
->Flags
.Zf
= (Value
== 0);
3063 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3068 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3070 UCHAR FirstValue
, SecondValue
, Result
;
3071 FAST486_MOD_REG_RM ModRegRm
;
3072 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3074 /* Make sure this is the right instruction */
3075 ASSERT((Opcode
& 0xED) == 0x28);
3077 TOGGLE_ADSIZE(AddressSize
);
3079 /* Get the operands */
3080 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3082 /* Exception occurred */
3086 if (!Fast486ReadModrmByteOperands(State
,
3091 /* Exception occurred */
3095 /* Check if this is the instruction that writes to R/M */
3096 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3098 /* Swap the order */
3099 SWAP(FirstValue
, SecondValue
);
3102 /* Calculate the result */
3103 Result
= FirstValue
- SecondValue
;
3105 /* Update the flags */
3106 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3107 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3108 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3109 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3110 State
->Flags
.Zf
= (Result
== 0);
3111 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3112 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3114 /* Check if this is not a CMP */
3115 if (!(Opcode
& 0x10))
3117 /* Write back the result */
3118 return Fast486WriteModrmByteOperands(State
,
3120 Opcode
& FAST486_OPCODE_WRITE_REG
,
3125 /* Discard the result */
3130 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3132 FAST486_MOD_REG_RM ModRegRm
;
3133 BOOLEAN OperandSize
, AddressSize
;
3135 /* Make sure this is the right instruction */
3136 ASSERT((Opcode
& 0xED) == 0x29);
3138 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3140 TOGGLE_ADSIZE(AddressSize
);
3141 TOGGLE_OPSIZE(OperandSize
);
3143 /* Get the operands */
3144 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3146 /* Exception occurred */
3150 /* Check the operand size */
3153 ULONG FirstValue
, SecondValue
, Result
;
3155 if (!Fast486ReadModrmDwordOperands(State
,
3160 /* Exception occurred */
3164 /* Check if this is the instruction that writes to R/M */
3165 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3167 /* Swap the order */
3168 SWAP(FirstValue
, SecondValue
);
3171 /* Calculate the result */
3172 Result
= FirstValue
- SecondValue
;
3174 /* Update the flags */
3175 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3176 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3177 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3178 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3179 State
->Flags
.Zf
= (Result
== 0);
3180 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3181 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3183 /* Check if this is not a CMP */
3184 if (!(Opcode
& 0x10))
3186 /* Write back the result */
3187 return Fast486WriteModrmDwordOperands(State
,
3189 Opcode
& FAST486_OPCODE_WRITE_REG
,
3194 /* Discard the result */
3200 USHORT FirstValue
, SecondValue
, Result
;
3202 if (!Fast486ReadModrmWordOperands(State
,
3207 /* Exception occurred */
3211 /* Check if this is the instruction that writes to R/M */
3212 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3214 /* Swap the order */
3215 SWAP(FirstValue
, SecondValue
);
3218 /* Calculate the result */
3219 Result
= FirstValue
- SecondValue
;
3221 /* Update the flags */
3222 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3223 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3224 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3225 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3226 State
->Flags
.Zf
= (Result
== 0);
3227 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3228 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3230 /* Check if this is not a CMP */
3231 if (!(Opcode
& 0x10))
3233 /* Write back the result */
3234 return Fast486WriteModrmWordOperands(State
,
3236 Opcode
& FAST486_OPCODE_WRITE_REG
,
3241 /* Discard the result */
3247 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3249 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3250 UCHAR SecondValue
, Result
;
3252 /* Make sure this is the right instruction */
3253 ASSERT((Opcode
& 0xEF) == 0x2C);
3255 if (State
->PrefixFlags
)
3257 /* This opcode doesn't take any prefixes */
3258 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3262 if (!Fast486FetchByte(State
, &SecondValue
))
3264 /* Exception occurred */
3268 /* Calculate the result */
3269 Result
= FirstValue
- SecondValue
;
3271 /* Update the flags */
3272 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3273 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3274 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3275 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3276 State
->Flags
.Zf
= (Result
== 0);
3277 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3278 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3280 /* Check if this is not a CMP */
3281 if (!(Opcode
& 0x10))
3283 /* Write back the result */
3284 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3290 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3292 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3294 /* Make sure this is the right instruction */
3295 ASSERT((Opcode
& 0xEF) == 0x2D);
3298 TOGGLE_OPSIZE(Size
);
3302 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3303 ULONG SecondValue
, Result
;
3305 if (!Fast486FetchDword(State
, &SecondValue
))
3307 /* Exception occurred */
3311 /* Calculate the result */
3312 Result
= FirstValue
- SecondValue
;
3314 /* Update the flags */
3315 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3316 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3317 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3318 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3319 State
->Flags
.Zf
= (Result
== 0);
3320 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3321 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3323 /* Check if this is not a CMP */
3324 if (!(Opcode
& 0x10))
3326 /* Write back the result */
3327 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3332 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3333 USHORT SecondValue
, Result
;
3335 if (!Fast486FetchWord(State
, &SecondValue
))
3337 /* Exception occurred */
3341 /* Calculate the result */
3342 Result
= FirstValue
- SecondValue
;
3344 /* Update the flags */
3345 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3346 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3347 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3348 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3349 State
->Flags
.Zf
= (Result
== 0);
3350 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3351 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3353 /* Check if this is not a CMP */
3354 if (!(Opcode
& 0x10))
3356 /* Write back the result */
3357 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3364 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3366 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3367 BOOLEAN Carry
= State
->Flags
.Cf
;
3369 /* Clear the carry flag */
3370 State
->Flags
.Cf
= FALSE
;
3372 /* Check if the first BCD digit is invalid or there was a borrow */
3373 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3376 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3377 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3379 /* A borrow occurred */
3380 State
->Flags
.Cf
= TRUE
;
3383 /* Set the adjust flag */
3384 State
->Flags
.Af
= TRUE
;
3387 /* Check if the second BCD digit is invalid or there was a borrow */
3388 if ((Value
> 0x99) || Carry
)
3391 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3393 /* There was a borrow */
3394 State
->Flags
.Cf
= TRUE
;
3397 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3399 /* Update the flags */
3400 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3401 State
->Flags
.Zf
= (Value
== 0);
3402 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3407 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3409 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3412 * Check if the value in AL is not a valid BCD digit,
3413 * or there was a carry from the lowest 4 bits of AL
3415 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3418 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3419 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3422 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3426 /* Clear CF and AF */
3427 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3430 /* Keep only the lowest 4 bits of AL */
3431 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3436 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3438 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3441 * Check if the value in AL is not a valid BCD digit,
3442 * or there was a borrow from the lowest 4 bits of AL
3444 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3447 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3448 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3451 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3455 /* Clear CF and AF */
3456 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3459 /* Keep only the lowest 4 bits of AL */
3460 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3465 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3468 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3469 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3471 /* Make sure this is the right instruction */
3472 ASSERT(Opcode
== 0x60);
3474 TOGGLE_OPSIZE(Size
);
3477 /* Push all the registers in order */
3478 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3480 if (i
== FAST486_REG_ESP
)
3482 /* Use the saved ESP instead */
3483 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3485 /* Exception occurred */
3491 /* Push the register */
3492 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3493 : State
->GeneralRegs
[i
].LowWord
))
3495 /* Exception occurred */
3504 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3507 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3510 /* Make sure this is the right instruction */
3511 ASSERT(Opcode
== 0x61);
3513 TOGGLE_OPSIZE(Size
);
3516 /* Pop all the registers in reverse order */
3517 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3520 if (!Fast486StackPop(State
, &Value
))
3522 /* Exception occurred */
3526 /* Don't modify ESP */
3527 if (i
!= FAST486_REG_ESP
)
3529 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3530 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3537 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3539 BOOLEAN OperandSize
, AddressSize
;
3540 FAST486_MOD_REG_RM ModRegRm
;
3541 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3543 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3546 TOGGLE_OPSIZE(OperandSize
);
3547 TOGGLE_ADSIZE(AddressSize
);
3549 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3551 /* Exception occurred */
3555 if (!ModRegRm
.Memory
)
3558 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3562 /* Check for the segment override */
3563 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3565 /* Use the override segment instead */
3566 Segment
= State
->SegmentOverride
;
3571 LONG Index
, LowerBound
, UpperBound
;
3573 /* Read the operands */
3574 if (!Fast486ReadModrmDwordOperands(State
,
3577 (PULONG
)&LowerBound
))
3579 /* Exception occurred */
3583 if (!Fast486ReadMemory(State
,
3585 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3590 /* Exception occurred */
3594 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3597 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3603 SHORT Index
, LowerBound
, UpperBound
;
3605 /* Read the operands */
3606 if (!Fast486ReadModrmWordOperands(State
,
3609 (PUSHORT
)&LowerBound
))
3611 /* Exception occurred */
3615 if (!Fast486ReadMemory(State
,
3617 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3622 /* Exception occurred */
3626 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3629 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3637 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3639 USHORT FirstValue
, SecondValue
;
3640 FAST486_MOD_REG_RM ModRegRm
;
3641 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3643 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3645 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3647 /* Cannot be used in real mode or with a LOCK prefix */
3648 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3652 TOGGLE_ADSIZE(AddressSize
);
3654 /* Get the operands */
3655 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3657 /* Exception occurred */
3661 /* Read the operands */
3662 if (!Fast486ReadModrmWordOperands(State
,
3667 /* Exception occurred */
3671 /* Check if the RPL needs adjusting */
3672 if ((SecondValue
& 3) < (FirstValue
& 3))
3674 /* Adjust the RPL */
3676 SecondValue
|= FirstValue
& 3;
3679 State
->Flags
.Zf
= TRUE
;
3681 /* Write back the result */
3682 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3687 State
->Flags
.Zf
= FALSE
;
3692 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3694 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3696 /* Make sure this is the right instruction */
3697 ASSERT(Opcode
== 0x68);
3700 TOGGLE_OPSIZE(Size
);
3706 if (!Fast486FetchDword(State
, &Data
))
3708 /* Exception occurred */
3712 /* Call the internal API */
3713 return Fast486StackPush(State
, Data
);
3719 if (!Fast486FetchWord(State
, (PUSHORT
)&Data
))
3721 /* Exception occurred */
3725 /* Call the internal API */
3726 return Fast486StackPush(State
, Data
);
3730 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3732 BOOLEAN OperandSize
, AddressSize
;
3733 FAST486_MOD_REG_RM ModRegRm
;
3736 /* Make sure this is the right instruction */
3737 ASSERT((Opcode
& 0xFD) == 0x69);
3739 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3741 TOGGLE_ADSIZE(AddressSize
);
3742 TOGGLE_OPSIZE(OperandSize
);
3744 /* Fetch the parameters */
3745 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3747 /* Exception occurred */
3755 /* Fetch the immediate operand */
3756 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3758 /* Exception occurred */
3762 Multiplier
= (LONG
)Byte
;
3770 /* Fetch the immediate operand */
3771 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3773 /* Exception occurred */
3783 /* Fetch the immediate operand */
3784 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3786 /* Exception occurred */
3790 Multiplier
= (LONG
)Word
;
3796 LONG RegValue
, Multiplicand
;
3799 /* Read the operands */
3800 if (!Fast486ReadModrmDwordOperands(State
,
3803 (PULONG
)&Multiplicand
))
3805 /* Exception occurred */
3810 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3812 /* Check for carry/overflow */
3813 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3815 /* Write-back the result */
3816 return Fast486WriteModrmDwordOperands(State
,
3819 (ULONG
)((LONG
)Product
));
3823 SHORT RegValue
, Multiplicand
;
3826 /* Read the operands */
3827 if (!Fast486ReadModrmWordOperands(State
,
3830 (PUSHORT
)&Multiplicand
))
3832 /* Exception occurred */
3837 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3839 /* Check for carry/overflow */
3840 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3842 /* Write-back the result */
3843 return Fast486WriteModrmWordOperands(State
,
3846 (USHORT
)((SHORT
)Product
));
3850 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3854 /* Make sure this is the right instruction */
3855 ASSERT(Opcode
== 0x6A);
3857 if (!Fast486FetchByte(State
, (PUCHAR
)&Data
))
3859 /* Exception occurred */
3863 /* Call the internal API */
3864 return Fast486StackPush(State
, Data
);
3867 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3869 UCHAR FirstValue
, SecondValue
, Result
;
3870 FAST486_MOD_REG_RM ModRegRm
;
3871 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3873 /* Make sure this is the right instruction */
3874 ASSERT((Opcode
& 0xFD) == 0x88);
3876 TOGGLE_ADSIZE(AddressSize
);
3878 /* Get the operands */
3879 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3881 /* Exception occurred */
3885 if (!Fast486ReadModrmByteOperands(State
,
3890 /* Exception occurred */
3894 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3895 else Result
= FirstValue
;
3897 /* Write back the result */
3898 return Fast486WriteModrmByteOperands(State
,
3900 Opcode
& FAST486_OPCODE_WRITE_REG
,
3905 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3907 FAST486_MOD_REG_RM ModRegRm
;
3908 BOOLEAN OperandSize
, AddressSize
;
3910 /* Make sure this is the right instruction */
3911 ASSERT((Opcode
& 0xFD) == 0x89);
3913 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3915 TOGGLE_ADSIZE(AddressSize
);
3916 TOGGLE_OPSIZE(OperandSize
);
3918 /* Get the operands */
3919 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3921 /* Exception occurred */
3925 /* Check the operand size */
3928 ULONG FirstValue
, SecondValue
, Result
;
3930 if (!Fast486ReadModrmDwordOperands(State
,
3935 /* Exception occurred */
3939 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3940 else Result
= FirstValue
;
3942 /* Write back the result */
3943 return Fast486WriteModrmDwordOperands(State
,
3945 Opcode
& FAST486_OPCODE_WRITE_REG
,
3950 USHORT FirstValue
, SecondValue
, Result
;
3952 if (!Fast486ReadModrmWordOperands(State
,
3957 /* Exception occurred */
3961 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3962 else Result
= FirstValue
;
3964 /* Write back the result */
3965 return Fast486WriteModrmWordOperands(State
,
3967 Opcode
& FAST486_OPCODE_WRITE_REG
,
3972 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3974 BOOLEAN OperandSize
, AddressSize
;
3975 FAST486_MOD_REG_RM ModRegRm
;
3977 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3979 /* Make sure this is the right instruction */
3980 ASSERT(Opcode
== 0x8C);
3982 TOGGLE_ADSIZE(AddressSize
);
3983 TOGGLE_OPSIZE(OperandSize
);
3985 /* Get the operands */
3986 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3988 /* Exception occurred */
3992 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3995 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4001 return Fast486WriteModrmDwordOperands(State
,
4004 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4008 return Fast486WriteModrmWordOperands(State
,
4011 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4015 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
4017 FAST486_MOD_REG_RM ModRegRm
;
4018 BOOLEAN OperandSize
, AddressSize
;
4020 /* Make sure this is the right instruction */
4021 ASSERT(Opcode
== 0x8D);
4023 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4025 TOGGLE_ADSIZE(AddressSize
);
4026 TOGGLE_OPSIZE(OperandSize
);
4028 /* Get the operands */
4029 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4031 /* Exception occurred */
4035 /* The second operand must be memory */
4036 if (!ModRegRm
.Memory
)
4039 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4043 /* Write the address to the register */
4046 return Fast486WriteModrmDwordOperands(State
,
4049 ModRegRm
.MemoryAddress
);
4053 return Fast486WriteModrmWordOperands(State
,
4056 ModRegRm
.MemoryAddress
);
4061 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
4063 BOOLEAN OperandSize
, AddressSize
;
4064 FAST486_MOD_REG_RM ModRegRm
;
4066 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4068 /* Make sure this is the right instruction */
4069 ASSERT(Opcode
== 0x8E);
4071 TOGGLE_ADSIZE(AddressSize
);
4072 TOGGLE_OPSIZE(OperandSize
);
4074 /* Get the operands */
4075 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4077 /* Exception occurred */
4081 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4082 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
4085 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4093 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4095 /* Exception occurred */
4099 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4105 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4107 /* Exception occurred */
4111 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4115 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4117 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4119 /* Make sure this is the right instruction */
4120 ASSERT(Opcode
== 0x98);
4122 TOGGLE_OPSIZE(Size
);
4127 /* Sign extend AX to EAX */
4128 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4130 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4131 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4137 /* Sign extend AL to AX */
4138 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4139 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4146 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4148 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4150 /* Make sure this is the right instruction */
4151 ASSERT(Opcode
== 0x99);
4153 TOGGLE_OPSIZE(Size
);
4158 /* Sign extend EAX to EDX:EAX */
4159 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4160 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4161 ? 0xFFFFFFFF : 0x00000000;
4165 /* Sign extend AX to DX:AX */
4166 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4167 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4174 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4178 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4180 /* Make sure this is the right instruction */
4181 ASSERT(Opcode
== 0x9A);
4183 TOGGLE_OPSIZE(Size
);
4186 /* Fetch the offset */
4189 if (!Fast486FetchDword(State
, &Offset
))
4191 /* Exception occurred */
4197 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4199 /* Exception occurred */
4204 /* Fetch the segment */
4205 if (!Fast486FetchWord(State
, &Segment
))
4207 /* Exception occurred */
4211 /* Push the current code segment selector */
4212 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4214 /* Exception occurred */
4218 /* Push the current value of the instruction pointer */
4219 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4221 /* Exception occurred */
4225 /* Load the new CS */
4226 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4228 /* Exception occurred */
4232 /* Load new (E)IP */
4233 if (Size
) State
->InstPtr
.Long
= Offset
;
4234 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4239 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4241 // TODO: NOT IMPLEMENTED
4247 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4249 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4252 TOGGLE_OPSIZE(Size
);
4254 /* Check for VM86 mode when IOPL is not 3 */
4255 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4257 /* Call the VM86 monitor */
4258 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4262 /* Push the flags */
4263 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4264 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4267 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4269 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4270 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4271 FAST486_FLAGS_REG NewFlags
;
4274 TOGGLE_OPSIZE(Size
);
4276 /* Pop the new flags */
4277 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4279 /* Exception occurred */
4283 /* Check for VM86 mode when IOPL is not 3 */
4284 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4286 /* Call the VM86 monitor */
4287 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4291 State
->Flags
.Cf
= NewFlags
.Cf
;
4292 State
->Flags
.Pf
= NewFlags
.Pf
;
4293 State
->Flags
.Af
= NewFlags
.Af
;
4294 State
->Flags
.Zf
= NewFlags
.Zf
;
4295 State
->Flags
.Sf
= NewFlags
.Sf
;
4296 State
->Flags
.Tf
= NewFlags
.Tf
;
4297 State
->Flags
.Df
= NewFlags
.Df
;
4298 State
->Flags
.Of
= NewFlags
.Of
;
4299 State
->Flags
.Nt
= NewFlags
.Nt
;
4300 State
->Flags
.Ac
= NewFlags
.Ac
;
4302 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4303 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4308 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4310 /* Make sure this is the right instruction */
4311 ASSERT(Opcode
== 0x9E);
4313 /* Set the low-order byte of FLAGS to AH */
4314 State
->Flags
.Long
&= 0xFFFFFF00;
4315 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4317 /* Restore the reserved bits of FLAGS */
4318 State
->Flags
.AlwaysSet
= TRUE
;
4319 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4324 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4326 /* Make sure this is the right instruction */
4327 ASSERT(Opcode
== 0x9F);
4329 /* Set AH to the low-order byte of FLAGS */
4330 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4335 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4337 ULONG ReturnAddress
;
4338 USHORT BytesToPop
= 0;
4339 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4341 /* Make sure this is the right instruction */
4342 ASSERT((Opcode
& 0xFE) == 0xC2);
4345 TOGGLE_OPSIZE(Size
);
4349 /* Fetch the number of bytes to pop after the return */
4350 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4353 /* Pop the return address */
4354 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4356 /* Return to the calling procedure, and if necessary, pop the parameters */
4359 State
->InstPtr
.Long
= ReturnAddress
;
4360 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4364 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4365 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4371 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4373 UCHAR FarPointer
[6];
4374 BOOLEAN OperandSize
, AddressSize
;
4375 FAST486_MOD_REG_RM ModRegRm
;
4377 /* Make sure this is the right instruction */
4378 ASSERT((Opcode
& 0xFE) == 0xC4);
4380 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4382 TOGGLE_OPSIZE(OperandSize
);
4383 TOGGLE_ADSIZE(AddressSize
);
4385 /* Get the operands */
4386 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4388 /* Exception occurred */
4392 if (!ModRegRm
.Memory
)
4394 /* Check if this is a BOP and the host supports BOPs */
4395 if ((Opcode
== 0xC4)
4396 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4397 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4398 && (State
->BopCallback
!= NULL
))
4402 /* Fetch the BOP code */
4403 if (!Fast486FetchByte(State
, &BopCode
))
4405 /* Exception occurred */
4409 /* Call the BOP handler */
4410 State
->BopCallback(State
, BopCode
);
4413 * If an interrupt should occur at this time, delay it.
4414 * We must do this because if an interrupt begins and the BOP callback
4415 * changes the CS:IP, the interrupt handler won't execute and the
4416 * stack pointer will never be restored.
4418 if (State
->IntStatus
== FAST486_INT_EXECUTE
)
4420 State
->IntStatus
= FAST486_INT_DELAYED
;
4423 /* Return success */
4428 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4432 if (!Fast486ReadMemory(State
,
4433 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4434 ? State
->SegmentOverride
: FAST486_REG_DS
,
4435 ModRegRm
.MemoryAddress
,
4438 OperandSize
? 6 : 4))
4440 /* Exception occurred */
4446 ULONG Offset
= *((PULONG
)FarPointer
);
4447 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4449 /* Set the register to the offset */
4450 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4452 /* Load the segment */
4453 return Fast486LoadSegment(State
,
4455 ? FAST486_REG_ES
: FAST486_REG_DS
,
4460 USHORT Offset
= *((PUSHORT
)FarPointer
);
4461 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4463 /* Set the register to the offset */
4464 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4466 /* Load the segment */
4467 return Fast486LoadSegment(State
,
4469 ? FAST486_REG_ES
: FAST486_REG_DS
,
4474 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4477 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4480 FAST486_REG FramePointer
;
4482 /* Make sure this is the right instruction */
4483 ASSERT(Opcode
== 0xC8);
4486 TOGGLE_OPSIZE(Size
);
4488 if (!Fast486FetchWord(State
, &FrameSize
))
4490 /* Exception occurred */
4494 if (!Fast486FetchByte(State
, &NestingLevel
))
4496 /* Exception occurred */
4501 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4503 /* Exception occurred */
4508 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4510 /* Set up the nested procedure stacks */
4511 for (i
= 1; i
< NestingLevel
; i
++)
4515 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4516 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4520 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4521 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4525 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4527 /* Set EBP to the frame pointer */
4528 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4530 /* Reserve space for the frame */
4531 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4532 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4537 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4539 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4541 /* Make sure this is the right instruction */
4542 ASSERT(Opcode
== 0xC9);
4545 TOGGLE_OPSIZE(Size
);
4549 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4550 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4552 /* Pop the saved base pointer from the stack */
4553 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4559 /* Set the stack pointer (SP) to the base pointer (BP) */
4560 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4562 /* Pop the saved base pointer from the stack */
4563 if (Fast486StackPop(State
, &Value
))
4565 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4572 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4576 USHORT BytesToPop
= 0;
4577 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4579 /* Make sure this is the right instruction */
4580 ASSERT((Opcode
& 0xFE) == 0xCA);
4582 TOGGLE_OPSIZE(Size
);
4587 /* Fetch the number of bytes to pop after the return */
4588 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4591 /* Pop the offset */
4592 if (!Fast486StackPop(State
, &Offset
))
4594 /* Exception occurred */
4598 /* Pop the segment */
4599 if (!Fast486StackPop(State
, &Segment
))
4601 /* Exception occurred */
4605 /* Load the new CS */
4606 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4608 /* Exception occurred */
4612 /* Load new (E)IP, and if necessary, pop the parameters */
4615 State
->InstPtr
.Long
= Offset
;
4616 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4620 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4621 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4627 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4635 /* This is the INT3 instruction */
4642 /* Fetch the interrupt number */
4643 if (!Fast486FetchByte(State
, &IntNum
))
4645 /* Exception occurred */
4654 /* Don't do anything if OF is cleared */
4655 if (!State
->Flags
.Of
) return TRUE
;
4658 IntNum
= FAST486_EXCEPTION_OF
;
4665 /* Should not happen */
4670 /* Perform the interrupt */
4671 return Fast486PerformInterrupt(State
, IntNum
);
4674 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4677 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4678 FAST486_FLAGS_REG NewFlags
;
4679 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4681 /* Make sure this is the right instruction */
4682 ASSERT(Opcode
== 0xCF);
4685 TOGGLE_OPSIZE(Size
);
4688 if (!Fast486StackPop(State
, &InstPtr
))
4690 /* Exception occurred */
4695 if (!Fast486StackPop(State
, &CodeSel
))
4697 /* Exception occurred */
4702 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4704 /* Exception occurred */
4708 /* Check for protected mode */
4709 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4711 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4713 if (State
->Flags
.Vm
)
4715 /* Return from VM86 mode */
4717 /* Check the IOPL */
4718 if (State
->Flags
.Iopl
== 3)
4721 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4724 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4726 /* Exception occurred */
4730 /* Set the new flags */
4731 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4732 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4733 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4734 State
->Flags
.Iopl
= 3;
4738 /* Call the VM86 monitor */
4739 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4746 if (State
->Flags
.Nt
)
4748 /* Nested task return */
4756 /* Return to VM86 mode */
4757 ULONG Es
, Ds
, Fs
, Gs
;
4759 /* Pop ESP, SS, ES, FS, GS */
4760 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4761 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4762 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4763 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4764 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4765 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4767 /* Set the new IP */
4768 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4770 /* Set the new flags */
4771 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4772 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4773 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4775 /* Load the new segments */
4776 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4777 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4778 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4779 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4780 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4781 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4786 /* Load the new CS */
4787 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4789 /* Exception occurred */
4794 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4795 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4797 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4800 if (!Fast486StackPop(State
, &StackPtr
))
4807 if (!Fast486StackPop(State
, &StackSel
))
4814 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4821 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4822 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4825 /* Set the new flags */
4826 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4827 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4828 State
->Flags
.AlwaysSet
= TRUE
;
4830 /* Set additional flags */
4831 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4832 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4834 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4836 /* Update the CPL */
4837 Cpl
= Fast486GetCurrentPrivLevel(State
);
4839 /* Check segment security */
4840 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4842 /* Don't check CS or SS */
4843 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4845 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4846 && (!State
->SegmentRegs
[i
].Executable
4847 || !State
->SegmentRegs
[i
].DirConf
))
4849 /* Load the NULL descriptor in the segment */
4850 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4857 if (Size
&& (InstPtr
& 0xFFFF0000))
4860 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4865 State
->InstPtr
.Long
= InstPtr
;
4868 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4870 /* Exception occurred */
4874 /* Set the new flags */
4875 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4876 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4877 State
->Flags
.AlwaysSet
= TRUE
;
4883 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4886 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4890 /* Fetch the base */
4891 if (!Fast486FetchByte(State
, &Base
))
4893 /* Exception occurred */
4897 /* Check if the base is zero */
4901 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4906 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4907 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4910 State
->Flags
.Af
= FALSE
;
4911 State
->Flags
.Zf
= (Value
== 0);
4912 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4913 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4918 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4921 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4925 /* Fetch the base */
4926 if (!Fast486FetchByte(State
, &Base
))
4928 /* Exception occurred */
4933 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4934 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4937 State
->Flags
.Af
= FALSE
;
4938 State
->Flags
.Zf
= (Value
== 0);
4939 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4940 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4945 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4948 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4950 TOGGLE_ADSIZE(AddressSize
);
4952 /* Read a byte from DS:[(E)BX + AL] */
4953 if (!Fast486ReadMemory(State
,
4954 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4955 ? State
->SegmentOverride
: FAST486_REG_DS
,
4956 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4957 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4958 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4963 /* Exception occurred */
4967 /* Set AL to the result */
4968 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4970 /* Return success */
4974 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4977 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4980 /* Make sure this is the right instruction */
4981 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4984 TOGGLE_ADSIZE(Size
);
4986 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4987 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4991 /* Additional rule for LOOPNZ */
4992 if (State
->Flags
.Zf
) Condition
= FALSE
;
4997 /* Additional rule for LOOPZ */
4998 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5001 /* Fetch the offset */
5002 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5004 /* An exception occurred */
5010 /* Move the instruction pointer */
5011 if (Size
) State
->InstPtr
.Long
+= Offset
;
5012 else State
->InstPtr
.LowWord
+= Offset
;
5018 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5021 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5024 /* Make sure this is the right instruction */
5025 ASSERT(Opcode
== 0xE3);
5028 TOGGLE_ADSIZE(Size
);
5030 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5031 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5033 /* Fetch the offset */
5034 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5036 /* An exception occurred */
5042 /* Move the instruction pointer */
5043 if (Size
) State
->InstPtr
.Long
+= Offset
;
5044 else State
->InstPtr
.LowWord
+= Offset
;
5050 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5052 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5054 /* Make sure this is the right instruction */
5055 ASSERT(Opcode
== 0xE8);
5057 TOGGLE_OPSIZE(Size
);
5064 /* Fetch the offset */
5065 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5067 /* An exception occurred */
5071 /* Push the current value of the instruction pointer */
5072 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5074 /* Exception occurred */
5078 /* Move the instruction pointer */
5079 State
->InstPtr
.Long
+= Offset
;
5085 /* Fetch the offset */
5086 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5088 /* An exception occurred */
5092 /* Push the current value of the instruction pointer */
5093 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5095 /* Exception occurred */
5099 /* Move the instruction pointer */
5100 State
->InstPtr
.LowWord
+= Offset
;
5106 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5108 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5110 /* Make sure this is the right instruction */
5111 ASSERT(Opcode
== 0xE9);
5113 TOGGLE_OPSIZE(Size
);
5120 /* Fetch the offset */
5121 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5123 /* An exception occurred */
5127 /* Move the instruction pointer */
5128 State
->InstPtr
.Long
+= Offset
;
5134 /* Fetch the offset */
5135 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5137 /* An exception occurred */
5141 /* Move the instruction pointer */
5142 State
->InstPtr
.Long
+= Offset
;
5144 /* Clear the top half of EIP */
5145 State
->InstPtr
.Long
&= 0xFFFF;
5151 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5155 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5157 /* Make sure this is the right instruction */
5158 ASSERT(Opcode
== 0xEA);
5160 TOGGLE_OPSIZE(Size
);
5163 /* Fetch the offset */
5166 if (!Fast486FetchDword(State
, &Offset
))
5168 /* Exception occurred */
5174 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5176 /* Exception occurred */
5181 /* Fetch the segment */
5182 if (!Fast486FetchWord(State
, &Segment
))
5184 /* Exception occurred */
5188 /* Load the new CS */
5189 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5191 /* Exception occurred */
5196 State
->InstPtr
.Long
= Offset
;
5201 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5203 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5206 /* Make sure this is the right instruction */
5207 ASSERT(Opcode
== 0xA0);
5209 TOGGLE_ADSIZE(AddressSize
);
5213 if (!Fast486FetchDword(State
, &Offset
))
5215 /* Exception occurred */
5223 if (!Fast486FetchWord(State
, &WordOffset
))
5225 /* Exception occurred */
5229 Offset
= (ULONG
)WordOffset
;
5232 /* Read from memory */
5233 return Fast486ReadMemory(State
,
5234 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5235 State
->SegmentOverride
: FAST486_REG_DS
,
5238 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5242 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5244 BOOLEAN OperandSize
, AddressSize
;
5246 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5248 /* Make sure this is the right instruction */
5249 ASSERT(Opcode
== 0xA1);
5251 TOGGLE_OPSIZE(OperandSize
);
5252 TOGGLE_ADSIZE(AddressSize
);
5258 if (!Fast486FetchDword(State
, &Offset
))
5260 /* Exception occurred */
5264 /* Read from memory */
5267 return Fast486ReadMemory(State
,
5268 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5269 State
->SegmentOverride
: FAST486_REG_DS
,
5272 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5277 return Fast486ReadMemory(State
,
5278 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5279 State
->SegmentOverride
: FAST486_REG_DS
,
5282 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5290 if (!Fast486FetchWord(State
, &Offset
))
5292 /* Exception occurred */
5296 /* Read from memory */
5299 return Fast486ReadMemory(State
,
5300 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5301 State
->SegmentOverride
: FAST486_REG_DS
,
5304 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5309 return Fast486ReadMemory(State
,
5310 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5311 State
->SegmentOverride
: FAST486_REG_DS
,
5314 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5320 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5322 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5325 /* Make sure this is the right instruction */
5326 ASSERT(Opcode
== 0xA2);
5328 TOGGLE_ADSIZE(AddressSize
);
5332 if (!Fast486FetchDword(State
, &Offset
))
5334 /* Exception occurred */
5342 if (!Fast486FetchWord(State
, &WordOffset
))
5344 /* Exception occurred */
5348 Offset
= (ULONG
)WordOffset
;
5351 /* Write to memory */
5352 return Fast486WriteMemory(State
,
5353 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5354 State
->SegmentOverride
: FAST486_REG_DS
,
5356 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5360 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5362 BOOLEAN OperandSize
, AddressSize
;
5364 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5366 /* Make sure this is the right instruction */
5367 ASSERT(Opcode
== 0xA3);
5369 TOGGLE_OPSIZE(OperandSize
);
5370 TOGGLE_ADSIZE(AddressSize
);
5376 if (!Fast486FetchDword(State
, &Offset
))
5378 /* Exception occurred */
5382 /* Write to memory */
5385 return Fast486WriteMemory(State
,
5386 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5387 State
->SegmentOverride
: FAST486_REG_DS
,
5389 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5394 return Fast486WriteMemory(State
,
5395 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5396 State
->SegmentOverride
: FAST486_REG_DS
,
5398 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5406 if (!Fast486FetchWord(State
, &Offset
))
5408 /* Exception occurred */
5412 /* Write to memory */
5415 return Fast486WriteMemory(State
,
5416 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5417 State
->SegmentOverride
: FAST486_REG_DS
,
5419 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5424 return Fast486WriteMemory(State
,
5425 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5426 State
->SegmentOverride
: FAST486_REG_DS
,
5428 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5434 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5437 * See: http://www.rcollins.org/secrets/opcodes/SALC.html
5438 * for more information.
5441 /* Make sure this is the right instruction */
5442 ASSERT(Opcode
== 0xD6);
5446 /* Set all the bits of AL to CF */
5447 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5452 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5454 ULONG Data
, DataSize
;
5455 BOOLEAN OperandSize
, AddressSize
;
5456 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5458 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5460 /* Make sure this is the right instruction */
5461 ASSERT((Opcode
& 0xFE) == 0xA4);
5463 TOGGLE_OPSIZE(OperandSize
);
5464 TOGGLE_ADSIZE(AddressSize
);
5466 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5468 /* Use the override segment instead of DS */
5469 Segment
= State
->SegmentOverride
;
5472 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5474 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5475 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5482 /* Calculate the size */
5483 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5484 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5486 /* Read from the source operand */
5487 if (!Fast486ReadMemory(State
,
5489 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5490 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5495 /* Exception occurred */
5499 /* Write to the destination operand */
5500 if (!Fast486WriteMemory(State
,
5502 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5503 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5507 /* Exception occurred */
5511 /* Increment/decrement ESI and EDI */
5514 if (!State
->Flags
.Df
)
5516 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5517 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5521 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5522 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5527 if (!State
->Flags
.Df
)
5529 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5530 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5534 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5535 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5539 // FIXME: This method is slow!
5540 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5544 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5546 /* Repeat the instruction */
5547 State
->InstPtr
= State
->SavedInstPtr
;
5552 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5554 /* Repeat the instruction */
5555 State
->InstPtr
= State
->SavedInstPtr
;
5560 /* Return success */
5564 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5566 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5567 ULONG DataSize
, DataMask
, SignFlag
;
5568 BOOLEAN OperandSize
, AddressSize
;
5569 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5571 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5573 /* Make sure this is the right instruction */
5574 ASSERT((Opcode
& 0xFE) == 0xA6);
5576 TOGGLE_OPSIZE(OperandSize
);
5577 TOGGLE_ADSIZE(AddressSize
);
5579 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5581 /* Use the override segment instead of DS */
5582 Segment
= State
->SegmentOverride
;
5585 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5586 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5588 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5589 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5596 /* Calculate the size */
5597 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5598 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5600 /* Calculate the mask and sign flag */
5601 SignFlag
= 1 << ((DataSize
* 8) - 1);
5602 DataMask
= SignFlag
| (SignFlag
- 1);
5604 /* Read from the first source operand */
5605 if (!Fast486ReadMemory(State
,
5607 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5608 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5613 /* Exception occurred */
5617 /* Read from the second source operand */
5618 if (!Fast486ReadMemory(State
,
5620 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5621 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5626 /* Exception occurred */
5630 /* Calculate the result */
5631 FirstValue
&= DataMask
;
5632 SecondValue
&= DataMask
;
5633 Result
= (FirstValue
- SecondValue
) & DataMask
;
5635 /* Update the flags */
5636 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5637 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5638 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5639 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5640 State
->Flags
.Zf
= (Result
== 0);
5641 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5642 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5644 /* Increment/decrement ESI and EDI */
5647 if (!State
->Flags
.Df
)
5649 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5650 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5654 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5655 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5660 if (!State
->Flags
.Df
)
5662 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5663 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5667 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5668 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5672 // FIXME: This method is slow!
5673 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5674 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5676 BOOLEAN Repeat
= TRUE
;
5680 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5688 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5695 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5696 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5698 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5704 /* Repeat the instruction */
5705 State
->InstPtr
= State
->SavedInstPtr
;
5709 /* Return success */
5713 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5716 BOOLEAN OperandSize
, AddressSize
;
5718 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5720 /* Make sure this is the right instruction */
5721 ASSERT((Opcode
& 0xFE) == 0xAA);
5723 TOGGLE_OPSIZE(OperandSize
);
5724 TOGGLE_ADSIZE(AddressSize
);
5726 /* Calculate the size */
5727 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5728 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5730 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5732 UCHAR Block
[STRING_BLOCK_SIZE
];
5733 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5734 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5736 /* Fill the memory block with the data */
5737 if (DataSize
== sizeof(UCHAR
))
5739 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5745 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5747 if (DataSize
== sizeof(USHORT
))
5749 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5753 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5758 /* Transfer until finished */
5761 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5763 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5766 ULONG MaxBytes
= State
->Flags
.Df
5767 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5768 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5770 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5771 if (Processed
== 0) Processed
= 1;
5774 if (State
->Flags
.Df
)
5776 /* Set EDI to the starting location */
5777 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5778 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5781 /* Write to memory */
5782 if (!Fast486WriteMemory(State
,
5784 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5785 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5787 Processed
* DataSize
))
5790 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5791 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5793 /* Exception occurred */
5797 if (!State
->Flags
.Df
)
5799 /* Increase EDI by the number of bytes transfered */
5800 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5801 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5806 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5807 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5810 /* Reduce the total count by the number processed in this run */
5815 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5816 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5820 /* Write to the destination operand */
5821 if (!Fast486WriteMemory(State
,
5823 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5824 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5825 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5828 /* Exception occurred */
5832 /* Increment/decrement EDI */
5835 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5836 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5840 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5841 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5845 /* Return success */
5849 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5852 BOOLEAN OperandSize
, AddressSize
;
5853 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5855 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5857 /* Make sure this is the right instruction */
5858 ASSERT((Opcode
& 0xFE) == 0xAC);
5860 TOGGLE_OPSIZE(OperandSize
);
5861 TOGGLE_ADSIZE(AddressSize
);
5863 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5865 /* Use the override segment instead of DS */
5866 Segment
= State
->SegmentOverride
;
5869 /* Calculate the size */
5870 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5871 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5873 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5875 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5876 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5878 /* If the count is 0, do nothing */
5879 if (Count
== 0) return TRUE
;
5881 /* Only the last entry will be loaded */
5882 if (!State
->Flags
.Df
)
5884 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5885 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5889 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5890 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5894 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5895 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5898 /* Read from the source operand */
5899 if (!Fast486ReadMemory(State
,
5901 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5902 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5904 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5907 /* Exception occurred */
5911 /* Increment/decrement ESI */
5914 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5915 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5919 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5920 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5923 /* Return success */
5927 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5929 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5930 ULONG SecondValue
= 0;
5932 ULONG DataSize
, DataMask
, SignFlag
;
5933 BOOLEAN OperandSize
, AddressSize
;
5935 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5937 /* Make sure this is the right instruction */
5938 ASSERT((Opcode
& 0xFE) == 0xAE);
5940 TOGGLE_OPSIZE(OperandSize
);
5941 TOGGLE_ADSIZE(AddressSize
);
5943 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5944 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5946 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5947 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5954 /* Calculate the size */
5955 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5956 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5958 /* Calculate the mask and sign flag */
5959 SignFlag
= 1 << ((DataSize
* 8) - 1);
5960 DataMask
= SignFlag
| (SignFlag
- 1);
5962 /* Read from the source operand */
5963 if (!Fast486ReadMemory(State
,
5965 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5966 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5971 /* Exception occurred */
5975 /* Calculate the result */
5976 FirstValue
&= DataMask
;
5977 SecondValue
&= DataMask
;
5978 Result
= (FirstValue
- SecondValue
) & DataMask
;
5980 /* Update the flags */
5981 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5982 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5983 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5984 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5985 State
->Flags
.Zf
= (Result
== 0);
5986 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5987 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5989 /* Increment/decrement EDI */
5992 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5993 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5997 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5998 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6001 // FIXME: This method is slow!
6002 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
6003 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
6005 BOOLEAN Repeat
= TRUE
;
6009 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6017 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6024 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6025 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6027 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6033 /* Repeat the instruction */
6034 State
->InstPtr
= State
->SavedInstPtr
;
6038 /* Return success */
6042 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6045 BOOLEAN OperandSize
, AddressSize
;
6047 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6049 /* Make sure this is the right instruction */
6050 ASSERT((Opcode
& 0xFE) == 0x6C);
6052 TOGGLE_OPSIZE(OperandSize
);
6053 TOGGLE_ADSIZE(AddressSize
);
6055 /* Calculate the size */
6056 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6057 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6059 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6061 UCHAR Block
[STRING_BLOCK_SIZE
];
6062 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6063 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6065 /* Clear the memory block */
6066 RtlZeroMemory(Block
, sizeof(Block
));
6068 /* Transfer until finished */
6071 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6073 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6076 ULONG MaxBytes
= State
->Flags
.Df
6077 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6078 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6080 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6081 if (Processed
== 0) Processed
= 1;
6084 /* Read from the I/O port */
6085 State
->IoReadCallback(State
,
6086 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6091 if (State
->Flags
.Df
)
6095 /* Reduce EDI by the number of bytes to transfer */
6096 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6097 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6099 /* Reverse the block data */
6100 for (i
= 0; i
< Processed
/ 2; i
++)
6102 /* Swap the values */
6103 for (j
= 0; j
< DataSize
; j
++)
6105 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6106 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6107 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6112 /* Write to memory */
6113 if (!Fast486WriteMemory(State
,
6115 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6116 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6118 Processed
* DataSize
))
6121 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6122 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6124 /* Exception occurred */
6128 if (!State
->Flags
.Df
)
6130 /* Increase EDI by the number of bytes transfered */
6131 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6132 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6135 /* Reduce the total count by the number processed in this run */
6140 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6141 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6147 /* Read from the I/O port */
6148 State
->IoReadCallback(State
,
6149 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6154 /* Write to the destination operand */
6155 if (!Fast486WriteMemory(State
,
6157 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6158 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6162 /* Exception occurred */
6166 /* Increment/decrement EDI */
6169 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6170 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6174 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6175 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6179 /* Return success */
6183 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6186 BOOLEAN OperandSize
, AddressSize
;
6188 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6190 /* Make sure this is the right instruction */
6191 ASSERT((Opcode
& 0xFE) == 0x6E);
6193 TOGGLE_OPSIZE(OperandSize
);
6194 TOGGLE_ADSIZE(AddressSize
);
6196 /* Calculate the size */
6197 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6198 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6200 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6202 UCHAR Block
[STRING_BLOCK_SIZE
];
6203 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6204 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6206 /* Clear the memory block */
6207 RtlZeroMemory(Block
, sizeof(Block
));
6209 /* Transfer until finished */
6212 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6214 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6217 ULONG MaxBytes
= State
->Flags
.Df
6218 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
6219 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
6221 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6222 if (Processed
== 0) Processed
= 1;
6225 /* Read from memory */
6226 if (!Fast486ReadMemory(State
,
6227 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6228 ? State
->SegmentOverride
: FAST486_REG_DS
,
6229 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6230 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6233 Processed
* DataSize
))
6236 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6237 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6239 /* Exception occurred */
6243 if (State
->Flags
.Df
)
6247 /* Reduce ESI by the number of bytes to transfer */
6248 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
6249 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
6251 /* Reverse the block data */
6252 for (i
= 0; i
< Processed
/ 2; i
++)
6254 /* Swap the values */
6255 for (j
= 0; j
< DataSize
; j
++)
6257 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6258 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6259 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6264 /* Write to the I/O port */
6265 State
->IoWriteCallback(State
,
6266 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6271 if (!State
->Flags
.Df
)
6273 /* Increase ESI by the number of bytes transfered */
6274 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
6275 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
6278 /* Reduce the total count by the number processed in this run */
6283 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6284 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6290 /* Read from the source operand */
6291 if (!Fast486ReadMemory(State
,
6292 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6293 ? State
->SegmentOverride
: FAST486_REG_DS
,
6294 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6295 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6300 /* Exception occurred */
6304 /* Write to the I/O port */
6305 State
->IoWriteCallback(State
,
6306 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6311 /* Increment/decrement ESI */
6314 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6315 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6319 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6320 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6324 /* Return success */