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 Fast486FpuOpcodeD8
, /* 0xD8 - 0xDF */
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
);
312 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
314 BOOLEAN Valid
= FALSE
;
321 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
323 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
324 State
->SegmentOverride
= FAST486_REG_ES
;
334 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
336 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
337 State
->SegmentOverride
= FAST486_REG_CS
;
347 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
349 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
350 State
->SegmentOverride
= FAST486_REG_SS
;
360 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
362 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
363 State
->SegmentOverride
= FAST486_REG_DS
;
373 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
375 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
376 State
->SegmentOverride
= FAST486_REG_FS
;
386 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
388 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
389 State
->SegmentOverride
= FAST486_REG_GS
;
399 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
401 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
411 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
413 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
422 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
424 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
434 /* Mutually exclusive with REP */
435 if (!(State
->PrefixFlags
436 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
438 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
448 /* Mutually exclusive with REPNZ */
449 if (!(State
->PrefixFlags
450 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
452 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
462 /* Clear all prefixes */
463 State
->PrefixFlags
= 0;
465 /* Throw an exception */
466 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
470 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
473 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
478 /* Make sure this is the right instruction */
479 ASSERT((Opcode
& 0xF8) == 0x40);
483 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
485 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
486 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
490 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
492 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
493 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
496 State
->Flags
.Zf
= (Value
== 0);
497 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
498 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
501 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
504 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
509 /* Make sure this is the right instruction */
510 ASSERT((Opcode
& 0xF8) == 0x48);
514 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
516 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
517 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
521 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
523 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
524 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
527 State
->Flags
.Zf
= (Value
== 0);
528 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
529 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
532 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
536 /* Make sure this is the right instruction */
537 ASSERT((Opcode
& 0xF8) == 0x50);
539 /* Call the internal function */
540 Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
543 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
546 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
551 /* Make sure this is the right instruction */
552 ASSERT((Opcode
& 0xF8) == 0x58);
554 /* Call the internal function */
555 if (!Fast486StackPop(State
, &Value
)) return;
557 /* Store the value */
558 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
559 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
562 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
566 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
568 INT Reg
= Opcode
& 0x07;
569 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
574 /* Make sure this is the right instruction */
575 ASSERT((Opcode
& 0xF8) == 0x90);
577 /* Exchange the values */
582 Value
= State
->GeneralRegs
[Reg
].Long
;
583 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
584 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
590 Value
= State
->GeneralRegs
[Reg
].LowWord
;
591 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
592 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
596 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
598 BOOLEAN Jump
= FALSE
;
600 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
602 /* Make sure this is the right instruction */
603 ASSERT((Opcode
& 0xF0) == 0x70);
607 /* Fetch the offset */
608 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
610 /* An exception occurred */
614 switch ((Opcode
& 0x0F) >> 1)
619 Jump
= State
->Flags
.Of
;
626 Jump
= State
->Flags
.Cf
;
633 Jump
= State
->Flags
.Zf
;
640 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
647 Jump
= State
->Flags
.Sf
;
654 Jump
= State
->Flags
.Pf
;
661 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
668 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
675 /* Invert the result */
681 /* Move the instruction pointer */
682 State
->InstPtr
.Long
+= Offset
;
686 /* Clear the top half of EIP */
687 State
->InstPtr
.Long
&= 0xFFFF;
692 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
694 /* Make sure this is the right instruction */
695 ASSERT(Opcode
== 0xF8);
697 /* No prefixes allowed */
698 if (State
->PrefixFlags
)
700 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
704 /* Clear CF and return success */
705 State
->Flags
.Cf
= FALSE
;
708 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
710 /* Make sure this is the right instruction */
711 ASSERT(Opcode
== 0xF9);
713 /* No prefixes allowed */
714 if (State
->PrefixFlags
)
716 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
720 /* Set CF and return success*/
721 State
->Flags
.Cf
= TRUE
;
724 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
726 /* Make sure this is the right instruction */
727 ASSERT(Opcode
== 0xF5);
729 /* No prefixes allowed */
730 if (State
->PrefixFlags
)
732 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
736 /* Toggle CF and return success */
737 State
->Flags
.Cf
= !State
->Flags
.Cf
;
741 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
743 /* Make sure this is the right instruction */
744 ASSERT(Opcode
== 0xFA);
746 /* No prefixes allowed */
747 if (State
->PrefixFlags
)
749 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
753 /* Check for protected mode */
754 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
757 if (State
->Flags
.Iopl
>= Fast486GetCurrentPrivLevel(State
))
759 /* Clear the interrupt flag */
760 State
->Flags
.If
= FALSE
;
764 /* General Protection Fault */
765 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
771 /* Just clear the interrupt flag */
772 State
->Flags
.If
= FALSE
;
776 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
778 /* Make sure this is the right instruction */
779 ASSERT(Opcode
== 0xFB);
781 /* No prefixes allowed */
782 if (State
->PrefixFlags
)
784 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
788 /* Check for protected mode */
789 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
792 if (State
->Flags
.Iopl
>= Fast486GetCurrentPrivLevel(State
))
794 /* Set the interrupt flag */
795 State
->Flags
.If
= TRUE
;
799 /* General Protection Fault */
800 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
806 /* Just set the interrupt flag */
807 State
->Flags
.If
= TRUE
;
811 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
813 /* Make sure this is the right instruction */
814 ASSERT(Opcode
== 0xFC);
816 /* No prefixes allowed */
817 if (State
->PrefixFlags
)
819 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
824 State
->Flags
.Df
= FALSE
;
827 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
829 /* Make sure this is the right instruction */
830 ASSERT(Opcode
== 0xFD);
832 /* No prefixes allowed */
833 if (State
->PrefixFlags
)
835 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
840 State
->Flags
.Df
= TRUE
;
843 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
845 /* Make sure this is the right instruction */
846 ASSERT(Opcode
== 0xF4);
848 /* No prefixes allowed */
849 if (State
->PrefixFlags
)
851 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
855 /* Privileged instructions can only be executed under CPL = 0 */
856 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
858 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
863 State
->Halted
= TRUE
;
866 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
871 /* Make sure this is the right instruction */
872 ASSERT((Opcode
& 0xF7) == 0xE4);
876 /* Fetch the parameter */
877 if (!Fast486FetchByte(State
, &Data
))
879 /* Exception occurred */
883 /* Set the port number to the parameter */
888 /* The port number is in DX */
889 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
892 /* Read a byte from the I/O port */
893 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
895 /* Store the result in AL */
896 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
899 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
902 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
904 /* Make sure this is the right instruction */
905 ASSERT((Opcode
& 0xF7) == 0xE5);
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
;
934 /* Read a dword from the I/O port */
935 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
937 /* Store the value in EAX */
938 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
944 /* Read a word from the I/O port */
945 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
947 /* Store the value in AX */
948 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
952 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
957 /* Make sure this is the right instruction */
958 ASSERT((Opcode
& 0xF7) == 0xE6);
962 /* Fetch the parameter */
963 if (!Fast486FetchByte(State
, &Data
))
965 /* Exception occurred */
969 /* Set the port number to the parameter */
974 /* The port number is in DX */
975 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
978 /* Read the value from AL */
979 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
981 /* Write the byte to the I/O port */
982 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
985 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
988 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
990 /* Make sure this is the right instruction */
991 ASSERT((Opcode
& 0xF7) == 0xE7);
1000 /* Fetch the parameter */
1001 if (!Fast486FetchByte(State
, &Data
))
1003 /* Exception occurred */
1007 /* Set the port number to the parameter */
1012 /* The port number is in DX */
1013 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1018 /* Get the value from EAX */
1019 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1021 /* Write a dword to the I/O port */
1022 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1026 /* Get the value from AX */
1027 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1029 /* Write a word to the I/O port */
1030 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1034 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1037 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1039 TOGGLE_OPSIZE(Size
);
1041 /* Make sure this is the right instruction */
1042 ASSERT(Opcode
== 0xEB);
1044 /* Fetch the offset */
1045 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1047 /* An exception occurred */
1051 /* Move the instruction pointer */
1052 State
->InstPtr
.Long
+= Offset
;
1056 /* Clear the top half of EIP */
1057 State
->InstPtr
.Long
&= 0xFFFF;
1061 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1063 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1065 /* Make sure this is the right instruction */
1066 ASSERT((Opcode
& 0xF8) == 0xB8);
1068 TOGGLE_OPSIZE(Size
);
1075 /* Fetch the dword */
1076 if (!Fast486FetchDword(State
, &Value
))
1078 /* Exception occurred */
1082 /* Store the value in the register */
1083 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1089 /* Fetch the word */
1090 if (!Fast486FetchWord(State
, &Value
))
1092 /* Exception occurred */
1096 /* Store the value in the register */
1097 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1101 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1105 /* Make sure this is the right instruction */
1106 ASSERT((Opcode
& 0xF8) == 0xB0);
1108 if (State
->PrefixFlags
!= 0)
1110 /* Invalid prefix */
1111 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1115 /* Fetch the byte */
1116 if (!Fast486FetchByte(State
, &Value
))
1118 /* Exception occurred */
1124 /* AH, CH, DH or BH */
1125 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1129 /* AL, CL, DL or BL */
1130 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1134 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1136 UCHAR FirstValue
, SecondValue
, Result
;
1137 FAST486_MOD_REG_RM ModRegRm
;
1138 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1140 /* Make sure this is the right instruction */
1141 ASSERT((Opcode
& 0xFD) == 0x00);
1143 TOGGLE_ADSIZE(AddressSize
);
1145 /* Get the operands */
1146 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1148 /* Exception occurred */
1152 if (!Fast486ReadModrmByteOperands(State
,
1157 /* Exception occurred */
1161 /* Calculate the result */
1162 Result
= FirstValue
+ SecondValue
;
1164 /* Update the flags */
1165 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1166 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1167 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1168 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1169 State
->Flags
.Zf
= (Result
== 0);
1170 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1171 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1173 /* Write back the result */
1174 Fast486WriteModrmByteOperands(State
,
1176 Opcode
& FAST486_OPCODE_WRITE_REG
,
1180 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1182 FAST486_MOD_REG_RM ModRegRm
;
1183 BOOLEAN OperandSize
, AddressSize
;
1185 /* Make sure this is the right instruction */
1186 ASSERT((Opcode
& 0xFD) == 0x01);
1188 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1190 TOGGLE_ADSIZE(AddressSize
);
1191 TOGGLE_OPSIZE(OperandSize
);
1193 /* Get the operands */
1194 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1196 /* Exception occurred */
1200 /* Check the operand size */
1203 ULONG FirstValue
, SecondValue
, Result
;
1205 if (!Fast486ReadModrmDwordOperands(State
,
1210 /* Exception occurred */
1214 /* Calculate the result */
1215 Result
= FirstValue
+ SecondValue
;
1217 /* Update the flags */
1218 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1219 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1220 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1221 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1222 State
->Flags
.Zf
= (Result
== 0);
1223 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1224 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1226 /* Write back the result */
1227 Fast486WriteModrmDwordOperands(State
,
1229 Opcode
& FAST486_OPCODE_WRITE_REG
,
1234 USHORT FirstValue
, SecondValue
, Result
;
1236 if (!Fast486ReadModrmWordOperands(State
,
1241 /* Exception occurred */
1245 /* Calculate the result */
1246 Result
= FirstValue
+ SecondValue
;
1248 /* Update the flags */
1249 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1250 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1251 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1252 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1253 State
->Flags
.Zf
= (Result
== 0);
1254 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1255 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1257 /* Write back the result */
1258 Fast486WriteModrmWordOperands(State
,
1260 Opcode
& FAST486_OPCODE_WRITE_REG
,
1265 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1267 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1268 UCHAR SecondValue
, Result
;
1270 /* Make sure this is the right instruction */
1271 ASSERT(Opcode
== 0x04);
1273 if (State
->PrefixFlags
)
1275 /* This opcode doesn't take any prefixes */
1276 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1280 if (!Fast486FetchByte(State
, &SecondValue
))
1282 /* Exception occurred */
1286 /* Calculate the result */
1287 Result
= FirstValue
+ SecondValue
;
1289 /* Update the flags */
1290 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1291 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1292 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1293 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1294 State
->Flags
.Zf
= (Result
== 0);
1295 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1296 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1298 /* Write back the result */
1299 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1302 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1304 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1306 /* Make sure this is the right instruction */
1307 ASSERT(Opcode
== 0x05);
1310 TOGGLE_OPSIZE(Size
);
1314 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1315 ULONG SecondValue
, Result
;
1317 if (!Fast486FetchDword(State
, &SecondValue
))
1319 /* Exception occurred */
1323 /* Calculate the result */
1324 Result
= FirstValue
+ SecondValue
;
1326 /* Update the flags */
1327 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1328 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1329 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1330 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1331 State
->Flags
.Zf
= (Result
== 0);
1332 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1333 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1335 /* Write back the result */
1336 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1340 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1341 USHORT SecondValue
, Result
;
1343 if (!Fast486FetchWord(State
, &SecondValue
))
1345 /* Exception occurred */
1349 /* Calculate the result */
1350 Result
= FirstValue
+ SecondValue
;
1352 /* Update the flags */
1353 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1354 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1355 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1356 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1357 State
->Flags
.Zf
= (Result
== 0);
1358 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1359 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1361 /* Write back the result */
1362 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1366 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1368 UCHAR FirstValue
, SecondValue
, Result
;
1369 FAST486_MOD_REG_RM ModRegRm
;
1370 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1372 /* Make sure this is the right instruction */
1373 ASSERT((Opcode
& 0xFD) == 0x08);
1375 TOGGLE_ADSIZE(AddressSize
);
1377 /* Get the operands */
1378 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1380 /* Exception occurred */
1384 if (!Fast486ReadModrmByteOperands(State
,
1389 /* Exception occurred */
1393 /* Calculate the result */
1394 Result
= FirstValue
| SecondValue
;
1396 /* Update the flags */
1397 State
->Flags
.Cf
= FALSE
;
1398 State
->Flags
.Of
= FALSE
;
1399 State
->Flags
.Zf
= (Result
== 0);
1400 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1401 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1403 /* Write back the result */
1404 Fast486WriteModrmByteOperands(State
,
1406 Opcode
& FAST486_OPCODE_WRITE_REG
,
1410 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1412 FAST486_MOD_REG_RM ModRegRm
;
1413 BOOLEAN OperandSize
, AddressSize
;
1415 /* Make sure this is the right instruction */
1416 ASSERT((Opcode
& 0xFD) == 0x09);
1418 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1420 TOGGLE_ADSIZE(AddressSize
);
1421 TOGGLE_OPSIZE(OperandSize
);
1423 /* Get the operands */
1424 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1426 /* Exception occurred */
1430 /* Check the operand size */
1433 ULONG FirstValue
, SecondValue
, Result
;
1435 if (!Fast486ReadModrmDwordOperands(State
,
1440 /* Exception occurred */
1444 /* Calculate the result */
1445 Result
= FirstValue
| SecondValue
;
1447 /* Update the flags */
1448 State
->Flags
.Cf
= FALSE
;
1449 State
->Flags
.Of
= FALSE
;
1450 State
->Flags
.Zf
= (Result
== 0);
1451 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1452 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1454 /* Write back the result */
1455 Fast486WriteModrmDwordOperands(State
,
1457 Opcode
& FAST486_OPCODE_WRITE_REG
,
1462 USHORT FirstValue
, SecondValue
, Result
;
1464 if (!Fast486ReadModrmWordOperands(State
,
1469 /* Exception occurred */
1473 /* Calculate the result */
1474 Result
= FirstValue
| SecondValue
;
1476 /* Update the flags */
1477 State
->Flags
.Cf
= FALSE
;
1478 State
->Flags
.Of
= FALSE
;
1479 State
->Flags
.Zf
= (Result
== 0);
1480 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1481 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1483 /* Write back the result */
1484 Fast486WriteModrmWordOperands(State
,
1486 Opcode
& FAST486_OPCODE_WRITE_REG
,
1491 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1493 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1494 UCHAR SecondValue
, Result
;
1496 /* Make sure this is the right instruction */
1497 ASSERT(Opcode
== 0x0C);
1499 if (State
->PrefixFlags
)
1501 /* This opcode doesn't take any prefixes */
1502 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1506 if (!Fast486FetchByte(State
, &SecondValue
))
1508 /* Exception occurred */
1512 /* Calculate the result */
1513 Result
= FirstValue
| SecondValue
;
1515 /* Update the flags */
1516 State
->Flags
.Cf
= FALSE
;
1517 State
->Flags
.Of
= FALSE
;
1518 State
->Flags
.Zf
= (Result
== 0);
1519 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1520 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1522 /* Write back the result */
1523 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1526 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1528 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1530 /* Make sure this is the right instruction */
1531 ASSERT(Opcode
== 0x0D);
1534 TOGGLE_OPSIZE(Size
);
1538 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1539 ULONG SecondValue
, Result
;
1541 if (!Fast486FetchDword(State
, &SecondValue
))
1543 /* Exception occurred */
1547 /* Calculate the result */
1548 Result
= FirstValue
| SecondValue
;
1550 /* Update the flags */
1551 State
->Flags
.Cf
= FALSE
;
1552 State
->Flags
.Of
= FALSE
;
1553 State
->Flags
.Zf
= (Result
== 0);
1554 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1555 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1557 /* Write back the result */
1558 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1562 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1563 USHORT SecondValue
, Result
;
1565 if (!Fast486FetchWord(State
, &SecondValue
))
1567 /* Exception occurred */
1571 /* Calculate the result */
1572 Result
= FirstValue
| SecondValue
;
1574 /* Update the flags */
1575 State
->Flags
.Cf
= FALSE
;
1576 State
->Flags
.Of
= FALSE
;
1577 State
->Flags
.Zf
= (Result
== 0);
1578 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1579 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1581 /* Write back the result */
1582 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1586 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1588 UCHAR FirstValue
, SecondValue
, Result
;
1589 FAST486_MOD_REG_RM ModRegRm
;
1590 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1592 /* Make sure this is the right instruction */
1593 ASSERT((Opcode
& 0xFD) == 0x20);
1595 TOGGLE_ADSIZE(AddressSize
);
1597 /* Get the operands */
1598 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1600 /* Exception occurred */
1604 if (!Fast486ReadModrmByteOperands(State
,
1609 /* Exception occurred */
1613 /* Calculate the result */
1614 Result
= FirstValue
& SecondValue
;
1616 /* Update the flags */
1617 State
->Flags
.Cf
= FALSE
;
1618 State
->Flags
.Of
= FALSE
;
1619 State
->Flags
.Zf
= (Result
== 0);
1620 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1621 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1623 /* Write back the result */
1624 Fast486WriteModrmByteOperands(State
,
1626 Opcode
& FAST486_OPCODE_WRITE_REG
,
1630 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1632 FAST486_MOD_REG_RM ModRegRm
;
1633 BOOLEAN OperandSize
, AddressSize
;
1635 /* Make sure this is the right instruction */
1636 ASSERT((Opcode
& 0xFD) == 0x21);
1638 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1640 TOGGLE_ADSIZE(AddressSize
);
1641 TOGGLE_OPSIZE(OperandSize
);
1643 /* Get the operands */
1644 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1646 /* Exception occurred */
1650 /* Check the operand size */
1653 ULONG FirstValue
, SecondValue
, Result
;
1655 if (!Fast486ReadModrmDwordOperands(State
,
1660 /* Exception occurred */
1664 /* Calculate the result */
1665 Result
= FirstValue
& SecondValue
;
1667 /* Update the flags */
1668 State
->Flags
.Cf
= FALSE
;
1669 State
->Flags
.Of
= FALSE
;
1670 State
->Flags
.Zf
= (Result
== 0);
1671 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1672 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1674 /* Write back the result */
1675 Fast486WriteModrmDwordOperands(State
,
1677 Opcode
& FAST486_OPCODE_WRITE_REG
,
1682 USHORT FirstValue
, SecondValue
, Result
;
1684 if (!Fast486ReadModrmWordOperands(State
,
1689 /* Exception occurred */
1693 /* Calculate the result */
1694 Result
= FirstValue
& SecondValue
;
1696 /* Update the flags */
1697 State
->Flags
.Cf
= FALSE
;
1698 State
->Flags
.Of
= FALSE
;
1699 State
->Flags
.Zf
= (Result
== 0);
1700 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1701 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1703 /* Write back the result */
1704 Fast486WriteModrmWordOperands(State
,
1706 Opcode
& FAST486_OPCODE_WRITE_REG
,
1711 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1713 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1714 UCHAR SecondValue
, Result
;
1716 /* Make sure this is the right instruction */
1717 ASSERT(Opcode
== 0x24);
1721 if (!Fast486FetchByte(State
, &SecondValue
))
1723 /* Exception occurred */
1727 /* Calculate the result */
1728 Result
= FirstValue
& SecondValue
;
1730 /* Update the flags */
1731 State
->Flags
.Cf
= FALSE
;
1732 State
->Flags
.Of
= FALSE
;
1733 State
->Flags
.Zf
= (Result
== 0);
1734 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1735 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1737 /* Write back the result */
1738 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1741 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1743 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1745 /* Make sure this is the right instruction */
1746 ASSERT(Opcode
== 0x25);
1749 TOGGLE_OPSIZE(Size
);
1753 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1754 ULONG SecondValue
, Result
;
1756 if (!Fast486FetchDword(State
, &SecondValue
))
1758 /* Exception occurred */
1762 /* Calculate the result */
1763 Result
= FirstValue
& SecondValue
;
1765 /* Update the flags */
1766 State
->Flags
.Cf
= FALSE
;
1767 State
->Flags
.Of
= FALSE
;
1768 State
->Flags
.Zf
= (Result
== 0);
1769 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1770 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1772 /* Write back the result */
1773 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1777 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1778 USHORT SecondValue
, Result
;
1780 if (!Fast486FetchWord(State
, &SecondValue
))
1782 /* Exception occurred */
1786 /* Calculate the result */
1787 Result
= FirstValue
& SecondValue
;
1789 /* Update the flags */
1790 State
->Flags
.Cf
= FALSE
;
1791 State
->Flags
.Of
= FALSE
;
1792 State
->Flags
.Zf
= (Result
== 0);
1793 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1794 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1796 /* Write back the result */
1797 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1801 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1803 UCHAR FirstValue
, SecondValue
, Result
;
1804 FAST486_MOD_REG_RM ModRegRm
;
1805 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1807 /* Make sure this is the right instruction */
1808 ASSERT((Opcode
& 0xFD) == 0x30);
1810 TOGGLE_ADSIZE(AddressSize
);
1812 /* Get the operands */
1813 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1815 /* Exception occurred */
1819 if (!Fast486ReadModrmByteOperands(State
,
1824 /* Exception occurred */
1828 /* Calculate the result */
1829 Result
= FirstValue
^ SecondValue
;
1831 /* Update the flags */
1832 State
->Flags
.Cf
= FALSE
;
1833 State
->Flags
.Of
= FALSE
;
1834 State
->Flags
.Zf
= (Result
== 0);
1835 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1836 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1838 /* Write back the result */
1839 Fast486WriteModrmByteOperands(State
,
1841 Opcode
& FAST486_OPCODE_WRITE_REG
,
1845 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1847 FAST486_MOD_REG_RM ModRegRm
;
1848 BOOLEAN OperandSize
, AddressSize
;
1850 /* Make sure this is the right instruction */
1851 ASSERT((Opcode
& 0xFD) == 0x31);
1853 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1855 TOGGLE_ADSIZE(AddressSize
);
1856 TOGGLE_OPSIZE(OperandSize
);
1858 /* Get the operands */
1859 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1861 /* Exception occurred */
1865 /* Check the operand size */
1868 ULONG FirstValue
, SecondValue
, Result
;
1870 if (!Fast486ReadModrmDwordOperands(State
,
1875 /* Exception occurred */
1879 /* Calculate the result */
1880 Result
= FirstValue
^ SecondValue
;
1882 /* Update the flags */
1883 State
->Flags
.Cf
= FALSE
;
1884 State
->Flags
.Of
= FALSE
;
1885 State
->Flags
.Zf
= (Result
== 0);
1886 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1887 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1889 /* Write back the result */
1890 Fast486WriteModrmDwordOperands(State
,
1892 Opcode
& FAST486_OPCODE_WRITE_REG
,
1897 USHORT FirstValue
, SecondValue
, Result
;
1899 if (!Fast486ReadModrmWordOperands(State
,
1904 /* Exception occurred */
1908 /* Calculate the result */
1909 Result
= FirstValue
^ SecondValue
;
1911 /* Update the flags */
1912 State
->Flags
.Cf
= FALSE
;
1913 State
->Flags
.Of
= FALSE
;
1914 State
->Flags
.Zf
= (Result
== 0);
1915 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1916 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1918 /* Write back the result */
1919 Fast486WriteModrmWordOperands(State
,
1921 Opcode
& FAST486_OPCODE_WRITE_REG
,
1926 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1928 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1929 UCHAR SecondValue
, Result
;
1931 /* Make sure this is the right instruction */
1932 ASSERT(Opcode
== 0x34);
1934 if (State
->PrefixFlags
)
1936 /* This opcode doesn't take any prefixes */
1937 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1941 if (!Fast486FetchByte(State
, &SecondValue
))
1943 /* Exception occurred */
1947 /* Calculate the result */
1948 Result
= FirstValue
^ SecondValue
;
1950 /* Update the flags */
1951 State
->Flags
.Cf
= FALSE
;
1952 State
->Flags
.Of
= FALSE
;
1953 State
->Flags
.Zf
= (Result
== 0);
1954 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1955 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1957 /* Write back the result */
1958 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1961 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
1963 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1965 /* Make sure this is the right instruction */
1966 ASSERT(Opcode
== 0x35);
1969 TOGGLE_OPSIZE(Size
);
1973 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1974 ULONG SecondValue
, Result
;
1976 if (!Fast486FetchDword(State
, &SecondValue
))
1978 /* Exception occurred */
1982 /* Calculate the result */
1983 Result
= FirstValue
^ SecondValue
;
1985 /* Update the flags */
1986 State
->Flags
.Cf
= FALSE
;
1987 State
->Flags
.Of
= FALSE
;
1988 State
->Flags
.Zf
= (Result
== 0);
1989 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1990 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1992 /* Write back the result */
1993 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1997 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1998 USHORT SecondValue
, Result
;
2000 if (!Fast486FetchWord(State
, &SecondValue
))
2002 /* Exception occurred */
2006 /* Calculate the result */
2007 Result
= FirstValue
^ SecondValue
;
2009 /* Update the flags */
2010 State
->Flags
.Cf
= FALSE
;
2011 State
->Flags
.Of
= FALSE
;
2012 State
->Flags
.Zf
= (Result
== 0);
2013 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2014 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2016 /* Write back the result */
2017 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2021 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2023 UCHAR FirstValue
, SecondValue
, Result
;
2024 FAST486_MOD_REG_RM ModRegRm
;
2025 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2027 /* Make sure this is the right instruction */
2028 ASSERT(Opcode
== 0x84);
2030 TOGGLE_ADSIZE(AddressSize
);
2032 /* Get the operands */
2033 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2035 /* Exception occurred */
2039 if (!Fast486ReadModrmByteOperands(State
,
2044 /* Exception occurred */
2047 /* Calculate the result */
2048 Result
= FirstValue
& SecondValue
;
2050 /* Update the flags */
2051 State
->Flags
.Cf
= FALSE
;
2052 State
->Flags
.Of
= FALSE
;
2053 State
->Flags
.Zf
= (Result
== 0);
2054 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2055 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2058 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2060 FAST486_MOD_REG_RM ModRegRm
;
2061 BOOLEAN OperandSize
, AddressSize
;
2063 /* Make sure this is the right instruction */
2064 ASSERT(Opcode
== 0x85);
2066 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2068 TOGGLE_ADSIZE(AddressSize
);
2069 TOGGLE_OPSIZE(OperandSize
);
2071 /* Get the operands */
2072 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2074 /* Exception occurred */
2078 /* Check the operand size */
2081 ULONG FirstValue
, SecondValue
, Result
;
2083 if (!Fast486ReadModrmDwordOperands(State
,
2088 /* Exception occurred */
2092 /* Calculate the result */
2093 Result
= FirstValue
& SecondValue
;
2095 /* Update the flags */
2096 State
->Flags
.Cf
= FALSE
;
2097 State
->Flags
.Of
= FALSE
;
2098 State
->Flags
.Zf
= (Result
== 0);
2099 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2100 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2104 USHORT FirstValue
, SecondValue
, Result
;
2106 if (!Fast486ReadModrmWordOperands(State
,
2111 /* 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_WORD
) != 0);
2123 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2127 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2129 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2130 UCHAR SecondValue
, Result
;
2132 /* Make sure this is the right instruction */
2133 ASSERT(Opcode
== 0xA8);
2135 if (State
->PrefixFlags
)
2137 /* This opcode doesn't take any prefixes */
2138 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2142 if (!Fast486FetchByte(State
, &SecondValue
))
2144 /* Exception occurred */
2148 /* Calculate the result */
2149 Result
= FirstValue
& SecondValue
;
2151 /* Update the flags */
2152 State
->Flags
.Cf
= FALSE
;
2153 State
->Flags
.Of
= FALSE
;
2154 State
->Flags
.Zf
= (Result
== 0);
2155 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2156 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2159 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2161 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2163 /* Make sure this is the right instruction */
2164 ASSERT(Opcode
== 0xA9);
2167 TOGGLE_OPSIZE(Size
);
2171 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2172 ULONG SecondValue
, Result
;
2174 if (!Fast486FetchDword(State
, &SecondValue
))
2176 /* Exception occurred */
2180 /* Calculate the result */
2181 Result
= FirstValue
& SecondValue
;
2183 /* Update the flags */
2184 State
->Flags
.Cf
= FALSE
;
2185 State
->Flags
.Of
= FALSE
;
2186 State
->Flags
.Zf
= (Result
== 0);
2187 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2188 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2192 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2193 USHORT SecondValue
, Result
;
2195 if (!Fast486FetchWord(State
, &SecondValue
))
2197 /* Exception occurred */
2201 /* Calculate the result */
2202 Result
= FirstValue
& SecondValue
;
2204 /* Update the flags */
2205 State
->Flags
.Cf
= FALSE
;
2206 State
->Flags
.Of
= FALSE
;
2207 State
->Flags
.Zf
= (Result
== 0);
2208 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2209 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2213 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2215 UCHAR FirstValue
, SecondValue
;
2216 FAST486_MOD_REG_RM ModRegRm
;
2217 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2219 /* Make sure this is the right instruction */
2220 ASSERT(Opcode
== 0x86);
2222 TOGGLE_ADSIZE(AddressSize
);
2224 /* Get the operands */
2225 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2227 /* Exception occurred */
2231 if (!Fast486ReadModrmByteOperands(State
,
2236 /* Exception occurred */
2240 /* Write the value from the register to the R/M */
2241 if (!Fast486WriteModrmByteOperands(State
,
2246 /* Exception occurred */
2250 /* Write the value from the R/M to the register */
2251 Fast486WriteModrmByteOperands(State
,
2257 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2259 FAST486_MOD_REG_RM ModRegRm
;
2260 BOOLEAN OperandSize
, AddressSize
;
2262 /* Make sure this is the right instruction */
2263 ASSERT(Opcode
== 0x87);
2265 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2267 TOGGLE_ADSIZE(AddressSize
);
2268 TOGGLE_OPSIZE(OperandSize
);
2270 /* Get the operands */
2271 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2273 /* Exception occurred */
2277 /* Check the operand size */
2280 ULONG FirstValue
, SecondValue
;
2282 if (!Fast486ReadModrmDwordOperands(State
,
2287 /* Exception occurred */
2291 /* Write the value from the register to the R/M */
2292 if (!Fast486WriteModrmDwordOperands(State
,
2297 /* Exception occurred */
2301 /* Write the value from the R/M to the register */
2302 Fast486WriteModrmDwordOperands(State
,
2309 USHORT FirstValue
, SecondValue
;
2311 if (!Fast486ReadModrmWordOperands(State
,
2316 /* Exception occurred */
2320 /* Write the value from the register to the R/M */
2321 if (!Fast486WriteModrmWordOperands(State
,
2326 /* Exception occurred */
2330 /* Write the value from the R/M to the register */
2331 Fast486WriteModrmWordOperands(State
,
2338 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2340 /* Call the internal API */
2341 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2344 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2348 if (!Fast486StackPop(State
, &NewSelector
))
2350 /* Exception occurred */
2354 /* Call the internal API */
2355 Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2358 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2360 /* Call the internal API */
2361 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2364 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2366 UCHAR FirstValue
, SecondValue
, Result
;
2367 FAST486_MOD_REG_RM ModRegRm
;
2368 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2370 /* Make sure this is the right instruction */
2371 ASSERT((Opcode
& 0xFD) == 0x10);
2373 TOGGLE_ADSIZE(AddressSize
);
2375 /* Get the operands */
2376 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2378 /* Exception occurred */
2382 if (!Fast486ReadModrmByteOperands(State
,
2387 /* Exception occurred */
2391 /* Calculate the result */
2392 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2394 /* Special exception for CF */
2395 State
->Flags
.Cf
= State
->Flags
.Cf
2396 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2398 /* Update the flags */
2399 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2400 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2401 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2402 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2403 State
->Flags
.Zf
= (Result
== 0);
2404 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2405 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2407 /* Write back the result */
2408 Fast486WriteModrmByteOperands(State
,
2410 Opcode
& FAST486_OPCODE_WRITE_REG
,
2414 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2416 FAST486_MOD_REG_RM ModRegRm
;
2417 BOOLEAN OperandSize
, AddressSize
;
2419 /* Make sure this is the right instruction */
2420 ASSERT((Opcode
& 0xFD) == 0x11);
2422 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2424 TOGGLE_ADSIZE(AddressSize
);
2425 TOGGLE_OPSIZE(OperandSize
);
2427 /* Get the operands */
2428 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2430 /* Exception occurred */
2434 /* Check the operand size */
2437 ULONG FirstValue
, SecondValue
, Result
;
2439 if (!Fast486ReadModrmDwordOperands(State
,
2444 /* Exception occurred */
2448 /* Calculate the result */
2449 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2451 /* Special exception for CF */
2452 State
->Flags
.Cf
= State
->Flags
.Cf
2453 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2455 /* Update the flags */
2456 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2457 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2458 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2459 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2460 State
->Flags
.Zf
= (Result
== 0);
2461 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2462 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2464 /* Write back the result */
2465 Fast486WriteModrmDwordOperands(State
,
2467 Opcode
& FAST486_OPCODE_WRITE_REG
,
2472 USHORT FirstValue
, SecondValue
, Result
;
2474 if (!Fast486ReadModrmWordOperands(State
,
2479 /* Exception occurred */
2483 /* Calculate the result */
2484 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2486 /* Special exception for CF */
2487 State
->Flags
.Cf
= State
->Flags
.Cf
2488 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2490 /* Update the flags */
2491 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2492 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2493 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2494 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2495 State
->Flags
.Zf
= (Result
== 0);
2496 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2497 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2499 /* Write back the result */
2500 Fast486WriteModrmWordOperands(State
,
2502 Opcode
& FAST486_OPCODE_WRITE_REG
,
2508 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2510 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2511 UCHAR SecondValue
, Result
;
2513 /* Make sure this is the right instruction */
2514 ASSERT(Opcode
== 0x14);
2516 if (State
->PrefixFlags
)
2518 /* This opcode doesn't take any prefixes */
2519 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2523 if (!Fast486FetchByte(State
, &SecondValue
))
2525 /* Exception occurred */
2529 /* Calculate the result */
2530 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2532 /* Special exception for CF */
2533 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2534 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2536 /* Update the flags */
2537 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2538 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2539 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2540 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2541 State
->Flags
.Zf
= (Result
== 0);
2542 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2543 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2545 /* Write back the result */
2546 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2549 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2551 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2553 /* Make sure this is the right instruction */
2554 ASSERT(Opcode
== 0x15);
2557 TOGGLE_OPSIZE(Size
);
2561 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2562 ULONG SecondValue
, Result
;
2564 if (!Fast486FetchDword(State
, &SecondValue
))
2566 /* Exception occurred */
2570 /* Calculate the result */
2571 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2573 /* Special exception for CF */
2574 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2575 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2577 /* Update the flags */
2578 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2579 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2580 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2581 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2582 State
->Flags
.Zf
= (Result
== 0);
2583 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2584 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2586 /* Write back the result */
2587 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2591 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2592 USHORT SecondValue
, Result
;
2594 if (!Fast486FetchWord(State
, &SecondValue
))
2596 /* Exception occurred */
2600 /* Calculate the result */
2601 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2603 /* Special exception for CF */
2604 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2605 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2607 /* Update the flags */
2608 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2609 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2610 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2611 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2612 State
->Flags
.Zf
= (Result
== 0);
2613 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2614 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2616 /* Write back the result */
2617 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2621 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2623 /* Call the internal API */
2624 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2627 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2631 if (!Fast486StackPop(State
, &NewSelector
))
2633 /* Exception occurred */
2637 /* Call the internal API */
2638 if (Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
)))
2640 /* Inhibit all interrupts until the next instruction */
2641 State
->DoNotInterrupt
= TRUE
;
2645 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2647 UCHAR FirstValue
, SecondValue
, Result
;
2648 FAST486_MOD_REG_RM ModRegRm
;
2649 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2650 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2652 /* Make sure this is the right instruction */
2653 ASSERT((Opcode
& 0xFD) == 0x18);
2655 TOGGLE_ADSIZE(AddressSize
);
2657 /* Get the operands */
2658 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2660 /* Exception occurred */
2664 if (!Fast486ReadModrmByteOperands(State
,
2669 /* Exception occurred */
2673 /* Check if this is the instruction that writes to R/M */
2674 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2676 /* Swap the order */
2677 SWAP(FirstValue
, SecondValue
);
2680 /* Calculate the result */
2681 Result
= FirstValue
- SecondValue
- Carry
;
2683 /* Update the flags */
2684 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2685 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2686 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2687 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2688 State
->Flags
.Zf
= (Result
== 0);
2689 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2690 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2692 /* Write back the result */
2693 Fast486WriteModrmByteOperands(State
,
2695 Opcode
& FAST486_OPCODE_WRITE_REG
,
2699 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2701 FAST486_MOD_REG_RM ModRegRm
;
2702 BOOLEAN OperandSize
, AddressSize
;
2703 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2705 /* Make sure this is the right instruction */
2706 ASSERT((Opcode
& 0xFD) == 0x19);
2708 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2710 TOGGLE_ADSIZE(AddressSize
);
2711 TOGGLE_OPSIZE(OperandSize
);
2713 /* Get the operands */
2714 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2716 /* Exception occurred */
2720 /* Check the operand size */
2723 ULONG FirstValue
, SecondValue
, Result
;
2725 if (!Fast486ReadModrmDwordOperands(State
,
2730 /* Exception occurred */
2734 /* Check if this is the instruction that writes to R/M */
2735 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2737 /* Swap the order */
2738 SWAP(FirstValue
, SecondValue
);
2741 /* Calculate the result */
2742 Result
= FirstValue
- SecondValue
- Carry
;
2744 /* Update the flags */
2745 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2746 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2747 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2748 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2749 State
->Flags
.Zf
= (Result
== 0);
2750 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2751 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2753 /* Write back the result */
2754 Fast486WriteModrmDwordOperands(State
,
2756 Opcode
& FAST486_OPCODE_WRITE_REG
,
2761 USHORT FirstValue
, SecondValue
, Result
;
2763 if (!Fast486ReadModrmWordOperands(State
,
2768 /* Exception occurred */
2772 /* Check if this is the instruction that writes to R/M */
2773 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2775 /* Swap the order */
2776 SWAP(FirstValue
, SecondValue
);
2779 /* Calculate the result */
2780 Result
= FirstValue
- SecondValue
- Carry
;
2782 /* Update the flags */
2783 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2784 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2785 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2786 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2787 State
->Flags
.Zf
= (Result
== 0);
2788 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2789 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2791 /* Write back the result */
2792 Fast486WriteModrmWordOperands(State
,
2794 Opcode
& FAST486_OPCODE_WRITE_REG
,
2799 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2801 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2802 UCHAR SecondValue
, Result
;
2803 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2805 /* Make sure this is the right instruction */
2806 ASSERT(Opcode
== 0x1C);
2808 if (State
->PrefixFlags
)
2810 /* This opcode doesn't take any prefixes */
2811 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2815 if (!Fast486FetchByte(State
, &SecondValue
))
2817 /* Exception occurred */
2821 /* Calculate the result */
2822 Result
= FirstValue
- SecondValue
- Carry
;
2824 /* Update the flags */
2825 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2826 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2827 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2828 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2829 State
->Flags
.Zf
= (Result
== 0);
2830 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2831 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2833 /* Write back the result */
2834 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2837 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2839 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2840 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2842 /* Make sure this is the right instruction */
2843 ASSERT(Opcode
== 0x1D);
2846 TOGGLE_OPSIZE(Size
);
2850 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2851 ULONG SecondValue
, Result
;
2853 if (!Fast486FetchDword(State
, &SecondValue
))
2855 /* Exception occurred */
2859 /* Calculate the result */
2860 Result
= FirstValue
- SecondValue
- Carry
;
2862 /* Update the flags */
2863 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2864 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2865 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2866 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2867 State
->Flags
.Zf
= (Result
== 0);
2868 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2869 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2871 /* Write back the result */
2872 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2876 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2877 USHORT SecondValue
, Result
;
2879 if (!Fast486FetchWord(State
, &SecondValue
))
2881 /* Exception occurred */
2885 /* Calculate the result */
2886 Result
= FirstValue
- SecondValue
- Carry
;
2888 /* Update the flags */
2889 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2890 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2891 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2892 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2893 State
->Flags
.Zf
= (Result
== 0);
2894 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2895 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2897 /* Write back the result */
2898 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2902 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2904 /* Call the internal API */
2905 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2908 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
2912 if (!Fast486StackPop(State
, &NewSelector
))
2914 /* Exception occurred */
2918 /* Call the internal API */
2919 Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
2922 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
2924 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2925 BOOLEAN Carry
= State
->Flags
.Cf
;
2927 /* Clear the carry flag */
2928 State
->Flags
.Cf
= FALSE
;
2930 /* Check if the first BCD digit is invalid or there was a carry from it */
2931 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
2934 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
2935 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
2937 /* A carry occurred */
2938 State
->Flags
.Cf
= TRUE
;
2941 /* Set the adjust flag */
2942 State
->Flags
.Af
= TRUE
;
2945 /* Check if the second BCD digit is invalid or there was a carry from it */
2946 if ((Value
> 0x99) || Carry
)
2949 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
2951 /* There was a carry */
2952 State
->Flags
.Cf
= TRUE
;
2955 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2957 /* Update the flags */
2958 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
2959 State
->Flags
.Zf
= (Value
== 0);
2960 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
2963 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
2965 UCHAR FirstValue
, SecondValue
, Result
;
2966 FAST486_MOD_REG_RM ModRegRm
;
2967 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2969 /* Make sure this is the right instruction */
2970 ASSERT((Opcode
& 0xED) == 0x28);
2972 TOGGLE_ADSIZE(AddressSize
);
2974 /* Get the operands */
2975 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2977 /* Exception occurred */
2981 if (!Fast486ReadModrmByteOperands(State
,
2986 /* Exception occurred */
2990 /* Check if this is the instruction that writes to R/M */
2991 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2993 /* Swap the order */
2994 SWAP(FirstValue
, SecondValue
);
2997 /* Calculate the result */
2998 Result
= FirstValue
- SecondValue
;
3000 /* Update the flags */
3001 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3002 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3003 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3004 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3005 State
->Flags
.Zf
= (Result
== 0);
3006 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3007 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3009 /* Check if this is not a CMP */
3010 if (!(Opcode
& 0x10))
3012 /* Write back the result */
3013 Fast486WriteModrmByteOperands(State
,
3015 Opcode
& FAST486_OPCODE_WRITE_REG
,
3020 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3022 FAST486_MOD_REG_RM ModRegRm
;
3023 BOOLEAN OperandSize
, AddressSize
;
3025 /* Make sure this is the right instruction */
3026 ASSERT((Opcode
& 0xED) == 0x29);
3028 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3030 TOGGLE_ADSIZE(AddressSize
);
3031 TOGGLE_OPSIZE(OperandSize
);
3033 /* Get the operands */
3034 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3036 /* Exception occurred */
3040 /* Check the operand size */
3043 ULONG FirstValue
, SecondValue
, Result
;
3045 if (!Fast486ReadModrmDwordOperands(State
,
3050 /* Exception occurred */
3054 /* Check if this is the instruction that writes to R/M */
3055 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3057 /* Swap the order */
3058 SWAP(FirstValue
, SecondValue
);
3061 /* Calculate the result */
3062 Result
= FirstValue
- SecondValue
;
3064 /* Update the flags */
3065 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3066 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3067 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3068 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3069 State
->Flags
.Zf
= (Result
== 0);
3070 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3071 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3073 /* Check if this is not a CMP */
3074 if (!(Opcode
& 0x10))
3076 /* Write back the result */
3077 Fast486WriteModrmDwordOperands(State
,
3079 Opcode
& FAST486_OPCODE_WRITE_REG
,
3085 USHORT FirstValue
, SecondValue
, Result
;
3087 if (!Fast486ReadModrmWordOperands(State
,
3092 /* Exception occurred */
3096 /* Check if this is the instruction that writes to R/M */
3097 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3099 /* Swap the order */
3100 SWAP(FirstValue
, SecondValue
);
3103 /* Calculate the result */
3104 Result
= FirstValue
- SecondValue
;
3106 /* Update the flags */
3107 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3108 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3109 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3110 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3111 State
->Flags
.Zf
= (Result
== 0);
3112 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3113 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3115 /* Check if this is not a CMP */
3116 if (!(Opcode
& 0x10))
3118 /* Write back the result */
3119 Fast486WriteModrmWordOperands(State
,
3121 Opcode
& FAST486_OPCODE_WRITE_REG
,
3127 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3129 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3130 UCHAR SecondValue
, Result
;
3132 /* Make sure this is the right instruction */
3133 ASSERT((Opcode
& 0xEF) == 0x2C);
3135 if (State
->PrefixFlags
)
3137 /* This opcode doesn't take any prefixes */
3138 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3142 if (!Fast486FetchByte(State
, &SecondValue
))
3144 /* Exception occurred */
3148 /* Calculate the result */
3149 Result
= FirstValue
- SecondValue
;
3151 /* Update the flags */
3152 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3153 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3154 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3155 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3156 State
->Flags
.Zf
= (Result
== 0);
3157 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3158 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3160 /* Check if this is not a CMP */
3161 if (!(Opcode
& 0x10))
3163 /* Write back the result */
3164 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3168 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3170 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3172 /* Make sure this is the right instruction */
3173 ASSERT((Opcode
& 0xEF) == 0x2D);
3176 TOGGLE_OPSIZE(Size
);
3180 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3181 ULONG SecondValue
, Result
;
3183 if (!Fast486FetchDword(State
, &SecondValue
))
3185 /* Exception occurred */
3189 /* Calculate the result */
3190 Result
= FirstValue
- SecondValue
;
3192 /* Update the flags */
3193 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3194 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3195 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3196 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3197 State
->Flags
.Zf
= (Result
== 0);
3198 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3199 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3201 /* Check if this is not a CMP */
3202 if (!(Opcode
& 0x10))
3204 /* Write back the result */
3205 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3210 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3211 USHORT SecondValue
, Result
;
3213 if (!Fast486FetchWord(State
, &SecondValue
))
3215 /* Exception occurred */
3219 /* Calculate the result */
3220 Result
= FirstValue
- SecondValue
;
3222 /* Update the flags */
3223 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3224 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3225 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3226 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3227 State
->Flags
.Zf
= (Result
== 0);
3228 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3229 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3231 /* Check if this is not a CMP */
3232 if (!(Opcode
& 0x10))
3234 /* Write back the result */
3235 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3240 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3242 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3243 BOOLEAN Carry
= State
->Flags
.Cf
;
3245 /* Clear the carry flag */
3246 State
->Flags
.Cf
= FALSE
;
3248 /* Check if the first BCD digit is invalid or there was a borrow */
3249 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3252 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3253 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3255 /* A borrow occurred */
3256 State
->Flags
.Cf
= TRUE
;
3259 /* Set the adjust flag */
3260 State
->Flags
.Af
= TRUE
;
3263 /* Check if the second BCD digit is invalid or there was a borrow */
3264 if ((Value
> 0x99) || Carry
)
3267 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3269 /* There was a borrow */
3270 State
->Flags
.Cf
= TRUE
;
3273 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3275 /* Update the flags */
3276 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3277 State
->Flags
.Zf
= (Value
== 0);
3278 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3281 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3283 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3286 * Check if the value in AL is not a valid BCD digit,
3287 * or there was a carry from the lowest 4 bits of AL
3289 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3292 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3293 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3296 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3300 /* Clear CF and AF */
3301 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3304 /* Keep only the lowest 4 bits of AL */
3305 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3308 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3310 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3313 * Check if the value in AL is not a valid BCD digit,
3314 * or there was a borrow from the lowest 4 bits of AL
3316 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3319 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3320 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3323 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3327 /* Clear CF and AF */
3328 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3331 /* Keep only the lowest 4 bits of AL */
3332 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3335 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3338 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3339 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3341 /* Make sure this is the right instruction */
3342 ASSERT(Opcode
== 0x60);
3344 TOGGLE_OPSIZE(Size
);
3347 /* Push all the registers in order */
3348 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3350 if (i
== FAST486_REG_ESP
)
3352 /* Use the saved ESP instead */
3353 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3355 /* Exception occurred */
3361 /* Push the register */
3362 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3363 : State
->GeneralRegs
[i
].LowWord
))
3365 /* Exception occurred */
3372 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3375 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3378 /* Make sure this is the right instruction */
3379 ASSERT(Opcode
== 0x61);
3381 TOGGLE_OPSIZE(Size
);
3384 /* Pop all the registers in reverse order */
3385 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3388 if (!Fast486StackPop(State
, &Value
))
3390 /* Exception occurred */
3394 /* Don't modify ESP */
3395 if (i
!= FAST486_REG_ESP
)
3397 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3398 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3403 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3405 BOOLEAN OperandSize
, AddressSize
;
3406 FAST486_MOD_REG_RM ModRegRm
;
3407 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3409 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3412 TOGGLE_OPSIZE(OperandSize
);
3413 TOGGLE_ADSIZE(AddressSize
);
3415 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3417 /* Exception occurred */
3421 if (!ModRegRm
.Memory
)
3424 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3428 /* Check for the segment override */
3429 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3431 /* Use the override segment instead */
3432 Segment
= State
->SegmentOverride
;
3437 LONG Index
, LowerBound
, UpperBound
;
3439 /* Read the operands */
3440 if (!Fast486ReadModrmDwordOperands(State
,
3443 (PULONG
)&LowerBound
))
3445 /* Exception occurred */
3449 if (!Fast486ReadMemory(State
,
3451 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3456 /* Exception occurred */
3460 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3463 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3468 SHORT Index
, LowerBound
, UpperBound
;
3470 /* Read the operands */
3471 if (!Fast486ReadModrmWordOperands(State
,
3474 (PUSHORT
)&LowerBound
))
3476 /* Exception occurred */
3480 if (!Fast486ReadMemory(State
,
3482 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3487 /* Exception occurred */
3491 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3494 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3499 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3501 USHORT FirstValue
, SecondValue
;
3502 FAST486_MOD_REG_RM ModRegRm
;
3503 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3505 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3507 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3509 /* Cannot be used in real mode or with a LOCK prefix */
3510 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3514 TOGGLE_ADSIZE(AddressSize
);
3516 /* Get the operands */
3517 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3519 /* Exception occurred */
3523 /* Read the operands */
3524 if (!Fast486ReadModrmWordOperands(State
,
3529 /* Exception occurred */
3533 /* Check if the RPL needs adjusting */
3534 if ((SecondValue
& 3) < (FirstValue
& 3))
3536 /* Adjust the RPL */
3538 SecondValue
|= FirstValue
& 3;
3541 State
->Flags
.Zf
= TRUE
;
3543 /* Write back the result */
3544 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3549 State
->Flags
.Zf
= FALSE
;
3553 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3555 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3557 /* Make sure this is the right instruction */
3558 ASSERT(Opcode
== 0x68);
3561 TOGGLE_OPSIZE(Size
);
3567 if (!Fast486FetchDword(State
, &Data
))
3569 /* Exception occurred */
3573 /* Call the internal API */
3574 Fast486StackPush(State
, Data
);
3580 if (!Fast486FetchWord(State
, (PUSHORT
)&Data
))
3582 /* Exception occurred */
3586 /* Call the internal API */
3587 Fast486StackPush(State
, Data
);
3591 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3593 BOOLEAN OperandSize
, AddressSize
;
3594 FAST486_MOD_REG_RM ModRegRm
;
3597 /* Make sure this is the right instruction */
3598 ASSERT((Opcode
& 0xFD) == 0x69);
3600 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3602 TOGGLE_ADSIZE(AddressSize
);
3603 TOGGLE_OPSIZE(OperandSize
);
3605 /* Fetch the parameters */
3606 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3608 /* Exception occurred */
3616 /* Fetch the immediate operand */
3617 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3619 /* Exception occurred */
3623 Multiplier
= (LONG
)Byte
;
3631 /* Fetch the immediate operand */
3632 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3634 /* Exception occurred */
3644 /* Fetch the immediate operand */
3645 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3647 /* Exception occurred */
3651 Multiplier
= (LONG
)Word
;
3657 LONG RegValue
, Multiplicand
;
3660 /* Read the operands */
3661 if (!Fast486ReadModrmDwordOperands(State
,
3664 (PULONG
)&Multiplicand
))
3666 /* Exception occurred */
3671 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3673 /* Check for carry/overflow */
3674 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3676 /* Write-back the result */
3677 Fast486WriteModrmDwordOperands(State
,
3680 (ULONG
)((LONG
)Product
));
3684 SHORT RegValue
, Multiplicand
;
3687 /* Read the operands */
3688 if (!Fast486ReadModrmWordOperands(State
,
3691 (PUSHORT
)&Multiplicand
))
3693 /* Exception occurred */
3698 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3700 /* Check for carry/overflow */
3701 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3703 /* Write-back the result */
3704 Fast486WriteModrmWordOperands(State
,
3707 (USHORT
)((SHORT
)Product
));
3711 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3715 /* Make sure this is the right instruction */
3716 ASSERT(Opcode
== 0x6A);
3718 if (!Fast486FetchByte(State
, (PUCHAR
)&Data
))
3720 /* Exception occurred */
3724 /* Call the internal API */
3725 Fast486StackPush(State
, Data
);
3728 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3730 UCHAR FirstValue
, SecondValue
, Result
;
3731 FAST486_MOD_REG_RM ModRegRm
;
3732 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3734 /* Make sure this is the right instruction */
3735 ASSERT((Opcode
& 0xFD) == 0x88);
3737 TOGGLE_ADSIZE(AddressSize
);
3739 /* Get the operands */
3740 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3742 /* Exception occurred */
3746 if (!Fast486ReadModrmByteOperands(State
,
3751 /* Exception occurred */
3755 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3756 else Result
= FirstValue
;
3758 /* Write back the result */
3759 Fast486WriteModrmByteOperands(State
,
3761 Opcode
& FAST486_OPCODE_WRITE_REG
,
3766 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3768 FAST486_MOD_REG_RM ModRegRm
;
3769 BOOLEAN OperandSize
, AddressSize
;
3771 /* Make sure this is the right instruction */
3772 ASSERT((Opcode
& 0xFD) == 0x89);
3774 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3776 TOGGLE_ADSIZE(AddressSize
);
3777 TOGGLE_OPSIZE(OperandSize
);
3779 /* Get the operands */
3780 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3782 /* Exception occurred */
3786 /* Check the operand size */
3789 ULONG FirstValue
, SecondValue
, Result
;
3791 if (!Fast486ReadModrmDwordOperands(State
,
3796 /* Exception occurred */
3800 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3801 else Result
= FirstValue
;
3803 /* Write back the result */
3804 Fast486WriteModrmDwordOperands(State
,
3806 Opcode
& FAST486_OPCODE_WRITE_REG
,
3811 USHORT FirstValue
, SecondValue
, Result
;
3813 if (!Fast486ReadModrmWordOperands(State
,
3818 /* Exception occurred */
3822 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3823 else Result
= FirstValue
;
3825 /* Write back the result */
3826 Fast486WriteModrmWordOperands(State
,
3828 Opcode
& FAST486_OPCODE_WRITE_REG
,
3833 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3835 BOOLEAN OperandSize
, AddressSize
;
3836 FAST486_MOD_REG_RM ModRegRm
;
3838 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3840 /* Make sure this is the right instruction */
3841 ASSERT(Opcode
== 0x8C);
3843 TOGGLE_ADSIZE(AddressSize
);
3844 TOGGLE_OPSIZE(OperandSize
);
3846 /* Get the operands */
3847 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3849 /* Exception occurred */
3853 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3856 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3862 Fast486WriteModrmDwordOperands(State
,
3865 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3869 Fast486WriteModrmWordOperands(State
,
3872 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3876 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3878 FAST486_MOD_REG_RM ModRegRm
;
3879 BOOLEAN OperandSize
, AddressSize
;
3881 /* Make sure this is the right instruction */
3882 ASSERT(Opcode
== 0x8D);
3884 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3886 TOGGLE_ADSIZE(AddressSize
);
3887 TOGGLE_OPSIZE(OperandSize
);
3889 /* Get the operands */
3890 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3892 /* Exception occurred */
3896 /* The second operand must be memory */
3897 if (!ModRegRm
.Memory
)
3900 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3904 /* Write the address to the register */
3907 Fast486WriteModrmDwordOperands(State
,
3910 ModRegRm
.MemoryAddress
);
3914 Fast486WriteModrmWordOperands(State
,
3917 ModRegRm
.MemoryAddress
);
3922 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3924 BOOLEAN OperandSize
, AddressSize
;
3925 FAST486_MOD_REG_RM ModRegRm
;
3927 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3929 /* Make sure this is the right instruction */
3930 ASSERT(Opcode
== 0x8E);
3932 TOGGLE_ADSIZE(AddressSize
);
3933 TOGGLE_OPSIZE(OperandSize
);
3935 /* Get the operands */
3936 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3938 /* Exception occurred */
3942 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3943 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3946 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3954 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
3956 /* Exception occurred */
3960 if (!Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
)))
3962 /* Exception occurred */
3970 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
3972 /* Exception occurred */
3976 if (!Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
))
3978 /* Exception occurred */
3983 if ((INT
)ModRegRm
.Register
== FAST486_REG_SS
)
3985 /* Inhibit all interrupts until the next instruction */
3986 State
->DoNotInterrupt
= TRUE
;
3990 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
3992 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3994 /* Make sure this is the right instruction */
3995 ASSERT(Opcode
== 0x98);
3997 TOGGLE_OPSIZE(Size
);
4002 /* Sign extend AX to EAX */
4003 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4005 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4006 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4012 /* Sign extend AL to AX */
4013 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4014 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4019 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4021 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4023 /* Make sure this is the right instruction */
4024 ASSERT(Opcode
== 0x99);
4026 TOGGLE_OPSIZE(Size
);
4031 /* Sign extend EAX to EDX:EAX */
4032 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4033 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4034 ? 0xFFFFFFFF : 0x00000000;
4038 /* Sign extend AX to DX:AX */
4039 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4040 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4045 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4049 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4051 /* Make sure this is the right instruction */
4052 ASSERT(Opcode
== 0x9A);
4054 TOGGLE_OPSIZE(Size
);
4057 /* Fetch the offset */
4060 if (!Fast486FetchDword(State
, &Offset
))
4062 /* Exception occurred */
4068 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4070 /* Exception occurred */
4075 /* Fetch the segment */
4076 if (!Fast486FetchWord(State
, &Segment
))
4078 /* Exception occurred */
4082 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4084 if (!Fast486ProcessGate(State
, Segment
, Offset
, TRUE
))
4086 /* Gate processed or exception occurred */
4091 /* Push the current code segment selector */
4092 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4094 /* Exception occurred */
4098 /* Push the current value of the instruction pointer */
4099 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4101 /* Exception occurred */
4105 /* Load the new CS */
4106 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4108 /* Exception occurred */
4112 /* Load new (E)IP */
4113 if (Size
) State
->InstPtr
.Long
= Offset
;
4114 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4117 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4119 #ifndef FAST486_NO_FPU
4121 if ((!State
->FpuControl
.Pm
&& State
->FpuStatus
.Pe
)
4122 || (!State
->FpuControl
.Um
&& State
->FpuStatus
.Ue
)
4123 || (!State
->FpuControl
.Om
&& State
->FpuStatus
.Oe
)
4124 || (!State
->FpuControl
.Zm
&& State
->FpuStatus
.Ze
)
4125 || (!State
->FpuControl
.Dm
&& State
->FpuStatus
.De
)
4126 || (!State
->FpuControl
.Im
&& State
->FpuStatus
.Ie
))
4128 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_NE
)
4130 /* Call the #MF handler */
4131 Fast486Exception(State
, FAST486_EXCEPTION_MF
);
4135 /* Use the external interrupt */
4136 State
->FpuCallback(State
);
4143 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4145 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4148 TOGGLE_OPSIZE(Size
);
4150 /* Check for VM86 mode when IOPL is not 3 */
4151 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4153 /* Call the VM86 monitor */
4154 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4158 /* Push the flags */
4159 if (Size
) Fast486StackPush(State
, State
->Flags
.Long
);
4160 else Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4163 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4165 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4166 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4167 FAST486_FLAGS_REG NewFlags
;
4170 TOGGLE_OPSIZE(Size
);
4172 /* Pop the new flags */
4173 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4175 /* Exception occurred */
4179 /* Check for VM86 mode when IOPL is not 3 */
4180 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4182 /* Call the VM86 monitor */
4183 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4187 State
->Flags
.Cf
= NewFlags
.Cf
;
4188 State
->Flags
.Pf
= NewFlags
.Pf
;
4189 State
->Flags
.Af
= NewFlags
.Af
;
4190 State
->Flags
.Zf
= NewFlags
.Zf
;
4191 State
->Flags
.Sf
= NewFlags
.Sf
;
4192 State
->Flags
.Tf
= NewFlags
.Tf
;
4193 State
->Flags
.Df
= NewFlags
.Df
;
4194 State
->Flags
.Of
= NewFlags
.Of
;
4195 State
->Flags
.Nt
= NewFlags
.Nt
;
4196 State
->Flags
.Ac
= NewFlags
.Ac
;
4198 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4199 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4202 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4204 /* Make sure this is the right instruction */
4205 ASSERT(Opcode
== 0x9E);
4207 /* Set the low-order byte of FLAGS to AH */
4208 State
->Flags
.Long
&= 0xFFFFFF00;
4209 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4211 /* Restore the reserved bits of FLAGS */
4212 State
->Flags
.AlwaysSet
= TRUE
;
4213 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4216 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4218 /* Make sure this is the right instruction */
4219 ASSERT(Opcode
== 0x9F);
4221 /* Set AH to the low-order byte of FLAGS */
4222 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4225 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4227 ULONG ReturnAddress
;
4228 USHORT BytesToPop
= 0;
4229 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4231 /* Make sure this is the right instruction */
4232 ASSERT((Opcode
& 0xFE) == 0xC2);
4235 TOGGLE_OPSIZE(Size
);
4239 /* Fetch the number of bytes to pop after the return */
4240 if (!Fast486FetchWord(State
, &BytesToPop
)) return;
4243 /* Pop the return address */
4244 if (!Fast486StackPop(State
, &ReturnAddress
)) return;
4246 /* Return to the calling procedure, and if necessary, pop the parameters */
4249 State
->InstPtr
.Long
= ReturnAddress
;
4250 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4254 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4255 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4259 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4261 UCHAR FarPointer
[6];
4262 BOOLEAN OperandSize
, AddressSize
;
4263 FAST486_MOD_REG_RM ModRegRm
;
4265 /* Make sure this is the right instruction */
4266 ASSERT((Opcode
& 0xFE) == 0xC4);
4268 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4270 TOGGLE_OPSIZE(OperandSize
);
4271 TOGGLE_ADSIZE(AddressSize
);
4273 /* Get the operands */
4274 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4276 /* Exception occurred */
4280 if (!ModRegRm
.Memory
)
4282 /* Check if this is a BOP and the host supports BOPs */
4283 if ((Opcode
== 0xC4)
4284 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4285 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4286 && (State
->BopCallback
!= NULL
))
4290 /* Fetch the BOP code */
4291 if (!Fast486FetchByte(State
, &BopCode
))
4293 /* Exception occurred */
4297 #ifndef FAST486_NO_PREFETCH
4298 /* Invalidate the prefetch since BOP handlers can alter the memory */
4299 State
->PrefetchValid
= FALSE
;
4302 /* Call the BOP handler */
4303 State
->BopCallback(State
, BopCode
);
4306 * If an interrupt should occur at this time, delay it.
4307 * We must do this because if an interrupt begins and the BOP callback
4308 * changes the CS:IP, the interrupt handler won't execute and the
4309 * stack pointer will never be restored.
4311 State
->DoNotInterrupt
= TRUE
;
4317 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4321 if (!Fast486ReadMemory(State
,
4322 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4323 ? State
->SegmentOverride
: FAST486_REG_DS
,
4324 ModRegRm
.MemoryAddress
,
4327 OperandSize
? 6 : 4))
4329 /* Exception occurred */
4335 ULONG Offset
= *((PULONG
)FarPointer
);
4336 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4338 /* Set the register to the offset */
4339 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4341 /* Load the segment */
4342 Fast486LoadSegment(State
,
4344 ? FAST486_REG_ES
: FAST486_REG_DS
,
4349 USHORT Offset
= *((PUSHORT
)FarPointer
);
4350 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4352 /* Set the register to the offset */
4353 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4355 /* Load the segment */
4356 Fast486LoadSegment(State
,
4358 ? FAST486_REG_ES
: FAST486_REG_DS
,
4363 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4366 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4369 FAST486_REG FramePointer
;
4371 /* Make sure this is the right instruction */
4372 ASSERT(Opcode
== 0xC8);
4375 TOGGLE_OPSIZE(Size
);
4377 if (!Fast486FetchWord(State
, &FrameSize
))
4379 /* Exception occurred */
4383 if (!Fast486FetchByte(State
, &NestingLevel
))
4385 /* Exception occurred */
4390 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4392 /* Exception occurred */
4397 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4399 /* Set up the nested procedure stacks */
4400 for (i
= 1; i
< NestingLevel
; i
++)
4404 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4405 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4409 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4410 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4414 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4416 /* Set EBP to the frame pointer */
4417 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4419 /* Reserve space for the frame */
4420 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4421 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4424 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4426 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4428 /* Make sure this is the right instruction */
4429 ASSERT(Opcode
== 0xC9);
4432 TOGGLE_OPSIZE(Size
);
4436 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4437 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4439 /* Pop the saved base pointer from the stack */
4440 Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4446 /* Set the stack pointer (SP) to the base pointer (BP) */
4447 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4449 /* Pop the saved base pointer from the stack */
4450 if (Fast486StackPop(State
, &Value
))
4452 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4457 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4461 USHORT BytesToPop
= 0;
4462 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4464 /* Make sure this is the right instruction */
4465 ASSERT((Opcode
& 0xFE) == 0xCA);
4467 TOGGLE_OPSIZE(Size
);
4472 /* Fetch the number of bytes to pop after the return */
4473 if (!Fast486FetchWord(State
, &BytesToPop
)) return;
4476 /* Pop the offset */
4477 if (!Fast486StackPop(State
, &Offset
))
4479 /* Exception occurred */
4483 /* Pop the segment */
4484 if (!Fast486StackPop(State
, &Segment
))
4486 /* Exception occurred */
4490 /* Load the new CS */
4491 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4493 /* Exception occurred */
4497 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
) && !State
->Flags
.Vm
)
4500 INT OldCpl
= Fast486GetCurrentPrivLevel(State
);
4504 if (GET_SEGMENT_RPL(Segment
) > OldCpl
)
4507 if (!Fast486StackPop(State
, &StackPtr
))
4514 if (!Fast486StackPop(State
, &StackSel
))
4521 /* Update the CPL */
4522 State
->Cpl
= GET_SEGMENT_RPL(Segment
);
4524 if (State
->Cpl
> OldCpl
)
4527 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4534 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4535 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4537 /* Check segment security */
4538 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4540 /* Don't check CS or SS */
4541 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4543 if ((State
->Cpl
> State
->SegmentRegs
[i
].Dpl
)
4544 && (!State
->SegmentRegs
[i
].Executable
4545 || !State
->SegmentRegs
[i
].DirConf
))
4547 /* Load the NULL descriptor in the segment */
4548 if (!Fast486LoadSegment(State
, i
, 0)) return;
4554 /* Load new (E)IP, and if necessary, pop the parameters */
4557 State
->InstPtr
.Long
= Offset
;
4558 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4562 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4563 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4567 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4571 /* Check for V86 mode */
4572 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4574 /* Call the V86 monitor */
4575 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
4583 /* This is the INT3 instruction */
4588 case 0xCD: // INT xx
4590 /* Fetch the interrupt number */
4591 if (!Fast486FetchByte(State
, &IntNum
))
4593 /* Exception occurred */
4602 /* Don't do anything if OF is cleared */
4603 if (!State
->Flags
.Of
) return;
4606 IntNum
= FAST486_EXCEPTION_OF
;
4613 /* Should not happen */
4618 /* Perform the interrupt */
4619 Fast486PerformInterrupt(State
, IntNum
);
4622 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4625 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4626 FAST486_FLAGS_REG NewFlags
;
4627 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4629 /* Make sure this is the right instruction */
4630 ASSERT(Opcode
== 0xCF);
4633 TOGGLE_OPSIZE(Size
);
4635 /* Check if this is a nested task return */
4636 if (State
->Flags
.Nt
&& (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
))
4638 /* Clear the NT flag of the current task */
4639 State
->Flags
.Nt
= FALSE
;
4641 /* Switch to the old task */
4642 Fast486TaskSwitch(State
, FAST486_TASK_RETURN
, 0);
4647 if (!Fast486StackPop(State
, &InstPtr
))
4649 /* Exception occurred */
4654 if (!Fast486StackPop(State
, &CodeSel
))
4656 /* Exception occurred */
4661 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4663 /* Exception occurred */
4667 /* Check for protected mode */
4668 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4670 INT OldCpl
= Fast486GetCurrentPrivLevel(State
);
4672 if (State
->Flags
.Vm
)
4674 /* Return from VM86 mode */
4676 /* Check the IOPL */
4677 if (State
->Flags
.Iopl
== 3)
4680 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4683 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4685 /* Exception occurred */
4689 /* Set the new flags */
4690 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4691 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4692 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4693 State
->Flags
.Iopl
= 3;
4697 /* Call the VM86 monitor */
4698 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4707 /* Return to VM86 mode */
4708 ULONG Es
, Ds
, Fs
, Gs
;
4710 /* Pop ESP, SS, ES, DS, FS, GS */
4711 if (!Fast486StackPop(State
, &StackPtr
)) return;
4712 if (!Fast486StackPop(State
, &StackSel
)) return;
4713 if (!Fast486StackPop(State
, &Es
)) return;
4714 if (!Fast486StackPop(State
, &Ds
)) return;
4715 if (!Fast486StackPop(State
, &Fs
)) return;
4716 if (!Fast486StackPop(State
, &Gs
)) return;
4718 /* Set the new IP */
4719 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4721 /* Set the new flags */
4722 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4723 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4724 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4726 /* Load the new segments */
4727 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return;
4728 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return;
4729 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return;
4730 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return;
4731 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return;
4732 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return;
4737 /* Load the new CS */
4738 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4740 /* Exception occurred */
4745 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4746 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4748 if (GET_SEGMENT_RPL(CodeSel
) > OldCpl
)
4751 if (!Fast486StackPop(State
, &StackPtr
))
4758 if (!Fast486StackPop(State
, &StackSel
))
4765 /* Update the CPL */
4766 State
->Cpl
= GET_SEGMENT_RPL(CodeSel
);
4768 /* Set the new flags */
4769 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4770 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4771 State
->Flags
.AlwaysSet
= TRUE
;
4773 /* Set additional flags */
4774 if (OldCpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4775 if (OldCpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4777 if (State
->Cpl
> OldCpl
)
4780 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4787 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4788 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4790 /* Check segment security */
4791 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4793 /* Don't check CS or SS */
4794 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4796 if ((State
->Cpl
> State
->SegmentRegs
[i
].Dpl
)
4797 && (!State
->SegmentRegs
[i
].Executable
4798 || !State
->SegmentRegs
[i
].DirConf
))
4800 /* Load the NULL descriptor in the segment */
4801 if (!Fast486LoadSegment(State
, i
, 0)) return;
4808 if (Size
&& (InstPtr
& 0xFFFF0000))
4811 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4816 State
->InstPtr
.Long
= InstPtr
;
4819 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4821 /* Exception occurred */
4825 /* Set the new flags */
4826 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4827 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4828 State
->Flags
.AlwaysSet
= TRUE
;
4832 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4835 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4839 /* Fetch the base */
4840 if (!Fast486FetchByte(State
, &Base
))
4842 /* Exception occurred */
4846 /* Check if the base is zero */
4850 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4855 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4856 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4859 State
->Flags
.Af
= FALSE
;
4860 State
->Flags
.Zf
= (Value
== 0);
4861 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4862 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4865 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4868 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4872 /* Fetch the base */
4873 if (!Fast486FetchByte(State
, &Base
))
4875 /* Exception occurred */
4880 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4881 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4884 State
->Flags
.Af
= FALSE
;
4885 State
->Flags
.Zf
= (Value
== 0);
4886 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4887 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4890 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4893 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4895 TOGGLE_ADSIZE(AddressSize
);
4897 /* Read a byte from DS:[(E)BX + AL] */
4898 if (!Fast486ReadMemory(State
,
4899 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4900 ? State
->SegmentOverride
: FAST486_REG_DS
,
4901 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4902 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4903 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4908 /* Exception occurred */
4912 /* Set AL to the result */
4913 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4916 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4919 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4922 /* Make sure this is the right instruction */
4923 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4926 TOGGLE_ADSIZE(Size
);
4928 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4929 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4933 /* Additional rule for LOOPNZ */
4934 if (State
->Flags
.Zf
) Condition
= FALSE
;
4936 else if (Opcode
== 0xE1)
4938 /* Additional rule for LOOPZ */
4939 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4942 /* Fetch the offset */
4943 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4945 /* An exception occurred */
4951 /* Move the instruction pointer */
4952 if (Size
) State
->InstPtr
.Long
+= Offset
;
4953 else State
->InstPtr
.LowWord
+= Offset
;
4957 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
4960 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4963 /* Make sure this is the right instruction */
4964 ASSERT(Opcode
== 0xE3);
4967 TOGGLE_ADSIZE(Size
);
4969 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
4970 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
4972 /* Fetch the offset */
4973 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4975 /* An exception occurred */
4981 /* Move the instruction pointer */
4982 if (Size
) State
->InstPtr
.Long
+= Offset
;
4983 else State
->InstPtr
.LowWord
+= Offset
;
4987 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
4989 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4991 /* Make sure this is the right instruction */
4992 ASSERT(Opcode
== 0xE8);
4994 TOGGLE_OPSIZE(Size
);
5001 /* Fetch the offset */
5002 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5004 /* An exception occurred */
5008 /* Push the current value of the instruction pointer */
5009 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5011 /* Exception occurred */
5015 /* Move the instruction pointer */
5016 State
->InstPtr
.Long
+= Offset
;
5022 /* Fetch the offset */
5023 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5025 /* An exception occurred */
5029 /* Push the current value of the instruction pointer */
5030 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5032 /* Exception occurred */
5036 /* Move the instruction pointer */
5037 State
->InstPtr
.LowWord
+= Offset
;
5041 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5043 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5045 /* Make sure this is the right instruction */
5046 ASSERT(Opcode
== 0xE9);
5048 TOGGLE_OPSIZE(Size
);
5055 /* Fetch the offset */
5056 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5058 /* An exception occurred */
5062 /* Move the instruction pointer */
5063 State
->InstPtr
.Long
+= Offset
;
5069 /* Fetch the offset */
5070 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5072 /* An exception occurred */
5076 /* Move the instruction pointer */
5077 State
->InstPtr
.Long
+= Offset
;
5079 /* Clear the top half of EIP */
5080 State
->InstPtr
.Long
&= 0xFFFF;
5084 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5088 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5090 /* Make sure this is the right instruction */
5091 ASSERT(Opcode
== 0xEA);
5093 TOGGLE_OPSIZE(Size
);
5096 /* Fetch the offset */
5099 if (!Fast486FetchDword(State
, &Offset
))
5101 /* Exception occurred */
5107 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5109 /* Exception occurred */
5114 /* Fetch the segment */
5115 if (!Fast486FetchWord(State
, &Segment
))
5117 /* Exception occurred */
5121 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
5123 if (!Fast486ProcessGate(State
, Segment
, Offset
, FALSE
))
5125 /* Gate processed or exception occurred */
5130 /* Load the new CS */
5131 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5133 /* Exception occurred */
5138 State
->InstPtr
.Long
= Offset
;
5141 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5143 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5146 /* Make sure this is the right instruction */
5147 ASSERT(Opcode
== 0xA0);
5149 TOGGLE_ADSIZE(AddressSize
);
5153 if (!Fast486FetchDword(State
, &Offset
))
5155 /* Exception occurred */
5163 if (!Fast486FetchWord(State
, &WordOffset
))
5165 /* Exception occurred */
5169 Offset
= (ULONG
)WordOffset
;
5172 /* Read from memory */
5173 Fast486ReadMemory(State
,
5174 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5175 State
->SegmentOverride
: FAST486_REG_DS
,
5178 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5182 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5184 BOOLEAN OperandSize
, AddressSize
;
5186 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5188 /* Make sure this is the right instruction */
5189 ASSERT(Opcode
== 0xA1);
5191 TOGGLE_OPSIZE(OperandSize
);
5192 TOGGLE_ADSIZE(AddressSize
);
5198 if (!Fast486FetchDword(State
, &Offset
))
5200 /* Exception occurred */
5204 /* Read from memory */
5207 Fast486ReadMemory(State
,
5208 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5209 State
->SegmentOverride
: FAST486_REG_DS
,
5212 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5217 Fast486ReadMemory(State
,
5218 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5219 State
->SegmentOverride
: FAST486_REG_DS
,
5222 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5230 if (!Fast486FetchWord(State
, &Offset
))
5232 /* Exception occurred */
5236 /* Read from memory */
5239 Fast486ReadMemory(State
,
5240 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5241 State
->SegmentOverride
: FAST486_REG_DS
,
5244 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5249 Fast486ReadMemory(State
,
5250 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5251 State
->SegmentOverride
: FAST486_REG_DS
,
5254 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5260 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5262 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5265 /* Make sure this is the right instruction */
5266 ASSERT(Opcode
== 0xA2);
5268 TOGGLE_ADSIZE(AddressSize
);
5272 if (!Fast486FetchDword(State
, &Offset
))
5274 /* Exception occurred */
5282 if (!Fast486FetchWord(State
, &WordOffset
))
5284 /* Exception occurred */
5288 Offset
= (ULONG
)WordOffset
;
5291 /* Write to memory */
5292 Fast486WriteMemory(State
,
5293 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5294 State
->SegmentOverride
: FAST486_REG_DS
,
5296 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5300 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5302 BOOLEAN OperandSize
, AddressSize
;
5304 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5306 /* Make sure this is the right instruction */
5307 ASSERT(Opcode
== 0xA3);
5309 TOGGLE_OPSIZE(OperandSize
);
5310 TOGGLE_ADSIZE(AddressSize
);
5316 if (!Fast486FetchDword(State
, &Offset
))
5318 /* Exception occurred */
5322 /* Write to memory */
5325 Fast486WriteMemory(State
,
5326 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5327 State
->SegmentOverride
: FAST486_REG_DS
,
5329 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5334 Fast486WriteMemory(State
,
5335 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5336 State
->SegmentOverride
: FAST486_REG_DS
,
5338 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5346 if (!Fast486FetchWord(State
, &Offset
))
5348 /* Exception occurred */
5352 /* Write to memory */
5355 Fast486WriteMemory(State
,
5356 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5357 State
->SegmentOverride
: FAST486_REG_DS
,
5359 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5364 Fast486WriteMemory(State
,
5365 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5366 State
->SegmentOverride
: FAST486_REG_DS
,
5368 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5374 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5377 * See: http://www.rcollins.org/secrets/opcodes/SALC.html
5378 * for more information.
5381 /* Make sure this is the right instruction */
5382 ASSERT(Opcode
== 0xD6);
5386 /* Set all the bits of AL to CF */
5387 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5390 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5392 ULONG Data
, DataSize
;
5393 BOOLEAN OperandSize
, AddressSize
;
5394 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5396 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5398 /* Make sure this is the right instruction */
5399 ASSERT((Opcode
& 0xFE) == 0xA4);
5401 TOGGLE_OPSIZE(OperandSize
);
5402 TOGGLE_ADSIZE(AddressSize
);
5404 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5406 /* Use the override segment instead of DS */
5407 Segment
= State
->SegmentOverride
;
5410 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5412 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5413 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5420 /* Calculate the size */
5421 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5422 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5424 /* Read from the source operand */
5425 if (!Fast486ReadMemory(State
,
5427 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5428 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5433 /* Exception occurred */
5437 /* Write to the destination operand */
5438 if (!Fast486WriteMemory(State
,
5440 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5441 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5445 /* Exception occurred */
5449 /* Increment/decrement ESI and EDI */
5452 if (!State
->Flags
.Df
)
5454 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5455 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5459 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5460 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5465 if (!State
->Flags
.Df
)
5467 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5468 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5472 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5473 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5477 // FIXME: This method is slow!
5478 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5482 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5484 /* Repeat the instruction */
5485 State
->InstPtr
= State
->SavedInstPtr
;
5490 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5492 /* Repeat the instruction */
5493 State
->InstPtr
= State
->SavedInstPtr
;
5499 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5501 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5502 ULONG DataSize
, DataMask
, SignFlag
;
5503 BOOLEAN OperandSize
, AddressSize
;
5504 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5506 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5508 /* Make sure this is the right instruction */
5509 ASSERT((Opcode
& 0xFE) == 0xA6);
5511 TOGGLE_OPSIZE(OperandSize
);
5512 TOGGLE_ADSIZE(AddressSize
);
5514 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5516 /* Use the override segment instead of DS */
5517 Segment
= State
->SegmentOverride
;
5520 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5521 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5523 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5524 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5531 /* Calculate the size */
5532 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5533 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5535 /* Calculate the mask and sign flag */
5536 SignFlag
= 1 << ((DataSize
* 8) - 1);
5537 DataMask
= SignFlag
| (SignFlag
- 1);
5539 /* Read from the first source operand */
5540 if (!Fast486ReadMemory(State
,
5542 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5543 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5548 /* Exception occurred */
5552 /* Read from the second source operand */
5553 if (!Fast486ReadMemory(State
,
5555 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5556 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5561 /* Exception occurred */
5565 /* Calculate the result */
5566 FirstValue
&= DataMask
;
5567 SecondValue
&= DataMask
;
5568 Result
= (FirstValue
- SecondValue
) & DataMask
;
5570 /* Update the flags */
5571 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5572 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5573 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5574 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5575 State
->Flags
.Zf
= (Result
== 0);
5576 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5577 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5579 /* Increment/decrement ESI and EDI */
5582 if (!State
->Flags
.Df
)
5584 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5585 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5589 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5590 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5595 if (!State
->Flags
.Df
)
5597 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5598 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5602 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5603 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5607 // FIXME: This method is slow!
5608 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5609 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5611 BOOLEAN Repeat
= TRUE
;
5615 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5623 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5630 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5631 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5633 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5639 /* Repeat the instruction */
5640 State
->InstPtr
= State
->SavedInstPtr
;
5645 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5648 BOOLEAN OperandSize
, AddressSize
;
5650 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5652 /* Make sure this is the right instruction */
5653 ASSERT((Opcode
& 0xFE) == 0xAA);
5655 TOGGLE_OPSIZE(OperandSize
);
5656 TOGGLE_ADSIZE(AddressSize
);
5658 /* Calculate the size */
5659 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5660 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5662 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5664 UCHAR Block
[STRING_BLOCK_SIZE
];
5665 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5666 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5668 /* Fill the memory block with the data */
5669 if (DataSize
== sizeof(UCHAR
))
5671 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5677 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5679 if (DataSize
== sizeof(USHORT
))
5681 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5685 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5690 /* Transfer until finished */
5693 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5695 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5698 ULONG MaxBytes
= State
->Flags
.Df
5699 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5700 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5702 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5703 if (Processed
== 0) Processed
= 1;
5706 if (State
->Flags
.Df
)
5708 /* Set EDI to the starting location */
5709 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5710 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5713 /* Write to memory */
5714 if (!Fast486WriteMemory(State
,
5716 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5717 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5719 Processed
* DataSize
))
5722 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5723 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5725 /* Exception occurred */
5729 if (!State
->Flags
.Df
)
5731 /* Increase EDI by the number of bytes transfered */
5732 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5733 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5738 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5739 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5742 /* Reduce the total count by the number processed in this run */
5747 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5748 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5752 /* Write to the destination operand */
5753 if (!Fast486WriteMemory(State
,
5755 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5756 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5757 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5760 /* Exception occurred */
5764 /* Increment/decrement EDI */
5767 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5768 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5772 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5773 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5778 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5781 BOOLEAN OperandSize
, AddressSize
;
5782 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5784 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5786 /* Make sure this is the right instruction */
5787 ASSERT((Opcode
& 0xFE) == 0xAC);
5789 TOGGLE_OPSIZE(OperandSize
);
5790 TOGGLE_ADSIZE(AddressSize
);
5792 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5794 /* Use the override segment instead of DS */
5795 Segment
= State
->SegmentOverride
;
5798 /* Calculate the size */
5799 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5800 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5802 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5804 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5805 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5807 /* If the count is 0, do nothing */
5808 if (Count
== 0) return;
5810 /* Only the last entry will be loaded */
5811 if (!State
->Flags
.Df
)
5813 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5814 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5818 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5819 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5823 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5824 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5827 /* Read from the source operand */
5828 if (!Fast486ReadMemory(State
,
5830 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5831 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5833 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5836 /* Exception occurred */
5840 /* Increment/decrement ESI */
5843 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5844 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5848 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5849 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5853 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5855 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5856 ULONG SecondValue
= 0;
5858 ULONG DataSize
, DataMask
, SignFlag
;
5859 BOOLEAN OperandSize
, AddressSize
;
5861 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5863 /* Make sure this is the right instruction */
5864 ASSERT((Opcode
& 0xFE) == 0xAE);
5866 TOGGLE_OPSIZE(OperandSize
);
5867 TOGGLE_ADSIZE(AddressSize
);
5869 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5870 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5872 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5873 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5880 /* Calculate the size */
5881 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5882 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5884 /* Calculate the mask and sign flag */
5885 SignFlag
= 1 << ((DataSize
* 8) - 1);
5886 DataMask
= SignFlag
| (SignFlag
- 1);
5888 /* Read from the source operand */
5889 if (!Fast486ReadMemory(State
,
5891 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5892 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5897 /* Exception occurred */
5901 /* Calculate the result */
5902 FirstValue
&= DataMask
;
5903 SecondValue
&= DataMask
;
5904 Result
= (FirstValue
- SecondValue
) & DataMask
;
5906 /* Update the flags */
5907 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5908 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5909 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5910 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5911 State
->Flags
.Zf
= (Result
== 0);
5912 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5913 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5915 /* Increment/decrement EDI */
5918 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5919 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5923 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5924 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5927 // FIXME: This method is slow!
5928 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5929 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5931 BOOLEAN Repeat
= TRUE
;
5935 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5943 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5950 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5951 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5953 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5959 /* Repeat the instruction */
5960 State
->InstPtr
= State
->SavedInstPtr
;
5965 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
5968 BOOLEAN OperandSize
, AddressSize
;
5970 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5972 /* Make sure this is the right instruction */
5973 ASSERT((Opcode
& 0xFE) == 0x6C);
5975 TOGGLE_OPSIZE(OperandSize
);
5976 TOGGLE_ADSIZE(AddressSize
);
5978 /* Calculate the size */
5979 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
5980 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5982 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5984 UCHAR Block
[STRING_BLOCK_SIZE
];
5985 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5986 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5988 /* Clear the memory block */
5989 RtlZeroMemory(Block
, sizeof(Block
));
5991 /* Transfer until finished */
5994 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5996 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5999 ULONG MaxBytes
= State
->Flags
.Df
6000 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6001 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6003 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6004 if (Processed
== 0) Processed
= 1;
6007 /* Read from the I/O port */
6008 State
->IoReadCallback(State
,
6009 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6014 if (State
->Flags
.Df
)
6018 /* Reduce EDI by the number of bytes to transfer */
6019 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6020 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6022 /* Reverse the block data */
6023 for (i
= 0; i
< Processed
/ 2; i
++)
6025 /* Swap the values */
6026 for (j
= 0; j
< DataSize
; j
++)
6028 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6029 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6030 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6035 /* Write to memory */
6036 if (!Fast486WriteMemory(State
,
6038 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6039 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6041 Processed
* DataSize
))
6044 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6045 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6047 /* Exception occurred */
6051 if (!State
->Flags
.Df
)
6053 /* Increase EDI by the number of bytes transfered */
6054 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6055 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6058 /* Reduce the total count by the number processed in this run */
6063 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6064 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6070 /* Read from the I/O port */
6071 State
->IoReadCallback(State
,
6072 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6077 /* Write to the destination operand */
6078 if (!Fast486WriteMemory(State
,
6080 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6081 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6085 /* Exception occurred */
6089 /* Increment/decrement EDI */
6092 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6093 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6097 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6098 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6103 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6106 BOOLEAN OperandSize
, AddressSize
;
6108 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6110 /* Make sure this is the right instruction */
6111 ASSERT((Opcode
& 0xFE) == 0x6E);
6113 TOGGLE_OPSIZE(OperandSize
);
6114 TOGGLE_ADSIZE(AddressSize
);
6116 /* Calculate the size */
6117 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6118 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6120 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
6122 UCHAR Block
[STRING_BLOCK_SIZE
];
6123 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6124 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6126 /* Clear the memory block */
6127 RtlZeroMemory(Block
, sizeof(Block
));
6129 /* Transfer until finished */
6132 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6134 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6137 ULONG MaxBytes
= State
->Flags
.Df
6138 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
6139 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
6141 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6142 if (Processed
== 0) Processed
= 1;
6145 /* Read from memory */
6146 if (!Fast486ReadMemory(State
,
6147 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6148 ? State
->SegmentOverride
: FAST486_REG_DS
,
6149 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6150 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6153 Processed
* DataSize
))
6156 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6157 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6159 /* Exception occurred */
6163 if (State
->Flags
.Df
)
6167 /* Reduce ESI by the number of bytes to transfer */
6168 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
6169 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
6171 /* Reverse the block data */
6172 for (i
= 0; i
< Processed
/ 2; i
++)
6174 /* Swap the values */
6175 for (j
= 0; j
< DataSize
; j
++)
6177 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6178 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6179 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6184 /* Write to the I/O port */
6185 State
->IoWriteCallback(State
,
6186 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6191 if (!State
->Flags
.Df
)
6193 /* Increase ESI by the number of bytes transfered */
6194 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
6195 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
6198 /* Reduce the total count by the number processed in this run */
6203 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6204 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6210 /* Read from the source operand */
6211 if (!Fast486ReadMemory(State
,
6212 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6213 ? State
->SegmentOverride
: FAST486_REG_DS
,
6214 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6215 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6220 /* Exception occurred */
6224 /* Write to the I/O port */
6225 State
->IoWriteCallback(State
,
6226 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6231 /* Increment/decrement ESI */
6234 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6235 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6239 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6240 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;