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