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