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