2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2015 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
)
319 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
320 State
->SegmentOverride
= FAST486_REG_ES
;
327 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
328 State
->SegmentOverride
= FAST486_REG_CS
;
335 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
336 State
->SegmentOverride
= FAST486_REG_SS
;
343 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
344 State
->SegmentOverride
= FAST486_REG_DS
;
351 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
352 State
->SegmentOverride
= FAST486_REG_FS
;
359 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
360 State
->SegmentOverride
= FAST486_REG_GS
;
367 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
374 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
381 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
388 /* Mutually exclusive with REP */
389 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
390 State
->PrefixFlags
&= ~FAST486_PREFIX_REP
;
397 /* Mutually exclusive with REPNZ */
398 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
399 State
->PrefixFlags
&= ~FAST486_PREFIX_REPNZ
;
405 /* Shouldn't happen */
411 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
414 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
419 /* Make sure this is the right instruction */
420 ASSERT((Opcode
& 0xF8) == 0x40);
424 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
426 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
427 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
431 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
433 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
434 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
437 State
->Flags
.Zf
= (Value
== 0);
438 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
439 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
442 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
445 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
450 /* Make sure this is the right instruction */
451 ASSERT((Opcode
& 0xF8) == 0x48);
455 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
457 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
458 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
462 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
464 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
465 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
468 State
->Flags
.Zf
= (Value
== 0);
469 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
470 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
473 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
477 /* Make sure this is the right instruction */
478 ASSERT((Opcode
& 0xF8) == 0x50);
480 /* Call the internal function */
481 Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
484 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
487 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
492 /* Make sure this is the right instruction */
493 ASSERT((Opcode
& 0xF8) == 0x58);
495 /* Call the internal function */
496 if (!Fast486StackPop(State
, &Value
)) return;
498 /* Store the value */
499 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
500 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
503 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
507 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
509 INT Reg
= Opcode
& 0x07;
510 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
515 /* Make sure this is the right instruction */
516 ASSERT((Opcode
& 0xF8) == 0x90);
518 /* Exchange the values */
523 Value
= State
->GeneralRegs
[Reg
].Long
;
524 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
525 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
531 Value
= State
->GeneralRegs
[Reg
].LowWord
;
532 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
533 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
537 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
539 BOOLEAN Jump
= FALSE
;
541 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
543 /* Make sure this is the right instruction */
544 ASSERT((Opcode
& 0xF0) == 0x70);
548 /* Fetch the offset */
549 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
551 /* An exception occurred */
555 switch ((Opcode
& 0x0F) >> 1)
560 Jump
= State
->Flags
.Of
;
567 Jump
= State
->Flags
.Cf
;
574 Jump
= State
->Flags
.Zf
;
581 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
588 Jump
= State
->Flags
.Sf
;
595 Jump
= State
->Flags
.Pf
;
602 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
609 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
616 /* Invert the result */
622 /* Move the instruction pointer */
623 State
->InstPtr
.Long
+= Offset
;
627 /* Clear the top half of EIP */
628 State
->InstPtr
.Long
&= 0xFFFF;
633 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
635 /* Make sure this is the right instruction */
636 ASSERT(Opcode
== 0xF8);
640 /* Clear CF and return success */
641 State
->Flags
.Cf
= FALSE
;
644 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
646 /* Make sure this is the right instruction */
647 ASSERT(Opcode
== 0xF9);
651 /* Set CF and return success*/
652 State
->Flags
.Cf
= TRUE
;
655 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
657 /* Make sure this is the right instruction */
658 ASSERT(Opcode
== 0xF5);
662 /* Toggle CF and return success */
663 State
->Flags
.Cf
= !State
->Flags
.Cf
;
667 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
669 /* Make sure this is the right instruction */
670 ASSERT(Opcode
== 0xFA);
674 /* Check for protected mode */
675 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
678 if (State
->Flags
.Iopl
>= Fast486GetCurrentPrivLevel(State
))
680 /* Clear the interrupt flag */
681 State
->Flags
.If
= FALSE
;
685 /* General Protection Fault */
686 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
692 /* Just clear the interrupt flag */
693 State
->Flags
.If
= FALSE
;
697 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
699 /* Make sure this is the right instruction */
700 ASSERT(Opcode
== 0xFB);
704 /* Check for protected mode */
705 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
708 if (State
->Flags
.Iopl
>= Fast486GetCurrentPrivLevel(State
))
710 /* Set the interrupt flag */
711 State
->Flags
.If
= TRUE
;
715 /* General Protection Fault */
716 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
722 /* Just set the interrupt flag */
723 State
->Flags
.If
= TRUE
;
727 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
729 /* Make sure this is the right instruction */
730 ASSERT(Opcode
== 0xFC);
735 State
->Flags
.Df
= FALSE
;
738 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
740 /* Make sure this is the right instruction */
741 ASSERT(Opcode
== 0xFD);
746 State
->Flags
.Df
= TRUE
;
749 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
751 /* Make sure this is the right instruction */
752 ASSERT(Opcode
== 0xF4);
756 /* Privileged instructions can only be executed under CPL = 0 */
757 if (Fast486GetCurrentPrivLevel(State
) != 0)
759 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
764 State
->Halted
= TRUE
;
767 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
772 /* Make sure this is the right instruction */
773 ASSERT((Opcode
& 0xF7) == 0xE4);
777 /* Fetch the parameter */
778 if (!Fast486FetchByte(State
, &Data
))
780 /* Exception occurred */
784 /* Set the port number to the parameter */
789 /* The port number is in DX */
790 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
793 if (!Fast486IoPrivilegeCheck(State
, Port
)) return;
795 /* Read a byte from the I/O port */
796 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
798 /* Store the result in AL */
799 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
802 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
805 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
807 /* Make sure this is the right instruction */
808 ASSERT((Opcode
& 0xF7) == 0xE5);
817 /* Fetch the parameter */
818 if (!Fast486FetchByte(State
, &Data
))
820 /* Exception occurred */
824 /* Set the port number to the parameter */
829 /* The port number is in DX */
830 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
833 if (!Fast486IoPrivilegeCheck(State
, Port
)) return;
839 /* Read a dword from the I/O port */
840 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
842 /* Store the value in EAX */
843 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
849 /* Read a word from the I/O port */
850 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
852 /* Store the value in AX */
853 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
857 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
862 /* Make sure this is the right instruction */
863 ASSERT((Opcode
& 0xF7) == 0xE6);
867 /* Fetch the parameter */
868 if (!Fast486FetchByte(State
, &Data
))
870 /* Exception occurred */
874 /* Set the port number to the parameter */
879 /* The port number is in DX */
880 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
883 if (!Fast486IoPrivilegeCheck(State
, Port
)) return;
885 /* Read the value from AL */
886 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
888 /* Write the byte to the I/O port */
889 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
892 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
895 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
897 /* Make sure this is the right instruction */
898 ASSERT((Opcode
& 0xF7) == 0xE7);
907 /* Fetch the parameter */
908 if (!Fast486FetchByte(State
, &Data
))
910 /* Exception occurred */
914 /* Set the port number to the parameter */
919 /* The port number is in DX */
920 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
923 if (!Fast486IoPrivilegeCheck(State
, Port
)) return;
927 /* Get the value from EAX */
928 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
930 /* Write a dword to the I/O port */
931 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
935 /* Get the value from AX */
936 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
938 /* Write a word to the I/O port */
939 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
943 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
946 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
950 /* Make sure this is the right instruction */
951 ASSERT(Opcode
== 0xEB);
953 /* Fetch the offset */
954 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
956 /* An exception occurred */
960 /* Move the instruction pointer */
961 State
->InstPtr
.Long
+= Offset
;
965 /* Clear the top half of EIP */
966 State
->InstPtr
.Long
&= 0xFFFF;
970 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
972 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
974 /* Make sure this is the right instruction */
975 ASSERT((Opcode
& 0xF8) == 0xB8);
984 /* Fetch the dword */
985 if (!Fast486FetchDword(State
, &Value
))
987 /* Exception occurred */
991 /* Store the value in the register */
992 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
999 if (!Fast486FetchWord(State
, &Value
))
1001 /* Exception occurred */
1005 /* Store the value in the register */
1006 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1010 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1014 /* Make sure this is the right instruction */
1015 ASSERT((Opcode
& 0xF8) == 0xB0);
1019 /* Fetch the byte */
1020 if (!Fast486FetchByte(State
, &Value
))
1022 /* Exception occurred */
1028 /* AH, CH, DH or BH */
1029 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1033 /* AL, CL, DL or BL */
1034 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1038 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1040 UCHAR FirstValue
, SecondValue
, Result
;
1041 FAST486_MOD_REG_RM ModRegRm
;
1042 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1044 /* Make sure this is the right instruction */
1045 ASSERT((Opcode
& 0xFD) == 0x00);
1047 TOGGLE_ADSIZE(AddressSize
);
1049 /* Get the operands */
1050 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1052 /* Exception occurred */
1056 if (!Fast486ReadModrmByteOperands(State
,
1061 /* Exception occurred */
1065 /* Calculate the result */
1066 Result
= FirstValue
+ SecondValue
;
1068 /* Update the flags */
1069 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1070 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1071 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1072 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1073 State
->Flags
.Zf
= (Result
== 0);
1074 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1075 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1077 /* Write back the result */
1078 Fast486WriteModrmByteOperands(State
,
1080 Opcode
& FAST486_OPCODE_WRITE_REG
,
1084 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1086 FAST486_MOD_REG_RM ModRegRm
;
1087 BOOLEAN OperandSize
, AddressSize
;
1089 /* Make sure this is the right instruction */
1090 ASSERT((Opcode
& 0xFD) == 0x01);
1092 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1094 TOGGLE_ADSIZE(AddressSize
);
1095 TOGGLE_OPSIZE(OperandSize
);
1097 /* Get the operands */
1098 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1100 /* Exception occurred */
1104 /* Check the operand size */
1107 ULONG FirstValue
, SecondValue
, Result
;
1109 if (!Fast486ReadModrmDwordOperands(State
,
1114 /* Exception occurred */
1118 /* Calculate the result */
1119 Result
= FirstValue
+ SecondValue
;
1121 /* Update the flags */
1122 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1123 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1124 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1125 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1126 State
->Flags
.Zf
= (Result
== 0);
1127 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1128 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1130 /* Write back the result */
1131 Fast486WriteModrmDwordOperands(State
,
1133 Opcode
& FAST486_OPCODE_WRITE_REG
,
1138 USHORT FirstValue
, SecondValue
, Result
;
1140 if (!Fast486ReadModrmWordOperands(State
,
1145 /* Exception occurred */
1149 /* Calculate the result */
1150 Result
= FirstValue
+ SecondValue
;
1152 /* Update the flags */
1153 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1154 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1155 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1156 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1157 State
->Flags
.Zf
= (Result
== 0);
1158 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1159 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1161 /* Write back the result */
1162 Fast486WriteModrmWordOperands(State
,
1164 Opcode
& FAST486_OPCODE_WRITE_REG
,
1169 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1171 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1172 UCHAR SecondValue
, Result
;
1174 /* Make sure this is the right instruction */
1175 ASSERT(Opcode
== 0x04);
1179 if (!Fast486FetchByte(State
, &SecondValue
))
1181 /* Exception occurred */
1185 /* Calculate the result */
1186 Result
= FirstValue
+ SecondValue
;
1188 /* Update the flags */
1189 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1190 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1191 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1192 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1193 State
->Flags
.Zf
= (Result
== 0);
1194 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1195 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1197 /* Write back the result */
1198 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1201 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1203 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1205 /* Make sure this is the right instruction */
1206 ASSERT(Opcode
== 0x05);
1209 TOGGLE_OPSIZE(Size
);
1213 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1214 ULONG SecondValue
, Result
;
1216 if (!Fast486FetchDword(State
, &SecondValue
))
1218 /* Exception occurred */
1222 /* Calculate the result */
1223 Result
= FirstValue
+ SecondValue
;
1225 /* Update the flags */
1226 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1227 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1228 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1229 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1230 State
->Flags
.Zf
= (Result
== 0);
1231 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1232 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1234 /* Write back the result */
1235 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1239 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1240 USHORT SecondValue
, Result
;
1242 if (!Fast486FetchWord(State
, &SecondValue
))
1244 /* Exception occurred */
1248 /* Calculate the result */
1249 Result
= FirstValue
+ SecondValue
;
1251 /* Update the flags */
1252 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1253 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1254 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1255 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1256 State
->Flags
.Zf
= (Result
== 0);
1257 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1258 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1260 /* Write back the result */
1261 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1265 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1267 UCHAR FirstValue
, SecondValue
, Result
;
1268 FAST486_MOD_REG_RM ModRegRm
;
1269 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1271 /* Make sure this is the right instruction */
1272 ASSERT((Opcode
& 0xFD) == 0x08);
1274 TOGGLE_ADSIZE(AddressSize
);
1276 /* Get the operands */
1277 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1279 /* Exception occurred */
1283 if (!Fast486ReadModrmByteOperands(State
,
1288 /* Exception occurred */
1292 /* Calculate the result */
1293 Result
= FirstValue
| SecondValue
;
1295 /* Update the flags */
1296 State
->Flags
.Cf
= FALSE
;
1297 State
->Flags
.Of
= FALSE
;
1298 State
->Flags
.Zf
= (Result
== 0);
1299 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1300 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1302 /* Write back the result */
1303 Fast486WriteModrmByteOperands(State
,
1305 Opcode
& FAST486_OPCODE_WRITE_REG
,
1309 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1311 FAST486_MOD_REG_RM ModRegRm
;
1312 BOOLEAN OperandSize
, AddressSize
;
1314 /* Make sure this is the right instruction */
1315 ASSERT((Opcode
& 0xFD) == 0x09);
1317 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1319 TOGGLE_ADSIZE(AddressSize
);
1320 TOGGLE_OPSIZE(OperandSize
);
1322 /* Get the operands */
1323 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1325 /* Exception occurred */
1329 /* Check the operand size */
1332 ULONG FirstValue
, SecondValue
, Result
;
1334 if (!Fast486ReadModrmDwordOperands(State
,
1339 /* Exception occurred */
1343 /* Calculate the result */
1344 Result
= FirstValue
| SecondValue
;
1346 /* Update the flags */
1347 State
->Flags
.Cf
= FALSE
;
1348 State
->Flags
.Of
= FALSE
;
1349 State
->Flags
.Zf
= (Result
== 0);
1350 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1351 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1353 /* Write back the result */
1354 Fast486WriteModrmDwordOperands(State
,
1356 Opcode
& FAST486_OPCODE_WRITE_REG
,
1361 USHORT FirstValue
, SecondValue
, Result
;
1363 if (!Fast486ReadModrmWordOperands(State
,
1368 /* Exception occurred */
1372 /* Calculate the result */
1373 Result
= FirstValue
| SecondValue
;
1375 /* Update the flags */
1376 State
->Flags
.Cf
= FALSE
;
1377 State
->Flags
.Of
= FALSE
;
1378 State
->Flags
.Zf
= (Result
== 0);
1379 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1380 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1382 /* Write back the result */
1383 Fast486WriteModrmWordOperands(State
,
1385 Opcode
& FAST486_OPCODE_WRITE_REG
,
1390 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1392 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1393 UCHAR SecondValue
, Result
;
1395 /* Make sure this is the right instruction */
1396 ASSERT(Opcode
== 0x0C);
1400 if (!Fast486FetchByte(State
, &SecondValue
))
1402 /* Exception occurred */
1406 /* Calculate the result */
1407 Result
= FirstValue
| SecondValue
;
1409 /* Update the flags */
1410 State
->Flags
.Cf
= FALSE
;
1411 State
->Flags
.Of
= FALSE
;
1412 State
->Flags
.Zf
= (Result
== 0);
1413 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1414 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1416 /* Write back the result */
1417 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1420 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1422 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1424 /* Make sure this is the right instruction */
1425 ASSERT(Opcode
== 0x0D);
1428 TOGGLE_OPSIZE(Size
);
1432 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1433 ULONG SecondValue
, Result
;
1435 if (!Fast486FetchDword(State
, &SecondValue
))
1437 /* Exception occurred */
1441 /* Calculate the result */
1442 Result
= FirstValue
| SecondValue
;
1444 /* Update the flags */
1445 State
->Flags
.Cf
= FALSE
;
1446 State
->Flags
.Of
= FALSE
;
1447 State
->Flags
.Zf
= (Result
== 0);
1448 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1449 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1451 /* Write back the result */
1452 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1456 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1457 USHORT SecondValue
, Result
;
1459 if (!Fast486FetchWord(State
, &SecondValue
))
1461 /* Exception occurred */
1465 /* Calculate the result */
1466 Result
= FirstValue
| SecondValue
;
1468 /* Update the flags */
1469 State
->Flags
.Cf
= FALSE
;
1470 State
->Flags
.Of
= FALSE
;
1471 State
->Flags
.Zf
= (Result
== 0);
1472 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1473 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1475 /* Write back the result */
1476 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1480 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1482 UCHAR FirstValue
, SecondValue
, Result
;
1483 FAST486_MOD_REG_RM ModRegRm
;
1484 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1486 /* Make sure this is the right instruction */
1487 ASSERT((Opcode
& 0xFD) == 0x20);
1489 TOGGLE_ADSIZE(AddressSize
);
1491 /* Get the operands */
1492 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1494 /* Exception occurred */
1498 if (!Fast486ReadModrmByteOperands(State
,
1503 /* Exception occurred */
1507 /* Calculate the result */
1508 Result
= FirstValue
& SecondValue
;
1510 /* Update the flags */
1511 State
->Flags
.Cf
= FALSE
;
1512 State
->Flags
.Of
= FALSE
;
1513 State
->Flags
.Zf
= (Result
== 0);
1514 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1515 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1517 /* Write back the result */
1518 Fast486WriteModrmByteOperands(State
,
1520 Opcode
& FAST486_OPCODE_WRITE_REG
,
1524 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1526 FAST486_MOD_REG_RM ModRegRm
;
1527 BOOLEAN OperandSize
, AddressSize
;
1529 /* Make sure this is the right instruction */
1530 ASSERT((Opcode
& 0xFD) == 0x21);
1532 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1534 TOGGLE_ADSIZE(AddressSize
);
1535 TOGGLE_OPSIZE(OperandSize
);
1537 /* Get the operands */
1538 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1540 /* Exception occurred */
1544 /* Check the operand size */
1547 ULONG FirstValue
, SecondValue
, Result
;
1549 if (!Fast486ReadModrmDwordOperands(State
,
1554 /* Exception occurred */
1558 /* Calculate the result */
1559 Result
= FirstValue
& SecondValue
;
1561 /* Update the flags */
1562 State
->Flags
.Cf
= FALSE
;
1563 State
->Flags
.Of
= FALSE
;
1564 State
->Flags
.Zf
= (Result
== 0);
1565 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1566 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1568 /* Write back the result */
1569 Fast486WriteModrmDwordOperands(State
,
1571 Opcode
& FAST486_OPCODE_WRITE_REG
,
1576 USHORT FirstValue
, SecondValue
, Result
;
1578 if (!Fast486ReadModrmWordOperands(State
,
1583 /* Exception occurred */
1587 /* Calculate the result */
1588 Result
= FirstValue
& SecondValue
;
1590 /* Update the flags */
1591 State
->Flags
.Cf
= FALSE
;
1592 State
->Flags
.Of
= FALSE
;
1593 State
->Flags
.Zf
= (Result
== 0);
1594 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1595 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1597 /* Write back the result */
1598 Fast486WriteModrmWordOperands(State
,
1600 Opcode
& FAST486_OPCODE_WRITE_REG
,
1605 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1607 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1608 UCHAR SecondValue
, Result
;
1610 /* Make sure this is the right instruction */
1611 ASSERT(Opcode
== 0x24);
1615 if (!Fast486FetchByte(State
, &SecondValue
))
1617 /* Exception occurred */
1621 /* Calculate the result */
1622 Result
= FirstValue
& SecondValue
;
1624 /* Update the flags */
1625 State
->Flags
.Cf
= FALSE
;
1626 State
->Flags
.Of
= FALSE
;
1627 State
->Flags
.Zf
= (Result
== 0);
1628 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1629 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1631 /* Write back the result */
1632 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1635 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1637 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1639 /* Make sure this is the right instruction */
1640 ASSERT(Opcode
== 0x25);
1643 TOGGLE_OPSIZE(Size
);
1647 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1648 ULONG SecondValue
, Result
;
1650 if (!Fast486FetchDword(State
, &SecondValue
))
1652 /* Exception occurred */
1656 /* Calculate the result */
1657 Result
= FirstValue
& SecondValue
;
1659 /* Update the flags */
1660 State
->Flags
.Cf
= FALSE
;
1661 State
->Flags
.Of
= FALSE
;
1662 State
->Flags
.Zf
= (Result
== 0);
1663 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1664 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1666 /* Write back the result */
1667 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1671 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1672 USHORT SecondValue
, Result
;
1674 if (!Fast486FetchWord(State
, &SecondValue
))
1676 /* Exception occurred */
1680 /* Calculate the result */
1681 Result
= FirstValue
& SecondValue
;
1683 /* Update the flags */
1684 State
->Flags
.Cf
= FALSE
;
1685 State
->Flags
.Of
= FALSE
;
1686 State
->Flags
.Zf
= (Result
== 0);
1687 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1688 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1690 /* Write back the result */
1691 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1695 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1697 UCHAR FirstValue
, SecondValue
, Result
;
1698 FAST486_MOD_REG_RM ModRegRm
;
1699 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1701 /* Make sure this is the right instruction */
1702 ASSERT((Opcode
& 0xFD) == 0x30);
1704 TOGGLE_ADSIZE(AddressSize
);
1706 /* Get the operands */
1707 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1709 /* Exception occurred */
1713 if (!Fast486ReadModrmByteOperands(State
,
1718 /* Exception occurred */
1722 /* Calculate the result */
1723 Result
= FirstValue
^ SecondValue
;
1725 /* Update the flags */
1726 State
->Flags
.Cf
= FALSE
;
1727 State
->Flags
.Of
= FALSE
;
1728 State
->Flags
.Zf
= (Result
== 0);
1729 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1730 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1732 /* Write back the result */
1733 Fast486WriteModrmByteOperands(State
,
1735 Opcode
& FAST486_OPCODE_WRITE_REG
,
1739 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1741 FAST486_MOD_REG_RM ModRegRm
;
1742 BOOLEAN OperandSize
, AddressSize
;
1744 /* Make sure this is the right instruction */
1745 ASSERT((Opcode
& 0xFD) == 0x31);
1747 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1749 TOGGLE_ADSIZE(AddressSize
);
1750 TOGGLE_OPSIZE(OperandSize
);
1752 /* Get the operands */
1753 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1755 /* Exception occurred */
1759 /* Check the operand size */
1762 ULONG FirstValue
, SecondValue
, Result
;
1764 if (!Fast486ReadModrmDwordOperands(State
,
1769 /* Exception occurred */
1773 /* Calculate the result */
1774 Result
= FirstValue
^ SecondValue
;
1776 /* Update the flags */
1777 State
->Flags
.Cf
= FALSE
;
1778 State
->Flags
.Of
= FALSE
;
1779 State
->Flags
.Zf
= (Result
== 0);
1780 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1781 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1783 /* Write back the result */
1784 Fast486WriteModrmDwordOperands(State
,
1786 Opcode
& FAST486_OPCODE_WRITE_REG
,
1791 USHORT FirstValue
, SecondValue
, Result
;
1793 if (!Fast486ReadModrmWordOperands(State
,
1798 /* Exception occurred */
1802 /* Calculate the result */
1803 Result
= FirstValue
^ SecondValue
;
1805 /* Update the flags */
1806 State
->Flags
.Cf
= FALSE
;
1807 State
->Flags
.Of
= FALSE
;
1808 State
->Flags
.Zf
= (Result
== 0);
1809 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1810 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1812 /* Write back the result */
1813 Fast486WriteModrmWordOperands(State
,
1815 Opcode
& FAST486_OPCODE_WRITE_REG
,
1820 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1822 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1823 UCHAR SecondValue
, Result
;
1825 /* Make sure this is the right instruction */
1826 ASSERT(Opcode
== 0x34);
1830 if (!Fast486FetchByte(State
, &SecondValue
))
1832 /* Exception occurred */
1836 /* Calculate the result */
1837 Result
= FirstValue
^ SecondValue
;
1839 /* Update the flags */
1840 State
->Flags
.Cf
= FALSE
;
1841 State
->Flags
.Of
= FALSE
;
1842 State
->Flags
.Zf
= (Result
== 0);
1843 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1844 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1846 /* Write back the result */
1847 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1850 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
1852 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1854 /* Make sure this is the right instruction */
1855 ASSERT(Opcode
== 0x35);
1858 TOGGLE_OPSIZE(Size
);
1862 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1863 ULONG SecondValue
, Result
;
1865 if (!Fast486FetchDword(State
, &SecondValue
))
1867 /* Exception occurred */
1871 /* Calculate the result */
1872 Result
= FirstValue
^ SecondValue
;
1874 /* Update the flags */
1875 State
->Flags
.Cf
= FALSE
;
1876 State
->Flags
.Of
= FALSE
;
1877 State
->Flags
.Zf
= (Result
== 0);
1878 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1879 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1881 /* Write back the result */
1882 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1886 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1887 USHORT SecondValue
, Result
;
1889 if (!Fast486FetchWord(State
, &SecondValue
))
1891 /* Exception occurred */
1895 /* Calculate the result */
1896 Result
= FirstValue
^ SecondValue
;
1898 /* Update the flags */
1899 State
->Flags
.Cf
= FALSE
;
1900 State
->Flags
.Of
= FALSE
;
1901 State
->Flags
.Zf
= (Result
== 0);
1902 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1903 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1905 /* Write back the result */
1906 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1910 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
1912 UCHAR FirstValue
, SecondValue
, Result
;
1913 FAST486_MOD_REG_RM ModRegRm
;
1914 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1916 /* Make sure this is the right instruction */
1917 ASSERT(Opcode
== 0x84);
1919 TOGGLE_ADSIZE(AddressSize
);
1921 /* Get the operands */
1922 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1924 /* Exception occurred */
1928 if (!Fast486ReadModrmByteOperands(State
,
1933 /* Exception occurred */
1936 /* Calculate the result */
1937 Result
= FirstValue
& SecondValue
;
1939 /* Update the flags */
1940 State
->Flags
.Cf
= FALSE
;
1941 State
->Flags
.Of
= FALSE
;
1942 State
->Flags
.Zf
= (Result
== 0);
1943 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1944 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1947 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
1949 FAST486_MOD_REG_RM ModRegRm
;
1950 BOOLEAN OperandSize
, AddressSize
;
1952 /* Make sure this is the right instruction */
1953 ASSERT(Opcode
== 0x85);
1955 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1957 TOGGLE_ADSIZE(AddressSize
);
1958 TOGGLE_OPSIZE(OperandSize
);
1960 /* Get the operands */
1961 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1963 /* Exception occurred */
1967 /* Check the operand size */
1970 ULONG FirstValue
, SecondValue
, Result
;
1972 if (!Fast486ReadModrmDwordOperands(State
,
1977 /* Exception occurred */
1981 /* Calculate the result */
1982 Result
= FirstValue
& SecondValue
;
1984 /* Update the flags */
1985 State
->Flags
.Cf
= FALSE
;
1986 State
->Flags
.Of
= FALSE
;
1987 State
->Flags
.Zf
= (Result
== 0);
1988 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1989 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1993 USHORT FirstValue
, SecondValue
, Result
;
1995 if (!Fast486ReadModrmWordOperands(State
,
2000 /* Exception occurred */
2004 /* Calculate the result */
2005 Result
= FirstValue
& SecondValue
;
2007 /* Update the flags */
2008 State
->Flags
.Cf
= FALSE
;
2009 State
->Flags
.Of
= FALSE
;
2010 State
->Flags
.Zf
= (Result
== 0);
2011 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2012 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2016 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2018 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2019 UCHAR SecondValue
, Result
;
2021 /* Make sure this is the right instruction */
2022 ASSERT(Opcode
== 0xA8);
2026 if (!Fast486FetchByte(State
, &SecondValue
))
2028 /* Exception occurred */
2032 /* Calculate the result */
2033 Result
= FirstValue
& SecondValue
;
2035 /* Update the flags */
2036 State
->Flags
.Cf
= FALSE
;
2037 State
->Flags
.Of
= FALSE
;
2038 State
->Flags
.Zf
= (Result
== 0);
2039 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2040 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2043 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2045 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2047 /* Make sure this is the right instruction */
2048 ASSERT(Opcode
== 0xA9);
2051 TOGGLE_OPSIZE(Size
);
2055 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2056 ULONG SecondValue
, Result
;
2058 if (!Fast486FetchDword(State
, &SecondValue
))
2060 /* Exception occurred */
2064 /* Calculate the result */
2065 Result
= FirstValue
& SecondValue
;
2067 /* Update the flags */
2068 State
->Flags
.Cf
= FALSE
;
2069 State
->Flags
.Of
= FALSE
;
2070 State
->Flags
.Zf
= (Result
== 0);
2071 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2072 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2076 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2077 USHORT SecondValue
, Result
;
2079 if (!Fast486FetchWord(State
, &SecondValue
))
2081 /* Exception occurred */
2085 /* Calculate the result */
2086 Result
= FirstValue
& SecondValue
;
2088 /* Update the flags */
2089 State
->Flags
.Cf
= FALSE
;
2090 State
->Flags
.Of
= FALSE
;
2091 State
->Flags
.Zf
= (Result
== 0);
2092 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2093 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2097 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2099 UCHAR FirstValue
, SecondValue
;
2100 FAST486_MOD_REG_RM ModRegRm
;
2101 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2103 /* Make sure this is the right instruction */
2104 ASSERT(Opcode
== 0x86);
2106 TOGGLE_ADSIZE(AddressSize
);
2108 /* Get the operands */
2109 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2111 /* Exception occurred */
2115 if (!Fast486ReadModrmByteOperands(State
,
2120 /* Exception occurred */
2124 /* Write the value from the register to the R/M */
2125 if (!Fast486WriteModrmByteOperands(State
,
2130 /* Exception occurred */
2134 /* Write the value from the R/M to the register */
2135 Fast486WriteModrmByteOperands(State
,
2141 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2143 FAST486_MOD_REG_RM ModRegRm
;
2144 BOOLEAN OperandSize
, AddressSize
;
2146 /* Make sure this is the right instruction */
2147 ASSERT(Opcode
== 0x87);
2149 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2151 TOGGLE_ADSIZE(AddressSize
);
2152 TOGGLE_OPSIZE(OperandSize
);
2154 /* Get the operands */
2155 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2157 /* Exception occurred */
2161 /* Check the operand size */
2164 ULONG FirstValue
, SecondValue
;
2166 if (!Fast486ReadModrmDwordOperands(State
,
2171 /* Exception occurred */
2175 /* Write the value from the register to the R/M */
2176 if (!Fast486WriteModrmDwordOperands(State
,
2181 /* Exception occurred */
2185 /* Write the value from the R/M to the register */
2186 Fast486WriteModrmDwordOperands(State
,
2193 USHORT FirstValue
, SecondValue
;
2195 if (!Fast486ReadModrmWordOperands(State
,
2200 /* Exception occurred */
2204 /* Write the value from the register to the R/M */
2205 if (!Fast486WriteModrmWordOperands(State
,
2210 /* Exception occurred */
2214 /* Write the value from the R/M to the register */
2215 Fast486WriteModrmWordOperands(State
,
2222 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2224 /* Call the internal API */
2225 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2228 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2232 if (!Fast486StackPop(State
, &NewSelector
))
2234 /* Exception occurred */
2238 /* Call the internal API */
2239 Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2242 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2244 /* Call the internal API */
2245 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2248 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2250 UCHAR FirstValue
, SecondValue
, Result
;
2251 FAST486_MOD_REG_RM ModRegRm
;
2252 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2254 /* Make sure this is the right instruction */
2255 ASSERT((Opcode
& 0xFD) == 0x10);
2257 TOGGLE_ADSIZE(AddressSize
);
2259 /* Get the operands */
2260 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2262 /* Exception occurred */
2266 if (!Fast486ReadModrmByteOperands(State
,
2271 /* Exception occurred */
2275 /* Calculate the result */
2276 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2278 /* Special exception for CF */
2279 State
->Flags
.Cf
= State
->Flags
.Cf
2280 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2282 /* Update the flags */
2283 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2284 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2285 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2286 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2287 State
->Flags
.Zf
= (Result
== 0);
2288 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2289 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2291 /* Write back the result */
2292 Fast486WriteModrmByteOperands(State
,
2294 Opcode
& FAST486_OPCODE_WRITE_REG
,
2298 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2300 FAST486_MOD_REG_RM ModRegRm
;
2301 BOOLEAN OperandSize
, AddressSize
;
2303 /* Make sure this is the right instruction */
2304 ASSERT((Opcode
& 0xFD) == 0x11);
2306 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2308 TOGGLE_ADSIZE(AddressSize
);
2309 TOGGLE_OPSIZE(OperandSize
);
2311 /* Get the operands */
2312 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2314 /* Exception occurred */
2318 /* Check the operand size */
2321 ULONG FirstValue
, SecondValue
, Result
;
2323 if (!Fast486ReadModrmDwordOperands(State
,
2328 /* Exception occurred */
2332 /* Calculate the result */
2333 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2335 /* Special exception for CF */
2336 State
->Flags
.Cf
= State
->Flags
.Cf
2337 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2339 /* Update the flags */
2340 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2341 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2342 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2343 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2344 State
->Flags
.Zf
= (Result
== 0);
2345 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2346 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2348 /* Write back the result */
2349 Fast486WriteModrmDwordOperands(State
,
2351 Opcode
& FAST486_OPCODE_WRITE_REG
,
2356 USHORT FirstValue
, SecondValue
, Result
;
2358 if (!Fast486ReadModrmWordOperands(State
,
2363 /* Exception occurred */
2367 /* Calculate the result */
2368 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2370 /* Special exception for CF */
2371 State
->Flags
.Cf
= State
->Flags
.Cf
2372 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2374 /* Update the flags */
2375 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2376 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2377 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2378 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2379 State
->Flags
.Zf
= (Result
== 0);
2380 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2381 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2383 /* Write back the result */
2384 Fast486WriteModrmWordOperands(State
,
2386 Opcode
& FAST486_OPCODE_WRITE_REG
,
2392 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2394 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2395 UCHAR SecondValue
, Result
;
2397 /* Make sure this is the right instruction */
2398 ASSERT(Opcode
== 0x14);
2402 if (!Fast486FetchByte(State
, &SecondValue
))
2404 /* Exception occurred */
2408 /* Calculate the result */
2409 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2411 /* Special exception for CF */
2412 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2413 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2415 /* Update the flags */
2416 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2417 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2418 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2419 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2420 State
->Flags
.Zf
= (Result
== 0);
2421 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2422 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2424 /* Write back the result */
2425 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2428 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2430 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2432 /* Make sure this is the right instruction */
2433 ASSERT(Opcode
== 0x15);
2436 TOGGLE_OPSIZE(Size
);
2440 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2441 ULONG SecondValue
, Result
;
2443 if (!Fast486FetchDword(State
, &SecondValue
))
2445 /* Exception occurred */
2449 /* Calculate the result */
2450 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2452 /* Special exception for CF */
2453 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2454 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2456 /* Update the flags */
2457 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2458 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2459 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2460 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2461 State
->Flags
.Zf
= (Result
== 0);
2462 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2463 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2465 /* Write back the result */
2466 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2470 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2471 USHORT SecondValue
, Result
;
2473 if (!Fast486FetchWord(State
, &SecondValue
))
2475 /* Exception occurred */
2479 /* Calculate the result */
2480 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2482 /* Special exception for CF */
2483 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2484 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2486 /* Update the flags */
2487 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2488 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2489 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2490 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2491 State
->Flags
.Zf
= (Result
== 0);
2492 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2493 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2495 /* Write back the result */
2496 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2500 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2502 /* Call the internal API */
2503 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2506 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2510 if (!Fast486StackPop(State
, &NewSelector
))
2512 /* Exception occurred */
2516 /* Call the internal API */
2517 if (Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
)))
2519 /* Inhibit all interrupts until the next instruction */
2520 State
->DoNotInterrupt
= TRUE
;
2524 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2526 UCHAR FirstValue
, SecondValue
, Result
;
2527 FAST486_MOD_REG_RM ModRegRm
;
2528 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2529 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2531 /* Make sure this is the right instruction */
2532 ASSERT((Opcode
& 0xFD) == 0x18);
2534 TOGGLE_ADSIZE(AddressSize
);
2536 /* Get the operands */
2537 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2539 /* Exception occurred */
2543 if (!Fast486ReadModrmByteOperands(State
,
2548 /* Exception occurred */
2552 /* Check if this is the instruction that writes to R/M */
2553 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2555 /* Swap the order */
2556 SWAP(FirstValue
, SecondValue
);
2559 /* Calculate the result */
2560 Result
= FirstValue
- SecondValue
- Carry
;
2562 /* Update the flags */
2563 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2564 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2565 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2566 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2567 State
->Flags
.Zf
= (Result
== 0);
2568 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2569 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2571 /* Write back the result */
2572 Fast486WriteModrmByteOperands(State
,
2574 Opcode
& FAST486_OPCODE_WRITE_REG
,
2578 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2580 FAST486_MOD_REG_RM ModRegRm
;
2581 BOOLEAN OperandSize
, AddressSize
;
2582 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2584 /* Make sure this is the right instruction */
2585 ASSERT((Opcode
& 0xFD) == 0x19);
2587 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2589 TOGGLE_ADSIZE(AddressSize
);
2590 TOGGLE_OPSIZE(OperandSize
);
2592 /* Get the operands */
2593 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2595 /* Exception occurred */
2599 /* Check the operand size */
2602 ULONG FirstValue
, SecondValue
, Result
;
2604 if (!Fast486ReadModrmDwordOperands(State
,
2609 /* Exception occurred */
2613 /* Check if this is the instruction that writes to R/M */
2614 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2616 /* Swap the order */
2617 SWAP(FirstValue
, SecondValue
);
2620 /* Calculate the result */
2621 Result
= FirstValue
- SecondValue
- Carry
;
2623 /* Update the flags */
2624 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2625 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2626 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2627 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2628 State
->Flags
.Zf
= (Result
== 0);
2629 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2630 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2632 /* Write back the result */
2633 Fast486WriteModrmDwordOperands(State
,
2635 Opcode
& FAST486_OPCODE_WRITE_REG
,
2640 USHORT FirstValue
, SecondValue
, Result
;
2642 if (!Fast486ReadModrmWordOperands(State
,
2647 /* Exception occurred */
2651 /* Check if this is the instruction that writes to R/M */
2652 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2654 /* Swap the order */
2655 SWAP(FirstValue
, SecondValue
);
2658 /* Calculate the result */
2659 Result
= FirstValue
- SecondValue
- Carry
;
2661 /* Update the flags */
2662 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2663 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2664 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2665 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2666 State
->Flags
.Zf
= (Result
== 0);
2667 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2668 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2670 /* Write back the result */
2671 Fast486WriteModrmWordOperands(State
,
2673 Opcode
& FAST486_OPCODE_WRITE_REG
,
2678 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2680 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2681 UCHAR SecondValue
, Result
;
2682 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2684 /* Make sure this is the right instruction */
2685 ASSERT(Opcode
== 0x1C);
2689 if (!Fast486FetchByte(State
, &SecondValue
))
2691 /* Exception occurred */
2695 /* Calculate the result */
2696 Result
= FirstValue
- SecondValue
- Carry
;
2698 /* Update the flags */
2699 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2700 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2701 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2702 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2703 State
->Flags
.Zf
= (Result
== 0);
2704 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2705 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2707 /* Write back the result */
2708 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2711 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2713 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2714 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2716 /* Make sure this is the right instruction */
2717 ASSERT(Opcode
== 0x1D);
2720 TOGGLE_OPSIZE(Size
);
2724 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2725 ULONG SecondValue
, Result
;
2727 if (!Fast486FetchDword(State
, &SecondValue
))
2729 /* Exception occurred */
2733 /* Calculate the result */
2734 Result
= FirstValue
- SecondValue
- Carry
;
2736 /* Update the flags */
2737 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2738 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2739 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2740 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2741 State
->Flags
.Zf
= (Result
== 0);
2742 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2743 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2745 /* Write back the result */
2746 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2750 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2751 USHORT SecondValue
, Result
;
2753 if (!Fast486FetchWord(State
, &SecondValue
))
2755 /* Exception occurred */
2759 /* Calculate the result */
2760 Result
= FirstValue
- SecondValue
- Carry
;
2762 /* Update the flags */
2763 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2764 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2765 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2766 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2767 State
->Flags
.Zf
= (Result
== 0);
2768 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2769 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2771 /* Write back the result */
2772 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2776 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2778 /* Call the internal API */
2779 Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2782 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
2786 if (!Fast486StackPop(State
, &NewSelector
))
2788 /* Exception occurred */
2792 /* Call the internal API */
2793 Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
2796 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
2798 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2799 BOOLEAN Carry
= State
->Flags
.Cf
;
2801 /* Clear the carry flag */
2802 State
->Flags
.Cf
= FALSE
;
2804 /* Check if the first BCD digit is invalid or there was a carry from it */
2805 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
2808 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
2809 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
2811 /* A carry occurred */
2812 State
->Flags
.Cf
= TRUE
;
2815 /* Set the adjust flag */
2816 State
->Flags
.Af
= TRUE
;
2819 /* Check if the second BCD digit is invalid or there was a carry from it */
2820 if ((Value
> 0x99) || Carry
)
2823 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
2825 /* There was a carry */
2826 State
->Flags
.Cf
= TRUE
;
2829 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2831 /* Update the flags */
2832 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
2833 State
->Flags
.Zf
= (Value
== 0);
2834 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
2837 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
2839 UCHAR FirstValue
, SecondValue
, Result
;
2840 FAST486_MOD_REG_RM ModRegRm
;
2841 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2843 /* Make sure this is the right instruction */
2844 ASSERT((Opcode
& 0xED) == 0x28);
2846 TOGGLE_ADSIZE(AddressSize
);
2848 /* Get the operands */
2849 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2851 /* Exception occurred */
2855 if (!Fast486ReadModrmByteOperands(State
,
2860 /* Exception occurred */
2864 /* Check if this is the instruction that writes to R/M */
2865 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2867 /* Swap the order */
2868 SWAP(FirstValue
, SecondValue
);
2871 /* Calculate the result */
2872 Result
= FirstValue
- SecondValue
;
2874 /* Update the flags */
2875 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
2876 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2877 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2878 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
2879 State
->Flags
.Zf
= (Result
== 0);
2880 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2881 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2883 /* Check if this is not a CMP */
2884 if (!(Opcode
& 0x10))
2886 /* Write back the result */
2887 Fast486WriteModrmByteOperands(State
,
2889 Opcode
& FAST486_OPCODE_WRITE_REG
,
2894 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
2896 FAST486_MOD_REG_RM ModRegRm
;
2897 BOOLEAN OperandSize
, AddressSize
;
2899 /* Make sure this is the right instruction */
2900 ASSERT((Opcode
& 0xED) == 0x29);
2902 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2904 TOGGLE_ADSIZE(AddressSize
);
2905 TOGGLE_OPSIZE(OperandSize
);
2907 /* Get the operands */
2908 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2910 /* Exception occurred */
2914 /* Check the operand size */
2917 ULONG FirstValue
, SecondValue
, Result
;
2919 if (!Fast486ReadModrmDwordOperands(State
,
2924 /* Exception occurred */
2928 /* Check if this is the instruction that writes to R/M */
2929 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2931 /* Swap the order */
2932 SWAP(FirstValue
, SecondValue
);
2935 /* Calculate the result */
2936 Result
= FirstValue
- SecondValue
;
2938 /* Update the flags */
2939 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
2940 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2941 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2942 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
2943 State
->Flags
.Zf
= (Result
== 0);
2944 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2945 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2947 /* Check if this is not a CMP */
2948 if (!(Opcode
& 0x10))
2950 /* Write back the result */
2951 Fast486WriteModrmDwordOperands(State
,
2953 Opcode
& FAST486_OPCODE_WRITE_REG
,
2959 USHORT FirstValue
, SecondValue
, Result
;
2961 if (!Fast486ReadModrmWordOperands(State
,
2966 /* Exception occurred */
2970 /* Check if this is the instruction that writes to R/M */
2971 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2973 /* Swap the order */
2974 SWAP(FirstValue
, SecondValue
);
2977 /* Calculate the result */
2978 Result
= FirstValue
- SecondValue
;
2980 /* Update the flags */
2981 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
2982 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2983 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2984 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
2985 State
->Flags
.Zf
= (Result
== 0);
2986 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2987 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2989 /* Check if this is not a CMP */
2990 if (!(Opcode
& 0x10))
2992 /* Write back the result */
2993 Fast486WriteModrmWordOperands(State
,
2995 Opcode
& FAST486_OPCODE_WRITE_REG
,
3001 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3003 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3004 UCHAR SecondValue
, Result
;
3006 /* Make sure this is the right instruction */
3007 ASSERT((Opcode
& 0xEF) == 0x2C);
3011 if (!Fast486FetchByte(State
, &SecondValue
))
3013 /* Exception occurred */
3017 /* Calculate the result */
3018 Result
= FirstValue
- SecondValue
;
3020 /* Update the flags */
3021 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3022 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3023 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3024 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3025 State
->Flags
.Zf
= (Result
== 0);
3026 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3027 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3029 /* Check if this is not a CMP */
3030 if (!(Opcode
& 0x10))
3032 /* Write back the result */
3033 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3037 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3039 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3041 /* Make sure this is the right instruction */
3042 ASSERT((Opcode
& 0xEF) == 0x2D);
3045 TOGGLE_OPSIZE(Size
);
3049 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3050 ULONG SecondValue
, Result
;
3052 if (!Fast486FetchDword(State
, &SecondValue
))
3054 /* Exception occurred */
3058 /* Calculate the result */
3059 Result
= FirstValue
- SecondValue
;
3061 /* Update the flags */
3062 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3063 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3064 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3065 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3066 State
->Flags
.Zf
= (Result
== 0);
3067 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3068 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3070 /* Check if this is not a CMP */
3071 if (!(Opcode
& 0x10))
3073 /* Write back the result */
3074 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3079 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3080 USHORT SecondValue
, Result
;
3082 if (!Fast486FetchWord(State
, &SecondValue
))
3084 /* Exception occurred */
3088 /* Calculate the result */
3089 Result
= FirstValue
- SecondValue
;
3091 /* Update the flags */
3092 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3093 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3094 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3095 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3096 State
->Flags
.Zf
= (Result
== 0);
3097 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3098 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3100 /* Check if this is not a CMP */
3101 if (!(Opcode
& 0x10))
3103 /* Write back the result */
3104 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3109 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3111 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3112 BOOLEAN Carry
= State
->Flags
.Cf
;
3114 /* Clear the carry flag */
3115 State
->Flags
.Cf
= FALSE
;
3117 /* Check if the first BCD digit is invalid or there was a borrow */
3118 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3121 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3122 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3124 /* A borrow occurred */
3125 State
->Flags
.Cf
= TRUE
;
3128 /* Set the adjust flag */
3129 State
->Flags
.Af
= TRUE
;
3132 /* Check if the second BCD digit is invalid or there was a borrow */
3133 if ((Value
> 0x99) || Carry
)
3136 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3138 /* There was a borrow */
3139 State
->Flags
.Cf
= TRUE
;
3142 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3144 /* Update the flags */
3145 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3146 State
->Flags
.Zf
= (Value
== 0);
3147 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3150 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3152 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3155 * Check if the value in AL is not a valid BCD digit,
3156 * or there was a carry from the lowest 4 bits of AL
3158 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3161 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3162 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3165 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3169 /* Clear CF and AF */
3170 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3173 /* Keep only the lowest 4 bits of AL */
3174 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3177 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3179 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3182 * Check if the value in AL is not a valid BCD digit,
3183 * or there was a borrow from the lowest 4 bits of AL
3185 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3188 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3189 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3192 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3196 /* Clear CF and AF */
3197 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3200 /* Keep only the lowest 4 bits of AL */
3201 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3204 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3207 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3208 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3210 /* Make sure this is the right instruction */
3211 ASSERT(Opcode
== 0x60);
3213 TOGGLE_OPSIZE(Size
);
3216 /* Push all the registers in order */
3217 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3219 if (i
== FAST486_REG_ESP
)
3221 /* Use the saved ESP instead */
3222 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3224 /* Exception occurred */
3230 /* Push the register */
3231 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3232 : State
->GeneralRegs
[i
].LowWord
))
3234 /* Exception occurred */
3241 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3244 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3247 /* Make sure this is the right instruction */
3248 ASSERT(Opcode
== 0x61);
3250 TOGGLE_OPSIZE(Size
);
3253 /* Pop all the registers in reverse order */
3254 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3257 if (!Fast486StackPop(State
, &Value
))
3259 /* Exception occurred */
3263 /* Don't modify ESP */
3264 if (i
!= FAST486_REG_ESP
)
3266 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3267 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3272 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3274 BOOLEAN OperandSize
, AddressSize
;
3275 FAST486_MOD_REG_RM ModRegRm
;
3276 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3278 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3281 TOGGLE_OPSIZE(OperandSize
);
3282 TOGGLE_ADSIZE(AddressSize
);
3284 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3286 /* Exception occurred */
3290 if (!ModRegRm
.Memory
)
3293 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3297 /* Check for the segment override */
3298 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3300 /* Use the override segment instead */
3301 Segment
= State
->SegmentOverride
;
3306 LONG Index
, LowerBound
, UpperBound
;
3308 /* Read the operands */
3309 if (!Fast486ReadModrmDwordOperands(State
,
3312 (PULONG
)&LowerBound
))
3314 /* Exception occurred */
3318 if (!Fast486ReadMemory(State
,
3320 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3325 /* Exception occurred */
3329 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3332 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3337 SHORT Index
, LowerBound
, UpperBound
;
3339 /* Read the operands */
3340 if (!Fast486ReadModrmWordOperands(State
,
3343 (PUSHORT
)&LowerBound
))
3345 /* Exception occurred */
3349 if (!Fast486ReadMemory(State
,
3351 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3356 /* Exception occurred */
3360 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3363 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3368 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3370 USHORT FirstValue
, SecondValue
;
3371 FAST486_MOD_REG_RM ModRegRm
;
3372 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3374 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3376 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3378 /* Cannot be used in real mode or with a LOCK prefix */
3379 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3383 TOGGLE_ADSIZE(AddressSize
);
3385 /* Get the operands */
3386 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3388 /* Exception occurred */
3392 /* Read the operands */
3393 if (!Fast486ReadModrmWordOperands(State
,
3398 /* Exception occurred */
3402 /* Check if the RPL needs adjusting */
3403 if ((SecondValue
& 3) < (FirstValue
& 3))
3405 /* Adjust the RPL */
3407 SecondValue
|= FirstValue
& 3;
3410 State
->Flags
.Zf
= TRUE
;
3412 /* Write back the result */
3413 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3418 State
->Flags
.Zf
= FALSE
;
3422 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3424 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3426 /* Make sure this is the right instruction */
3427 ASSERT(Opcode
== 0x68);
3430 TOGGLE_OPSIZE(Size
);
3436 if (!Fast486FetchDword(State
, &Data
))
3438 /* Exception occurred */
3442 /* Call the internal API */
3443 Fast486StackPush(State
, Data
);
3449 if (!Fast486FetchWord(State
, (PUSHORT
)&Data
))
3451 /* Exception occurred */
3455 /* Call the internal API */
3456 Fast486StackPush(State
, Data
);
3460 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3462 BOOLEAN OperandSize
, AddressSize
;
3463 FAST486_MOD_REG_RM ModRegRm
;
3466 /* Make sure this is the right instruction */
3467 ASSERT((Opcode
& 0xFD) == 0x69);
3469 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3471 TOGGLE_ADSIZE(AddressSize
);
3472 TOGGLE_OPSIZE(OperandSize
);
3474 /* Fetch the parameters */
3475 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3477 /* Exception occurred */
3485 /* Fetch the immediate operand */
3486 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3488 /* Exception occurred */
3492 Multiplier
= (LONG
)Byte
;
3500 /* Fetch the immediate operand */
3501 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3503 /* Exception occurred */
3513 /* Fetch the immediate operand */
3514 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3516 /* Exception occurred */
3520 Multiplier
= (LONG
)Word
;
3526 LONG RegValue
, Multiplicand
;
3529 /* Read the operands */
3530 if (!Fast486ReadModrmDwordOperands(State
,
3533 (PULONG
)&Multiplicand
))
3535 /* Exception occurred */
3540 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3542 /* Check for carry/overflow */
3543 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< FAST486_LONG_MIN
)
3544 || (Product
> FAST486_LONG_MAX
));
3546 /* Write-back the result */
3547 Fast486WriteModrmDwordOperands(State
,
3550 (ULONG
)((LONG
)Product
));
3554 SHORT RegValue
, Multiplicand
;
3557 /* Read the operands */
3558 if (!Fast486ReadModrmWordOperands(State
,
3561 (PUSHORT
)&Multiplicand
))
3563 /* Exception occurred */
3568 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3570 /* Check for carry/overflow */
3571 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< FAST486_SHORT_MIN
)
3572 || (Product
> FAST486_SHORT_MAX
));
3574 /* Write-back the result */
3575 Fast486WriteModrmWordOperands(State
,
3578 (USHORT
)((SHORT
)Product
));
3582 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3586 /* Make sure this is the right instruction */
3587 ASSERT(Opcode
== 0x6A);
3589 if (!Fast486FetchByte(State
, (PUCHAR
)&Data
))
3591 /* Exception occurred */
3595 /* Call the internal API */
3596 Fast486StackPush(State
, Data
);
3599 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3602 FAST486_MOD_REG_RM ModRegRm
;
3603 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3605 /* Make sure this is the right instruction */
3606 ASSERT((Opcode
& 0xFD) == 0x88);
3608 TOGGLE_ADSIZE(AddressSize
);
3610 /* Get the operands */
3611 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3613 /* Exception occurred */
3617 if (Opcode
& FAST486_OPCODE_WRITE_REG
)
3619 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Result
))
3621 /* Exception occurred */
3627 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Result
, NULL
))
3629 /* Exception occurred */
3634 /* Write back the result */
3635 Fast486WriteModrmByteOperands(State
,
3637 Opcode
& FAST486_OPCODE_WRITE_REG
,
3641 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3643 FAST486_MOD_REG_RM ModRegRm
;
3644 BOOLEAN OperandSize
, AddressSize
;
3646 /* Make sure this is the right instruction */
3647 ASSERT((Opcode
& 0xFD) == 0x89);
3649 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3651 TOGGLE_ADSIZE(AddressSize
);
3652 TOGGLE_OPSIZE(OperandSize
);
3654 /* Get the operands */
3655 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3657 /* Exception occurred */
3661 /* Check the operand size */
3668 if (Opcode
& FAST486_OPCODE_WRITE_REG
)
3670 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Result
))
3672 /* Exception occurred */
3678 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Result
, NULL
))
3680 /* Exception occurred */
3685 /* Write back the result */
3686 Fast486WriteModrmDwordOperands(State
,
3688 Opcode
& FAST486_OPCODE_WRITE_REG
,
3695 if (Opcode
& FAST486_OPCODE_WRITE_REG
)
3697 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Result
))
3699 /* Exception occurred */
3705 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Result
, NULL
))
3707 /* Exception occurred */
3712 /* Write back the result */
3713 Fast486WriteModrmWordOperands(State
,
3715 Opcode
& FAST486_OPCODE_WRITE_REG
,
3720 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3722 BOOLEAN OperandSize
, AddressSize
;
3723 FAST486_MOD_REG_RM ModRegRm
;
3725 /* Make sure this is the right instruction */
3726 ASSERT(Opcode
== 0x8C);
3728 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3730 TOGGLE_ADSIZE(AddressSize
);
3731 TOGGLE_OPSIZE(OperandSize
);
3733 /* Get the operands */
3734 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3736 /* Exception occurred */
3740 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3743 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3747 /* When the other operand is a memory location, always use 16-bit */
3748 if (OperandSize
&& !ModRegRm
.Memory
)
3750 Fast486WriteModrmDwordOperands(State
,
3753 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3757 Fast486WriteModrmWordOperands(State
,
3760 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3764 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3766 FAST486_MOD_REG_RM ModRegRm
;
3767 BOOLEAN OperandSize
, AddressSize
;
3769 /* Make sure this is the right instruction */
3770 ASSERT(Opcode
== 0x8D);
3772 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3774 TOGGLE_ADSIZE(AddressSize
);
3775 TOGGLE_OPSIZE(OperandSize
);
3777 /* Get the operands */
3778 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3780 /* Exception occurred */
3784 /* The second operand must be memory */
3785 if (!ModRegRm
.Memory
)
3788 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3792 /* Write the address to the register */
3795 Fast486WriteModrmDwordOperands(State
,
3798 ModRegRm
.MemoryAddress
);
3802 Fast486WriteModrmWordOperands(State
,
3805 ModRegRm
.MemoryAddress
);
3810 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3812 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3813 FAST486_MOD_REG_RM ModRegRm
;
3816 /* Make sure this is the right instruction */
3817 ASSERT(Opcode
== 0x8E);
3819 TOGGLE_ADSIZE(AddressSize
);
3821 /* Get the operands */
3822 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3824 /* Exception occurred */
3828 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3829 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3832 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3836 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
3838 /* Exception occurred */
3842 if (!Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
))
3844 /* Exception occurred */
3848 if ((INT
)ModRegRm
.Register
== FAST486_REG_SS
)
3850 /* Inhibit all interrupts until the next instruction */
3851 State
->DoNotInterrupt
= TRUE
;
3855 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
3857 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3859 /* Make sure this is the right instruction */
3860 ASSERT(Opcode
== 0x98);
3862 TOGGLE_OPSIZE(Size
);
3867 /* Sign extend AX to EAX */
3868 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
3870 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
3871 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
3877 /* Sign extend AL to AX */
3878 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
3879 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
3884 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
3886 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3888 /* Make sure this is the right instruction */
3889 ASSERT(Opcode
== 0x99);
3891 TOGGLE_OPSIZE(Size
);
3896 /* Sign extend EAX to EDX:EAX */
3897 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
3898 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
3899 ? 0xFFFFFFFF : 0x00000000;
3903 /* Sign extend AX to DX:AX */
3904 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
3905 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
3910 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
3914 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3916 /* Make sure this is the right instruction */
3917 ASSERT(Opcode
== 0x9A);
3919 TOGGLE_OPSIZE(Size
);
3922 /* Fetch the offset */
3925 if (!Fast486FetchDword(State
, &Offset
))
3927 /* Exception occurred */
3933 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
3935 /* Exception occurred */
3940 /* Fetch the segment */
3941 if (!Fast486FetchWord(State
, &Segment
))
3943 /* Exception occurred */
3947 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
) && !State
->Flags
.Vm
)
3949 if (!Fast486ProcessGate(State
, Segment
, Offset
, TRUE
))
3951 /* Gate processed or exception occurred */
3956 /* Push the current code segment selector */
3957 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
3959 /* Exception occurred */
3963 /* Push the current value of the instruction pointer */
3964 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
3966 /* Exception occurred */
3970 /* Load the new CS */
3971 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
3973 /* Exception occurred */
3977 /* Load new (E)IP */
3978 if (Size
) State
->InstPtr
.Long
= Offset
;
3979 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
3982 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
3984 #ifndef FAST486_NO_FPU
3985 Fast486FpuExceptionCheck(State
);
3989 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
3991 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3994 TOGGLE_OPSIZE(Size
);
3996 /* Check for VM86 mode when IOPL is not 3 */
3997 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
3999 /* Call the VM86 monitor */
4000 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4004 /* Push the flags */
4005 if (Size
) Fast486StackPush(State
, State
->Flags
.Long
);
4006 else Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4009 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4011 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4012 UINT Cpl
= Fast486GetCurrentPrivLevel(State
);
4013 FAST486_FLAGS_REG NewFlags
;
4016 TOGGLE_OPSIZE(Size
);
4018 /* Pop the new flags */
4019 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4021 /* Exception occurred */
4025 /* Check for VM86 mode when IOPL is not 3 */
4026 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4028 /* Call the VM86 monitor */
4029 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4033 State
->Flags
.Cf
= NewFlags
.Cf
;
4034 State
->Flags
.Pf
= NewFlags
.Pf
;
4035 State
->Flags
.Af
= NewFlags
.Af
;
4036 State
->Flags
.Zf
= NewFlags
.Zf
;
4037 State
->Flags
.Sf
= NewFlags
.Sf
;
4038 State
->Flags
.Tf
= NewFlags
.Tf
;
4039 State
->Flags
.Df
= NewFlags
.Df
;
4040 State
->Flags
.Of
= NewFlags
.Of
;
4041 State
->Flags
.Nt
= NewFlags
.Nt
;
4042 State
->Flags
.Ac
= NewFlags
.Ac
;
4044 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4045 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4048 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4050 /* Make sure this is the right instruction */
4051 ASSERT(Opcode
== 0x9E);
4053 /* Set the low-order byte of FLAGS to AH */
4054 State
->Flags
.Long
&= 0xFFFFFF00;
4055 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4057 /* Restore the reserved bits of FLAGS */
4058 State
->Flags
.AlwaysSet
= TRUE
;
4059 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4062 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4064 /* Make sure this is the right instruction */
4065 ASSERT(Opcode
== 0x9F);
4067 /* Set AH to the low-order byte of FLAGS */
4068 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4071 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4073 ULONG ReturnAddress
;
4074 USHORT BytesToPop
= 0;
4075 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4077 /* Make sure this is the right instruction */
4078 ASSERT((Opcode
& 0xFE) == 0xC2);
4081 TOGGLE_OPSIZE(Size
);
4085 /* Fetch the number of bytes to pop after the return */
4086 if (!Fast486FetchWord(State
, &BytesToPop
)) return;
4089 /* Pop the return address */
4090 if (!Fast486StackPop(State
, &ReturnAddress
)) return;
4092 /* Return to the calling procedure, and if necessary, pop the parameters */
4095 State
->InstPtr
.Long
= ReturnAddress
;
4096 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4100 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4101 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4105 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4107 UCHAR FarPointer
[6];
4108 BOOLEAN OperandSize
, AddressSize
;
4109 FAST486_MOD_REG_RM ModRegRm
;
4111 /* Make sure this is the right instruction */
4112 ASSERT((Opcode
& 0xFE) == 0xC4);
4114 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4116 TOGGLE_OPSIZE(OperandSize
);
4117 TOGGLE_ADSIZE(AddressSize
);
4119 /* Get the operands */
4120 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4122 /* Exception occurred */
4126 if (!ModRegRm
.Memory
)
4128 /* Check if this is a BOP and the host supports BOPs */
4129 if ((Opcode
== 0xC4)
4130 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4131 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4132 && (State
->BopCallback
!= NULL
))
4136 /* Fetch the BOP code */
4137 if (!Fast486FetchByte(State
, &BopCode
))
4139 /* Exception occurred */
4143 #ifndef FAST486_NO_PREFETCH
4144 /* Invalidate the prefetch since BOP handlers can alter the memory */
4145 State
->PrefetchValid
= FALSE
;
4148 /* Call the BOP handler */
4149 State
->BopCallback(State
, BopCode
);
4152 * If an interrupt should occur at this time, delay it.
4153 * We must do this because if an interrupt begins and the BOP callback
4154 * changes the CS:IP, the interrupt handler won't execute and the
4155 * stack pointer will never be restored.
4157 State
->DoNotInterrupt
= TRUE
;
4163 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4167 if (!Fast486ReadMemory(State
,
4168 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4169 ? State
->SegmentOverride
: FAST486_REG_DS
,
4170 ModRegRm
.MemoryAddress
,
4173 OperandSize
? 6 : 4))
4175 /* Exception occurred */
4181 ULONG Offset
= *((PULONG
)FarPointer
);
4182 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4184 /* Set the register to the offset */
4185 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4187 /* Load the segment */
4188 Fast486LoadSegment(State
,
4190 ? FAST486_REG_ES
: FAST486_REG_DS
,
4195 USHORT Offset
= *((PUSHORT
)FarPointer
);
4196 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4198 /* Set the register to the offset */
4199 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4201 /* Load the segment */
4202 Fast486LoadSegment(State
,
4204 ? FAST486_REG_ES
: FAST486_REG_DS
,
4209 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4212 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4215 FAST486_REG FramePointer
;
4217 /* Make sure this is the right instruction */
4218 ASSERT(Opcode
== 0xC8);
4221 TOGGLE_OPSIZE(Size
);
4223 if (!Fast486FetchWord(State
, &FrameSize
))
4225 /* Exception occurred */
4229 if (!Fast486FetchByte(State
, &NestingLevel
))
4231 /* Exception occurred */
4236 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4238 /* Exception occurred */
4243 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4245 /* Set up the nested procedure stacks */
4246 for (i
= 1; i
< NestingLevel
; i
++)
4250 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4251 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4255 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4256 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4260 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4262 /* Set EBP to the frame pointer */
4263 if (Size
) State
->GeneralRegs
[FAST486_REG_EBP
].Long
= FramePointer
.Long
;
4264 else State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= FramePointer
.LowWord
;
4266 /* Reserve space for the frame */
4267 if (State
->SegmentRegs
[FAST486_REG_SS
].Size
)
4269 State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4273 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4277 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4279 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4282 /* Make sure this is the right instruction */
4283 ASSERT(Opcode
== 0xC9);
4286 TOGGLE_OPSIZE(Size
);
4288 if (State
->SegmentRegs
[FAST486_REG_SS
].Size
)
4290 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4291 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4295 /* Set the stack pointer (SP) to the base pointer (BP) */
4296 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4299 /* Pop the saved base pointer from the stack */
4300 if (Fast486StackPop(State
, &Value
))
4302 if (Size
) State
->GeneralRegs
[FAST486_REG_EBP
].Long
= Value
;
4303 else State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4307 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4311 USHORT BytesToPop
= 0;
4312 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4315 UCHAR OldCpl
= Fast486GetCurrentPrivLevel(State
);
4317 /* Make sure this is the right instruction */
4318 ASSERT((Opcode
& 0xFE) == 0xCA);
4320 TOGGLE_OPSIZE(Size
);
4325 /* Fetch the number of bytes to pop after the return */
4326 if (!Fast486FetchWord(State
, &BytesToPop
)) return;
4329 /* Pop the offset */
4330 if (!Fast486StackPop(State
, &Offset
))
4332 /* Exception occurred */
4336 /* Pop the segment */
4337 if (!Fast486StackPop(State
, &Segment
))
4339 /* Exception occurred */
4343 /* Pop the parameters */
4344 if (State
->SegmentRegs
[FAST486_REG_SS
].Size
)
4346 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4350 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4353 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
) && !State
->Flags
.Vm
)
4355 if (GET_SEGMENT_RPL(Segment
) > OldCpl
)
4358 if (!Fast486StackPop(State
, &StackPtr
))
4365 if (!Fast486StackPop(State
, &StackSel
))
4373 /* Load the new CS */
4374 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4376 /* Exception occurred */
4380 /* Load new (E)IP */
4381 if (Size
) State
->InstPtr
.Long
= Offset
;
4382 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4384 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
) && !State
->Flags
.Vm
)
4388 /* Update the CPL */
4389 State
->Cpl
= GET_SEGMENT_RPL(Segment
);
4391 if (State
->Cpl
> OldCpl
)
4394 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4401 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4402 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4404 /* Check segment security */
4405 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4407 /* Don't check CS or SS */
4408 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4410 if ((State
->Cpl
> State
->SegmentRegs
[i
].Dpl
)
4411 && (!State
->SegmentRegs
[i
].Executable
4412 || !State
->SegmentRegs
[i
].DirConf
))
4414 /* Load the NULL descriptor in the segment */
4415 if (!Fast486LoadSegment(State
, i
, 0)) return;
4422 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4426 /* Check for V86 mode */
4427 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4429 /* Call the V86 monitor */
4430 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
4438 /* This is the INT3 instruction */
4443 case 0xCD: // INT xx
4445 /* Fetch the interrupt number */
4446 if (!Fast486FetchByte(State
, &IntNum
))
4448 /* Exception occurred */
4457 /* Don't do anything if OF is cleared */
4458 if (!State
->Flags
.Of
) return;
4461 IntNum
= FAST486_EXCEPTION_OF
;
4468 /* Should not happen */
4473 /* Perform the interrupt */
4474 Fast486PerformInterrupt(State
, IntNum
);
4477 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4480 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4481 FAST486_FLAGS_REG NewFlags
;
4482 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4484 /* Make sure this is the right instruction */
4485 ASSERT(Opcode
== 0xCF);
4488 TOGGLE_OPSIZE(Size
);
4490 /* Check if this is a nested task return */
4491 if (State
->Flags
.Nt
&& (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
))
4493 /* Clear the NT flag of the current task */
4494 State
->Flags
.Nt
= FALSE
;
4496 /* Switch to the old task */
4497 Fast486TaskSwitch(State
, FAST486_TASK_RETURN
, 0);
4502 if (!Fast486StackPop(State
, &InstPtr
))
4504 /* Exception occurred */
4509 if (!Fast486StackPop(State
, &CodeSel
))
4511 /* Exception occurred */
4516 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4518 /* Exception occurred */
4522 /* Check for protected mode */
4523 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4525 UINT OldCpl
= Fast486GetCurrentPrivLevel(State
);
4527 if (State
->Flags
.Vm
)
4529 /* Return from VM86 mode */
4531 /* Check the IOPL */
4532 if (State
->Flags
.Iopl
== 3)
4535 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4538 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4540 /* Exception occurred */
4544 /* Set the new flags */
4545 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4546 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4547 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4548 State
->Flags
.Iopl
= 3;
4552 /* Call the VM86 monitor */
4553 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4562 /* Return to VM86 mode */
4563 ULONG Es
, Ds
, Fs
, Gs
;
4565 /* Pop ESP, SS, ES, DS, FS, GS */
4566 if (!Fast486StackPop(State
, &StackPtr
)) return;
4567 if (!Fast486StackPop(State
, &StackSel
)) return;
4568 if (!Fast486StackPop(State
, &Es
)) return;
4569 if (!Fast486StackPop(State
, &Ds
)) return;
4570 if (!Fast486StackPop(State
, &Fs
)) return;
4571 if (!Fast486StackPop(State
, &Gs
)) return;
4573 /* Set the new IP */
4574 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4576 /* Set the new SP */
4577 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4579 /* Set the new flags */
4580 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4581 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4582 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4584 /* Switch to CPL 3 */
4587 /* Load the new segments */
4588 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return;
4589 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return;
4590 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return;
4591 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return;
4592 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return;
4593 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return;
4598 if (GET_SEGMENT_RPL(CodeSel
) > OldCpl
)
4601 if (!Fast486StackPop(State
, &StackPtr
))
4608 if (!Fast486StackPop(State
, &StackSel
))
4615 /* Load the new CS */
4616 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4618 /* Exception occurred */
4623 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4624 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4626 /* Update the CPL */
4627 State
->Cpl
= GET_SEGMENT_RPL(CodeSel
);
4629 /* Set the new flags */
4632 State
->Flags
.Long
= (State
->Flags
.Long
& ~PROT_MODE_FLAGS_MASK
)
4633 | (NewFlags
.Long
& PROT_MODE_FLAGS_MASK
);
4637 State
->Flags
.LowWord
= (State
->Flags
.LowWord
& ~PROT_MODE_FLAGS_MASK
)
4638 | (NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
);
4640 State
->Flags
.AlwaysSet
= TRUE
;
4642 /* Set additional flags */
4643 if (OldCpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4644 if (OldCpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4646 if (State
->Cpl
> OldCpl
)
4649 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4656 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4657 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4659 /* Check segment security */
4660 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4662 /* Don't check CS or SS */
4663 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4665 if ((State
->Cpl
> State
->SegmentRegs
[i
].Dpl
)
4666 && (!State
->SegmentRegs
[i
].Executable
4667 || !State
->SegmentRegs
[i
].DirConf
))
4669 /* Load the NULL descriptor in the segment */
4670 if (!Fast486LoadSegment(State
, i
, 0)) return;
4677 if (Size
&& (InstPtr
& 0xFFFF0000))
4680 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4685 State
->InstPtr
.Long
= InstPtr
;
4688 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4690 /* Exception occurred */
4694 /* Set the new flags */
4695 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4696 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4697 State
->Flags
.AlwaysSet
= TRUE
;
4701 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4704 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4708 /* Fetch the base */
4709 if (!Fast486FetchByte(State
, &Base
))
4711 /* Exception occurred */
4715 /* Check if the base is zero */
4719 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4724 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4725 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4728 State
->Flags
.Af
= FALSE
;
4729 State
->Flags
.Zf
= (Value
== 0);
4730 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4731 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4734 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4737 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4741 /* Fetch the base */
4742 if (!Fast486FetchByte(State
, &Base
))
4744 /* Exception occurred */
4749 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4750 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4753 State
->Flags
.Af
= FALSE
;
4754 State
->Flags
.Zf
= (Value
== 0);
4755 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4756 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4759 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4762 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4764 TOGGLE_ADSIZE(AddressSize
);
4766 /* Read a byte from DS:[(E)BX + AL] */
4767 if (!Fast486ReadMemory(State
,
4768 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4769 ? State
->SegmentOverride
: FAST486_REG_DS
,
4770 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4771 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4772 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4777 /* Exception occurred */
4781 /* Set AL to the result */
4782 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4785 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4788 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4791 /* Make sure this is the right instruction */
4792 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4795 TOGGLE_ADSIZE(Size
);
4797 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4798 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4802 /* Additional rule for LOOPNZ */
4803 if (State
->Flags
.Zf
) Condition
= FALSE
;
4805 else if (Opcode
== 0xE1)
4807 /* Additional rule for LOOPZ */
4808 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4811 /* Fetch the offset */
4812 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4814 /* An exception occurred */
4820 /* Move the instruction pointer */
4821 if (Size
) State
->InstPtr
.Long
+= Offset
;
4822 else State
->InstPtr
.LowWord
+= Offset
;
4826 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
4829 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4832 /* Make sure this is the right instruction */
4833 ASSERT(Opcode
== 0xE3);
4836 TOGGLE_ADSIZE(Size
);
4838 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
4839 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
4841 /* Fetch the offset */
4842 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4844 /* An exception occurred */
4850 /* Move the instruction pointer */
4851 if (Size
) State
->InstPtr
.Long
+= Offset
;
4852 else State
->InstPtr
.LowWord
+= Offset
;
4856 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
4858 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4860 /* Make sure this is the right instruction */
4861 ASSERT(Opcode
== 0xE8);
4863 TOGGLE_OPSIZE(Size
);
4870 /* Fetch the offset */
4871 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
4873 /* An exception occurred */
4877 /* Push the current value of the instruction pointer */
4878 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4880 /* Exception occurred */
4884 /* Move the instruction pointer */
4885 State
->InstPtr
.Long
+= Offset
;
4891 /* Fetch the offset */
4892 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4894 /* An exception occurred */
4898 /* Push the current value of the instruction pointer */
4899 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4901 /* Exception occurred */
4905 /* Move the instruction pointer */
4906 State
->InstPtr
.LowWord
+= Offset
;
4910 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
4912 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4914 /* Make sure this is the right instruction */
4915 ASSERT(Opcode
== 0xE9);
4917 TOGGLE_OPSIZE(Size
);
4924 /* Fetch the offset */
4925 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
4927 /* An exception occurred */
4931 /* Move the instruction pointer */
4932 State
->InstPtr
.Long
+= Offset
;
4938 /* Fetch the offset */
4939 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4941 /* An exception occurred */
4945 /* Move the instruction pointer */
4946 State
->InstPtr
.Long
+= Offset
;
4948 /* Clear the top half of EIP */
4949 State
->InstPtr
.Long
&= 0xFFFF;
4953 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
4957 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4959 /* Make sure this is the right instruction */
4960 ASSERT(Opcode
== 0xEA);
4962 TOGGLE_OPSIZE(Size
);
4965 /* Fetch the offset */
4968 if (!Fast486FetchDword(State
, &Offset
))
4970 /* Exception occurred */
4976 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4978 /* Exception occurred */
4983 /* Fetch the segment */
4984 if (!Fast486FetchWord(State
, &Segment
))
4986 /* Exception occurred */
4990 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
) && !State
->Flags
.Vm
)
4992 if (!Fast486ProcessGate(State
, Segment
, Offset
, FALSE
))
4994 /* Gate processed or exception occurred */
4999 /* Load the new CS */
5000 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5002 /* Exception occurred */
5007 State
->InstPtr
.Long
= Offset
;
5010 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5012 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5015 /* Make sure this is the right instruction */
5016 ASSERT(Opcode
== 0xA0);
5018 TOGGLE_ADSIZE(AddressSize
);
5022 if (!Fast486FetchDword(State
, &Offset
))
5024 /* Exception occurred */
5032 if (!Fast486FetchWord(State
, &WordOffset
))
5034 /* Exception occurred */
5038 Offset
= (ULONG
)WordOffset
;
5041 /* Read from memory */
5042 Fast486ReadMemory(State
,
5043 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5044 State
->SegmentOverride
: FAST486_REG_DS
,
5047 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5051 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5053 BOOLEAN OperandSize
, AddressSize
;
5055 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5057 /* Make sure this is the right instruction */
5058 ASSERT(Opcode
== 0xA1);
5060 TOGGLE_OPSIZE(OperandSize
);
5061 TOGGLE_ADSIZE(AddressSize
);
5067 if (!Fast486FetchDword(State
, &Offset
))
5069 /* Exception occurred */
5073 /* Read from memory */
5076 Fast486ReadMemory(State
,
5077 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5078 State
->SegmentOverride
: FAST486_REG_DS
,
5081 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5086 Fast486ReadMemory(State
,
5087 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5088 State
->SegmentOverride
: FAST486_REG_DS
,
5091 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5099 if (!Fast486FetchWord(State
, &Offset
))
5101 /* Exception occurred */
5105 /* Read from memory */
5108 Fast486ReadMemory(State
,
5109 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5110 State
->SegmentOverride
: FAST486_REG_DS
,
5113 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5118 Fast486ReadMemory(State
,
5119 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5120 State
->SegmentOverride
: FAST486_REG_DS
,
5123 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5129 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5131 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5134 /* Make sure this is the right instruction */
5135 ASSERT(Opcode
== 0xA2);
5137 TOGGLE_ADSIZE(AddressSize
);
5141 if (!Fast486FetchDword(State
, &Offset
))
5143 /* Exception occurred */
5151 if (!Fast486FetchWord(State
, &WordOffset
))
5153 /* Exception occurred */
5157 Offset
= (ULONG
)WordOffset
;
5160 /* Write to memory */
5161 Fast486WriteMemory(State
,
5162 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5163 State
->SegmentOverride
: FAST486_REG_DS
,
5165 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5169 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5171 BOOLEAN OperandSize
, AddressSize
;
5173 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5175 /* Make sure this is the right instruction */
5176 ASSERT(Opcode
== 0xA3);
5178 TOGGLE_OPSIZE(OperandSize
);
5179 TOGGLE_ADSIZE(AddressSize
);
5185 if (!Fast486FetchDword(State
, &Offset
))
5187 /* Exception occurred */
5191 /* Write to memory */
5194 Fast486WriteMemory(State
,
5195 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5196 State
->SegmentOverride
: FAST486_REG_DS
,
5198 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5203 Fast486WriteMemory(State
,
5204 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5205 State
->SegmentOverride
: FAST486_REG_DS
,
5207 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5215 if (!Fast486FetchWord(State
, &Offset
))
5217 /* Exception occurred */
5221 /* Write to memory */
5224 Fast486WriteMemory(State
,
5225 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5226 State
->SegmentOverride
: FAST486_REG_DS
,
5228 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5233 Fast486WriteMemory(State
,
5234 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5235 State
->SegmentOverride
: FAST486_REG_DS
,
5237 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5243 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5246 * See: http://www.rcollins.org/secrets/opcodes/SALC.html
5247 * for more information.
5250 /* Make sure this is the right instruction */
5251 ASSERT(Opcode
== 0xD6);
5255 /* Set all the bits of AL to CF */
5256 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5259 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5261 ULONG Data
, DataSize
;
5262 BOOLEAN OperandSize
, AddressSize
;
5263 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5265 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5267 /* Make sure this is the right instruction */
5268 ASSERT((Opcode
& 0xFE) == 0xA4);
5270 TOGGLE_OPSIZE(OperandSize
);
5271 TOGGLE_ADSIZE(AddressSize
);
5273 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5275 /* Use the override segment instead of DS */
5276 Segment
= State
->SegmentOverride
;
5279 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5281 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5282 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5289 /* Calculate the size */
5290 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5291 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5293 /* Read from the source operand */
5294 if (!Fast486ReadMemory(State
,
5296 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5297 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5302 /* Exception occurred */
5306 /* Write to the destination operand */
5307 if (!Fast486WriteMemory(State
,
5309 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5310 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5314 /* Exception occurred */
5318 /* Increment/decrement ESI and EDI */
5321 if (!State
->Flags
.Df
)
5323 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5324 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5328 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5329 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5334 if (!State
->Flags
.Df
)
5336 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5337 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5341 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5342 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5346 // FIXME: This method is slow!
5347 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5351 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5353 /* Repeat the instruction */
5354 State
->InstPtr
= State
->SavedInstPtr
;
5359 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5361 /* Repeat the instruction */
5362 State
->InstPtr
= State
->SavedInstPtr
;
5368 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5370 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5371 ULONG DataSize
, DataMask
, SignFlag
;
5372 BOOLEAN OperandSize
, AddressSize
;
5373 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5375 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5377 /* Make sure this is the right instruction */
5378 ASSERT((Opcode
& 0xFE) == 0xA6);
5380 TOGGLE_OPSIZE(OperandSize
);
5381 TOGGLE_ADSIZE(AddressSize
);
5383 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5385 /* Use the override segment instead of DS */
5386 Segment
= State
->SegmentOverride
;
5389 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5390 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5392 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5393 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5400 /* Calculate the size */
5401 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5402 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5404 /* Calculate the mask and sign flag */
5405 SignFlag
= 1 << ((DataSize
* 8) - 1);
5406 DataMask
= SignFlag
| (SignFlag
- 1);
5408 /* Read from the first source operand */
5409 if (!Fast486ReadMemory(State
,
5411 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5412 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5417 /* Exception occurred */
5421 /* Read from the second source operand */
5422 if (!Fast486ReadMemory(State
,
5424 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5425 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5430 /* Exception occurred */
5434 /* Calculate the result */
5435 FirstValue
&= DataMask
;
5436 SecondValue
&= DataMask
;
5437 Result
= (FirstValue
- SecondValue
) & DataMask
;
5439 /* Update the flags */
5440 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5441 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5442 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5443 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5444 State
->Flags
.Zf
= (Result
== 0);
5445 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5446 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5448 /* Increment/decrement ESI and EDI */
5451 if (!State
->Flags
.Df
)
5453 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5454 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5458 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5459 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5464 if (!State
->Flags
.Df
)
5466 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5467 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5471 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5472 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5476 // FIXME: This method is slow!
5477 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5478 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5480 BOOLEAN Repeat
= TRUE
;
5484 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5492 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5499 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5500 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5502 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5508 /* Repeat the instruction */
5509 State
->InstPtr
= State
->SavedInstPtr
;
5514 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5517 BOOLEAN OperandSize
, AddressSize
;
5519 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5521 /* Make sure this is the right instruction */
5522 ASSERT((Opcode
& 0xFE) == 0xAA);
5524 TOGGLE_OPSIZE(OperandSize
);
5525 TOGGLE_ADSIZE(AddressSize
);
5527 /* Calculate the size */
5528 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5529 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5531 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5533 UCHAR Block
[STRING_BLOCK_SIZE
];
5534 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5535 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5537 /* Fill the memory block with the data */
5538 if (DataSize
== sizeof(UCHAR
))
5540 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5546 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5548 if (DataSize
== sizeof(USHORT
))
5550 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5554 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5559 /* Transfer until finished */
5562 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5564 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5567 ULONG MaxBytes
= State
->Flags
.Df
5568 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5569 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5571 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5572 if (Processed
== 0) Processed
= 1;
5575 if (State
->Flags
.Df
)
5577 /* Set EDI to the starting location */
5578 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5579 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5582 /* Write to memory */
5583 if (!Fast486WriteMemory(State
,
5585 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5586 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5588 Processed
* DataSize
))
5591 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5592 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5594 /* Exception occurred */
5598 if (!State
->Flags
.Df
)
5600 /* Increase EDI by the number of bytes transfered */
5601 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5602 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5607 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5608 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5611 /* Reduce the total count by the number processed in this run */
5616 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5617 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5621 /* Write to the destination operand */
5622 if (!Fast486WriteMemory(State
,
5624 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5625 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5626 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5629 /* Exception occurred */
5633 /* Increment/decrement EDI */
5636 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5637 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5641 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5642 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5647 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5650 BOOLEAN OperandSize
, AddressSize
;
5651 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5653 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5655 /* Make sure this is the right instruction */
5656 ASSERT((Opcode
& 0xFE) == 0xAC);
5658 TOGGLE_OPSIZE(OperandSize
);
5659 TOGGLE_ADSIZE(AddressSize
);
5661 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5663 /* Use the override segment instead of DS */
5664 Segment
= State
->SegmentOverride
;
5667 /* Calculate the size */
5668 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5669 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5671 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5673 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5674 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5676 /* If the count is 0, do nothing */
5677 if (Count
== 0) return;
5679 /* Only the last entry will be loaded */
5680 if (!State
->Flags
.Df
)
5682 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5683 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5687 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5688 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5692 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5693 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5696 /* Read from the source operand */
5697 if (!Fast486ReadMemory(State
,
5699 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5700 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5702 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5705 /* Exception occurred */
5709 /* Increment/decrement ESI */
5712 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5713 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5717 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5718 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5722 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5724 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5725 ULONG SecondValue
= 0;
5727 ULONG DataSize
, DataMask
, SignFlag
;
5728 BOOLEAN OperandSize
, AddressSize
;
5730 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5732 /* Make sure this is the right instruction */
5733 ASSERT((Opcode
& 0xFE) == 0xAE);
5735 TOGGLE_OPSIZE(OperandSize
);
5736 TOGGLE_ADSIZE(AddressSize
);
5738 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5739 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5741 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5742 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5749 /* Calculate the size */
5750 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5751 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5753 /* Calculate the mask and sign flag */
5754 SignFlag
= 1 << ((DataSize
* 8) - 1);
5755 DataMask
= SignFlag
| (SignFlag
- 1);
5757 /* Read from the source operand */
5758 if (!Fast486ReadMemory(State
,
5760 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5761 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5766 /* Exception occurred */
5770 /* Calculate the result */
5771 FirstValue
&= DataMask
;
5772 SecondValue
&= DataMask
;
5773 Result
= (FirstValue
- SecondValue
) & DataMask
;
5775 /* Update the flags */
5776 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5777 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5778 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5779 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5780 State
->Flags
.Zf
= (Result
== 0);
5781 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5782 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5784 /* Increment/decrement EDI */
5787 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5788 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5792 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5793 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5796 // FIXME: This method is slow!
5797 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5798 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5800 BOOLEAN Repeat
= TRUE
;
5804 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5812 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5819 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5820 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5822 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5828 /* Repeat the instruction */
5829 State
->InstPtr
= State
->SavedInstPtr
;
5834 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
5837 BOOLEAN OperandSize
, AddressSize
;
5839 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5841 /* Make sure this is the right instruction */
5842 ASSERT((Opcode
& 0xFE) == 0x6C);
5844 TOGGLE_OPSIZE(OperandSize
);
5845 TOGGLE_ADSIZE(AddressSize
);
5847 if (!Fast486IoPrivilegeCheck(State
, State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
)) return;
5849 /* Calculate the size */
5850 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
5851 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5853 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5855 UCHAR Block
[STRING_BLOCK_SIZE
];
5856 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5857 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5859 /* Clear the memory block */
5860 RtlZeroMemory(Block
, sizeof(Block
));
5862 /* Transfer until finished */
5865 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5867 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5870 ULONG MaxBytes
= State
->Flags
.Df
5871 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5872 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5874 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5875 if (Processed
== 0) Processed
= 1;
5878 /* Read from the I/O port */
5879 State
->IoReadCallback(State
,
5880 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
5885 if (State
->Flags
.Df
)
5889 /* Reduce EDI by the number of bytes to transfer */
5890 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5891 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5893 /* Reverse the block data */
5894 for (i
= 0; i
< Processed
/ 2; i
++)
5896 /* Swap the values */
5897 for (j
= 0; j
< DataSize
; j
++)
5899 UCHAR Temp
= Block
[i
* DataSize
+ j
];
5900 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
5901 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
5906 /* Write to memory */
5907 if (!Fast486WriteMemory(State
,
5909 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5910 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5912 Processed
* DataSize
))
5915 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5916 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5918 /* Exception occurred */
5922 if (!State
->Flags
.Df
)
5924 /* Increase EDI by the number of bytes transfered */
5925 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5926 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5929 /* Reduce the total count by the number processed in this run */
5934 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5935 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5941 /* Read from the I/O port */
5942 State
->IoReadCallback(State
,
5943 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
5948 /* Write to the destination operand */
5949 if (!Fast486WriteMemory(State
,
5951 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5952 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5956 /* Exception occurred */
5960 /* Increment/decrement EDI */
5963 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5964 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5968 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5969 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5974 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
5977 BOOLEAN OperandSize
, AddressSize
;
5979 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5981 /* Make sure this is the right instruction */
5982 ASSERT((Opcode
& 0xFE) == 0x6E);
5984 TOGGLE_OPSIZE(OperandSize
);
5985 TOGGLE_ADSIZE(AddressSize
);
5987 if (!Fast486IoPrivilegeCheck(State
, State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
)) return;
5989 /* Calculate the size */
5990 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
5991 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5993 if (State
->PrefixFlags
& (FAST486_PREFIX_REP
| FAST486_PREFIX_REPNZ
))
5995 UCHAR Block
[STRING_BLOCK_SIZE
];
5996 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5997 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5999 /* Clear the memory block */
6000 RtlZeroMemory(Block
, sizeof(Block
));
6002 /* Transfer until finished */
6005 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6007 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6010 ULONG MaxBytes
= State
->Flags
.Df
6011 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
6012 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
6014 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6015 if (Processed
== 0) Processed
= 1;
6018 /* Read from memory */
6019 if (!Fast486ReadMemory(State
,
6020 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6021 ? State
->SegmentOverride
: FAST486_REG_DS
,
6022 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6023 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6026 Processed
* DataSize
))
6029 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6030 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6032 /* Exception occurred */
6036 if (State
->Flags
.Df
)
6040 /* Reduce ESI by the number of bytes to transfer */
6041 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
6042 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
6044 /* Reverse the block data */
6045 for (i
= 0; i
< Processed
/ 2; i
++)
6047 /* Swap the values */
6048 for (j
= 0; j
< DataSize
; j
++)
6050 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6051 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6052 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6057 /* Write to the I/O port */
6058 State
->IoWriteCallback(State
,
6059 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6064 if (!State
->Flags
.Df
)
6066 /* Increase ESI by the number of bytes transfered */
6067 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
6068 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
6071 /* Reduce the total count by the number processed in this run */
6076 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6077 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6083 /* Read from the source operand */
6084 if (!Fast486ReadMemory(State
,
6085 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6086 ? State
->SegmentOverride
: FAST486_REG_DS
,
6087 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6088 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6093 /* Exception occurred */
6097 /* Write to the I/O port */
6098 State
->IoWriteCallback(State
,
6099 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6104 /* Increment/decrement ESI */
6107 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6108 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6112 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6113 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;