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