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