[FAST486]
[reactos.git] / reactos / lib / fast486 / opcodes.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opcodes.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
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.
11 *
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.
16 *
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.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "opgroups.h"
32 #include "extraops.h"
33 #include "common.h"
34 #include "fpu.h"
35
36 /* PUBLIC VARIABLES ***********************************************************/
37
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS] =
40 {
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 */
50 Fast486OpcodeOrModrm,
51 Fast486OpcodeOrByteModrm,
52 Fast486OpcodeOrModrm,
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 */
130 Fast486OpcodePopReg,
131 Fast486OpcodePopReg,
132 Fast486OpcodePopReg,
133 Fast486OpcodePopReg,
134 Fast486OpcodePopReg,
135 Fast486OpcodePopReg,
136 Fast486OpcodePopReg,
137 Fast486OpcodePushAll, /* 0x60 */
138 Fast486OpcodePopAll, /* 0x61 */
139 Fast486OpcodeBound, /* 0x62 */
140 Fast486OpcodeArpl, /* 0x63 */
141 Fast486OpcodePrefix, /* 0x64 - 0x67 */
142 Fast486OpcodePrefix,
143 Fast486OpcodePrefix,
144 Fast486OpcodePrefix,
145 Fast486OpcodePushImm, /* 0x68 */
146 Fast486OpcodeImulModrmImm, /* 0x69 */
147 Fast486OpcodePushByteImm, /* 0x6A */
148 Fast486OpcodeImulModrmImm, /* 0x6B */
149 Fast486OpcodeIns, /* 0x6C */
150 Fast486OpcodeIns, /* 0x6D */
151 Fast486OpcodeOuts, /* 0x6E */
152 Fast486OpcodeOuts, /* 0x6F */
153 Fast486OpcodeShortConditionalJmp, /* 0x70 - 0x7F */
154 Fast486OpcodeShortConditionalJmp,
155 Fast486OpcodeShortConditionalJmp,
156 Fast486OpcodeShortConditionalJmp,
157 Fast486OpcodeShortConditionalJmp,
158 Fast486OpcodeShortConditionalJmp,
159 Fast486OpcodeShortConditionalJmp,
160 Fast486OpcodeShortConditionalJmp,
161 Fast486OpcodeShortConditionalJmp,
162 Fast486OpcodeShortConditionalJmp,
163 Fast486OpcodeShortConditionalJmp,
164 Fast486OpcodeShortConditionalJmp,
165 Fast486OpcodeShortConditionalJmp,
166 Fast486OpcodeShortConditionalJmp,
167 Fast486OpcodeShortConditionalJmp,
168 Fast486OpcodeShortConditionalJmp,
169 Fast486OpcodeGroup8082, /* 0x80 */
170 Fast486OpcodeGroup81, /* 0x81 */
171 Fast486OpcodeGroup8082, /* 0x82 */
172 Fast486OpcodeGroup83, /* 0x83 */
173 Fast486OpcodeTestByteModrm, /* 0x84 */
174 Fast486OpcodeTestModrm, /* 0x85 */
175 Fast486OpcodeXchgByteModrm, /* 0x86 */
176 Fast486OpcodeXchgModrm, /* 0x87 */
177 Fast486OpcodeMovByteModrm, /* 0x88 */
178 Fast486OpcodeMovModrm, /* 0x89 */
179 Fast486OpcodeMovByteModrm, /* 0x8A */
180 Fast486OpcodeMovModrm, /* 0x8B */
181 Fast486OpcodeMovStoreSeg, /* 0x8C */
182 Fast486OpcodeLea, /* 0x8D */
183 Fast486OpcodeMovLoadSeg, /* 0x8E */
184 Fast486OpcodeGroup8F, /* 0x8F */
185 Fast486OpcodeNop, /* 0x90 */
186 Fast486OpcodeExchangeEax, /* 0x91 - 0x97 */
187 Fast486OpcodeExchangeEax,
188 Fast486OpcodeExchangeEax,
189 Fast486OpcodeExchangeEax,
190 Fast486OpcodeExchangeEax,
191 Fast486OpcodeExchangeEax,
192 Fast486OpcodeExchangeEax,
193 Fast486OpcodeCwde, /* 0x98 */
194 Fast486OpcodeCdq, /* 0x99 */
195 Fast486OpcodeCallAbs, /* 0x9A */
196 Fast486OpcodeWait, /* 0x9B */
197 Fast486OpcodePushFlags, /* 0x9C */
198 Fast486OpcodePopFlags, /* 0x9D */
199 Fast486OpcodeSahf, /* 0x9E */
200 Fast486OpcodeLahf, /* 0x9F */
201 Fast486OpcodeMovAlOffset, /* 0xA0 */
202 Fast486OpcodeMovEaxOffset, /* 0xA1 */
203 Fast486OpcodeMovOffsetAl, /* 0xA2 */
204 Fast486OpcodeMovOffsetEax, /* 0xA3 */
205 Fast486OpcodeMovs, /* 0xA4 */
206 Fast486OpcodeMovs, /* 0xA5 */
207 Fast486OpcodeCmps, /* 0xA6 */
208 Fast486OpcodeCmps, /* 0xA7 */
209 Fast486OpcodeTestAl, /* 0xA8 */
210 Fast486OpcodeTestEax, /* 0xA9 */
211 Fast486OpcodeStos, /* 0xAA */
212 Fast486OpcodeStos, /* 0xAB */
213 Fast486OpcodeLods, /* 0xAC */
214 Fast486OpcodeLods, /* 0xAD */
215 Fast486OpcodeScas, /* 0xAE */
216 Fast486OpcodeScas, /* 0xAF */
217 Fast486OpcodeMovByteRegImm, /* 0xB0 - 0xB7 */
218 Fast486OpcodeMovByteRegImm,
219 Fast486OpcodeMovByteRegImm,
220 Fast486OpcodeMovByteRegImm,
221 Fast486OpcodeMovByteRegImm,
222 Fast486OpcodeMovByteRegImm,
223 Fast486OpcodeMovByteRegImm,
224 Fast486OpcodeMovByteRegImm,
225 Fast486OpcodeMovRegImm, /* 0xB8 - 0xBF */
226 Fast486OpcodeMovRegImm,
227 Fast486OpcodeMovRegImm,
228 Fast486OpcodeMovRegImm,
229 Fast486OpcodeMovRegImm,
230 Fast486OpcodeMovRegImm,
231 Fast486OpcodeMovRegImm,
232 Fast486OpcodeMovRegImm,
233 Fast486OpcodeGroupC0, /* 0xC0 */
234 Fast486OpcodeGroupC1, /* 0xC1 */
235 Fast486OpcodeRet, /* 0xC2 */
236 Fast486OpcodeRet, /* 0xC3 */
237 Fast486OpcodeLdsLes, /* 0xC4 */
238 Fast486OpcodeLdsLes, /* 0xC5 */
239 Fast486OpcodeGroupC6, /* 0xC6 */
240 Fast486OpcodeGroupC7, /* 0xC7 */
241 Fast486OpcodeEnter, /* 0xC8 */
242 Fast486OpcodeLeave, /* 0xC9 */
243 Fast486OpcodeRetFar, /* 0xCA */
244 Fast486OpcodeRetFar, /* 0xCB */
245 Fast486OpcodeInt, /* 0xCC */
246 Fast486OpcodeInt, /* 0xCD */
247 Fast486OpcodeInt, /* 0xCE */
248 Fast486OpcodeIret, /* 0xCF */
249 Fast486OpcodeGroupD0, /* 0xD0 - 0xD3 */
250 Fast486OpcodeGroupD1,
251 Fast486OpcodeGroupD2,
252 Fast486OpcodeGroupD3,
253 Fast486OpcodeAam, /* 0xD4 */
254 Fast486OpcodeAad, /* 0xD5 */
255 Fast486OpcodeSalc, /* 0xD6 */
256 Fast486OpcodeXlat, /* 0xD7 */
257 Fast486FpuOpcodeD8DC, /* 0xD8 - 0xDF */
258 Fast486FpuOpcodeD9,
259 Fast486FpuOpcodeDA,
260 Fast486FpuOpcodeDB,
261 Fast486FpuOpcodeD8DC,
262 Fast486FpuOpcodeDD,
263 Fast486FpuOpcodeDE,
264 Fast486FpuOpcodeDF,
265 Fast486OpcodeLoop, /* 0xE0 - 0xE2 */
266 Fast486OpcodeLoop,
267 Fast486OpcodeLoop,
268 Fast486OpcodeJecxz, /* 0xE3 */
269 Fast486OpcodeInByte, /* 0xE4 */
270 Fast486OpcodeIn, /* 0xE5 */
271 Fast486OpcodeOutByte, /* 0xE6 */
272 Fast486OpcodeOut, /* 0xE7 */
273 Fast486OpcodeCall, /* 0xE8 */
274 Fast486OpcodeJmp, /* 0xE9 */
275 Fast486OpcodeJmpAbs, /* 0xEA */
276 Fast486OpcodeShortJump, /* 0xEB */
277 Fast486OpcodeInByte, /* 0xEC */
278 Fast486OpcodeIn, /* 0xED */
279 Fast486OpcodeOutByte, /* 0xEE */
280 Fast486OpcodeOut, /* 0xEF */
281 Fast486OpcodePrefix, /* 0xF0 */
282 Fast486OpcodeInvalid, /* 0xF1 */ // Invalid opcode
283 Fast486OpcodePrefix, /* 0xF2 */
284 Fast486OpcodePrefix, /* 0xF3 */
285 Fast486OpcodeHalt, /* 0xF4 */
286 Fast486OpcodeComplCarry, /* 0xF5 */
287 Fast486OpcodeGroupF6, /* 0xF6 */
288 Fast486OpcodeGroupF7, /* 0xF7 */
289 Fast486OpcodeClearCarry, /* 0xF8 */
290 Fast486OpcodeSetCarry, /* 0xF9 */
291 Fast486OpcodeClearInt, /* 0xFA */
292 Fast486OpcodeSetInt, /* 0xFB */
293 Fast486OpcodeClearDir, /* 0xFC */
294 Fast486OpcodeSetDir, /* 0xFD */
295 Fast486OpcodeGroupFE, /* 0xFE */
296 Fast486OpcodeGroupFF, /* 0xFF */
297 };
298
299 /* PUBLIC FUNCTIONS ***********************************************************/
300
301 FAST486_OPCODE_HANDLER(Fast486OpcodeInvalid)
302 {
303 /* This is not a valid opcode */
304 Fast486Exception(State, FAST486_EXCEPTION_UD);
305 return FALSE;
306 }
307
308 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix)
309 {
310 BOOLEAN Valid = FALSE;
311
312 switch (Opcode)
313 {
314 /* ES: */
315 case 0x26:
316 {
317 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
318 {
319 State->PrefixFlags |= FAST486_PREFIX_SEG;
320 State->SegmentOverride = FAST486_REG_ES;
321 Valid = TRUE;
322 }
323
324 break;
325 }
326
327 /* CS: */
328 case 0x2E:
329 {
330 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
331 {
332 State->PrefixFlags |= FAST486_PREFIX_SEG;
333 State->SegmentOverride = FAST486_REG_CS;
334 Valid = TRUE;
335 }
336
337 break;
338 }
339
340 /* SS: */
341 case 0x36:
342 {
343 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
344 {
345 State->PrefixFlags |= FAST486_PREFIX_SEG;
346 State->SegmentOverride = FAST486_REG_SS;
347 Valid = TRUE;
348 }
349
350 break;
351 }
352
353 /* DS: */
354 case 0x3E:
355 {
356 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
357 {
358 State->PrefixFlags |= FAST486_PREFIX_SEG;
359 State->SegmentOverride = FAST486_REG_DS;
360 Valid = TRUE;
361 }
362
363 break;
364 }
365
366 /* FS: */
367 case 0x64:
368 {
369 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
370 {
371 State->PrefixFlags |= FAST486_PREFIX_SEG;
372 State->SegmentOverride = FAST486_REG_FS;
373 Valid = TRUE;
374 }
375
376 break;
377 }
378
379 /* GS: */
380 case 0x65:
381 {
382 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
383 {
384 State->PrefixFlags |= FAST486_PREFIX_SEG;
385 State->SegmentOverride = FAST486_REG_GS;
386 Valid = TRUE;
387 }
388
389 break;
390 }
391
392 /* OPSIZE */
393 case 0x66:
394 {
395 if (!(State->PrefixFlags & FAST486_PREFIX_OPSIZE))
396 {
397 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
398 Valid = TRUE;
399 }
400
401 break;
402 }
403
404 /* ADSIZE */
405 case 0x67:
406 {
407 if (!(State->PrefixFlags & FAST486_PREFIX_ADSIZE))
408 {
409 State->PrefixFlags |= FAST486_PREFIX_ADSIZE;
410 Valid = TRUE;
411 }
412 break;
413 }
414
415 /* LOCK */
416 case 0xF0:
417 {
418 if (!(State->PrefixFlags & FAST486_PREFIX_LOCK))
419 {
420 State->PrefixFlags |= FAST486_PREFIX_LOCK;
421 Valid = TRUE;
422 }
423
424 break;
425 }
426
427 /* REPNZ */
428 case 0xF2:
429 {
430 /* Mutually exclusive with REP */
431 if (!(State->PrefixFlags
432 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
433 {
434 State->PrefixFlags |= FAST486_PREFIX_REPNZ;
435 Valid = TRUE;
436 }
437
438 break;
439 }
440
441 /* REP / REPZ */
442 case 0xF3:
443 {
444 /* Mutually exclusive with REPNZ */
445 if (!(State->PrefixFlags
446 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
447 {
448 State->PrefixFlags |= FAST486_PREFIX_REP;
449 Valid = TRUE;
450 }
451
452 break;
453 }
454 }
455
456 if (!Valid)
457 {
458 /* Clear all prefixes */
459 State->PrefixFlags = 0;
460
461 /* Throw an exception */
462 Fast486Exception(State, FAST486_EXCEPTION_UD);
463 return FALSE;
464 }
465
466 return TRUE;
467 }
468
469 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement)
470 {
471 ULONG Value;
472 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
473
474 TOGGLE_OPSIZE(Size);
475 NO_LOCK_PREFIX();
476
477 /* Make sure this is the right instruction */
478 ASSERT((Opcode & 0xF8) == 0x40);
479
480 if (Size)
481 {
482 Value = ++State->GeneralRegs[Opcode & 0x07].Long;
483
484 State->Flags.Of = (Value == SIGN_FLAG_LONG);
485 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
486 }
487 else
488 {
489 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
490
491 State->Flags.Of = (Value == SIGN_FLAG_WORD);
492 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
493 }
494
495 State->Flags.Zf = (Value == 0);
496 State->Flags.Af = ((Value & 0x0F) == 0);
497 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
498
499 /* Return success */
500 return TRUE;
501 }
502
503 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement)
504 {
505 ULONG Value;
506 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
507
508 TOGGLE_OPSIZE(Size);
509 NO_LOCK_PREFIX();
510
511 /* Make sure this is the right instruction */
512 ASSERT((Opcode & 0xF8) == 0x48);
513
514 if (Size)
515 {
516 Value = --State->GeneralRegs[Opcode & 0x07].Long;
517
518 State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1));
519 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
520 }
521 else
522 {
523 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
524
525 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1));
526 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
527 }
528
529 State->Flags.Zf = (Value == 0);
530 State->Flags.Af = ((Value & 0x0F) == 0x0F);
531 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
532
533 /* Return success */
534 return TRUE;
535 }
536
537 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg)
538 {
539 NO_LOCK_PREFIX();
540
541 /* Make sure this is the right instruction */
542 ASSERT((Opcode & 0xF8) == 0x50);
543
544 /* Call the internal function */
545 return Fast486StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
546 }
547
548 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg)
549 {
550 ULONG Value;
551 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
552
553 TOGGLE_OPSIZE(Size);
554 NO_LOCK_PREFIX();
555
556 /* Make sure this is the right instruction */
557 ASSERT((Opcode & 0xF8) == 0x58);
558
559 /* Call the internal function */
560 if (!Fast486StackPop(State, &Value)) return FALSE;
561
562 /* Store the value */
563 if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value;
564 else State->GeneralRegs[Opcode & 0x07].LowWord = Value;
565
566 /* Return success */
567 return TRUE;
568 }
569
570 FAST486_OPCODE_HANDLER(Fast486OpcodeNop)
571 {
572 if (State->PrefixFlags & FAST486_PREFIX_REP)
573 {
574 /* Idle cycle */
575 State->IdleCallback(State);
576 }
577
578 return TRUE;
579 }
580
581 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax)
582 {
583 INT Reg = Opcode & 0x07;
584 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
585
586 TOGGLE_OPSIZE(Size);
587 NO_LOCK_PREFIX();
588
589 /* Make sure this is the right instruction */
590 ASSERT((Opcode & 0xF8) == 0x90);
591
592 /* Exchange the values */
593 if (Size)
594 {
595 ULONG Value;
596
597 Value = State->GeneralRegs[Reg].Long;
598 State->GeneralRegs[Reg].Long = State->GeneralRegs[FAST486_REG_EAX].Long;
599 State->GeneralRegs[FAST486_REG_EAX].Long = Value;
600 }
601 else
602 {
603 USHORT Value;
604
605 Value = State->GeneralRegs[Reg].LowWord;
606 State->GeneralRegs[Reg].LowWord = State->GeneralRegs[FAST486_REG_EAX].LowWord;
607 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
608 }
609
610 return TRUE;
611 }
612
613 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp)
614 {
615 BOOLEAN Jump = FALSE;
616 CHAR Offset = 0;
617 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
618
619 /* Make sure this is the right instruction */
620 ASSERT((Opcode & 0xF0) == 0x70);
621
622 TOGGLE_OPSIZE(Size);
623
624 /* Fetch the offset */
625 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
626 {
627 /* An exception occurred */
628 return FALSE;
629 }
630
631 switch ((Opcode & 0x0F) >> 1)
632 {
633 /* JO / JNO */
634 case 0:
635 {
636 Jump = State->Flags.Of;
637 break;
638 }
639
640 /* JC / JNC */
641 case 1:
642 {
643 Jump = State->Flags.Cf;
644 break;
645 }
646
647 /* JZ / JNZ */
648 case 2:
649 {
650 Jump = State->Flags.Zf;
651 break;
652 }
653
654 /* JBE / JNBE */
655 case 3:
656 {
657 Jump = State->Flags.Cf || State->Flags.Zf;
658 break;
659 }
660
661 /* JS / JNS */
662 case 4:
663 {
664 Jump = State->Flags.Sf;
665 break;
666 }
667
668 /* JP / JNP */
669 case 5:
670 {
671 Jump = State->Flags.Pf;
672 break;
673 }
674
675 /* JL / JNL */
676 case 6:
677 {
678 Jump = State->Flags.Sf != State->Flags.Of;
679 break;
680 }
681
682 /* JLE / JNLE */
683 case 7:
684 {
685 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
686 break;
687 }
688 }
689
690 if (Opcode & 1)
691 {
692 /* Invert the result */
693 Jump = !Jump;
694 }
695
696 if (Jump)
697 {
698 /* Move the instruction pointer */
699 State->InstPtr.Long += Offset;
700
701 if (!Size)
702 {
703 /* Clear the top half of EIP */
704 State->InstPtr.Long &= 0xFFFF;
705 }
706 }
707
708 /* Return success */
709 return TRUE;
710 }
711
712 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry)
713 {
714 /* Make sure this is the right instruction */
715 ASSERT(Opcode == 0xF8);
716
717 /* No prefixes allowed */
718 if (State->PrefixFlags)
719 {
720 Fast486Exception(State, FAST486_EXCEPTION_UD);
721 return FALSE;
722 }
723
724 /* Clear CF and return success */
725 State->Flags.Cf = FALSE;
726 return TRUE;
727 }
728
729 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry)
730 {
731 /* Make sure this is the right instruction */
732 ASSERT(Opcode == 0xF9);
733
734 /* No prefixes allowed */
735 if (State->PrefixFlags)
736 {
737 Fast486Exception(State, FAST486_EXCEPTION_UD);
738 return FALSE;
739 }
740
741 /* Set CF and return success*/
742 State->Flags.Cf = TRUE;
743 return TRUE;
744 }
745
746 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry)
747 {
748 /* Make sure this is the right instruction */
749 ASSERT(Opcode == 0xF5);
750
751 /* No prefixes allowed */
752 if (State->PrefixFlags)
753 {
754 Fast486Exception(State, FAST486_EXCEPTION_UD);
755 return FALSE;
756 }
757
758 /* Toggle CF and return success */
759 State->Flags.Cf = !State->Flags.Cf;
760 return TRUE;
761 }
762
763 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt)
764 {
765 /* Make sure this is the right instruction */
766 ASSERT(Opcode == 0xFA);
767
768 /* No prefixes allowed */
769 if (State->PrefixFlags)
770 {
771 Fast486Exception(State, FAST486_EXCEPTION_UD);
772 return FALSE;
773 }
774
775 /* Check for protected mode */
776 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
777 {
778 /* Check IOPL */
779 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
780 {
781 /* Clear the interrupt flag */
782 State->Flags.If = FALSE;
783 }
784 else
785 {
786 /* General Protection Fault */
787 Fast486Exception(State, FAST486_EXCEPTION_GP);
788 return FALSE;
789 }
790 }
791 else
792 {
793 /* Just clear the interrupt flag */
794 State->Flags.If = FALSE;
795 }
796
797 /* Return success */
798 return TRUE;
799 }
800
801 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt)
802 {
803 /* Make sure this is the right instruction */
804 ASSERT(Opcode == 0xFB);
805
806 /* No prefixes allowed */
807 if (State->PrefixFlags)
808 {
809 Fast486Exception(State, FAST486_EXCEPTION_UD);
810 return FALSE;
811 }
812
813 /* Check for protected mode */
814 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
815 {
816 /* Check IOPL */
817 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
818 {
819 /* Set the interrupt flag */
820 State->Flags.If = TRUE;
821 }
822 else
823 {
824 /* General Protection Fault */
825 Fast486Exception(State, FAST486_EXCEPTION_GP);
826 return FALSE;
827 }
828 }
829 else
830 {
831 /* Just set the interrupt flag */
832 State->Flags.If = TRUE;
833 }
834
835 /* Return success */
836 return TRUE;
837 }
838
839 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir)
840 {
841 /* Make sure this is the right instruction */
842 ASSERT(Opcode == 0xFC);
843
844 /* No prefixes allowed */
845 if (State->PrefixFlags)
846 {
847 Fast486Exception(State, FAST486_EXCEPTION_UD);
848 return FALSE;
849 }
850
851 /* Clear DF and return success */
852 State->Flags.Df = FALSE;
853 return TRUE;
854 }
855
856 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir)
857 {
858 /* Make sure this is the right instruction */
859 ASSERT(Opcode == 0xFD);
860
861 /* No prefixes allowed */
862 if (State->PrefixFlags)
863 {
864 Fast486Exception(State, FAST486_EXCEPTION_UD);
865 return FALSE;
866 }
867
868 /* Set DF and return success*/
869 State->Flags.Df = TRUE;
870 return TRUE;
871 }
872
873 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
874 {
875 /* Make sure this is the right instruction */
876 ASSERT(Opcode == 0xF4);
877
878 /* No prefixes allowed */
879 if (State->PrefixFlags)
880 {
881 Fast486Exception(State, FAST486_EXCEPTION_UD);
882 return FALSE;
883 }
884
885 /* Privileged instructions can only be executed under CPL = 0 */
886 if (State->SegmentRegs[FAST486_REG_CS].Dpl != 0)
887 {
888 Fast486Exception(State, FAST486_EXCEPTION_GP);
889 return FALSE;
890 }
891
892 /* Halt */
893 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
894
895 /* Return success */
896 return TRUE;
897 }
898
899 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte)
900 {
901 UCHAR Data;
902 ULONG Port;
903
904 /* Make sure this is the right instruction */
905 ASSERT((Opcode & 0xF7) == 0xE4);
906
907 if (Opcode == 0xE4)
908 {
909 /* Fetch the parameter */
910 if (!Fast486FetchByte(State, &Data))
911 {
912 /* Exception occurred */
913 return FALSE;
914 }
915
916 /* Set the port number to the parameter */
917 Port = Data;
918 }
919 else
920 {
921 /* The port number is in DX */
922 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
923 }
924
925 /* Read a byte from the I/O port */
926 State->IoReadCallback(State, Port, &Data, 1, sizeof(UCHAR));
927
928 /* Store the result in AL */
929 State->GeneralRegs[FAST486_REG_EAX].LowByte = Data;
930
931 return TRUE;
932 }
933
934 FAST486_OPCODE_HANDLER(Fast486OpcodeIn)
935 {
936 ULONG Port;
937 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
938
939 /* Make sure this is the right instruction */
940 ASSERT((Opcode & 0xF7) == 0xE5);
941
942 TOGGLE_OPSIZE(Size);
943 NO_LOCK_PREFIX();
944
945 if (Opcode == 0xE5)
946 {
947 UCHAR Data;
948
949 /* Fetch the parameter */
950 if (!Fast486FetchByte(State, &Data))
951 {
952 /* Exception occurred */
953 return FALSE;
954 }
955
956 /* Set the port number to the parameter */
957 Port = Data;
958 }
959 else
960 {
961 /* The port number is in DX */
962 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
963 }
964
965 if (Size)
966 {
967 ULONG Data;
968
969 /* Read a dword from the I/O port */
970 State->IoReadCallback(State, Port, &Data, 1, sizeof(ULONG));
971
972 /* Store the value in EAX */
973 State->GeneralRegs[FAST486_REG_EAX].Long = Data;
974 }
975 else
976 {
977 USHORT Data;
978
979 /* Read a word from the I/O port */
980 State->IoReadCallback(State, Port, &Data, 1, sizeof(USHORT));
981
982 /* Store the value in AX */
983 State->GeneralRegs[FAST486_REG_EAX].LowWord = Data;
984 }
985
986 return TRUE;
987 }
988
989 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte)
990 {
991 UCHAR Data;
992 ULONG Port;
993
994 /* Make sure this is the right instruction */
995 ASSERT((Opcode & 0xF7) == 0xE6);
996
997 if (Opcode == 0xE6)
998 {
999 /* Fetch the parameter */
1000 if (!Fast486FetchByte(State, &Data))
1001 {
1002 /* Exception occurred */
1003 return FALSE;
1004 }
1005
1006 /* Set the port number to the parameter */
1007 Port = Data;
1008 }
1009 else
1010 {
1011 /* The port number is in DX */
1012 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1013 }
1014
1015 /* Read the value from AL */
1016 Data = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1017
1018 /* Write the byte to the I/O port */
1019 State->IoWriteCallback(State, Port, &Data, 1, sizeof(UCHAR));
1020
1021 return TRUE;
1022 }
1023
1024 FAST486_OPCODE_HANDLER(Fast486OpcodeOut)
1025 {
1026 ULONG Port;
1027 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1028
1029 /* Make sure this is the right instruction */
1030 ASSERT((Opcode & 0xF7) == 0xE7);
1031
1032 TOGGLE_OPSIZE(Size);
1033 NO_LOCK_PREFIX();
1034
1035 if (Opcode == 0xE7)
1036 {
1037 UCHAR Data;
1038
1039 /* Fetch the parameter */
1040 if (!Fast486FetchByte(State, &Data))
1041 {
1042 /* Exception occurred */
1043 return FALSE;
1044 }
1045
1046 /* Set the port number to the parameter */
1047 Port = Data;
1048 }
1049 else
1050 {
1051 /* The port number is in DX */
1052 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1053 }
1054
1055 if (Size)
1056 {
1057 /* Get the value from EAX */
1058 ULONG Data = State->GeneralRegs[FAST486_REG_EAX].Long;
1059
1060 /* Write a dword to the I/O port */
1061 State->IoWriteCallback(State, Port, &Data, 1, sizeof(ULONG));
1062 }
1063 else
1064 {
1065 /* Get the value from AX */
1066 USHORT Data = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1067
1068 /* Write a word to the I/O port */
1069 State->IoWriteCallback(State, Port, &Data, 1, sizeof(USHORT));
1070 }
1071
1072 return TRUE;
1073 }
1074
1075 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump)
1076 {
1077 CHAR Offset = 0;
1078 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1079
1080 TOGGLE_OPSIZE(Size);
1081
1082 /* Make sure this is the right instruction */
1083 ASSERT(Opcode == 0xEB);
1084
1085 /* Fetch the offset */
1086 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1087 {
1088 /* An exception occurred */
1089 return FALSE;
1090 }
1091
1092 /* Move the instruction pointer */
1093 State->InstPtr.Long += Offset;
1094
1095 if (!Size)
1096 {
1097 /* Clear the top half of EIP */
1098 State->InstPtr.Long &= 0xFFFF;
1099 }
1100
1101 return TRUE;
1102 }
1103
1104 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm)
1105 {
1106 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1107
1108 /* Make sure this is the right instruction */
1109 ASSERT((Opcode & 0xF8) == 0xB8);
1110
1111 TOGGLE_OPSIZE(Size);
1112 NO_LOCK_PREFIX();
1113
1114 if (Size)
1115 {
1116 ULONG Value;
1117
1118 /* Fetch the dword */
1119 if (!Fast486FetchDword(State, &Value))
1120 {
1121 /* Exception occurred */
1122 return FALSE;
1123 }
1124
1125 /* Store the value in the register */
1126 State->GeneralRegs[Opcode & 0x07].Long = Value;
1127 }
1128 else
1129 {
1130 USHORT Value;
1131
1132 /* Fetch the word */
1133 if (!Fast486FetchWord(State, &Value))
1134 {
1135 /* Exception occurred */
1136 return FALSE;
1137 }
1138
1139 /* Store the value in the register */
1140 State->GeneralRegs[Opcode & 0x07].LowWord = Value;
1141 }
1142
1143 return TRUE;
1144 }
1145
1146 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm)
1147 {
1148 UCHAR Value;
1149
1150 /* Make sure this is the right instruction */
1151 ASSERT((Opcode & 0xF8) == 0xB0);
1152
1153 if (State->PrefixFlags != 0)
1154 {
1155 /* Invalid prefix */
1156 Fast486Exception(State, FAST486_EXCEPTION_UD);
1157 return FALSE;
1158 }
1159
1160 /* Fetch the byte */
1161 if (!Fast486FetchByte(State, &Value))
1162 {
1163 /* Exception occurred */
1164 return FALSE;
1165 }
1166
1167 if (Opcode & 0x04)
1168 {
1169 /* AH, CH, DH or BH */
1170 State->GeneralRegs[Opcode & 0x03].HighByte = Value;
1171 }
1172 else
1173 {
1174 /* AL, CL, DL or BL */
1175 State->GeneralRegs[Opcode & 0x03].LowByte = Value;
1176 }
1177
1178 return TRUE;
1179 }
1180
1181 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm)
1182 {
1183 UCHAR FirstValue, SecondValue, Result;
1184 FAST486_MOD_REG_RM ModRegRm;
1185 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1186
1187 /* Make sure this is the right instruction */
1188 ASSERT((Opcode & 0xFD) == 0x00);
1189
1190 TOGGLE_ADSIZE(AddressSize);
1191
1192 /* Get the operands */
1193 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1194 {
1195 /* Exception occurred */
1196 return FALSE;
1197 }
1198
1199 if (!Fast486ReadModrmByteOperands(State,
1200 &ModRegRm,
1201 &FirstValue,
1202 &SecondValue))
1203 {
1204 /* Exception occurred */
1205 return FALSE;
1206 }
1207
1208 /* Calculate the result */
1209 Result = FirstValue + SecondValue;
1210
1211 /* Update the flags */
1212 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1213 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1214 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1215 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1216 State->Flags.Zf = (Result == 0);
1217 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1218 State->Flags.Pf = Fast486CalculateParity(Result);
1219
1220 /* Write back the result */
1221 return Fast486WriteModrmByteOperands(State,
1222 &ModRegRm,
1223 Opcode & FAST486_OPCODE_WRITE_REG,
1224 Result);
1225 }
1226
1227 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm)
1228 {
1229 FAST486_MOD_REG_RM ModRegRm;
1230 BOOLEAN OperandSize, AddressSize;
1231
1232 /* Make sure this is the right instruction */
1233 ASSERT((Opcode & 0xFD) == 0x01);
1234
1235 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1236
1237 TOGGLE_ADSIZE(AddressSize);
1238 TOGGLE_OPSIZE(OperandSize);
1239
1240 /* Get the operands */
1241 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1242 {
1243 /* Exception occurred */
1244 return FALSE;
1245 }
1246
1247 /* Check the operand size */
1248 if (OperandSize)
1249 {
1250 ULONG FirstValue, SecondValue, Result;
1251
1252 if (!Fast486ReadModrmDwordOperands(State,
1253 &ModRegRm,
1254 &FirstValue,
1255 &SecondValue))
1256 {
1257 /* Exception occurred */
1258 return FALSE;
1259 }
1260
1261 /* Calculate the result */
1262 Result = FirstValue + SecondValue;
1263
1264 /* Update the flags */
1265 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1266 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1267 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1268 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1269 State->Flags.Zf = (Result == 0);
1270 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1271 State->Flags.Pf = Fast486CalculateParity(Result);
1272
1273 /* Write back the result */
1274 return Fast486WriteModrmDwordOperands(State,
1275 &ModRegRm,
1276 Opcode & FAST486_OPCODE_WRITE_REG,
1277 Result);
1278 }
1279 else
1280 {
1281 USHORT FirstValue, SecondValue, Result;
1282
1283 if (!Fast486ReadModrmWordOperands(State,
1284 &ModRegRm,
1285 &FirstValue,
1286 &SecondValue))
1287 {
1288 /* Exception occurred */
1289 return FALSE;
1290 }
1291
1292 /* Calculate the result */
1293 Result = FirstValue + SecondValue;
1294
1295 /* Update the flags */
1296 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1297 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1298 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1299 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1300 State->Flags.Zf = (Result == 0);
1301 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1302 State->Flags.Pf = Fast486CalculateParity(Result);
1303
1304 /* Write back the result */
1305 return Fast486WriteModrmWordOperands(State,
1306 &ModRegRm,
1307 Opcode & FAST486_OPCODE_WRITE_REG,
1308 Result);
1309 }
1310 }
1311
1312 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl)
1313 {
1314 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1315 UCHAR SecondValue, Result;
1316
1317 /* Make sure this is the right instruction */
1318 ASSERT(Opcode == 0x04);
1319
1320 if (State->PrefixFlags)
1321 {
1322 /* This opcode doesn't take any prefixes */
1323 Fast486Exception(State, FAST486_EXCEPTION_UD);
1324 return FALSE;
1325 }
1326
1327 if (!Fast486FetchByte(State, &SecondValue))
1328 {
1329 /* Exception occurred */
1330 return FALSE;
1331 }
1332
1333 /* Calculate the result */
1334 Result = FirstValue + SecondValue;
1335
1336 /* Update the flags */
1337 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1338 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1339 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1340 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1341 State->Flags.Zf = (Result == 0);
1342 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1343 State->Flags.Pf = Fast486CalculateParity(Result);
1344
1345 /* Write back the result */
1346 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1347
1348 return TRUE;
1349 }
1350
1351 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax)
1352 {
1353 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1354
1355 /* Make sure this is the right instruction */
1356 ASSERT(Opcode == 0x05);
1357
1358 NO_LOCK_PREFIX();
1359 TOGGLE_OPSIZE(Size);
1360
1361 if (Size)
1362 {
1363 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1364 ULONG SecondValue, Result;
1365
1366 if (!Fast486FetchDword(State, &SecondValue))
1367 {
1368 /* Exception occurred */
1369 return FALSE;
1370 }
1371
1372 /* Calculate the result */
1373 Result = FirstValue + SecondValue;
1374
1375 /* Update the flags */
1376 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1377 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1378 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1379 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1380 State->Flags.Zf = (Result == 0);
1381 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1382 State->Flags.Pf = Fast486CalculateParity(Result);
1383
1384 /* Write back the result */
1385 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1386 }
1387 else
1388 {
1389 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1390 USHORT SecondValue, Result;
1391
1392 if (!Fast486FetchWord(State, &SecondValue))
1393 {
1394 /* Exception occurred */
1395 return FALSE;
1396 }
1397
1398 /* Calculate the result */
1399 Result = FirstValue + SecondValue;
1400
1401 /* Update the flags */
1402 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1403 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1404 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1405 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1406 State->Flags.Zf = (Result == 0);
1407 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1408 State->Flags.Pf = Fast486CalculateParity(Result);
1409
1410 /* Write back the result */
1411 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1412 }
1413
1414 return TRUE;
1415 }
1416
1417 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm)
1418 {
1419 UCHAR FirstValue, SecondValue, Result;
1420 FAST486_MOD_REG_RM ModRegRm;
1421 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1422
1423 /* Make sure this is the right instruction */
1424 ASSERT((Opcode & 0xFD) == 0x08);
1425
1426 TOGGLE_ADSIZE(AddressSize);
1427
1428 /* Get the operands */
1429 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1430 {
1431 /* Exception occurred */
1432 return FALSE;
1433 }
1434
1435 if (!Fast486ReadModrmByteOperands(State,
1436 &ModRegRm,
1437 &FirstValue,
1438 &SecondValue))
1439 {
1440 /* Exception occurred */
1441 return FALSE;
1442 }
1443
1444 /* Calculate the result */
1445 Result = FirstValue | SecondValue;
1446
1447 /* Update the flags */
1448 State->Flags.Cf = FALSE;
1449 State->Flags.Of = FALSE;
1450 State->Flags.Zf = (Result == 0);
1451 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1452 State->Flags.Pf = Fast486CalculateParity(Result);
1453
1454 /* Write back the result */
1455 return Fast486WriteModrmByteOperands(State,
1456 &ModRegRm,
1457 Opcode & FAST486_OPCODE_WRITE_REG,
1458 Result);
1459 }
1460
1461 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm)
1462 {
1463 FAST486_MOD_REG_RM ModRegRm;
1464 BOOLEAN OperandSize, AddressSize;
1465
1466 /* Make sure this is the right instruction */
1467 ASSERT((Opcode & 0xFD) == 0x09);
1468
1469 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1470
1471 TOGGLE_ADSIZE(AddressSize);
1472 TOGGLE_OPSIZE(OperandSize);
1473
1474 /* Get the operands */
1475 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1476 {
1477 /* Exception occurred */
1478 return FALSE;
1479 }
1480
1481 /* Check the operand size */
1482 if (OperandSize)
1483 {
1484 ULONG FirstValue, SecondValue, Result;
1485
1486 if (!Fast486ReadModrmDwordOperands(State,
1487 &ModRegRm,
1488 &FirstValue,
1489 &SecondValue))
1490 {
1491 /* Exception occurred */
1492 return FALSE;
1493 }
1494
1495 /* Calculate the result */
1496 Result = FirstValue | SecondValue;
1497
1498 /* Update the flags */
1499 State->Flags.Cf = FALSE;
1500 State->Flags.Of = FALSE;
1501 State->Flags.Zf = (Result == 0);
1502 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1503 State->Flags.Pf = Fast486CalculateParity(Result);
1504
1505 /* Write back the result */
1506 return Fast486WriteModrmDwordOperands(State,
1507 &ModRegRm,
1508 Opcode & FAST486_OPCODE_WRITE_REG,
1509 Result);
1510 }
1511 else
1512 {
1513 USHORT FirstValue, SecondValue, Result;
1514
1515 if (!Fast486ReadModrmWordOperands(State,
1516 &ModRegRm,
1517 &FirstValue,
1518 &SecondValue))
1519 {
1520 /* Exception occurred */
1521 return FALSE;
1522 }
1523
1524 /* Calculate the result */
1525 Result = FirstValue | SecondValue;
1526
1527 /* Update the flags */
1528 State->Flags.Cf = FALSE;
1529 State->Flags.Of = FALSE;
1530 State->Flags.Zf = (Result == 0);
1531 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1532 State->Flags.Pf = Fast486CalculateParity(Result);
1533
1534 /* Write back the result */
1535 return Fast486WriteModrmWordOperands(State,
1536 &ModRegRm,
1537 Opcode & FAST486_OPCODE_WRITE_REG,
1538 Result);
1539 }
1540 }
1541
1542 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl)
1543 {
1544 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1545 UCHAR SecondValue, Result;
1546
1547 /* Make sure this is the right instruction */
1548 ASSERT(Opcode == 0x0C);
1549
1550 if (State->PrefixFlags)
1551 {
1552 /* This opcode doesn't take any prefixes */
1553 Fast486Exception(State, FAST486_EXCEPTION_UD);
1554 return FALSE;
1555 }
1556
1557 if (!Fast486FetchByte(State, &SecondValue))
1558 {
1559 /* Exception occurred */
1560 return FALSE;
1561 }
1562
1563 /* Calculate the result */
1564 Result = FirstValue | SecondValue;
1565
1566 /* Update the flags */
1567 State->Flags.Cf = FALSE;
1568 State->Flags.Of = FALSE;
1569 State->Flags.Zf = (Result == 0);
1570 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1571 State->Flags.Pf = Fast486CalculateParity(Result);
1572
1573 /* Write back the result */
1574 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1575
1576 return TRUE;
1577 }
1578
1579 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax)
1580 {
1581 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1582
1583 /* Make sure this is the right instruction */
1584 ASSERT(Opcode == 0x0D);
1585
1586 NO_LOCK_PREFIX();
1587 TOGGLE_OPSIZE(Size);
1588
1589 if (Size)
1590 {
1591 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1592 ULONG SecondValue, Result;
1593
1594 if (!Fast486FetchDword(State, &SecondValue))
1595 {
1596 /* Exception occurred */
1597 return FALSE;
1598 }
1599
1600 /* Calculate the result */
1601 Result = FirstValue | SecondValue;
1602
1603 /* Update the flags */
1604 State->Flags.Cf = FALSE;
1605 State->Flags.Of = FALSE;
1606 State->Flags.Zf = (Result == 0);
1607 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1608 State->Flags.Pf = Fast486CalculateParity(Result);
1609
1610 /* Write back the result */
1611 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1612 }
1613 else
1614 {
1615 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1616 USHORT SecondValue, Result;
1617
1618 if (!Fast486FetchWord(State, &SecondValue))
1619 {
1620 /* Exception occurred */
1621 return FALSE;
1622 }
1623
1624 /* Calculate the result */
1625 Result = FirstValue | SecondValue;
1626
1627 /* Update the flags */
1628 State->Flags.Cf = FALSE;
1629 State->Flags.Of = FALSE;
1630 State->Flags.Zf = (Result == 0);
1631 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1632 State->Flags.Pf = Fast486CalculateParity(Result);
1633
1634 /* Write back the result */
1635 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1636 }
1637
1638 return TRUE;
1639 }
1640
1641 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm)
1642 {
1643 UCHAR FirstValue, SecondValue, Result;
1644 FAST486_MOD_REG_RM ModRegRm;
1645 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1646
1647 /* Make sure this is the right instruction */
1648 ASSERT((Opcode & 0xFD) == 0x20);
1649
1650 TOGGLE_ADSIZE(AddressSize);
1651
1652 /* Get the operands */
1653 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1654 {
1655 /* Exception occurred */
1656 return FALSE;
1657 }
1658
1659 if (!Fast486ReadModrmByteOperands(State,
1660 &ModRegRm,
1661 &FirstValue,
1662 &SecondValue))
1663 {
1664 /* Exception occurred */
1665 return FALSE;
1666 }
1667
1668 /* Calculate the result */
1669 Result = FirstValue & SecondValue;
1670
1671 /* Update the flags */
1672 State->Flags.Cf = FALSE;
1673 State->Flags.Of = FALSE;
1674 State->Flags.Zf = (Result == 0);
1675 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1676 State->Flags.Pf = Fast486CalculateParity(Result);
1677
1678 /* Write back the result */
1679 return Fast486WriteModrmByteOperands(State,
1680 &ModRegRm,
1681 Opcode & FAST486_OPCODE_WRITE_REG,
1682 Result);
1683 }
1684
1685 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm)
1686 {
1687 FAST486_MOD_REG_RM ModRegRm;
1688 BOOLEAN OperandSize, AddressSize;
1689
1690 /* Make sure this is the right instruction */
1691 ASSERT((Opcode & 0xFD) == 0x21);
1692
1693 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1694
1695 TOGGLE_ADSIZE(AddressSize);
1696 TOGGLE_OPSIZE(OperandSize);
1697
1698 /* Get the operands */
1699 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1700 {
1701 /* Exception occurred */
1702 return FALSE;
1703 }
1704
1705 /* Check the operand size */
1706 if (OperandSize)
1707 {
1708 ULONG FirstValue, SecondValue, Result;
1709
1710 if (!Fast486ReadModrmDwordOperands(State,
1711 &ModRegRm,
1712 &FirstValue,
1713 &SecondValue))
1714 {
1715 /* Exception occurred */
1716 return FALSE;
1717 }
1718
1719 /* Calculate the result */
1720 Result = FirstValue & SecondValue;
1721
1722 /* Update the flags */
1723 State->Flags.Cf = FALSE;
1724 State->Flags.Of = FALSE;
1725 State->Flags.Zf = (Result == 0);
1726 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1727 State->Flags.Pf = Fast486CalculateParity(Result);
1728
1729 /* Write back the result */
1730 return Fast486WriteModrmDwordOperands(State,
1731 &ModRegRm,
1732 Opcode & FAST486_OPCODE_WRITE_REG,
1733 Result);
1734 }
1735 else
1736 {
1737 USHORT FirstValue, SecondValue, Result;
1738
1739 if (!Fast486ReadModrmWordOperands(State,
1740 &ModRegRm,
1741 &FirstValue,
1742 &SecondValue))
1743 {
1744 /* Exception occurred */
1745 return FALSE;
1746 }
1747
1748 /* Calculate the result */
1749 Result = FirstValue & SecondValue;
1750
1751 /* Update the flags */
1752 State->Flags.Cf = FALSE;
1753 State->Flags.Of = FALSE;
1754 State->Flags.Zf = (Result == 0);
1755 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1756 State->Flags.Pf = Fast486CalculateParity(Result);
1757
1758 /* Write back the result */
1759 return Fast486WriteModrmWordOperands(State,
1760 &ModRegRm,
1761 Opcode & FAST486_OPCODE_WRITE_REG,
1762 Result);
1763 }
1764 }
1765
1766 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl)
1767 {
1768 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1769 UCHAR SecondValue, Result;
1770
1771 /* Make sure this is the right instruction */
1772 ASSERT(Opcode == 0x24);
1773
1774 NO_LOCK_PREFIX();
1775
1776 if (!Fast486FetchByte(State, &SecondValue))
1777 {
1778 /* Exception occurred */
1779 return FALSE;
1780 }
1781
1782 /* Calculate the result */
1783 Result = FirstValue & SecondValue;
1784
1785 /* Update the flags */
1786 State->Flags.Cf = FALSE;
1787 State->Flags.Of = FALSE;
1788 State->Flags.Zf = (Result == 0);
1789 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1790 State->Flags.Pf = Fast486CalculateParity(Result);
1791
1792 /* Write back the result */
1793 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1794
1795 return TRUE;
1796 }
1797
1798 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax)
1799 {
1800 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1801
1802 /* Make sure this is the right instruction */
1803 ASSERT(Opcode == 0x25);
1804
1805 NO_LOCK_PREFIX();
1806 TOGGLE_OPSIZE(Size);
1807
1808 if (Size)
1809 {
1810 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1811 ULONG SecondValue, Result;
1812
1813 if (!Fast486FetchDword(State, &SecondValue))
1814 {
1815 /* Exception occurred */
1816 return FALSE;
1817 }
1818
1819 /* Calculate the result */
1820 Result = FirstValue & SecondValue;
1821
1822 /* Update the flags */
1823 State->Flags.Cf = FALSE;
1824 State->Flags.Of = FALSE;
1825 State->Flags.Zf = (Result == 0);
1826 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1827 State->Flags.Pf = Fast486CalculateParity(Result);
1828
1829 /* Write back the result */
1830 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1831 }
1832 else
1833 {
1834 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1835 USHORT SecondValue, Result;
1836
1837 if (!Fast486FetchWord(State, &SecondValue))
1838 {
1839 /* Exception occurred */
1840 return FALSE;
1841 }
1842
1843 /* Calculate the result */
1844 Result = FirstValue & SecondValue;
1845
1846 /* Update the flags */
1847 State->Flags.Cf = FALSE;
1848 State->Flags.Of = FALSE;
1849 State->Flags.Zf = (Result == 0);
1850 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1851 State->Flags.Pf = Fast486CalculateParity(Result);
1852
1853 /* Write back the result */
1854 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1855 }
1856
1857 return TRUE;
1858 }
1859
1860 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm)
1861 {
1862 UCHAR FirstValue, SecondValue, Result;
1863 FAST486_MOD_REG_RM ModRegRm;
1864 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1865
1866 /* Make sure this is the right instruction */
1867 ASSERT((Opcode & 0xFD) == 0x30);
1868
1869 TOGGLE_ADSIZE(AddressSize);
1870
1871 /* Get the operands */
1872 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1873 {
1874 /* Exception occurred */
1875 return FALSE;
1876 }
1877
1878 if (!Fast486ReadModrmByteOperands(State,
1879 &ModRegRm,
1880 &FirstValue,
1881 &SecondValue))
1882 {
1883 /* Exception occurred */
1884 return FALSE;
1885 }
1886
1887 /* Calculate the result */
1888 Result = FirstValue ^ SecondValue;
1889
1890 /* Update the flags */
1891 State->Flags.Cf = FALSE;
1892 State->Flags.Of = FALSE;
1893 State->Flags.Zf = (Result == 0);
1894 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1895 State->Flags.Pf = Fast486CalculateParity(Result);
1896
1897 /* Write back the result */
1898 return Fast486WriteModrmByteOperands(State,
1899 &ModRegRm,
1900 Opcode & FAST486_OPCODE_WRITE_REG,
1901 Result);
1902 }
1903
1904 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm)
1905 {
1906 FAST486_MOD_REG_RM ModRegRm;
1907 BOOLEAN OperandSize, AddressSize;
1908
1909 /* Make sure this is the right instruction */
1910 ASSERT((Opcode & 0xFD) == 0x31);
1911
1912 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1913
1914 TOGGLE_ADSIZE(AddressSize);
1915 TOGGLE_OPSIZE(OperandSize);
1916
1917 /* Get the operands */
1918 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1919 {
1920 /* Exception occurred */
1921 return FALSE;
1922 }
1923
1924 /* Check the operand size */
1925 if (OperandSize)
1926 {
1927 ULONG FirstValue, SecondValue, Result;
1928
1929 if (!Fast486ReadModrmDwordOperands(State,
1930 &ModRegRm,
1931 &FirstValue,
1932 &SecondValue))
1933 {
1934 /* Exception occurred */
1935 return FALSE;
1936 }
1937
1938 /* Calculate the result */
1939 Result = FirstValue ^ SecondValue;
1940
1941 /* Update the flags */
1942 State->Flags.Cf = FALSE;
1943 State->Flags.Of = FALSE;
1944 State->Flags.Zf = (Result == 0);
1945 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1946 State->Flags.Pf = Fast486CalculateParity(Result);
1947
1948 /* Write back the result */
1949 return Fast486WriteModrmDwordOperands(State,
1950 &ModRegRm,
1951 Opcode & FAST486_OPCODE_WRITE_REG,
1952 Result);
1953 }
1954 else
1955 {
1956 USHORT FirstValue, SecondValue, Result;
1957
1958 if (!Fast486ReadModrmWordOperands(State,
1959 &ModRegRm,
1960 &FirstValue,
1961 &SecondValue))
1962 {
1963 /* Exception occurred */
1964 return FALSE;
1965 }
1966
1967 /* Calculate the result */
1968 Result = FirstValue ^ SecondValue;
1969
1970 /* Update the flags */
1971 State->Flags.Cf = FALSE;
1972 State->Flags.Of = FALSE;
1973 State->Flags.Zf = (Result == 0);
1974 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1975 State->Flags.Pf = Fast486CalculateParity(Result);
1976
1977 /* Write back the result */
1978 return Fast486WriteModrmWordOperands(State,
1979 &ModRegRm,
1980 Opcode & FAST486_OPCODE_WRITE_REG,
1981 Result);
1982 }
1983 }
1984
1985 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl)
1986 {
1987 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1988 UCHAR SecondValue, Result;
1989
1990 /* Make sure this is the right instruction */
1991 ASSERT(Opcode == 0x34);
1992
1993 if (State->PrefixFlags)
1994 {
1995 /* This opcode doesn't take any prefixes */
1996 Fast486Exception(State, FAST486_EXCEPTION_UD);
1997 return FALSE;
1998 }
1999
2000 if (!Fast486FetchByte(State, &SecondValue))
2001 {
2002 /* Exception occurred */
2003 return FALSE;
2004 }
2005
2006 /* Calculate the result */
2007 Result = FirstValue ^ SecondValue;
2008
2009 /* Update the flags */
2010 State->Flags.Cf = FALSE;
2011 State->Flags.Of = FALSE;
2012 State->Flags.Zf = (Result == 0);
2013 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2014 State->Flags.Pf = Fast486CalculateParity(Result);
2015
2016 /* Write back the result */
2017 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2018
2019 return TRUE;
2020 }
2021
2022 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax)
2023 {
2024 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2025
2026 /* Make sure this is the right instruction */
2027 ASSERT(Opcode == 0x35);
2028
2029 NO_LOCK_PREFIX();
2030 TOGGLE_OPSIZE(Size);
2031
2032 if (Size)
2033 {
2034 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2035 ULONG SecondValue, Result;
2036
2037 if (!Fast486FetchDword(State, &SecondValue))
2038 {
2039 /* Exception occurred */
2040 return FALSE;
2041 }
2042
2043 /* Calculate the result */
2044 Result = FirstValue ^ SecondValue;
2045
2046 /* Update the flags */
2047 State->Flags.Cf = FALSE;
2048 State->Flags.Of = FALSE;
2049 State->Flags.Zf = (Result == 0);
2050 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2051 State->Flags.Pf = Fast486CalculateParity(Result);
2052
2053 /* Write back the result */
2054 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2055 }
2056 else
2057 {
2058 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2059 USHORT SecondValue, Result;
2060
2061 if (!Fast486FetchWord(State, &SecondValue))
2062 {
2063 /* Exception occurred */
2064 return FALSE;
2065 }
2066
2067 /* Calculate the result */
2068 Result = FirstValue ^ SecondValue;
2069
2070 /* Update the flags */
2071 State->Flags.Cf = FALSE;
2072 State->Flags.Of = FALSE;
2073 State->Flags.Zf = (Result == 0);
2074 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2075 State->Flags.Pf = Fast486CalculateParity(Result);
2076
2077 /* Write back the result */
2078 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2079 }
2080
2081 return TRUE;
2082 }
2083
2084 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm)
2085 {
2086 UCHAR FirstValue, SecondValue, Result;
2087 FAST486_MOD_REG_RM ModRegRm;
2088 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2089
2090 /* Make sure this is the right instruction */
2091 ASSERT(Opcode == 0x84);
2092
2093 TOGGLE_ADSIZE(AddressSize);
2094
2095 /* Get the operands */
2096 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2097 {
2098 /* Exception occurred */
2099 return FALSE;
2100 }
2101
2102 if (!Fast486ReadModrmByteOperands(State,
2103 &ModRegRm,
2104 &FirstValue,
2105 &SecondValue))
2106 {
2107 /* Exception occurred */
2108 return FALSE;
2109 }
2110 /* Calculate the result */
2111 Result = FirstValue & SecondValue;
2112
2113 /* Update the flags */
2114 State->Flags.Cf = FALSE;
2115 State->Flags.Of = FALSE;
2116 State->Flags.Zf = (Result == 0);
2117 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2118 State->Flags.Pf = Fast486CalculateParity(Result);
2119
2120 /* The result is discarded */
2121 return TRUE;
2122 }
2123
2124 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm)
2125 {
2126 FAST486_MOD_REG_RM ModRegRm;
2127 BOOLEAN OperandSize, AddressSize;
2128
2129 /* Make sure this is the right instruction */
2130 ASSERT(Opcode == 0x85);
2131
2132 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2133
2134 TOGGLE_ADSIZE(AddressSize);
2135 TOGGLE_OPSIZE(OperandSize);
2136
2137 /* Get the operands */
2138 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2139 {
2140 /* Exception occurred */
2141 return FALSE;
2142 }
2143
2144 /* Check the operand size */
2145 if (OperandSize)
2146 {
2147 ULONG FirstValue, SecondValue, Result;
2148
2149 if (!Fast486ReadModrmDwordOperands(State,
2150 &ModRegRm,
2151 &FirstValue,
2152 &SecondValue))
2153 {
2154 /* Exception occurred */
2155 return FALSE;
2156 }
2157
2158 /* Calculate the result */
2159 Result = FirstValue & SecondValue;
2160
2161 /* Update the flags */
2162 State->Flags.Cf = FALSE;
2163 State->Flags.Of = FALSE;
2164 State->Flags.Zf = (Result == 0);
2165 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2166 State->Flags.Pf = Fast486CalculateParity(Result);
2167 }
2168 else
2169 {
2170 USHORT FirstValue, SecondValue, Result;
2171
2172 if (!Fast486ReadModrmWordOperands(State,
2173 &ModRegRm,
2174 &FirstValue,
2175 &SecondValue))
2176 {
2177 /* Exception occurred */
2178 return FALSE;
2179 }
2180
2181 /* Calculate the result */
2182 Result = FirstValue & SecondValue;
2183
2184 /* Update the flags */
2185 State->Flags.Cf = FALSE;
2186 State->Flags.Of = FALSE;
2187 State->Flags.Zf = (Result == 0);
2188 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2189 State->Flags.Pf = Fast486CalculateParity(Result);
2190 }
2191
2192 /* The result is discarded */
2193 return TRUE;
2194 }
2195
2196 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl)
2197 {
2198 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2199 UCHAR SecondValue, Result;
2200
2201 /* Make sure this is the right instruction */
2202 ASSERT(Opcode == 0xA8);
2203
2204 if (State->PrefixFlags)
2205 {
2206 /* This opcode doesn't take any prefixes */
2207 Fast486Exception(State, FAST486_EXCEPTION_UD);
2208 return FALSE;
2209 }
2210
2211 if (!Fast486FetchByte(State, &SecondValue))
2212 {
2213 /* Exception occurred */
2214 return FALSE;
2215 }
2216
2217 /* Calculate the result */
2218 Result = FirstValue & SecondValue;
2219
2220 /* Update the flags */
2221 State->Flags.Cf = FALSE;
2222 State->Flags.Of = FALSE;
2223 State->Flags.Zf = (Result == 0);
2224 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2225 State->Flags.Pf = Fast486CalculateParity(Result);
2226
2227 /* The result is discarded */
2228 return TRUE;
2229 }
2230
2231 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax)
2232 {
2233 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2234
2235 /* Make sure this is the right instruction */
2236 ASSERT(Opcode == 0xA9);
2237
2238 NO_LOCK_PREFIX();
2239 TOGGLE_OPSIZE(Size);
2240
2241 if (Size)
2242 {
2243 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2244 ULONG SecondValue, Result;
2245
2246 if (!Fast486FetchDword(State, &SecondValue))
2247 {
2248 /* Exception occurred */
2249 return FALSE;
2250 }
2251
2252 /* Calculate the result */
2253 Result = FirstValue & SecondValue;
2254
2255 /* Update the flags */
2256 State->Flags.Cf = FALSE;
2257 State->Flags.Of = FALSE;
2258 State->Flags.Zf = (Result == 0);
2259 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2260 State->Flags.Pf = Fast486CalculateParity(Result);
2261 }
2262 else
2263 {
2264 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2265 USHORT SecondValue, Result;
2266
2267 if (!Fast486FetchWord(State, &SecondValue))
2268 {
2269 /* Exception occurred */
2270 return FALSE;
2271 }
2272
2273 /* Calculate the result */
2274 Result = FirstValue & SecondValue;
2275
2276 /* Update the flags */
2277 State->Flags.Cf = FALSE;
2278 State->Flags.Of = FALSE;
2279 State->Flags.Zf = (Result == 0);
2280 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2281 State->Flags.Pf = Fast486CalculateParity(Result);
2282 }
2283
2284 /* The result is discarded */
2285 return TRUE;
2286 }
2287
2288 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm)
2289 {
2290 UCHAR FirstValue, SecondValue;
2291 FAST486_MOD_REG_RM ModRegRm;
2292 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2293
2294 /* Make sure this is the right instruction */
2295 ASSERT(Opcode == 0x86);
2296
2297 TOGGLE_ADSIZE(AddressSize);
2298
2299 /* Get the operands */
2300 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2301 {
2302 /* Exception occurred */
2303 return FALSE;
2304 }
2305
2306 if (!Fast486ReadModrmByteOperands(State,
2307 &ModRegRm,
2308 &FirstValue,
2309 &SecondValue))
2310 {
2311 /* Exception occurred */
2312 return FALSE;
2313 }
2314
2315 /* Write the value from the register to the R/M */
2316 if (!Fast486WriteModrmByteOperands(State,
2317 &ModRegRm,
2318 FALSE,
2319 FirstValue))
2320 {
2321 /* Exception occurred */
2322 return FALSE;
2323 }
2324
2325 /* Write the value from the R/M to the register */
2326 if (!Fast486WriteModrmByteOperands(State,
2327 &ModRegRm,
2328 TRUE,
2329 SecondValue))
2330 {
2331 /* Exception occurred */
2332 return FALSE;
2333 }
2334
2335 return TRUE;
2336 }
2337
2338 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm)
2339 {
2340 FAST486_MOD_REG_RM ModRegRm;
2341 BOOLEAN OperandSize, AddressSize;
2342
2343 /* Make sure this is the right instruction */
2344 ASSERT(Opcode == 0x87);
2345
2346 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2347
2348 TOGGLE_ADSIZE(AddressSize);
2349 TOGGLE_OPSIZE(OperandSize);
2350
2351 /* Get the operands */
2352 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2353 {
2354 /* Exception occurred */
2355 return FALSE;
2356 }
2357
2358 /* Check the operand size */
2359 if (OperandSize)
2360 {
2361 ULONG FirstValue, SecondValue;
2362
2363 if (!Fast486ReadModrmDwordOperands(State,
2364 &ModRegRm,
2365 &FirstValue,
2366 &SecondValue))
2367 {
2368 /* Exception occurred */
2369 return FALSE;
2370 }
2371
2372 /* Write the value from the register to the R/M */
2373 if (!Fast486WriteModrmDwordOperands(State,
2374 &ModRegRm,
2375 FALSE,
2376 FirstValue))
2377 {
2378 /* Exception occurred */
2379 return FALSE;
2380 }
2381
2382 /* Write the value from the R/M to the register */
2383 if (!Fast486WriteModrmDwordOperands(State,
2384 &ModRegRm,
2385 TRUE,
2386 SecondValue))
2387 {
2388 /* Exception occurred */
2389 return FALSE;
2390 }
2391 }
2392 else
2393 {
2394 USHORT FirstValue, SecondValue;
2395
2396 if (!Fast486ReadModrmWordOperands(State,
2397 &ModRegRm,
2398 &FirstValue,
2399 &SecondValue))
2400 {
2401 /* Exception occurred */
2402 return FALSE;
2403 }
2404
2405 /* Write the value from the register to the R/M */
2406 if (!Fast486WriteModrmWordOperands(State,
2407 &ModRegRm,
2408 FALSE,
2409 FirstValue))
2410 {
2411 /* Exception occurred */
2412 return FALSE;
2413 }
2414
2415 /* Write the value from the R/M to the register */
2416 if (!Fast486WriteModrmWordOperands(State,
2417 &ModRegRm,
2418 TRUE,
2419 SecondValue))
2420 {
2421 /* Exception occurred */
2422 return FALSE;
2423 }
2424 }
2425
2426 /* The result is discarded */
2427 return TRUE;
2428 }
2429
2430 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs)
2431 {
2432 /* Call the internal API */
2433 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector);
2434 }
2435
2436 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs)
2437 {
2438 ULONG NewSelector;
2439
2440 if (!Fast486StackPop(State, &NewSelector))
2441 {
2442 /* Exception occurred */
2443 return FALSE;
2444 }
2445
2446 /* Call the internal API */
2447 return Fast486LoadSegment(State, FAST486_REG_ES, LOWORD(NewSelector));
2448 }
2449
2450 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs)
2451 {
2452 /* Call the internal API */
2453 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector);
2454 }
2455
2456 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm)
2457 {
2458 UCHAR FirstValue, SecondValue, Result;
2459 FAST486_MOD_REG_RM ModRegRm;
2460 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2461
2462 /* Make sure this is the right instruction */
2463 ASSERT((Opcode & 0xFD) == 0x10);
2464
2465 TOGGLE_ADSIZE(AddressSize);
2466
2467 /* Get the operands */
2468 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2469 {
2470 /* Exception occurred */
2471 return FALSE;
2472 }
2473
2474 if (!Fast486ReadModrmByteOperands(State,
2475 &ModRegRm,
2476 &FirstValue,
2477 &SecondValue))
2478 {
2479 /* Exception occurred */
2480 return FALSE;
2481 }
2482
2483 /* Calculate the result */
2484 Result = FirstValue + SecondValue + State->Flags.Cf;
2485
2486 /* Special exception for CF */
2487 State->Flags.Cf = State->Flags.Cf
2488 && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2489
2490 /* Update the flags */
2491 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2492 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2493 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2494 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2495 State->Flags.Zf = (Result == 0);
2496 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2497 State->Flags.Pf = Fast486CalculateParity(Result);
2498
2499 /* Write back the result */
2500 return Fast486WriteModrmByteOperands(State,
2501 &ModRegRm,
2502 Opcode & FAST486_OPCODE_WRITE_REG,
2503 Result);
2504 }
2505
2506 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm)
2507 {
2508 FAST486_MOD_REG_RM ModRegRm;
2509 BOOLEAN OperandSize, AddressSize;
2510
2511 /* Make sure this is the right instruction */
2512 ASSERT((Opcode & 0xFD) == 0x11);
2513
2514 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2515
2516 TOGGLE_ADSIZE(AddressSize);
2517 TOGGLE_OPSIZE(OperandSize);
2518
2519 /* Get the operands */
2520 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2521 {
2522 /* Exception occurred */
2523 return FALSE;
2524 }
2525
2526 /* Check the operand size */
2527 if (OperandSize)
2528 {
2529 ULONG FirstValue, SecondValue, Result;
2530
2531 if (!Fast486ReadModrmDwordOperands(State,
2532 &ModRegRm,
2533 &FirstValue,
2534 &SecondValue))
2535 {
2536 /* Exception occurred */
2537 return FALSE;
2538 }
2539
2540 /* Calculate the result */
2541 Result = FirstValue + SecondValue + State->Flags.Cf;
2542
2543 /* Special exception for CF */
2544 State->Flags.Cf = State->Flags.Cf
2545 && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2546
2547 /* Update the flags */
2548 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2549 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2550 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2551 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2552 State->Flags.Zf = (Result == 0);
2553 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2554 State->Flags.Pf = Fast486CalculateParity(Result);
2555
2556 /* Write back the result */
2557 return Fast486WriteModrmDwordOperands(State,
2558 &ModRegRm,
2559 Opcode & FAST486_OPCODE_WRITE_REG,
2560 Result);
2561 }
2562 else
2563 {
2564 USHORT FirstValue, SecondValue, Result;
2565
2566 if (!Fast486ReadModrmWordOperands(State,
2567 &ModRegRm,
2568 &FirstValue,
2569 &SecondValue))
2570 {
2571 /* Exception occurred */
2572 return FALSE;
2573 }
2574
2575 /* Calculate the result */
2576 Result = FirstValue + SecondValue + State->Flags.Cf;
2577
2578 /* Special exception for CF */
2579 State->Flags.Cf = State->Flags.Cf
2580 && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2581
2582 /* Update the flags */
2583 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2584 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2585 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2586 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2587 State->Flags.Zf = (Result == 0);
2588 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2589 State->Flags.Pf = Fast486CalculateParity(Result);
2590
2591 /* Write back the result */
2592 return Fast486WriteModrmWordOperands(State,
2593 &ModRegRm,
2594 Opcode & FAST486_OPCODE_WRITE_REG,
2595 Result);
2596 }
2597
2598 }
2599
2600 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl)
2601 {
2602 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2603 UCHAR SecondValue, Result;
2604
2605 /* Make sure this is the right instruction */
2606 ASSERT(Opcode == 0x14);
2607
2608 if (State->PrefixFlags)
2609 {
2610 /* This opcode doesn't take any prefixes */
2611 Fast486Exception(State, FAST486_EXCEPTION_UD);
2612 return FALSE;
2613 }
2614
2615 if (!Fast486FetchByte(State, &SecondValue))
2616 {
2617 /* Exception occurred */
2618 return FALSE;
2619 }
2620
2621 /* Calculate the result */
2622 Result = FirstValue + SecondValue + State->Flags.Cf;
2623
2624 /* Special exception for CF */
2625 State->Flags.Cf = State->Flags.Cf &&
2626 ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2627
2628 /* Update the flags */
2629 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2630 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2631 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2632 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2633 State->Flags.Zf = (Result == 0);
2634 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2635 State->Flags.Pf = Fast486CalculateParity(Result);
2636
2637 /* Write back the result */
2638 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2639
2640 return TRUE;
2641 }
2642
2643 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax)
2644 {
2645 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2646
2647 /* Make sure this is the right instruction */
2648 ASSERT(Opcode == 0x15);
2649
2650 NO_LOCK_PREFIX();
2651 TOGGLE_OPSIZE(Size);
2652
2653 if (Size)
2654 {
2655 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2656 ULONG SecondValue, Result;
2657
2658 if (!Fast486FetchDword(State, &SecondValue))
2659 {
2660 /* Exception occurred */
2661 return FALSE;
2662 }
2663
2664 /* Calculate the result */
2665 Result = FirstValue + SecondValue + State->Flags.Cf;
2666
2667 /* Special exception for CF */
2668 State->Flags.Cf = State->Flags.Cf &&
2669 ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2670
2671 /* Update the flags */
2672 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2673 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2674 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2675 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2676 State->Flags.Zf = (Result == 0);
2677 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2678 State->Flags.Pf = Fast486CalculateParity(Result);
2679
2680 /* Write back the result */
2681 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2682 }
2683 else
2684 {
2685 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2686 USHORT SecondValue, Result;
2687
2688 if (!Fast486FetchWord(State, &SecondValue))
2689 {
2690 /* Exception occurred */
2691 return FALSE;
2692 }
2693
2694 /* Calculate the result */
2695 Result = FirstValue + SecondValue + State->Flags.Cf;
2696
2697 /* Special exception for CF */
2698 State->Flags.Cf = State->Flags.Cf &&
2699 ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2700
2701 /* Update the flags */
2702 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2703 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2704 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2705 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2706 State->Flags.Zf = (Result == 0);
2707 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2708 State->Flags.Pf = Fast486CalculateParity(Result);
2709
2710 /* Write back the result */
2711 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2712 }
2713
2714 return TRUE;
2715 }
2716
2717 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs)
2718 {
2719 /* Call the internal API */
2720 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_SS].Selector);
2721 }
2722
2723 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs)
2724 {
2725 ULONG NewSelector;
2726
2727 if (!Fast486StackPop(State, &NewSelector))
2728 {
2729 /* Exception occurred */
2730 return FALSE;
2731 }
2732
2733 /* Call the internal API */
2734 return Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector));
2735 }
2736
2737 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
2738 {
2739 UCHAR FirstValue, SecondValue, Result;
2740 FAST486_MOD_REG_RM ModRegRm;
2741 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2742 INT Carry = State->Flags.Cf ? 1 : 0;
2743
2744 /* Make sure this is the right instruction */
2745 ASSERT((Opcode & 0xFD) == 0x18);
2746
2747 TOGGLE_ADSIZE(AddressSize);
2748
2749 /* Get the operands */
2750 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2751 {
2752 /* Exception occurred */
2753 return FALSE;
2754 }
2755
2756 if (!Fast486ReadModrmByteOperands(State,
2757 &ModRegRm,
2758 &FirstValue,
2759 &SecondValue))
2760 {
2761 /* Exception occurred */
2762 return FALSE;
2763 }
2764
2765 /* Check if this is the instruction that writes to R/M */
2766 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2767 {
2768 /* Swap the order */
2769 SWAP(FirstValue, SecondValue);
2770 }
2771
2772 /* Calculate the result */
2773 Result = FirstValue - SecondValue - Carry;
2774
2775 /* Update the flags */
2776 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2777 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2778 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2779 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2780 State->Flags.Zf = (Result == 0);
2781 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2782 State->Flags.Pf = Fast486CalculateParity(Result);
2783
2784 /* Write back the result */
2785 return Fast486WriteModrmByteOperands(State,
2786 &ModRegRm,
2787 Opcode & FAST486_OPCODE_WRITE_REG,
2788 Result);
2789 }
2790
2791 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm)
2792 {
2793 FAST486_MOD_REG_RM ModRegRm;
2794 BOOLEAN OperandSize, AddressSize;
2795 INT Carry = State->Flags.Cf ? 1 : 0;
2796
2797 /* Make sure this is the right instruction */
2798 ASSERT((Opcode & 0xFD) == 0x19);
2799
2800 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2801
2802 TOGGLE_ADSIZE(AddressSize);
2803 TOGGLE_OPSIZE(OperandSize);
2804
2805 /* Get the operands */
2806 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2807 {
2808 /* Exception occurred */
2809 return FALSE;
2810 }
2811
2812 /* Check the operand size */
2813 if (OperandSize)
2814 {
2815 ULONG FirstValue, SecondValue, Result;
2816
2817 if (!Fast486ReadModrmDwordOperands(State,
2818 &ModRegRm,
2819 &FirstValue,
2820 &SecondValue))
2821 {
2822 /* Exception occurred */
2823 return FALSE;
2824 }
2825
2826 /* Check if this is the instruction that writes to R/M */
2827 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2828 {
2829 /* Swap the order */
2830 SWAP(FirstValue, SecondValue);
2831 }
2832
2833 /* Calculate the result */
2834 Result = FirstValue - SecondValue - Carry;
2835
2836 /* Update the flags */
2837 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2838 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2839 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2840 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2841 State->Flags.Zf = (Result == 0);
2842 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2843 State->Flags.Pf = Fast486CalculateParity(Result);
2844
2845 /* Write back the result */
2846 return Fast486WriteModrmDwordOperands(State,
2847 &ModRegRm,
2848 Opcode & FAST486_OPCODE_WRITE_REG,
2849 Result);
2850 }
2851 else
2852 {
2853 USHORT FirstValue, SecondValue, Result;
2854
2855 if (!Fast486ReadModrmWordOperands(State,
2856 &ModRegRm,
2857 &FirstValue,
2858 &SecondValue))
2859 {
2860 /* Exception occurred */
2861 return FALSE;
2862 }
2863
2864 /* Check if this is the instruction that writes to R/M */
2865 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2866 {
2867 /* Swap the order */
2868 SWAP(FirstValue, SecondValue);
2869 }
2870
2871 /* Calculate the result */
2872 Result = FirstValue - SecondValue - Carry;
2873
2874 /* Update the flags */
2875 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2876 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2877 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2878 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2879 State->Flags.Zf = (Result == 0);
2880 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2881 State->Flags.Pf = Fast486CalculateParity(Result);
2882
2883 /* Write back the result */
2884 return Fast486WriteModrmWordOperands(State,
2885 &ModRegRm,
2886 Opcode & FAST486_OPCODE_WRITE_REG,
2887 Result);
2888 }
2889 }
2890
2891 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl)
2892 {
2893 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2894 UCHAR SecondValue, Result;
2895 INT Carry = State->Flags.Cf ? 1 : 0;
2896
2897 /* Make sure this is the right instruction */
2898 ASSERT(Opcode == 0x1C);
2899
2900 if (State->PrefixFlags)
2901 {
2902 /* This opcode doesn't take any prefixes */
2903 Fast486Exception(State, FAST486_EXCEPTION_UD);
2904 return FALSE;
2905 }
2906
2907 if (!Fast486FetchByte(State, &SecondValue))
2908 {
2909 /* Exception occurred */
2910 return FALSE;
2911 }
2912
2913 /* Calculate the result */
2914 Result = FirstValue - SecondValue - Carry;
2915
2916 /* Update the flags */
2917 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2918 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2919 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2920 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2921 State->Flags.Zf = (Result == 0);
2922 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2923 State->Flags.Pf = Fast486CalculateParity(Result);
2924
2925 /* Write back the result */
2926 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2927
2928 return TRUE;
2929
2930 }
2931
2932 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax)
2933 {
2934 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2935 INT Carry = State->Flags.Cf ? 1 : 0;
2936
2937 /* Make sure this is the right instruction */
2938 ASSERT(Opcode == 0x1D);
2939
2940 NO_LOCK_PREFIX();
2941 TOGGLE_OPSIZE(Size);
2942
2943 if (Size)
2944 {
2945 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2946 ULONG SecondValue, Result;
2947
2948 if (!Fast486FetchDword(State, &SecondValue))
2949 {
2950 /* Exception occurred */
2951 return FALSE;
2952 }
2953
2954 /* Calculate the result */
2955 Result = FirstValue - SecondValue - Carry;
2956
2957 /* Update the flags */
2958 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2959 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2960 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2961 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2962 State->Flags.Zf = (Result == 0);
2963 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2964 State->Flags.Pf = Fast486CalculateParity(Result);
2965
2966 /* Write back the result */
2967 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2968 }
2969 else
2970 {
2971 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2972 USHORT SecondValue, Result;
2973
2974 if (!Fast486FetchWord(State, &SecondValue))
2975 {
2976 /* Exception occurred */
2977 return FALSE;
2978 }
2979
2980 /* Calculate the result */
2981 Result = FirstValue - SecondValue - Carry;
2982
2983 /* Update the flags */
2984 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2985 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2986 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2987 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2988 State->Flags.Zf = (Result == 0);
2989 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2990 State->Flags.Pf = Fast486CalculateParity(Result);
2991
2992 /* Write back the result */
2993 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2994 }
2995
2996 return TRUE;
2997
2998 }
2999
3000 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs)
3001 {
3002 /* Call the internal API */
3003 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector);
3004 }
3005
3006 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs)
3007 {
3008 ULONG NewSelector;
3009
3010 if (!Fast486StackPop(State, &NewSelector))
3011 {
3012 /* Exception occurred */
3013 return FALSE;
3014 }
3015
3016 /* Call the internal API */
3017 return Fast486LoadSegment(State, FAST486_REG_DS, LOWORD(NewSelector));
3018 }
3019
3020 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa)
3021 {
3022 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3023 BOOLEAN Carry = State->Flags.Cf;
3024
3025 /* Clear the carry flag */
3026 State->Flags.Cf = FALSE;
3027
3028 /* Check if the first BCD digit is invalid or there was a carry from it */
3029 if (((Value & 0x0F) > 9) || State->Flags.Af)
3030 {
3031 /* Correct it */
3032 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x06;
3033 if (State->GeneralRegs[FAST486_REG_EAX].LowByte < 0x06)
3034 {
3035 /* A carry occurred */
3036 State->Flags.Cf = TRUE;
3037 }
3038
3039 /* Set the adjust flag */
3040 State->Flags.Af = TRUE;
3041 }
3042
3043 /* Check if the second BCD digit is invalid or there was a carry from it */
3044 if ((Value > 0x99) || Carry)
3045 {
3046 /* Correct it */
3047 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x60;
3048
3049 /* There was a carry */
3050 State->Flags.Cf = TRUE;
3051 }
3052
3053 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3054
3055 /* Update the flags */
3056 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3057 State->Flags.Zf = (Value == 0);
3058 State->Flags.Pf = Fast486CalculateParity(Value);
3059
3060 return TRUE;
3061 }
3062
3063 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm)
3064 {
3065 UCHAR FirstValue, SecondValue, Result;
3066 FAST486_MOD_REG_RM ModRegRm;
3067 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3068
3069 /* Make sure this is the right instruction */
3070 ASSERT((Opcode & 0xED) == 0x28);
3071
3072 TOGGLE_ADSIZE(AddressSize);
3073
3074 /* Get the operands */
3075 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3076 {
3077 /* Exception occurred */
3078 return FALSE;
3079 }
3080
3081 if (!Fast486ReadModrmByteOperands(State,
3082 &ModRegRm,
3083 &FirstValue,
3084 &SecondValue))
3085 {
3086 /* Exception occurred */
3087 return FALSE;
3088 }
3089
3090 /* Check if this is the instruction that writes to R/M */
3091 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3092 {
3093 /* Swap the order */
3094 SWAP(FirstValue, SecondValue);
3095 }
3096
3097 /* Calculate the result */
3098 Result = FirstValue - SecondValue;
3099
3100 /* Update the flags */
3101 State->Flags.Cf = (FirstValue < SecondValue);
3102 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3103 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3104 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3105 State->Flags.Zf = (Result == 0);
3106 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3107 State->Flags.Pf = Fast486CalculateParity(Result);
3108
3109 /* Check if this is not a CMP */
3110 if (!(Opcode & 0x10))
3111 {
3112 /* Write back the result */
3113 return Fast486WriteModrmByteOperands(State,
3114 &ModRegRm,
3115 Opcode & FAST486_OPCODE_WRITE_REG,
3116 Result);
3117 }
3118 else
3119 {
3120 /* Discard the result */
3121 return TRUE;
3122 }
3123 }
3124
3125 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm)
3126 {
3127 FAST486_MOD_REG_RM ModRegRm;
3128 BOOLEAN OperandSize, AddressSize;
3129
3130 /* Make sure this is the right instruction */
3131 ASSERT((Opcode & 0xED) == 0x29);
3132
3133 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3134
3135 TOGGLE_ADSIZE(AddressSize);
3136 TOGGLE_OPSIZE(OperandSize);
3137
3138 /* Get the operands */
3139 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3140 {
3141 /* Exception occurred */
3142 return FALSE;
3143 }
3144
3145 /* Check the operand size */
3146 if (OperandSize)
3147 {
3148 ULONG FirstValue, SecondValue, Result;
3149
3150 if (!Fast486ReadModrmDwordOperands(State,
3151 &ModRegRm,
3152 &FirstValue,
3153 &SecondValue))
3154 {
3155 /* Exception occurred */
3156 return FALSE;
3157 }
3158
3159 /* Check if this is the instruction that writes to R/M */
3160 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3161 {
3162 /* Swap the order */
3163 SWAP(FirstValue, SecondValue);
3164 }
3165
3166 /* Calculate the result */
3167 Result = FirstValue - SecondValue;
3168
3169 /* Update the flags */
3170 State->Flags.Cf = (FirstValue < SecondValue);
3171 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3172 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3173 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3174 State->Flags.Zf = (Result == 0);
3175 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3176 State->Flags.Pf = Fast486CalculateParity(Result);
3177
3178 /* Check if this is not a CMP */
3179 if (!(Opcode & 0x10))
3180 {
3181 /* Write back the result */
3182 return Fast486WriteModrmDwordOperands(State,
3183 &ModRegRm,
3184 Opcode & FAST486_OPCODE_WRITE_REG,
3185 Result);
3186 }
3187 else
3188 {
3189 /* Discard the result */
3190 return TRUE;
3191 }
3192 }
3193 else
3194 {
3195 USHORT FirstValue, SecondValue, Result;
3196
3197 if (!Fast486ReadModrmWordOperands(State,
3198 &ModRegRm,
3199 &FirstValue,
3200 &SecondValue))
3201 {
3202 /* Exception occurred */
3203 return FALSE;
3204 }
3205
3206 /* Check if this is the instruction that writes to R/M */
3207 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3208 {
3209 /* Swap the order */
3210 SWAP(FirstValue, SecondValue);
3211 }
3212
3213 /* Calculate the result */
3214 Result = FirstValue - SecondValue;
3215
3216 /* Update the flags */
3217 State->Flags.Cf = (FirstValue < SecondValue);
3218 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3219 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3220 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3221 State->Flags.Zf = (Result == 0);
3222 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3223 State->Flags.Pf = Fast486CalculateParity(Result);
3224
3225 /* Check if this is not a CMP */
3226 if (!(Opcode & 0x10))
3227 {
3228 /* Write back the result */
3229 return Fast486WriteModrmWordOperands(State,
3230 &ModRegRm,
3231 Opcode & FAST486_OPCODE_WRITE_REG,
3232 Result);
3233 }
3234 else
3235 {
3236 /* Discard the result */
3237 return TRUE;
3238 }
3239 }
3240 }
3241
3242 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl)
3243 {
3244 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3245 UCHAR SecondValue, Result;
3246
3247 /* Make sure this is the right instruction */
3248 ASSERT((Opcode & 0xEF) == 0x2C);
3249
3250 if (State->PrefixFlags)
3251 {
3252 /* This opcode doesn't take any prefixes */
3253 Fast486Exception(State, FAST486_EXCEPTION_UD);
3254 return FALSE;
3255 }
3256
3257 if (!Fast486FetchByte(State, &SecondValue))
3258 {
3259 /* Exception occurred */
3260 return FALSE;
3261 }
3262
3263 /* Calculate the result */
3264 Result = FirstValue - SecondValue;
3265
3266 /* Update the flags */
3267 State->Flags.Cf = (FirstValue < SecondValue);
3268 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3269 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3270 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3271 State->Flags.Zf = (Result == 0);
3272 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3273 State->Flags.Pf = Fast486CalculateParity(Result);
3274
3275 /* Check if this is not a CMP */
3276 if (!(Opcode & 0x10))
3277 {
3278 /* Write back the result */
3279 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
3280 }
3281
3282 return TRUE;
3283 }
3284
3285 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax)
3286 {
3287 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3288
3289 /* Make sure this is the right instruction */
3290 ASSERT((Opcode & 0xEF) == 0x2D);
3291
3292 NO_LOCK_PREFIX();
3293 TOGGLE_OPSIZE(Size);
3294
3295 if (Size)
3296 {
3297 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
3298 ULONG SecondValue, Result;
3299
3300 if (!Fast486FetchDword(State, &SecondValue))
3301 {
3302 /* Exception occurred */
3303 return FALSE;
3304 }
3305
3306 /* Calculate the result */
3307 Result = FirstValue - SecondValue;
3308
3309 /* Update the flags */
3310 State->Flags.Cf = (FirstValue < SecondValue);
3311 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3312 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3313 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3314 State->Flags.Zf = (Result == 0);
3315 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3316 State->Flags.Pf = Fast486CalculateParity(Result);
3317
3318 /* Check if this is not a CMP */
3319 if (!(Opcode & 0x10))
3320 {
3321 /* Write back the result */
3322 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
3323 }
3324 }
3325 else
3326 {
3327 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
3328 USHORT SecondValue, Result;
3329
3330 if (!Fast486FetchWord(State, &SecondValue))
3331 {
3332 /* Exception occurred */
3333 return FALSE;
3334 }
3335
3336 /* Calculate the result */
3337 Result = FirstValue - SecondValue;
3338
3339 /* Update the flags */
3340 State->Flags.Cf = (FirstValue < SecondValue);
3341 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3342 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3343 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3344 State->Flags.Zf = (Result == 0);
3345 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3346 State->Flags.Pf = Fast486CalculateParity(Result);
3347
3348 /* Check if this is not a CMP */
3349 if (!(Opcode & 0x10))
3350 {
3351 /* Write back the result */
3352 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
3353 }
3354 }
3355
3356 return TRUE;
3357 }
3358
3359 FAST486_OPCODE_HANDLER(Fast486OpcodeDas)
3360 {
3361 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3362 BOOLEAN Carry = State->Flags.Cf;
3363
3364 /* Clear the carry flag */
3365 State->Flags.Cf = FALSE;
3366
3367 /* Check if the first BCD digit is invalid or there was a borrow */
3368 if (((Value & 0x0F) > 9) || State->Flags.Af)
3369 {
3370 /* Correct it */
3371 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x06;
3372 if (State->GeneralRegs[FAST486_REG_EAX].LowByte > 0xFB)
3373 {
3374 /* A borrow occurred */
3375 State->Flags.Cf = TRUE;
3376 }
3377
3378 /* Set the adjust flag */
3379 State->Flags.Af = TRUE;
3380 }
3381
3382 /* Check if the second BCD digit is invalid or there was a borrow */
3383 if ((Value > 0x99) || Carry)
3384 {
3385 /* Correct it */
3386 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x60;
3387
3388 /* There was a borrow */
3389 State->Flags.Cf = TRUE;
3390 }
3391
3392 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3393
3394 /* Update the flags */
3395 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3396 State->Flags.Zf = (Value == 0);
3397 State->Flags.Pf = Fast486CalculateParity