Sync to trunk revision 63857.
[reactos.git] / lib / fast486 / opcodes.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opcodes.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "opgroups.h"
32 #include "extraops.h"
33 #include "common.h"
34 #include "fpu.h"
35
36 /* PUBLIC VARIABLES ***********************************************************/
37
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS] =
40 {
41 Fast486OpcodeAddByteModrm,
42 Fast486OpcodeAddModrm,
43 Fast486OpcodeAddByteModrm,
44 Fast486OpcodeAddModrm,
45 Fast486OpcodeAddAl,
46 Fast486OpcodeAddEax,
47 Fast486OpcodePushEs,
48 Fast486OpcodePopEs,
49 Fast486OpcodeOrByteModrm,
50 Fast486OpcodeOrModrm,
51 Fast486OpcodeOrByteModrm,
52 Fast486OpcodeOrModrm,
53 Fast486OpcodeOrAl,
54 Fast486OpcodeOrEax,
55 Fast486OpcodePushCs,
56 Fast486OpcodeExtended,
57 Fast486OpcodeAdcByteModrm,
58 Fast486OpcodeAdcModrm,
59 Fast486OpcodeAdcByteModrm,
60 Fast486OpcodeAdcModrm,
61 Fast486OpcodeAdcAl,
62 Fast486OpcodeAdcEax,
63 Fast486OpcodePushSs,
64 Fast486OpcodePopSs,
65 Fast486OpcodeSbbByteModrm,
66 Fast486OpcodeSbbModrm,
67 Fast486OpcodeSbbByteModrm,
68 Fast486OpcodeSbbModrm,
69 Fast486OpcodeSbbAl,
70 Fast486OpcodeSbbEax,
71 Fast486OpcodePushDs,
72 Fast486OpcodePopDs,
73 Fast486OpcodeAndByteModrm,
74 Fast486OpcodeAndModrm,
75 Fast486OpcodeAndByteModrm,
76 Fast486OpcodeAndModrm,
77 Fast486OpcodeAndAl,
78 Fast486OpcodeAndEax,
79 Fast486OpcodePrefix,
80 Fast486OpcodeDaa,
81 Fast486OpcodeCmpSubByteModrm,
82 Fast486OpcodeCmpSubModrm,
83 Fast486OpcodeCmpSubByteModrm,
84 Fast486OpcodeCmpSubModrm,
85 Fast486OpcodeCmpSubAl,
86 Fast486OpcodeCmpSubEax,
87 Fast486OpcodePrefix,
88 Fast486OpcodeDas,
89 Fast486OpcodeXorByteModrm,
90 Fast486OpcodeXorModrm,
91 Fast486OpcodeXorByteModrm,
92 Fast486OpcodeXorModrm,
93 Fast486OpcodeXorAl,
94 Fast486OpcodeXorEax,
95 Fast486OpcodePrefix,
96 Fast486OpcodeAaa,
97 Fast486OpcodeCmpSubByteModrm,
98 Fast486OpcodeCmpSubModrm,
99 Fast486OpcodeCmpSubByteModrm,
100 Fast486OpcodeCmpSubModrm,
101 Fast486OpcodeCmpSubAl,
102 Fast486OpcodeCmpSubEax,
103 Fast486OpcodePrefix,
104 Fast486OpcodeAas,
105 Fast486OpcodeIncrement,
106 Fast486OpcodeIncrement,
107 Fast486OpcodeIncrement,
108 Fast486OpcodeIncrement,
109 Fast486OpcodeIncrement,
110 Fast486OpcodeIncrement,
111 Fast486OpcodeIncrement,
112 Fast486OpcodeIncrement,
113 Fast486OpcodeDecrement,
114 Fast486OpcodeDecrement,
115 Fast486OpcodeDecrement,
116 Fast486OpcodeDecrement,
117 Fast486OpcodeDecrement,
118 Fast486OpcodeDecrement,
119 Fast486OpcodeDecrement,
120 Fast486OpcodeDecrement,
121 Fast486OpcodePushReg,
122 Fast486OpcodePushReg,
123 Fast486OpcodePushReg,
124 Fast486OpcodePushReg,
125 Fast486OpcodePushReg,
126 Fast486OpcodePushReg,
127 Fast486OpcodePushReg,
128 Fast486OpcodePushReg,
129 Fast486OpcodePopReg,
130 Fast486OpcodePopReg,
131 Fast486OpcodePopReg,
132 Fast486OpcodePopReg,
133 Fast486OpcodePopReg,
134 Fast486OpcodePopReg,
135 Fast486OpcodePopReg,
136 Fast486OpcodePopReg,
137 Fast486OpcodePushAll,
138 Fast486OpcodePopAll,
139 Fast486OpcodeBound,
140 Fast486OpcodeArpl,
141 Fast486OpcodePrefix,
142 Fast486OpcodePrefix,
143 Fast486OpcodePrefix,
144 Fast486OpcodePrefix,
145 Fast486OpcodePushImm,
146 Fast486OpcodeImulModrmImm,
147 Fast486OpcodePushByteImm,
148 Fast486OpcodeImulModrmImm,
149 Fast486OpcodeIns,
150 Fast486OpcodeIns,
151 Fast486OpcodeOuts,
152 Fast486OpcodeOuts,
153 Fast486OpcodeShortConditionalJmp,
154 Fast486OpcodeShortConditionalJmp,
155 Fast486OpcodeShortConditionalJmp,
156 Fast486OpcodeShortConditionalJmp,
157 Fast486OpcodeShortConditionalJmp,
158 Fast486OpcodeShortConditionalJmp,
159 Fast486OpcodeShortConditionalJmp,
160 Fast486OpcodeShortConditionalJmp,
161 Fast486OpcodeShortConditionalJmp,
162 Fast486OpcodeShortConditionalJmp,
163 Fast486OpcodeShortConditionalJmp,
164 Fast486OpcodeShortConditionalJmp,
165 Fast486OpcodeShortConditionalJmp,
166 Fast486OpcodeShortConditionalJmp,
167 Fast486OpcodeShortConditionalJmp,
168 Fast486OpcodeShortConditionalJmp,
169 Fast486OpcodeGroup8082,
170 Fast486OpcodeGroup81,
171 Fast486OpcodeGroup8082,
172 Fast486OpcodeGroup83,
173 Fast486OpcodeTestByteModrm,
174 Fast486OpcodeTestModrm,
175 Fast486OpcodeXchgByteModrm,
176 Fast486OpcodeXchgModrm,
177 Fast486OpcodeMovByteModrm,
178 Fast486OpcodeMovModrm,
179 Fast486OpcodeMovByteModrm,
180 Fast486OpcodeMovModrm,
181 Fast486OpcodeMovStoreSeg,
182 Fast486OpcodeLea,
183 Fast486OpcodeMovLoadSeg,
184 Fast486OpcodeGroup8F,
185 Fast486OpcodeNop,
186 Fast486OpcodeExchangeEax,
187 Fast486OpcodeExchangeEax,
188 Fast486OpcodeExchangeEax,
189 Fast486OpcodeExchangeEax,
190 Fast486OpcodeExchangeEax,
191 Fast486OpcodeExchangeEax,
192 Fast486OpcodeExchangeEax,
193 Fast486OpcodeCwde,
194 Fast486OpcodeCdq,
195 Fast486OpcodeCallAbs,
196 Fast486OpcodeWait,
197 Fast486OpcodePushFlags,
198 Fast486OpcodePopFlags,
199 Fast486OpcodeSahf,
200 Fast486OpcodeLahf,
201 Fast486OpcodeMovAlOffset,
202 Fast486OpcodeMovEaxOffset,
203 Fast486OpcodeMovOffsetAl,
204 Fast486OpcodeMovOffsetEax,
205 Fast486OpcodeMovs,
206 Fast486OpcodeMovs,
207 Fast486OpcodeCmps,
208 Fast486OpcodeCmps,
209 Fast486OpcodeTestAl,
210 Fast486OpcodeTestEax,
211 Fast486OpcodeStos,
212 Fast486OpcodeStos,
213 Fast486OpcodeLods,
214 Fast486OpcodeLods,
215 Fast486OpcodeScas,
216 Fast486OpcodeScas,
217 Fast486OpcodeMovByteRegImm,
218 Fast486OpcodeMovByteRegImm,
219 Fast486OpcodeMovByteRegImm,
220 Fast486OpcodeMovByteRegImm,
221 Fast486OpcodeMovByteRegImm,
222 Fast486OpcodeMovByteRegImm,
223 Fast486OpcodeMovByteRegImm,
224 Fast486OpcodeMovByteRegImm,
225 Fast486OpcodeMovRegImm,
226 Fast486OpcodeMovRegImm,
227 Fast486OpcodeMovRegImm,
228 Fast486OpcodeMovRegImm,
229 Fast486OpcodeMovRegImm,
230 Fast486OpcodeMovRegImm,
231 Fast486OpcodeMovRegImm,
232 Fast486OpcodeMovRegImm,
233 Fast486OpcodeGroupC0,
234 Fast486OpcodeGroupC1,
235 Fast486OpcodeRet,
236 Fast486OpcodeRet,
237 Fast486OpcodeLdsLes,
238 Fast486OpcodeLdsLes,
239 Fast486OpcodeGroupC6,
240 Fast486OpcodeGroupC7,
241 Fast486OpcodeEnter,
242 Fast486OpcodeLeave,
243 Fast486OpcodeRetFar,
244 Fast486OpcodeRetFar,
245 Fast486OpcodeInt,
246 Fast486OpcodeInt,
247 Fast486OpcodeInt,
248 Fast486OpcodeIret,
249 Fast486OpcodeGroupD0,
250 Fast486OpcodeGroupD1,
251 Fast486OpcodeGroupD2,
252 Fast486OpcodeGroupD3,
253 Fast486OpcodeAam,
254 Fast486OpcodeAad,
255 Fast486OpcodeSalc,
256 Fast486OpcodeXlat,
257 Fast486FpuOpcodeD8,
258 Fast486FpuOpcodeD9,
259 Fast486FpuOpcodeDA,
260 Fast486FpuOpcodeDB,
261 Fast486FpuOpcodeDC,
262 Fast486FpuOpcodeDD,
263 Fast486FpuOpcodeDE,
264 Fast486FpuOpcodeDF,
265 Fast486OpcodeLoop,
266 Fast486OpcodeLoop,
267 Fast486OpcodeLoop,
268 Fast486OpcodeJecxz,
269 Fast486OpcodeInByte,
270 Fast486OpcodeIn,
271 Fast486OpcodeOutByte,
272 Fast486OpcodeOut,
273 Fast486OpcodeCall,
274 Fast486OpcodeJmp,
275 Fast486OpcodeJmpAbs,
276 Fast486OpcodeShortJump,
277 Fast486OpcodeInByte,
278 Fast486OpcodeIn,
279 Fast486OpcodeOutByte,
280 Fast486OpcodeOut,
281 Fast486OpcodePrefix,
282 NULL, // Invalid
283 Fast486OpcodePrefix,
284 Fast486OpcodePrefix,
285 Fast486OpcodeHalt,
286 Fast486OpcodeComplCarry,
287 Fast486OpcodeGroupF6,
288 Fast486OpcodeGroupF7,
289 Fast486OpcodeClearCarry,
290 Fast486OpcodeSetCarry,
291 Fast486OpcodeClearInt,
292 Fast486OpcodeSetInt,
293 Fast486OpcodeClearDir,
294 Fast486OpcodeSetDir,
295 Fast486OpcodeGroupFE,
296 Fast486OpcodeGroupFF,
297 };
298
299 /* PUBLIC FUNCTIONS ***********************************************************/
300
301 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix)
302 {
303 BOOLEAN Valid = FALSE;
304
305 switch (Opcode)
306 {
307 /* ES: */
308 case 0x26:
309 {
310 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
311 {
312 State->PrefixFlags |= FAST486_PREFIX_SEG;
313 State->SegmentOverride = FAST486_REG_ES;
314 Valid = TRUE;
315 }
316
317 break;
318 }
319
320 /* CS: */
321 case 0x2E:
322 {
323 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
324 {
325 State->PrefixFlags |= FAST486_PREFIX_SEG;
326 State->SegmentOverride = FAST486_REG_CS;
327 Valid = TRUE;
328 }
329
330 break;
331 }
332
333 /* SS: */
334 case 0x36:
335 {
336 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
337 {
338 State->PrefixFlags |= FAST486_PREFIX_SEG;
339 State->SegmentOverride = FAST486_REG_SS;
340 Valid = TRUE;
341 }
342
343 break;
344 }
345
346 /* DS: */
347 case 0x3E:
348 {
349 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
350 {
351 State->PrefixFlags |= FAST486_PREFIX_SEG;
352 State->SegmentOverride = FAST486_REG_DS;
353 Valid = TRUE;
354 }
355
356 break;
357 }
358
359 /* FS: */
360 case 0x64:
361 {
362 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
363 {
364 State->PrefixFlags |= FAST486_PREFIX_SEG;
365 State->SegmentOverride = FAST486_REG_FS;
366 Valid = TRUE;
367 }
368
369 break;
370 }
371
372 /* GS: */
373 case 0x65:
374 {
375 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
376 {
377 State->PrefixFlags |= FAST486_PREFIX_SEG;
378 State->SegmentOverride = FAST486_REG_GS;
379 Valid = TRUE;
380 }
381
382 break;
383 }
384
385 /* OPSIZE */
386 case 0x66:
387 {
388 if (!(State->PrefixFlags & FAST486_PREFIX_OPSIZE))
389 {
390 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
391 Valid = TRUE;
392 }
393
394 break;
395 }
396
397 /* ADSIZE */
398 case 0x67:
399 {
400 if (!(State->PrefixFlags & FAST486_PREFIX_ADSIZE))
401 {
402 State->PrefixFlags |= FAST486_PREFIX_ADSIZE;
403 Valid = TRUE;
404 }
405 break;
406 }
407
408 /* LOCK */
409 case 0xF0:
410 {
411 if (!(State->PrefixFlags & FAST486_PREFIX_LOCK))
412 {
413 State->PrefixFlags |= FAST486_PREFIX_LOCK;
414 Valid = TRUE;
415 }
416
417 break;
418 }
419
420 /* REPNZ */
421 case 0xF2:
422 {
423 /* Mutually exclusive with REP */
424 if (!(State->PrefixFlags
425 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
426 {
427 State->PrefixFlags |= FAST486_PREFIX_REPNZ;
428 Valid = TRUE;
429 }
430
431 break;
432 }
433
434 /* REP / REPZ */
435 case 0xF3:
436 {
437 /* Mutually exclusive with REPNZ */
438 if (!(State->PrefixFlags
439 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
440 {
441 State->PrefixFlags |= FAST486_PREFIX_REP;
442 Valid = TRUE;
443 }
444
445 break;
446 }
447 }
448
449 if (!Valid)
450 {
451 /* Clear all prefixes */
452 State->PrefixFlags = 0;
453
454 /* Throw an exception */
455 Fast486Exception(State, FAST486_EXCEPTION_UD);
456 return FALSE;
457 }
458
459 return TRUE;
460 }
461
462 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement)
463 {
464 ULONG Value;
465 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
466
467 TOGGLE_OPSIZE(Size);
468 NO_LOCK_PREFIX();
469
470 /* Make sure this is the right instruction */
471 ASSERT((Opcode & 0xF8) == 0x40);
472
473 if (Size)
474 {
475 Value = ++State->GeneralRegs[Opcode & 0x07].Long;
476
477 State->Flags.Of = (Value == SIGN_FLAG_LONG);
478 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
479 }
480 else
481 {
482 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
483
484 State->Flags.Of = (Value == SIGN_FLAG_WORD);
485 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
486 }
487
488 State->Flags.Zf = (Value == 0);
489 State->Flags.Af = ((Value & 0x0F) == 0);
490 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
491
492 /* Return success */
493 return TRUE;
494 }
495
496 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement)
497 {
498 ULONG Value;
499 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
500
501 TOGGLE_OPSIZE(Size);
502 NO_LOCK_PREFIX();
503
504 /* Make sure this is the right instruction */
505 ASSERT((Opcode & 0xF8) == 0x48);
506
507 if (Size)
508 {
509 Value = --State->GeneralRegs[Opcode & 0x07].Long;
510
511 State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1));
512 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
513 }
514 else
515 {
516 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
517
518 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1));
519 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
520 }
521
522 State->Flags.Zf = (Value == 0);
523 State->Flags.Af = ((Value & 0x0F) == 0x0F);
524 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
525
526 /* Return success */
527 return TRUE;
528 }
529
530 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg)
531 {
532 NO_LOCK_PREFIX();
533
534 /* Make sure this is the right instruction */
535 ASSERT((Opcode & 0xF8) == 0x50);
536
537 /* Call the internal function */
538 return Fast486StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
539 }
540
541 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg)
542 {
543 ULONG Value;
544 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
545
546 TOGGLE_OPSIZE(Size);
547 NO_LOCK_PREFIX();
548
549 /* Make sure this is the right instruction */
550 ASSERT((Opcode & 0xF8) == 0x58);
551
552 /* Call the internal function */
553 if (!Fast486StackPop(State, &Value)) return FALSE;
554
555 /* Store the value */
556 if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value;
557 else State->GeneralRegs[Opcode & 0x07].LowWord = Value;
558
559 /* Return success */
560 return TRUE;
561 }
562
563 FAST486_OPCODE_HANDLER(Fast486OpcodeNop)
564 {
565 if (State->PrefixFlags & FAST486_PREFIX_REP)
566 {
567 /* Idle cycle */
568 State->IdleCallback(State);
569 }
570
571 return TRUE;
572 }
573
574 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax)
575 {
576 INT Reg = Opcode & 0x07;
577 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
578
579 TOGGLE_OPSIZE(Size);
580 NO_LOCK_PREFIX();
581
582 /* Make sure this is the right instruction */
583 ASSERT((Opcode & 0xF8) == 0x90);
584
585 /* Exchange the values */
586 if (Size)
587 {
588 ULONG Value;
589
590 Value = State->GeneralRegs[Reg].Long;
591 State->GeneralRegs[Reg].Long = State->GeneralRegs[FAST486_REG_EAX].Long;
592 State->GeneralRegs[FAST486_REG_EAX].Long = Value;
593 }
594 else
595 {
596 USHORT Value;
597
598 Value = State->GeneralRegs[Reg].LowWord;
599 State->GeneralRegs[Reg].LowWord = State->GeneralRegs[FAST486_REG_EAX].LowWord;
600 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
601 }
602
603 return TRUE;
604 }
605
606 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp)
607 {
608 BOOLEAN Jump = FALSE;
609 CHAR Offset = 0;
610 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
611
612 /* Make sure this is the right instruction */
613 ASSERT((Opcode & 0xF0) == 0x70);
614
615 TOGGLE_OPSIZE(Size);
616
617 /* Fetch the offset */
618 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
619 {
620 /* An exception occurred */
621 return FALSE;
622 }
623
624 switch ((Opcode & 0x0F) >> 1)
625 {
626 /* JO / JNO */
627 case 0:
628 {
629 Jump = State->Flags.Of;
630 break;
631 }
632
633 /* JC / JNC */
634 case 1:
635 {
636 Jump = State->Flags.Cf;
637 break;
638 }
639
640 /* JZ / JNZ */
641 case 2:
642 {
643 Jump = State->Flags.Zf;
644 break;
645 }
646
647 /* JBE / JNBE */
648 case 3:
649 {
650 Jump = State->Flags.Cf || State->Flags.Zf;
651 break;
652 }
653
654 /* JS / JNS */
655 case 4:
656 {
657 Jump = State->Flags.Sf;
658 break;
659 }
660
661 /* JP / JNP */
662 case 5:
663 {
664 Jump = State->Flags.Pf;
665 break;
666 }
667
668 /* JL / JNL */
669 case 6:
670 {
671 Jump = State->Flags.Sf != State->Flags.Of;
672 break;
673 }
674
675 /* JLE / JNLE */
676 case 7:
677 {
678 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
679 break;
680 }
681 }
682
683 if (Opcode & 1)
684 {
685 /* Invert the result */
686 Jump = !Jump;
687 }
688
689 if (Jump)
690 {
691 /* Move the instruction pointer */
692 State->InstPtr.Long += Offset;
693
694 if (!Size)
695 {
696 /* Clear the top half of EIP */
697 State->InstPtr.Long &= 0xFFFF;
698 }
699 }
700
701 /* Return success */
702 return TRUE;
703 }
704
705 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry)
706 {
707 /* Make sure this is the right instruction */
708 ASSERT(Opcode == 0xF8);
709
710 /* No prefixes allowed */
711 if (State->PrefixFlags)
712 {
713 Fast486Exception(State, FAST486_EXCEPTION_UD);
714 return FALSE;
715 }
716
717 /* Clear CF and return success */
718 State->Flags.Cf = FALSE;
719 return TRUE;
720 }
721
722 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry)
723 {
724 /* Make sure this is the right instruction */
725 ASSERT(Opcode == 0xF9);
726
727 /* No prefixes allowed */
728 if (State->PrefixFlags)
729 {
730 Fast486Exception(State, FAST486_EXCEPTION_UD);
731 return FALSE;
732 }
733
734 /* Set CF and return success*/
735 State->Flags.Cf = TRUE;
736 return TRUE;
737 }
738
739 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry)
740 {
741 /* Make sure this is the right instruction */
742 ASSERT(Opcode == 0xF5);
743
744 /* No prefixes allowed */
745 if (State->PrefixFlags)
746 {
747 Fast486Exception(State, FAST486_EXCEPTION_UD);
748 return FALSE;
749 }
750
751 /* Toggle CF and return success */
752 State->Flags.Cf = !State->Flags.Cf;
753 return TRUE;
754 }
755
756 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt)
757 {
758 /* Make sure this is the right instruction */
759 ASSERT(Opcode == 0xFA);
760
761 /* No prefixes allowed */
762 if (State->PrefixFlags)
763 {
764 Fast486Exception(State, FAST486_EXCEPTION_UD);
765 return FALSE;
766 }
767
768 /* Check for protected mode */
769 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
770 {
771 /* Check IOPL */
772 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
773 {
774 /* Clear the interrupt flag */
775 State->Flags.If = FALSE;
776 }
777 else
778 {
779 /* General Protection Fault */
780 Fast486Exception(State, FAST486_EXCEPTION_GP);
781 return FALSE;
782 }
783 }
784 else
785 {
786 /* Just clear the interrupt flag */
787 State->Flags.If = FALSE;
788 }
789
790 /* Return success */
791 return TRUE;
792 }
793
794 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt)
795 {
796 /* Make sure this is the right instruction */
797 ASSERT(Opcode == 0xFB);
798
799 /* No prefixes allowed */
800 if (State->PrefixFlags)
801 {
802 Fast486Exception(State, FAST486_EXCEPTION_UD);
803 return FALSE;
804 }
805
806 /* Check for protected mode */
807 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
808 {
809 /* Check IOPL */
810 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
811 {
812 /* Set the interrupt flag */
813 State->Flags.If = TRUE;
814 }
815 else
816 {
817 /* General Protection Fault */
818 Fast486Exception(State, FAST486_EXCEPTION_GP);
819 return FALSE;
820 }
821 }
822 else
823 {
824 /* Just set the interrupt flag */
825 State->Flags.If = TRUE;
826 }
827
828 /* Return success */
829 return TRUE;
830 }
831
832 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir)
833 {
834 /* Make sure this is the right instruction */
835 ASSERT(Opcode == 0xFC);
836
837 /* No prefixes allowed */
838 if (State->PrefixFlags)
839 {
840 Fast486Exception(State, FAST486_EXCEPTION_UD);
841 return FALSE;
842 }
843
844 /* Clear DF and return success */
845 State->Flags.Df = FALSE;
846 return TRUE;
847 }
848
849 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir)
850 {
851 /* Make sure this is the right instruction */
852 ASSERT(Opcode == 0xFD);
853
854 /* No prefixes allowed */
855 if (State->PrefixFlags)
856 {
857 Fast486Exception(State, FAST486_EXCEPTION_UD);
858 return FALSE;
859 }
860
861 /* Set DF and return success*/
862 State->Flags.Df = TRUE;
863 return TRUE;
864 }
865
866 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
867 {
868 /* Make sure this is the right instruction */
869 ASSERT(Opcode == 0xF4);
870
871 /* No prefixes allowed */
872 if (State->PrefixFlags)
873 {
874 Fast486Exception(State, FAST486_EXCEPTION_UD);
875 return FALSE;
876 }
877
878 /* Privileged instructions can only be executed under CPL = 0 */
879 if (State->SegmentRegs[FAST486_REG_CS].Dpl != 0)
880 {
881 Fast486Exception(State, FAST486_EXCEPTION_GP);
882 return FALSE;
883 }
884
885 /* Halt */
886 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
887
888 /* Return success */
889 return TRUE;
890 }
891
892 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte)
893 {
894 UCHAR Data;
895 ULONG Port;
896
897 /* Make sure this is the right instruction */
898 ASSERT((Opcode & 0xF7) == 0xE4);
899
900 if (Opcode == 0xE4)
901 {
902 /* Fetch the parameter */
903 if (!Fast486FetchByte(State, &Data))
904 {
905 /* Exception occurred */
906 return FALSE;
907 }
908
909 /* Set the port number to the parameter */
910 Port = Data;
911 }
912 else
913 {
914 /* The port number is in DX */
915 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
916 }
917
918 /* Read a byte from the I/O port */
919 State->IoReadCallback(State, Port, &Data, 1, sizeof(UCHAR));
920
921 /* Store the result in AL */
922 State->GeneralRegs[FAST486_REG_EAX].LowByte = Data;
923
924 return TRUE;
925 }
926
927 FAST486_OPCODE_HANDLER(Fast486OpcodeIn)
928 {
929 ULONG Port;
930 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
931
932 /* Make sure this is the right instruction */
933 ASSERT((Opcode & 0xF7) == 0xE5);
934
935 TOGGLE_OPSIZE(Size);
936 NO_LOCK_PREFIX();
937
938 if (Opcode == 0xE5)
939 {
940 UCHAR Data;
941
942 /* Fetch the parameter */
943 if (!Fast486FetchByte(State, &Data))
944 {
945 /* Exception occurred */
946 return FALSE;
947 }
948
949 /* Set the port number to the parameter */
950 Port = Data;
951 }
952 else
953 {
954 /* The port number is in DX */
955 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
956 }
957
958 if (Size)
959 {
960 ULONG Data;
961
962 /* Read a dword from the I/O port */
963 State->IoReadCallback(State, Port, &Data, 1, sizeof(ULONG));
964
965 /* Store the value in EAX */
966 State->GeneralRegs[FAST486_REG_EAX].Long = Data;
967 }
968 else
969 {
970 USHORT Data;
971
972 /* Read a word from the I/O port */
973 State->IoReadCallback(State, Port, &Data, 1, sizeof(USHORT));
974
975 /* Store the value in AX */
976 State->GeneralRegs[FAST486_REG_EAX].LowWord = Data;
977 }
978
979 return TRUE;
980 }
981
982 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte)
983 {
984 UCHAR Data;
985 ULONG Port;
986
987 /* Make sure this is the right instruction */
988 ASSERT((Opcode & 0xF7) == 0xE6);
989
990 if (Opcode == 0xE6)
991 {
992 /* Fetch the parameter */
993 if (!Fast486FetchByte(State, &Data))
994 {
995 /* Exception occurred */
996 return FALSE;
997 }
998
999 /* Set the port number to the parameter */
1000 Port = Data;
1001 }
1002 else
1003 {
1004 /* The port number is in DX */
1005 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1006 }
1007
1008 /* Read the value from AL */
1009 Data = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1010
1011 /* Write the byte to the I/O port */
1012 State->IoWriteCallback(State, Port, &Data, 1, sizeof(UCHAR));
1013
1014 return TRUE;
1015 }
1016
1017 FAST486_OPCODE_HANDLER(Fast486OpcodeOut)
1018 {
1019 ULONG Port;
1020 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1021
1022 /* Make sure this is the right instruction */
1023 ASSERT((Opcode & 0xF7) == 0xE7);
1024
1025 TOGGLE_OPSIZE(Size);
1026 NO_LOCK_PREFIX();
1027
1028 if (Opcode == 0xE7)
1029 {
1030 UCHAR Data;
1031
1032 /* Fetch the parameter */
1033 if (!Fast486FetchByte(State, &Data))
1034 {
1035 /* Exception occurred */
1036 return FALSE;
1037 }
1038
1039 /* Set the port number to the parameter */
1040 Port = Data;
1041 }
1042 else
1043 {
1044 /* The port number is in DX */
1045 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1046 }
1047
1048 if (Size)
1049 {
1050 /* Get the value from EAX */
1051 ULONG Data = State->GeneralRegs[FAST486_REG_EAX].Long;
1052
1053 /* Write a dword to the I/O port */
1054 State->IoWriteCallback(State, Port, &Data, 1, sizeof(ULONG));
1055 }
1056 else
1057 {
1058 /* Get the value from AX */
1059 USHORT Data = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1060
1061 /* Write a word to the I/O port */
1062 State->IoWriteCallback(State, Port, &Data, 1, sizeof(USHORT));
1063 }
1064
1065 return TRUE;
1066 }
1067
1068 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump)
1069 {
1070 CHAR Offset = 0;
1071 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1072
1073 TOGGLE_OPSIZE(Size);
1074
1075 /* Make sure this is the right instruction */
1076 ASSERT(Opcode == 0xEB);
1077
1078 /* Fetch the offset */
1079 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1080 {
1081 /* An exception occurred */
1082 return FALSE;
1083 }
1084
1085 /* Move the instruction pointer */
1086 State->InstPtr.Long += Offset;
1087
1088 if (!Size)
1089 {
1090 /* Clear the top half of EIP */
1091 State->InstPtr.Long &= 0xFFFF;
1092 }
1093
1094 return TRUE;
1095 }
1096
1097 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm)
1098 {
1099 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1100
1101 /* Make sure this is the right instruction */
1102 ASSERT((Opcode & 0xF8) == 0xB8);
1103
1104 TOGGLE_OPSIZE(Size);
1105 NO_LOCK_PREFIX();
1106
1107 if (Size)
1108 {
1109 ULONG Value;
1110
1111 /* Fetch the dword */
1112 if (!Fast486FetchDword(State, &Value))
1113 {
1114 /* Exception occurred */
1115 return FALSE;
1116 }
1117
1118 /* Store the value in the register */
1119 State->GeneralRegs[Opcode & 0x07].Long = Value;
1120 }
1121 else
1122 {
1123 USHORT Value;
1124
1125 /* Fetch the word */
1126 if (!Fast486FetchWord(State, &Value))
1127 {
1128 /* Exception occurred */
1129 return FALSE;
1130 }
1131
1132 /* Store the value in the register */
1133 State->GeneralRegs[Opcode & 0x07].LowWord = Value;
1134 }
1135
1136 return TRUE;
1137 }
1138
1139 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm)
1140 {
1141 UCHAR Value;
1142
1143 /* Make sure this is the right instruction */
1144 ASSERT((Opcode & 0xF8) == 0xB0);
1145
1146 if (State->PrefixFlags != 0)
1147 {
1148 /* Invalid prefix */
1149 Fast486Exception(State, FAST486_EXCEPTION_UD);
1150 return FALSE;
1151 }
1152
1153 /* Fetch the byte */
1154 if (!Fast486FetchByte(State, &Value))
1155 {
1156 /* Exception occurred */
1157 return FALSE;
1158 }
1159
1160 if (Opcode & 0x04)
1161 {
1162 /* AH, CH, DH or BH */
1163 State->GeneralRegs[Opcode & 0x03].HighByte = Value;
1164 }
1165 else
1166 {
1167 /* AL, CL, DL or BL */
1168 State->GeneralRegs[Opcode & 0x03].LowByte = Value;
1169 }
1170
1171 return TRUE;
1172 }
1173
1174 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm)
1175 {
1176 UCHAR FirstValue, SecondValue, Result;
1177 FAST486_MOD_REG_RM ModRegRm;
1178 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1179
1180 /* Make sure this is the right instruction */
1181 ASSERT((Opcode & 0xFD) == 0x00);
1182
1183 TOGGLE_ADSIZE(AddressSize);
1184
1185 /* Get the operands */
1186 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1187 {
1188 /* Exception occurred */
1189 return FALSE;
1190 }
1191
1192 if (!Fast486ReadModrmByteOperands(State,
1193 &ModRegRm,
1194 &FirstValue,
1195 &SecondValue))
1196 {
1197 /* Exception occurred */
1198 return FALSE;
1199 }
1200
1201 /* Calculate the result */
1202 Result = FirstValue + SecondValue;
1203
1204 /* Update the flags */
1205 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1206 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1207 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1208 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1209 State->Flags.Zf = (Result == 0);
1210 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1211 State->Flags.Pf = Fast486CalculateParity(Result);
1212
1213 /* Write back the result */
1214 return Fast486WriteModrmByteOperands(State,
1215 &ModRegRm,
1216 Opcode & FAST486_OPCODE_WRITE_REG,
1217 Result);
1218 }
1219
1220 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm)
1221 {
1222 FAST486_MOD_REG_RM ModRegRm;
1223 BOOLEAN OperandSize, AddressSize;
1224
1225 /* Make sure this is the right instruction */
1226 ASSERT((Opcode & 0xFD) == 0x01);
1227
1228 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1229
1230 TOGGLE_ADSIZE(AddressSize);
1231 TOGGLE_OPSIZE(OperandSize);
1232
1233 /* Get the operands */
1234 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1235 {
1236 /* Exception occurred */
1237 return FALSE;
1238 }
1239
1240 /* Check the operand size */
1241 if (OperandSize)
1242 {
1243 ULONG FirstValue, SecondValue, Result;
1244
1245 if (!Fast486ReadModrmDwordOperands(State,
1246 &ModRegRm,
1247 &FirstValue,
1248 &SecondValue))
1249 {
1250 /* Exception occurred */
1251 return FALSE;
1252 }
1253
1254 /* Calculate the result */
1255 Result = FirstValue + SecondValue;
1256
1257 /* Update the flags */
1258 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1259 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1260 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1261 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1262 State->Flags.Zf = (Result == 0);
1263 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1264 State->Flags.Pf = Fast486CalculateParity(Result);
1265
1266 /* Write back the result */
1267 return Fast486WriteModrmDwordOperands(State,
1268 &ModRegRm,
1269 Opcode & FAST486_OPCODE_WRITE_REG,
1270 Result);
1271 }
1272 else
1273 {
1274 USHORT FirstValue, SecondValue, Result;
1275
1276 if (!Fast486ReadModrmWordOperands(State,
1277 &ModRegRm,
1278 &FirstValue,
1279 &SecondValue))
1280 {
1281 /* Exception occurred */
1282 return FALSE;
1283 }
1284
1285 /* Calculate the result */
1286 Result = FirstValue + SecondValue;
1287
1288 /* Update the flags */
1289 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1290 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1291 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1292 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1293 State->Flags.Zf = (Result == 0);
1294 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1295 State->Flags.Pf = Fast486CalculateParity(Result);
1296
1297 /* Write back the result */
1298 return Fast486WriteModrmWordOperands(State,
1299 &ModRegRm,
1300 Opcode & FAST486_OPCODE_WRITE_REG,
1301 Result);
1302 }
1303 }
1304
1305 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl)
1306 {
1307 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1308 UCHAR SecondValue, Result;
1309
1310 /* Make sure this is the right instruction */
1311 ASSERT(Opcode == 0x04);
1312
1313 if (State->PrefixFlags)
1314 {
1315 /* This opcode doesn't take any prefixes */
1316 Fast486Exception(State, FAST486_EXCEPTION_UD);
1317 return FALSE;
1318 }
1319
1320 if (!Fast486FetchByte(State, &SecondValue))
1321 {
1322 /* Exception occurred */
1323 return FALSE;
1324 }
1325
1326 /* Calculate the result */
1327 Result = FirstValue + SecondValue;
1328
1329 /* Update the flags */
1330 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1331 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1332 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1333 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1334 State->Flags.Zf = (Result == 0);
1335 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1336 State->Flags.Pf = Fast486CalculateParity(Result);
1337
1338 /* Write back the result */
1339 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1340
1341 return TRUE;
1342 }
1343
1344 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax)
1345 {
1346 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1347
1348 /* Make sure this is the right instruction */
1349 ASSERT(Opcode == 0x05);
1350
1351 NO_LOCK_PREFIX();
1352 TOGGLE_OPSIZE(Size);
1353
1354 if (Size)
1355 {
1356 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1357 ULONG SecondValue, Result;
1358
1359 if (!Fast486FetchDword(State, &SecondValue))
1360 {
1361 /* Exception occurred */
1362 return FALSE;
1363 }
1364
1365 /* Calculate the result */
1366 Result = FirstValue + SecondValue;
1367
1368 /* Update the flags */
1369 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1370 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1371 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1372 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1373 State->Flags.Zf = (Result == 0);
1374 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1375 State->Flags.Pf = Fast486CalculateParity(Result);
1376
1377 /* Write back the result */
1378 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1379 }
1380 else
1381 {
1382 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1383 USHORT SecondValue, Result;
1384
1385 if (!Fast486FetchWord(State, &SecondValue))
1386 {
1387 /* Exception occurred */
1388 return FALSE;
1389 }
1390
1391 /* Calculate the result */
1392 Result = FirstValue + SecondValue;
1393
1394 /* Update the flags */
1395 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1396 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1397 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1398 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1399 State->Flags.Zf = (Result == 0);
1400 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1401 State->Flags.Pf = Fast486CalculateParity(Result);
1402
1403 /* Write back the result */
1404 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1405 }
1406
1407 return TRUE;
1408 }
1409
1410 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm)
1411 {
1412 UCHAR FirstValue, SecondValue, Result;
1413 FAST486_MOD_REG_RM ModRegRm;
1414 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1415
1416 /* Make sure this is the right instruction */
1417 ASSERT((Opcode & 0xFD) == 0x08);
1418
1419 TOGGLE_ADSIZE(AddressSize);
1420
1421 /* Get the operands */
1422 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1423 {
1424 /* Exception occurred */
1425 return FALSE;
1426 }
1427
1428 if (!Fast486ReadModrmByteOperands(State,
1429 &ModRegRm,
1430 &FirstValue,
1431 &SecondValue))
1432 {
1433 /* Exception occurred */
1434 return FALSE;
1435 }
1436
1437 /* Calculate the result */
1438 Result = FirstValue | SecondValue;
1439
1440 /* Update the flags */
1441 State->Flags.Cf = FALSE;
1442 State->Flags.Of = FALSE;
1443 State->Flags.Zf = (Result == 0);
1444 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1445 State->Flags.Pf = Fast486CalculateParity(Result);
1446
1447 /* Write back the result */
1448 return Fast486WriteModrmByteOperands(State,
1449 &ModRegRm,
1450 Opcode & FAST486_OPCODE_WRITE_REG,
1451 Result);
1452 }
1453
1454 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm)
1455 {
1456 FAST486_MOD_REG_RM ModRegRm;
1457 BOOLEAN OperandSize, AddressSize;
1458
1459 /* Make sure this is the right instruction */
1460 ASSERT((Opcode & 0xFD) == 0x09);
1461
1462 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1463
1464 TOGGLE_ADSIZE(AddressSize);
1465 TOGGLE_OPSIZE(OperandSize);
1466
1467 /* Get the operands */
1468 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1469 {
1470 /* Exception occurred */
1471 return FALSE;
1472 }
1473
1474 /* Check the operand size */
1475 if (OperandSize)
1476 {
1477 ULONG FirstValue, SecondValue, Result;
1478
1479 if (!Fast486ReadModrmDwordOperands(State,
1480 &ModRegRm,
1481 &FirstValue,
1482 &SecondValue))
1483 {
1484 /* Exception occurred */
1485 return FALSE;
1486 }
1487
1488 /* Calculate the result */
1489 Result = FirstValue | SecondValue;
1490
1491 /* Update the flags */
1492 State->Flags.Cf = FALSE;
1493 State->Flags.Of = FALSE;
1494 State->Flags.Zf = (Result == 0);
1495 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1496 State->Flags.Pf = Fast486CalculateParity(Result);
1497
1498 /* Write back the result */
1499 return Fast486WriteModrmDwordOperands(State,
1500 &ModRegRm,
1501 Opcode & FAST486_OPCODE_WRITE_REG,
1502 Result);
1503 }
1504 else
1505 {
1506 USHORT FirstValue, SecondValue, Result;
1507
1508 if (!Fast486ReadModrmWordOperands(State,
1509 &ModRegRm,
1510 &FirstValue,
1511 &SecondValue))
1512 {
1513 /* Exception occurred */
1514 return FALSE;
1515 }
1516
1517 /* Calculate the result */
1518 Result = FirstValue | SecondValue;
1519
1520 /* Update the flags */
1521 State->Flags.Cf = FALSE;
1522 State->Flags.Of = FALSE;
1523 State->Flags.Zf = (Result == 0);
1524 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1525 State->Flags.Pf = Fast486CalculateParity(Result);
1526
1527 /* Write back the result */
1528 return Fast486WriteModrmWordOperands(State,
1529 &ModRegRm,
1530 Opcode & FAST486_OPCODE_WRITE_REG,
1531 Result);
1532 }
1533 }
1534
1535 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl)
1536 {
1537 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1538 UCHAR SecondValue, Result;
1539
1540 /* Make sure this is the right instruction */
1541 ASSERT(Opcode == 0x0C);
1542
1543 if (State->PrefixFlags)
1544 {
1545 /* This opcode doesn't take any prefixes */
1546 Fast486Exception(State, FAST486_EXCEPTION_UD);
1547 return FALSE;
1548 }
1549
1550 if (!Fast486FetchByte(State, &SecondValue))
1551 {
1552 /* Exception occurred */
1553 return FALSE;
1554 }
1555
1556 /* Calculate the result */
1557 Result = FirstValue | SecondValue;
1558
1559 /* Update the flags */
1560 State->Flags.Cf = FALSE;
1561 State->Flags.Of = FALSE;
1562 State->Flags.Zf = (Result == 0);
1563 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1564 State->Flags.Pf = Fast486CalculateParity(Result);
1565
1566 /* Write back the result */
1567 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1568
1569 return TRUE;
1570 }
1571
1572 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax)
1573 {
1574 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1575
1576 /* Make sure this is the right instruction */
1577 ASSERT(Opcode == 0x0D);
1578
1579 NO_LOCK_PREFIX();
1580 TOGGLE_OPSIZE(Size);
1581
1582 if (Size)
1583 {
1584 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1585 ULONG SecondValue, Result;
1586
1587 if (!Fast486FetchDword(State, &SecondValue))
1588 {
1589 /* Exception occurred */
1590 return FALSE;
1591 }
1592
1593 /* Calculate the result */
1594 Result = FirstValue | SecondValue;
1595
1596 /* Update the flags */
1597 State->Flags.Cf = FALSE;
1598 State->Flags.Of = FALSE;
1599 State->Flags.Zf = (Result == 0);
1600 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1601 State->Flags.Pf = Fast486CalculateParity(Result);
1602
1603 /* Write back the result */
1604 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1605 }
1606 else
1607 {
1608 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1609 USHORT SecondValue, Result;
1610
1611 if (!Fast486FetchWord(State, &SecondValue))
1612 {
1613 /* Exception occurred */
1614 return FALSE;
1615 }
1616
1617 /* Calculate the result */
1618 Result = FirstValue | SecondValue;
1619
1620 /* Update the flags */
1621 State->Flags.Cf = FALSE;
1622 State->Flags.Of = FALSE;
1623 State->Flags.Zf = (Result == 0);
1624 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1625 State->Flags.Pf = Fast486CalculateParity(Result);
1626
1627 /* Write back the result */
1628 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1629 }
1630
1631 return TRUE;
1632 }
1633
1634 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm)
1635 {
1636 UCHAR FirstValue, SecondValue, Result;
1637 FAST486_MOD_REG_RM ModRegRm;
1638 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1639
1640 /* Make sure this is the right instruction */
1641 ASSERT((Opcode & 0xFD) == 0x20);
1642
1643 TOGGLE_ADSIZE(AddressSize);
1644
1645 /* Get the operands */
1646 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1647 {
1648 /* Exception occurred */
1649 return FALSE;
1650 }
1651
1652 if (!Fast486ReadModrmByteOperands(State,
1653 &ModRegRm,
1654 &FirstValue,
1655 &SecondValue))
1656 {
1657 /* Exception occurred */
1658 return FALSE;
1659 }
1660
1661 /* Calculate the result */
1662 Result = FirstValue & SecondValue;
1663
1664 /* Update the flags */
1665 State->Flags.Cf = FALSE;
1666 State->Flags.Of = FALSE;
1667 State->Flags.Zf = (Result == 0);
1668 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1669 State->Flags.Pf = Fast486CalculateParity(Result);
1670
1671 /* Write back the result */
1672 return Fast486WriteModrmByteOperands(State,
1673 &ModRegRm,
1674 Opcode & FAST486_OPCODE_WRITE_REG,
1675 Result);
1676 }
1677
1678 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm)
1679 {
1680 FAST486_MOD_REG_RM ModRegRm;
1681 BOOLEAN OperandSize, AddressSize;
1682
1683 /* Make sure this is the right instruction */
1684 ASSERT((Opcode & 0xFD) == 0x21);
1685
1686 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1687
1688 TOGGLE_ADSIZE(AddressSize);
1689 TOGGLE_OPSIZE(OperandSize);
1690
1691 /* Get the operands */
1692 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1693 {
1694 /* Exception occurred */
1695 return FALSE;
1696 }
1697
1698 /* Check the operand size */
1699 if (OperandSize)
1700 {
1701 ULONG FirstValue, SecondValue, Result;
1702
1703 if (!Fast486ReadModrmDwordOperands(State,
1704 &ModRegRm,
1705 &FirstValue,
1706 &SecondValue))
1707 {
1708 /* Exception occurred */
1709 return FALSE;
1710 }
1711
1712 /* Calculate the result */
1713 Result = FirstValue & SecondValue;
1714
1715 /* Update the flags */
1716 State->Flags.Cf = FALSE;
1717 State->Flags.Of = FALSE;
1718 State->Flags.Zf = (Result == 0);
1719 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1720 State->Flags.Pf = Fast486CalculateParity(Result);
1721
1722 /* Write back the result */
1723 return Fast486WriteModrmDwordOperands(State,
1724 &ModRegRm,
1725 Opcode & FAST486_OPCODE_WRITE_REG,
1726 Result);
1727 }
1728 else
1729 {
1730 USHORT FirstValue, SecondValue, Result;
1731
1732 if (!Fast486ReadModrmWordOperands(State,
1733 &ModRegRm,
1734 &FirstValue,
1735 &SecondValue))
1736 {
1737 /* Exception occurred */
1738 return FALSE;
1739 }
1740
1741 /* Calculate the result */
1742 Result = FirstValue & SecondValue;
1743
1744 /* Update the flags */
1745 State->Flags.Cf = FALSE;
1746 State->Flags.Of = FALSE;
1747 State->Flags.Zf = (Result == 0);
1748 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1749 State->Flags.Pf = Fast486CalculateParity(Result);
1750
1751 /* Write back the result */
1752 return Fast486WriteModrmWordOperands(State,
1753 &ModRegRm,
1754 Opcode & FAST486_OPCODE_WRITE_REG,
1755 Result);
1756 }
1757 }
1758
1759 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl)
1760 {
1761 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1762 UCHAR SecondValue, Result;
1763
1764 /* Make sure this is the right instruction */
1765 ASSERT(Opcode == 0x24);
1766
1767 NO_LOCK_PREFIX();
1768
1769 if (!Fast486FetchByte(State, &SecondValue))
1770 {
1771 /* Exception occurred */
1772 return FALSE;
1773 }
1774
1775 /* Calculate the result */
1776 Result = FirstValue & SecondValue;
1777
1778 /* Update the flags */
1779 State->Flags.Cf = FALSE;
1780 State->Flags.Of = FALSE;
1781 State->Flags.Zf = (Result == 0);
1782 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1783 State->Flags.Pf = Fast486CalculateParity(Result);
1784
1785 /* Write back the result */
1786 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1787
1788 return TRUE;
1789 }
1790
1791 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax)
1792 {
1793 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1794
1795 /* Make sure this is the right instruction */
1796 ASSERT(Opcode == 0x25);
1797
1798 NO_LOCK_PREFIX();
1799 TOGGLE_OPSIZE(Size);
1800
1801 if (Size)
1802 {
1803 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1804 ULONG SecondValue, Result;
1805
1806 if (!Fast486FetchDword(State, &SecondValue))
1807 {
1808 /* Exception occurred */
1809 return FALSE;
1810 }
1811
1812 /* Calculate the result */
1813 Result = FirstValue & SecondValue;
1814
1815 /* Update the flags */
1816 State->Flags.Cf = FALSE;
1817 State->Flags.Of = FALSE;
1818 State->Flags.Zf = (Result == 0);
1819 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1820 State->Flags.Pf = Fast486CalculateParity(Result);
1821
1822 /* Write back the result */
1823 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1824 }
1825 else
1826 {
1827 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1828 USHORT SecondValue, Result;
1829
1830 if (!Fast486FetchWord(State, &SecondValue))
1831 {
1832 /* Exception occurred */
1833 return FALSE;
1834 }
1835
1836 /* Calculate the result */
1837 Result = FirstValue & SecondValue;
1838
1839 /* Update the flags */
1840 State->Flags.Cf = FALSE;
1841 State->Flags.Of = FALSE;
1842 State->Flags.Zf = (Result == 0);
1843 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1844 State->Flags.Pf = Fast486CalculateParity(Result);
1845
1846 /* Write back the result */
1847 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1848 }
1849
1850 return TRUE;
1851 }
1852
1853 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm)
1854 {
1855 UCHAR FirstValue, SecondValue, Result;
1856 FAST486_MOD_REG_RM ModRegRm;
1857 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1858
1859 /* Make sure this is the right instruction */
1860 ASSERT((Opcode & 0xFD) == 0x30);
1861
1862 TOGGLE_ADSIZE(AddressSize);
1863
1864 /* Get the operands */
1865 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1866 {
1867 /* Exception occurred */
1868 return FALSE;
1869 }
1870
1871 if (!Fast486ReadModrmByteOperands(State,
1872 &ModRegRm,
1873 &FirstValue,
1874 &SecondValue))
1875 {
1876 /* Exception occurred */
1877 return FALSE;
1878 }
1879
1880 /* Calculate the result */
1881 Result = FirstValue ^ SecondValue;
1882
1883 /* Update the flags */
1884 State->Flags.Cf = FALSE;
1885 State->Flags.Of = FALSE;
1886 State->Flags.Zf = (Result == 0);
1887 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1888 State->Flags.Pf = Fast486CalculateParity(Result);
1889
1890 /* Write back the result */
1891 return Fast486WriteModrmByteOperands(State,
1892 &ModRegRm,
1893 Opcode & FAST486_OPCODE_WRITE_REG,
1894 Result);
1895 }
1896
1897 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm)
1898 {
1899 FAST486_MOD_REG_RM ModRegRm;
1900 BOOLEAN OperandSize, AddressSize;
1901
1902 /* Make sure this is the right instruction */
1903 ASSERT((Opcode & 0xFD) == 0x31);
1904
1905 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1906
1907 TOGGLE_ADSIZE(AddressSize);
1908 TOGGLE_OPSIZE(OperandSize);
1909
1910 /* Get the operands */
1911 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1912 {
1913 /* Exception occurred */
1914 return FALSE;
1915 }
1916
1917 /* Check the operand size */
1918 if (OperandSize)
1919 {
1920 ULONG FirstValue, SecondValue, Result;
1921
1922 if (!Fast486ReadModrmDwordOperands(State,
1923 &ModRegRm,
1924 &FirstValue,
1925 &SecondValue))
1926 {
1927 /* Exception occurred */
1928 return FALSE;
1929 }
1930
1931 /* Calculate the result */
1932 Result = FirstValue ^ SecondValue;
1933
1934 /* Update the flags */
1935 State->Flags.Cf = FALSE;
1936 State->Flags.Of = FALSE;
1937 State->Flags.Zf = (Result == 0);
1938 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1939 State->Flags.Pf = Fast486CalculateParity(Result);
1940
1941 /* Write back the result */
1942 return Fast486WriteModrmDwordOperands(State,
1943 &ModRegRm,
1944 Opcode & FAST486_OPCODE_WRITE_REG,
1945 Result);
1946 }
1947 else
1948 {
1949 USHORT FirstValue, SecondValue, Result;
1950
1951 if (!Fast486ReadModrmWordOperands(State,
1952 &ModRegRm,
1953 &FirstValue,
1954 &SecondValue))
1955 {
1956 /* Exception occurred */
1957 return FALSE;
1958 }
1959
1960 /* Calculate the result */
1961 Result = FirstValue ^ SecondValue;
1962
1963 /* Update the flags */
1964 State->Flags.Cf = FALSE;
1965 State->Flags.Of = FALSE;
1966 State->Flags.Zf = (Result == 0);
1967 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1968 State->Flags.Pf = Fast486CalculateParity(Result);
1969
1970 /* Write back the result */
1971 return Fast486WriteModrmWordOperands(State,
1972 &ModRegRm,
1973 Opcode & FAST486_OPCODE_WRITE_REG,
1974 Result);
1975 }
1976 }
1977
1978 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl)
1979 {
1980 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1981 UCHAR SecondValue, Result;
1982
1983 /* Make sure this is the right instruction */
1984 ASSERT(Opcode == 0x34);
1985
1986 if (State->PrefixFlags)
1987 {
1988 /* This opcode doesn't take any prefixes */
1989 Fast486Exception(State, FAST486_EXCEPTION_UD);
1990 return FALSE;
1991 }
1992
1993 if (!Fast486FetchByte(State, &SecondValue))
1994 {
1995 /* Exception occurred */
1996 return FALSE;
1997 }
1998
1999 /* Calculate the result */
2000 Result = FirstValue ^ SecondValue;
2001
2002 /* Update the flags */
2003 State->Flags.Cf = FALSE;
2004 State->Flags.Of = FALSE;
2005 State->Flags.Zf = (Result == 0);
2006 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2007 State->Flags.Pf = Fast486CalculateParity(Result);
2008
2009 /* Write back the result */
2010 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2011
2012 return TRUE;
2013 }
2014
2015 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax)
2016 {
2017 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2018
2019 /* Make sure this is the right instruction */
2020 ASSERT(Opcode == 0x35);
2021
2022 NO_LOCK_PREFIX();
2023 TOGGLE_OPSIZE(Size);
2024
2025 if (Size)
2026 {
2027 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2028 ULONG SecondValue, Result;
2029
2030 if (!Fast486FetchDword(State, &SecondValue))
2031 {
2032 /* Exception occurred */
2033 return FALSE;
2034 }
2035
2036 /* Calculate the result */
2037 Result = FirstValue ^ SecondValue;
2038
2039 /* Update the flags */
2040 State->Flags.Cf = FALSE;
2041 State->Flags.Of = FALSE;
2042 State->Flags.Zf = (Result == 0);
2043 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2044 State->Flags.Pf = Fast486CalculateParity(Result);
2045
2046 /* Write back the result */
2047 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2048 }
2049 else
2050 {
2051 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2052 USHORT SecondValue, Result;
2053
2054 if (!Fast486FetchWord(State, &SecondValue))
2055 {
2056 /* Exception occurred */
2057 return FALSE;
2058 }
2059
2060 /* Calculate the result */
2061 Result = FirstValue ^ SecondValue;
2062
2063 /* Update the flags */
2064 State->Flags.Cf = FALSE;
2065 State->Flags.Of = FALSE;
2066 State->Flags.Zf = (Result == 0);
2067 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2068 State->Flags.Pf = Fast486CalculateParity(Result);
2069
2070 /* Write back the result */
2071 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2072 }
2073
2074 return TRUE;
2075 }
2076
2077 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm)
2078 {
2079 UCHAR FirstValue, SecondValue, Result;
2080 FAST486_MOD_REG_RM ModRegRm;
2081 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2082
2083 /* Make sure this is the right instruction */
2084 ASSERT(Opcode == 0x84);
2085
2086 TOGGLE_ADSIZE(AddressSize);
2087
2088 /* Get the operands */
2089 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2090 {
2091 /* Exception occurred */
2092 return FALSE;
2093 }
2094
2095 if (!Fast486ReadModrmByteOperands(State,
2096 &ModRegRm,
2097 &FirstValue,
2098 &SecondValue))
2099 {
2100 /* Exception occurred */
2101 return FALSE;
2102 }
2103 /* Calculate the result */
2104 Result = FirstValue & SecondValue;
2105
2106 /* Update the flags */
2107 State->Flags.Cf = FALSE;
2108 State->Flags.Of = FALSE;
2109 State->Flags.Zf = (Result == 0);
2110 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2111 State->Flags.Pf = Fast486CalculateParity(Result);
2112
2113 /* The result is discarded */
2114 return TRUE;
2115 }
2116
2117 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm)
2118 {
2119 FAST486_MOD_REG_RM ModRegRm;
2120 BOOLEAN OperandSize, AddressSize;
2121
2122 /* Make sure this is the right instruction */
2123 ASSERT(Opcode == 0x85);
2124
2125 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2126
2127 TOGGLE_ADSIZE(AddressSize);
2128 TOGGLE_OPSIZE(OperandSize);
2129
2130 /* Get the operands */
2131 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2132 {
2133 /* Exception occurred */
2134 return FALSE;
2135 }
2136
2137 /* Check the operand size */
2138 if (OperandSize)
2139 {
2140 ULONG FirstValue, SecondValue, Result;
2141
2142 if (!Fast486ReadModrmDwordOperands(State,
2143 &ModRegRm,
2144 &FirstValue,
2145 &SecondValue))
2146 {
2147 /* Exception occurred */
2148 return FALSE;
2149 }
2150
2151 /* Calculate the result */
2152 Result = FirstValue & SecondValue;
2153
2154 /* Update the flags */
2155 State->Flags.Cf = FALSE;
2156 State->Flags.Of = FALSE;
2157 State->Flags.Zf = (Result == 0);
2158 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2159 State->Flags.Pf = Fast486CalculateParity(Result);
2160 }
2161 else
2162 {
2163 USHORT FirstValue, SecondValue, Result;
2164
2165 if (!Fast486ReadModrmWordOperands(State,
2166 &ModRegRm,
2167 &FirstValue,
2168 &SecondValue))
2169 {
2170 /* Exception occurred */
2171 return FALSE;
2172 }
2173
2174 /* Calculate the result */
2175 Result = FirstValue & SecondValue;
2176
2177 /* Update the flags */
2178 State->Flags.Cf = FALSE;
2179 State->Flags.Of = FALSE;
2180 State->Flags.Zf = (Result == 0);
2181 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2182 State->Flags.Pf = Fast486CalculateParity(Result);
2183 }
2184
2185 /* The result is discarded */
2186 return TRUE;
2187 }
2188
2189 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl)
2190 {
2191 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2192 UCHAR SecondValue, Result;
2193
2194 /* Make sure this is the right instruction */
2195 ASSERT(Opcode == 0xA8);
2196
2197 if (State->PrefixFlags)
2198 {
2199 /* This opcode doesn't take any prefixes */
2200 Fast486Exception(State, FAST486_EXCEPTION_UD);
2201 return FALSE;
2202 }
2203
2204 if (!Fast486FetchByte(State, &SecondValue))
2205 {
2206 /* Exception occurred */
2207 return FALSE;
2208 }
2209
2210 /* Calculate the result */
2211 Result = FirstValue & SecondValue;
2212
2213 /* Update the flags */
2214 State->Flags.Cf = FALSE;
2215 State->Flags.Of = FALSE;
2216 State->Flags.Zf = (Result == 0);
2217 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2218 State->Flags.Pf = Fast486CalculateParity(Result);
2219
2220 /* The result is discarded */
2221 return TRUE;
2222 }
2223
2224 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax)
2225 {
2226 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2227
2228 /* Make sure this is the right instruction */
2229 ASSERT(Opcode == 0xA9);
2230
2231 NO_LOCK_PREFIX();
2232 TOGGLE_OPSIZE(Size);
2233
2234 if (Size)
2235 {
2236 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2237 ULONG SecondValue, Result;
2238
2239 if (!Fast486FetchDword(State, &SecondValue))
2240 {
2241 /* Exception occurred */
2242 return FALSE;
2243 }
2244
2245 /* Calculate the result */
2246 Result = FirstValue & SecondValue;
2247
2248 /* Update the flags */
2249 State->Flags.Cf = FALSE;
2250 State->Flags.Of = FALSE;
2251 State->Flags.Zf = (Result == 0);
2252 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2253 State->Flags.Pf = Fast486CalculateParity(Result);
2254 }
2255 else
2256 {
2257 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2258 USHORT SecondValue, Result;
2259
2260 if (!Fast486FetchWord(State, &SecondValue))
2261 {
2262 /* Exception occurred */
2263 return FALSE;
2264 }
2265
2266 /* Calculate the result */
2267 Result = FirstValue & SecondValue;
2268
2269 /* Update the flags */
2270 State->Flags.Cf = FALSE;
2271 State->Flags.Of = FALSE;
2272 State->Flags.Zf = (Result == 0);
2273 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2274 State->Flags.Pf = Fast486CalculateParity(Result);
2275 }
2276
2277 /* The result is discarded */
2278 return TRUE;
2279 }
2280
2281 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm)
2282 {
2283 UCHAR FirstValue, SecondValue;
2284 FAST486_MOD_REG_RM ModRegRm;
2285 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2286
2287 /* Make sure this is the right instruction */
2288 ASSERT(Opcode == 0x86);
2289
2290 TOGGLE_ADSIZE(AddressSize);
2291
2292 /* Get the operands */
2293 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2294 {
2295 /* Exception occurred */
2296 return FALSE;
2297 }
2298
2299 if (!Fast486ReadModrmByteOperands(State,
2300 &ModRegRm,
2301 &FirstValue,
2302 &SecondValue))
2303 {
2304 /* Exception occurred */
2305 return FALSE;
2306 }
2307
2308 /* Write the value from the register to the R/M */
2309 if (!Fast486WriteModrmByteOperands(State,
2310 &ModRegRm,
2311 FALSE,
2312 FirstValue))
2313 {
2314 /* Exception occurred */
2315 return FALSE;
2316 }
2317
2318 /* Write the value from the R/M to the register */
2319 if (!Fast486WriteModrmByteOperands(State,
2320 &ModRegRm,
2321 TRUE,
2322 SecondValue))
2323 {
2324 /* Exception occurred */
2325 return FALSE;
2326 }
2327
2328 return TRUE;
2329 }
2330
2331 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm)
2332 {
2333 FAST486_MOD_REG_RM ModRegRm;
2334 BOOLEAN OperandSize, AddressSize;
2335
2336 /* Make sure this is the right instruction */
2337 ASSERT(Opcode == 0x87);
2338
2339 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2340
2341 TOGGLE_ADSIZE(AddressSize);
2342 TOGGLE_OPSIZE(OperandSize);
2343
2344 /* Get the operands */
2345 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2346 {
2347 /* Exception occurred */
2348 return FALSE;
2349 }
2350
2351 /* Check the operand size */
2352 if (OperandSize)
2353 {
2354 ULONG FirstValue, SecondValue;
2355
2356 if (!Fast486ReadModrmDwordOperands(State,
2357 &ModRegRm,
2358 &FirstValue,
2359 &SecondValue))
2360 {
2361 /* Exception occurred */
2362 return FALSE;
2363 }
2364
2365 /* Write the value from the register to the R/M */
2366 if (!Fast486WriteModrmDwordOperands(State,
2367 &ModRegRm,
2368 FALSE,
2369 FirstValue))
2370 {
2371 /* Exception occurred */
2372 return FALSE;
2373 }
2374
2375 /* Write the value from the R/M to the register */
2376 if (!Fast486WriteModrmDwordOperands(State,
2377 &ModRegRm,
2378 TRUE,
2379 SecondValue))
2380 {
2381 /* Exception occurred */
2382 return FALSE;
2383 }
2384 }
2385 else
2386 {
2387 USHORT FirstValue, SecondValue;
2388
2389 if (!Fast486ReadModrmWordOperands(State,
2390 &ModRegRm,
2391 &FirstValue,
2392 &SecondValue))
2393 {
2394 /* Exception occurred */
2395 return FALSE;
2396 }
2397
2398 /* Write the value from the register to the R/M */
2399 if (!Fast486WriteModrmWordOperands(State,
2400 &ModRegRm,
2401 FALSE,
2402 FirstValue))
2403 {
2404 /* Exception occurred */
2405 return FALSE;
2406 }
2407
2408 /* Write the value from the R/M to the register */
2409 if (!Fast486WriteModrmWordOperands(State,
2410 &ModRegRm,
2411 TRUE,
2412 SecondValue))
2413 {
2414 /* Exception occurred */
2415 return FALSE;
2416 }
2417 }
2418
2419 /* The result is discarded */
2420 return TRUE;
2421 }
2422
2423 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs)
2424 {
2425 /* Call the internal API */
2426 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector);
2427 }
2428
2429 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs)
2430 {
2431 ULONG NewSelector;
2432
2433 if (!Fast486StackPop(State, &NewSelector))
2434 {
2435 /* Exception occurred */
2436 return FALSE;
2437 }
2438
2439 /* Call the internal API */
2440 return Fast486LoadSegment(State, FAST486_REG_ES, LOWORD(NewSelector));
2441 }
2442
2443 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs)
2444 {
2445 /* Call the internal API */
2446 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector);
2447 }
2448
2449 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm)
2450 {
2451 UCHAR FirstValue, SecondValue, Result;
2452 FAST486_MOD_REG_RM ModRegRm;
2453 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2454
2455 /* Make sure this is the right instruction */
2456 ASSERT((Opcode & 0xFD) == 0x10);
2457
2458 TOGGLE_ADSIZE(AddressSize);
2459
2460 /* Get the operands */
2461 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2462 {
2463 /* Exception occurred */
2464 return FALSE;
2465 }
2466
2467 if (!Fast486ReadModrmByteOperands(State,
2468 &ModRegRm,
2469 &FirstValue,
2470 &SecondValue))
2471 {
2472 /* Exception occurred */
2473 return FALSE;
2474 }
2475
2476 /* Calculate the result */
2477 Result = FirstValue + SecondValue + State->Flags.Cf;
2478
2479 /* Special exception for CF */
2480 State->Flags.Cf = State->Flags.Cf
2481 && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2482
2483 /* Update the flags */
2484 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2485 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2486 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2487 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2488 State->Flags.Zf = (Result == 0);
2489 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2490 State->Flags.Pf = Fast486CalculateParity(Result);
2491
2492 /* Write back the result */
2493 return Fast486WriteModrmByteOperands(State,
2494 &ModRegRm,
2495 Opcode & FAST486_OPCODE_WRITE_REG,
2496 Result);
2497 }
2498
2499 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm)
2500 {
2501 FAST486_MOD_REG_RM ModRegRm;
2502 BOOLEAN OperandSize, AddressSize;
2503
2504 /* Make sure this is the right instruction */
2505 ASSERT((Opcode & 0xFD) == 0x11);
2506
2507 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2508
2509 TOGGLE_ADSIZE(AddressSize);
2510 TOGGLE_OPSIZE(OperandSize);
2511
2512 /* Get the operands */
2513 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2514 {
2515 /* Exception occurred */
2516 return FALSE;
2517 }
2518
2519 /* Check the operand size */
2520 if (OperandSize)
2521 {
2522 ULONG FirstValue, SecondValue, Result;
2523
2524 if (!Fast486ReadModrmDwordOperands(State,
2525 &ModRegRm,
2526 &FirstValue,
2527 &SecondValue))
2528 {
2529 /* Exception occurred */
2530 return FALSE;
2531 }
2532
2533 /* Calculate the result */
2534 Result = FirstValue + SecondValue + State->Flags.Cf;
2535
2536 /* Special exception for CF */
2537 State->Flags.Cf = State->Flags.Cf
2538 && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2539
2540 /* Update the flags */
2541 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2542 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2543 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2544 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2545 State->Flags.Zf = (Result == 0);
2546 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2547 State->Flags.Pf = Fast486CalculateParity(Result);
2548
2549 /* Write back the result */
2550 return Fast486WriteModrmDwordOperands(State,
2551 &ModRegRm,
2552 Opcode & FAST486_OPCODE_WRITE_REG,
2553 Result);
2554 }
2555 else
2556 {
2557 USHORT FirstValue, SecondValue, Result;
2558
2559 if (!Fast486ReadModrmWordOperands(State,
2560 &ModRegRm,
2561 &FirstValue,
2562 &SecondValue))
2563 {
2564 /* Exception occurred */
2565 return FALSE;
2566 }
2567
2568 /* Calculate the result */
2569 Result = FirstValue + SecondValue + State->Flags.Cf;
2570
2571 /* Special exception for CF */
2572 State->Flags.Cf = State->Flags.Cf
2573 && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2574
2575 /* Update the flags */
2576 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2577 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2578 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2579 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2580 State->Flags.Zf = (Result == 0);
2581 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2582 State->Flags.Pf = Fast486CalculateParity(Result);
2583
2584 /* Write back the result */
2585 return Fast486WriteModrmWordOperands(State,
2586 &ModRegRm,
2587 Opcode & FAST486_OPCODE_WRITE_REG,
2588 Result);
2589 }
2590
2591 }
2592
2593 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl)
2594 {
2595 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2596 UCHAR SecondValue, Result;
2597
2598 /* Make sure this is the right instruction */
2599 ASSERT(Opcode == 0x14);
2600
2601 if (State->PrefixFlags)
2602 {
2603 /* This opcode doesn't take any prefixes */
2604 Fast486Exception(State, FAST486_EXCEPTION_UD);
2605 return FALSE;
2606 }
2607
2608 if (!Fast486FetchByte(State, &SecondValue))
2609 {
2610 /* Exception occurred */
2611 return FALSE;
2612 }
2613
2614 /* Calculate the result */
2615 Result = FirstValue + SecondValue + State->Flags.Cf;
2616
2617 /* Special exception for CF */
2618 State->Flags.Cf = State->Flags.Cf &&
2619 ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2620
2621 /* Update the flags */
2622 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2623 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2624 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2625 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2626 State->Flags.Zf = (Result == 0);
2627 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2628 State->Flags.Pf = Fast486CalculateParity(Result);
2629
2630 /* Write back the result */
2631 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2632
2633 return TRUE;
2634 }
2635
2636 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax)
2637 {
2638 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2639
2640 /* Make sure this is the right instruction */
2641 ASSERT(Opcode == 0x15);
2642
2643 NO_LOCK_PREFIX();
2644 TOGGLE_OPSIZE(Size);
2645
2646 if (Size)
2647 {
2648 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2649 ULONG SecondValue, Result;
2650
2651 if (!Fast486FetchDword(State, &SecondValue))
2652 {
2653 /* Exception occurred */
2654 return FALSE;
2655 }
2656
2657 /* Calculate the result */
2658 Result = FirstValue + SecondValue + State->Flags.Cf;
2659
2660 /* Special exception for CF */
2661 State->Flags.Cf = State->Flags.Cf &&
2662 ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2663
2664 /* Update the flags */
2665 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2666 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2667 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2668 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2669 State->Flags.Zf = (Result == 0);
2670 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2671 State->Flags.Pf = Fast486CalculateParity(Result);
2672
2673 /* Write back the result */
2674 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2675 }
2676 else
2677 {
2678 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2679 USHORT SecondValue, Result;
2680
2681 if (!Fast486FetchWord(State, &SecondValue))
2682 {
2683 /* Exception occurred */
2684 return FALSE;
2685 }
2686
2687 /* Calculate the result */
2688 Result = FirstValue + SecondValue + State->Flags.Cf;
2689
2690 /* Special exception for CF */
2691 State->Flags.Cf = State->Flags.Cf &&
2692 ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2693
2694 /* Update the flags */
2695 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2696 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2697 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2698 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2699 State->Flags.Zf = (Result == 0);
2700 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2701 State->Flags.Pf = Fast486CalculateParity(Result);
2702
2703 /* Write back the result */
2704 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2705 }
2706
2707 return TRUE;
2708 }
2709
2710 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs)
2711 {
2712 /* Call the internal API */
2713 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_SS].Selector);
2714 }
2715
2716 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs)
2717 {
2718 ULONG NewSelector;
2719
2720 if (!Fast486StackPop(State, &NewSelector))
2721 {
2722 /* Exception occurred */
2723 return FALSE;
2724 }
2725
2726 /* Call the internal API */
2727 return Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector));
2728 }
2729
2730 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
2731 {
2732 UCHAR FirstValue, SecondValue, Result;
2733 FAST486_MOD_REG_RM ModRegRm;
2734 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2735 INT Carry = State->Flags.Cf ? 1 : 0;
2736
2737 /* Make sure this is the right instruction */
2738 ASSERT((Opcode & 0xFD) == 0x18);
2739
2740 TOGGLE_ADSIZE(AddressSize);
2741
2742 /* Get the operands */
2743 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2744 {
2745 /* Exception occurred */
2746 return FALSE;
2747 }
2748
2749 if (!Fast486ReadModrmByteOperands(State,
2750 &ModRegRm,
2751 &FirstValue,
2752 &SecondValue))
2753 {
2754 /* Exception occurred */
2755 return FALSE;
2756 }
2757
2758 /* Check if this is the instruction that writes to R/M */
2759 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2760 {
2761 /* Swap the order */
2762 SWAP(FirstValue, SecondValue);
2763 }
2764
2765 /* Calculate the result */
2766 Result = FirstValue - SecondValue - Carry;
2767
2768 /* Update the flags */
2769 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2770 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2771 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2772 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2773 State->Flags.Zf = (Result == 0);
2774 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2775 State->Flags.Pf = Fast486CalculateParity(Result);
2776
2777 /* Write back the result */
2778 return Fast486WriteModrmByteOperands(State,
2779 &ModRegRm,
2780 Opcode & FAST486_OPCODE_WRITE_REG,
2781 Result);
2782 }
2783
2784 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm)
2785 {
2786 FAST486_MOD_REG_RM ModRegRm;
2787 BOOLEAN OperandSize, AddressSize;
2788 INT Carry = State->Flags.Cf ? 1 : 0;
2789
2790 /* Make sure this is the right instruction */
2791 ASSERT((Opcode & 0xFD) == 0x19);
2792
2793 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2794
2795 TOGGLE_ADSIZE(AddressSize);
2796 TOGGLE_OPSIZE(OperandSize);
2797
2798 /* Get the operands */
2799 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2800 {
2801 /* Exception occurred */
2802 return FALSE;
2803 }
2804
2805 /* Check the operand size */
2806 if (OperandSize)
2807 {
2808 ULONG FirstValue, SecondValue, Result;
2809
2810 if (!Fast486ReadModrmDwordOperands(State,
2811 &ModRegRm,
2812 &FirstValue,
2813 &SecondValue))
2814 {
2815 /* Exception occurred */
2816 return FALSE;
2817 }
2818
2819 /* Check if this is the instruction that writes to R/M */
2820 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2821 {
2822 /* Swap the order */
2823 SWAP(FirstValue, SecondValue);
2824 }
2825
2826 /* Calculate the result */
2827 Result = FirstValue - SecondValue - Carry;
2828
2829 /* Update the flags */
2830 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2831 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2832 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2833 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2834 State->Flags.Zf = (Result == 0);
2835 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2836 State->Flags.Pf = Fast486CalculateParity(Result);
2837
2838 /* Write back the result */
2839 return Fast486WriteModrmDwordOperands(State,
2840 &ModRegRm,
2841 Opcode & FAST486_OPCODE_WRITE_REG,
2842 Result);
2843 }
2844 else
2845 {
2846 USHORT FirstValue, SecondValue, Result;
2847
2848 if (!Fast486ReadModrmWordOperands(State,
2849 &ModRegRm,
2850 &FirstValue,
2851 &SecondValue))
2852 {
2853 /* Exception occurred */
2854 return FALSE;
2855 }
2856
2857 /* Check if this is the instruction that writes to R/M */
2858 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2859 {
2860 /* Swap the order */
2861 SWAP(FirstValue, SecondValue);
2862 }
2863
2864 /* Calculate the result */
2865 Result = FirstValue - SecondValue - Carry;
2866
2867 /* Update the flags */
2868 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2869 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2870 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2871 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2872 State->Flags.Zf = (Result == 0);
2873 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2874 State->Flags.Pf = Fast486CalculateParity(Result);
2875
2876 /* Write back the result */
2877 return Fast486WriteModrmWordOperands(State,
2878 &ModRegRm,
2879 Opcode & FAST486_OPCODE_WRITE_REG,
2880 Result);
2881 }
2882 }
2883
2884 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl)
2885 {
2886 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2887 UCHAR SecondValue, Result;
2888 INT Carry = State->Flags.Cf ? 1 : 0;
2889
2890 /* Make sure this is the right instruction */
2891 ASSERT(Opcode == 0x1C);
2892
2893 if (State->PrefixFlags)
2894 {
2895 /* This opcode doesn't take any prefixes */
2896 Fast486Exception(State, FAST486_EXCEPTION_UD);
2897 return FALSE;
2898 }
2899
2900 if (!Fast486FetchByte(State, &SecondValue))
2901 {
2902 /* Exception occurred */
2903 return FALSE;
2904 }
2905
2906 /* Calculate the result */
2907 Result = FirstValue - SecondValue - Carry;
2908
2909 /* Update the flags */
2910 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2911 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2912 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2913 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2914 State->Flags.Zf = (Result == 0);
2915 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2916 State->Flags.Pf = Fast486CalculateParity(Result);
2917
2918 /* Write back the result */
2919 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2920
2921 return TRUE;
2922
2923 }
2924
2925 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax)
2926 {
2927 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2928 INT Carry = State->Flags.Cf ? 1 : 0;
2929
2930 /* Make sure this is the right instruction */
2931 ASSERT(Opcode == 0x1D);
2932
2933 NO_LOCK_PREFIX();
2934 TOGGLE_OPSIZE(Size);
2935
2936 if (Size)
2937 {
2938 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2939 ULONG SecondValue, Result;
2940
2941 if (!Fast486FetchDword(State, &SecondValue))
2942 {
2943 /* Exception occurred */
2944 return FALSE;
2945 }
2946
2947 /* Calculate the result */
2948 Result = FirstValue - SecondValue - Carry;
2949
2950 /* Update the flags */
2951 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2952 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2953 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2954 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2955 State->Flags.Zf = (Result == 0);
2956 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2957 State->Flags.Pf = Fast486CalculateParity(Result);
2958
2959 /* Write back the result */
2960 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2961 }
2962 else
2963 {
2964 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2965 USHORT SecondValue, Result;
2966
2967 if (!Fast486FetchWord(State, &SecondValue))
2968 {
2969 /* Exception occurred */
2970 return FALSE;
2971 }
2972
2973 /* Calculate the result */
2974 Result = FirstValue - SecondValue - Carry;
2975
2976 /* Update the flags */
2977 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2978 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2979 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2980 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2981 State->Flags.Zf = (Result == 0);
2982 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2983 State->Flags.Pf = Fast486CalculateParity(Result);
2984
2985 /* Write back the result */
2986 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2987 }
2988
2989 return TRUE;
2990
2991 }
2992
2993 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs)
2994 {
2995 /* Call the internal API */
2996 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector);
2997 }
2998
2999 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs)
3000 {
3001 ULONG NewSelector;
3002
3003 if (!Fast486StackPop(State, &NewSelector))
3004 {
3005 /* Exception occurred */
3006 return FALSE;
3007 }
3008
3009 /* Call the internal API */
3010 return Fast486LoadSegment(State, FAST486_REG_DS, LOWORD(NewSelector));
3011 }
3012
3013 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa)
3014 {
3015 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3016 BOOLEAN Carry = State->Flags.Cf;
3017
3018 /* Clear the carry flag */
3019 State->Flags.Cf = FALSE;
3020
3021 /* Check if the first BCD digit is invalid or there was a carry from it */
3022 if (((Value & 0x0F) > 9) || State->Flags.Af)
3023 {
3024 /* Correct it */
3025 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x06;
3026 if (State->GeneralRegs[FAST486_REG_EAX].LowByte < 0x06)
3027 {
3028 /* A carry occurred */
3029 State->Flags.Cf = TRUE;
3030 }
3031
3032 /* Set the adjust flag */
3033 State->Flags.Af = TRUE;
3034 }
3035
3036 /* Check if the second BCD digit is invalid or there was a carry from it */
3037 if ((Value > 0x99) || Carry)
3038 {
3039 /* Correct it */
3040 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x60;
3041
3042 /* There was a carry */
3043 State->Flags.Cf = TRUE;
3044 }
3045
3046 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3047
3048 /* Update the flags */
3049 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3050 State->Flags.Zf = (Value == 0);
3051 State->Flags.Pf = Fast486CalculateParity(Value);
3052
3053 return TRUE;
3054 }
3055
3056 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm)
3057 {
3058 UCHAR FirstValue, SecondValue, Result;
3059 FAST486_MOD_REG_RM ModRegRm;
3060 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3061
3062 /* Make sure this is the right instruction */
3063 ASSERT((Opcode & 0xED) == 0x28);
3064
3065 TOGGLE_ADSIZE(AddressSize);
3066
3067 /* Get the operands */
3068 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3069 {
3070 /* Exception occurred */
3071 return FALSE;
3072 }
3073
3074 if (!Fast486ReadModrmByteOperands(State,
3075 &ModRegRm,
3076 &FirstValue,
3077 &SecondValue))
3078 {
3079 /* Exception occurred */
3080 return FALSE;
3081 }
3082
3083 /* Check if this is the instruction that writes to R/M */
3084 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3085 {
3086 /* Swap the order */
3087 SWAP(FirstValue, SecondValue);
3088 }
3089
3090 /* Calculate the result */
3091 Result = FirstValue - SecondValue;
3092
3093 /* Update the flags */
3094 State->Flags.Cf = (FirstValue < SecondValue);
3095 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3096 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3097 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3098 State->Flags.Zf = (Result == 0);
3099 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3100 State->Flags.Pf = Fast486CalculateParity(Result);
3101
3102 /* Check if this is not a CMP */
3103 if (!(Opcode & 0x10))
3104 {
3105 /* Write back the result */
3106 return Fast486WriteModrmByteOperands(State,
3107 &ModRegRm,
3108 Opcode & FAST486_OPCODE_WRITE_REG,
3109 Result);
3110 }
3111 else
3112 {
3113 /* Discard the result */
3114 return TRUE;
3115 }
3116 }
3117
3118 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm)
3119 {
3120 FAST486_MOD_REG_RM ModRegRm;
3121 BOOLEAN OperandSize, AddressSize;
3122
3123 /* Make sure this is the right instruction */
3124 ASSERT((Opcode & 0xED) == 0x29);
3125
3126 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3127
3128 TOGGLE_ADSIZE(AddressSize);
3129 TOGGLE_OPSIZE(OperandSize);
3130
3131 /* Get the operands */
3132 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3133 {
3134 /* Exception occurred */
3135 return FALSE;
3136 }
3137
3138 /* Check the operand size */
3139 if (OperandSize)
3140 {
3141 ULONG FirstValue, SecondValue, Result;
3142
3143 if (!Fast486ReadModrmDwordOperands(State,
3144 &ModRegRm,
3145 &FirstValue,
3146 &SecondValue))
3147 {
3148 /* Exception occurred */
3149 return FALSE;
3150 }
3151
3152 /* Check if this is the instruction that writes to R/M */
3153 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3154 {
3155 /* Swap the order */
3156 SWAP(FirstValue, SecondValue);
3157 }
3158
3159 /* Calculate the result */
3160 Result = FirstValue - SecondValue;
3161
3162 /* Update the flags */
3163 State->Flags.Cf = (FirstValue < SecondValue);
3164 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3165 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3166 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3167 State->Flags.Zf = (Result == 0);
3168 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3169 State->Flags.Pf = Fast486CalculateParity(Result);
3170
3171 /* Check if this is not a CMP */
3172 if (!(Opcode & 0x10))
3173 {
3174 /* Write back the result */
3175 return Fast486WriteModrmDwordOperands(State,
3176 &ModRegRm,
3177 Opcode & FAST486_OPCODE_WRITE_REG,
3178 Result);
3179 }
3180 else
3181 {
3182 /* Discard the result */
3183 return TRUE;
3184 }
3185 }
3186 else
3187 {
3188 USHORT FirstValue, SecondValue, Result;
3189
3190 if (!Fast486ReadModrmWordOperands(State,
3191 &ModRegRm,
3192 &FirstValue,
3193 &SecondValue))
3194 {
3195 /* Exception occurred */
3196 return FALSE;
3197 }
3198
3199 /* Check if this is the instruction that writes to R/M */
3200 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3201 {
3202 /* Swap the order */
3203 SWAP(FirstValue, SecondValue);
3204 }
3205
3206 /* Calculate the result */
3207 Result = FirstValue - SecondValue;
3208
3209 /* Update the flags */
3210 State->Flags.Cf = (FirstValue < SecondValue);
3211 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3212 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3213 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3214 State->Flags.Zf = (Result == 0);
3215 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3216 State->Flags.Pf = Fast486CalculateParity(Result);
3217
3218 /* Check if this is not a CMP */
3219 if (!(Opcode & 0x10))
3220 {
3221 /* Write back the result */
3222 return Fast486WriteModrmWordOperands(State,
3223 &ModRegRm,
3224 Opcode & FAST486_OPCODE_WRITE_REG,
3225 Result);
3226 }
3227 else
3228 {
3229 /* Discard the result */
3230 return TRUE;
3231 }
3232 }
3233 }
3234
3235 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl)
3236 {
3237 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3238 UCHAR SecondValue, Result;
3239
3240 /* Make sure this is the right instruction */
3241 ASSERT((Opcode & 0xEF) == 0x2C);
3242
3243 if (State->PrefixFlags)
3244 {
3245 /* This opcode doesn't take any prefixes */
3246 Fast486Exception(State, FAST486_EXCEPTION_UD);
3247 return FALSE;
3248 }
3249
3250 if (!Fast486FetchByte(State, &SecondValue))
3251 {
3252 /* Exception occurred */
3253 return FALSE;
3254 }
3255
3256 /* Calculate the result */
3257 Result = FirstValue - SecondValue;
3258
3259 /* Update the flags */
3260 State->Flags.Cf = (FirstValue < SecondValue);
3261 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3262 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3263 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3264 State->Flags.Zf = (Result == 0);
3265 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3266 State->Flags.Pf = Fast486CalculateParity(Result);
3267
3268 /* Check if this is not a CMP */
3269 if (!(Opcode & 0x10))
3270 {
3271 /* Write back the result */
3272 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
3273 }
3274
3275 return TRUE;
3276 }
3277
3278 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax)
3279 {
3280 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3281
3282 /* Make sure this is the right instruction */
3283 ASSERT((Opcode & 0xEF) == 0x2D);
3284
3285 NO_LOCK_PREFIX();
3286 TOGGLE_OPSIZE(Size);
3287
3288 if (Size)
3289 {
3290 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
3291 ULONG SecondValue, Result;
3292
3293 if (!Fast486FetchDword(State, &SecondValue))
3294 {
3295 /* Exception occurred */
3296 return FALSE;
3297 }
3298
3299 /* Calculate the result */
3300 Result = FirstValue - SecondValue;
3301
3302 /* Update the flags */
3303 State->Flags.Cf = (FirstValue < SecondValue);
3304 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3305 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3306 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3307 State->Flags.Zf = (Result == 0);
3308 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3309 State->Flags.Pf = Fast486CalculateParity(Result);
3310
3311 /* Check if this is not a CMP */
3312 if (!(Opcode & 0x10))
3313 {
3314 /* Write back the result */
3315 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
3316 }
3317 }
3318 else
3319 {
3320 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
3321 USHORT SecondValue, Result;
3322
3323 if (!Fast486FetchWord(State, &SecondValue))
3324 {
3325 /* Exception occurred */
3326 return FALSE;
3327 }
3328
3329 /* Calculate the result */
3330 Result = FirstValue - SecondValue;
3331
3332 /* Update the flags */
3333 State->Flags.Cf = (FirstValue < SecondValue);
3334 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3335 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3336 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3337 State->Flags.Zf = (Result == 0);
3338 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3339 State->Flags.Pf = Fast486CalculateParity(Result);
3340
3341 /* Check if this is not a CMP */
3342 if (!(Opcode & 0x10))
3343 {
3344 /* Write back the result */
3345 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
3346 }
3347 }
3348
3349 return TRUE;
3350 }
3351
3352 FAST486_OPCODE_HANDLER(Fast486OpcodeDas)
3353 {
3354 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3355 BOOLEAN Carry = State->Flags.Cf;
3356
3357 /* Clear the carry flag */
3358 State->Flags.Cf = FALSE;
3359
3360 /* Check if the first BCD digit is invalid or there was a borrow */
3361 if (((Value & 0x0F) > 9) || State->Flags.Af)
3362 {
3363 /* Correct it */
3364 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x06;
3365 if (State->GeneralRegs[FAST486_REG_EAX].LowByte > 0xFB)
3366 {
3367 /* A borrow occurred */
3368 State->Flags.Cf = TRUE;
3369 }
3370
3371 /* Set the adjust flag */
3372 State->Flags.Af = TRUE;
3373 }
3374
3375 /* Check if the second BCD digit is invalid or there was a borrow */
3376 if ((Value > 0x99) || Carry)
3377 {
3378 /* Correct it */
3379 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x60;
3380
3381 /* There was a borrow */
3382 State->Flags.Cf = TRUE;
3383 }
3384
3385 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3386
3387 /* Update the flags */
3388 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3389 State->Flags.Zf = (Value == 0);
3390 State->Flags.Pf = Fast486CalculateParity(Value);
3391
3392 return TRUE;
3393 }
3394
3395 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa)
3396 {
3397 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3398
3399 /*
3400 * Check if the value in AL is not a valid BCD digit,
3401 * or there was a carry from the lowest 4 bits of AL
3402 */
3403 if (((Value & 0x0F) > 9) || State->Flags.Af)
3404 {
3405 /* Correct it */
3406 State->GeneralRegs[FAST486_REG_EAX].LowWord += 0x06;
3407 State->GeneralRegs[FAST486_REG_EAX].HighByte++;
3408
3409 /* Set CF and AF */
3410 State->Flags.Cf = State->Flags.Af = TRUE;
3411 }
3412 else
3413 {
3414 /* Clear CF and AF */
3415 State->Flags.Cf = State->Flags.Af = FALSE;
3416 }
3417
3418 /* Keep only the lowest 4 bits of AL */
3419 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3420
3421 return TRUE;
3422 }
3423
3424 FAST486_OPCODE_HANDLER(Fast486OpcodeAas)
3425 {
3426 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3427
3428 /*
3429 * Check if the value in AL is not a valid BCD digit,
3430 * or there was a borrow from the lowest 4 bits of AL
3431 */
3432 if (((Value & 0x0F) > 9) || State->Flags.Af)
3433 {
3434 /* Correct it */
3435 State->GeneralRegs[FAST486_REG_EAX].LowWord -= 0x06;
3436 State->GeneralRegs[FAST486_REG_EAX].HighByte--;
3437
3438 /* Set CF and AF */
3439 State->Flags.Cf = State->Flags.Af = TRUE;
3440 }
3441 else
3442 {
3443 /* Clear CF and AF */
3444 State->Flags.Cf = State->Flags.Af = FALSE;
3445 }
3446
3447 /* Keep only the lowest 4 bits of AL */
3448 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3449
3450 return TRUE;
3451 }
3452
3453 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll)
3454 {
3455 INT i;
3456 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3457 FAST486_REG SavedEsp = State->GeneralRegs[FAST486_REG_ESP];
3458
3459 /* Make sure this is the right instruction */
3460 ASSERT(Opcode == 0x60);
3461
3462 TOGGLE_OPSIZE(Size);
3463 NO_LOCK_PREFIX();
3464
3465 /* Push all the registers in order */
3466 for (i = 0; i < FAST486_NUM_GEN_REGS; i++)
3467 {
3468 if (i == FAST486_REG_ESP)
3469 {
3470 /* Use the saved ESP instead */
3471 if (!Fast486StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
3472 {
3473 /* Exception occurred */
3474 return FALSE;
3475 }
3476 }
3477 else
3478 {
3479 /* Push the register */
3480 if (!Fast486StackPush(State, Size ? State->GeneralRegs[i].Long
3481 : State->GeneralRegs[i].LowWord))
3482 {
3483 /* Exception occurred */
3484 return FALSE;
3485 }
3486 }
3487 }
3488
3489 return TRUE;
3490 }
3491
3492 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll)
3493 {
3494 INT i;
3495 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3496 ULONG Value;
3497
3498 /* Make sure this is the right instruction */
3499 ASSERT(Opcode == 0x61);
3500
3501 TOGGLE_OPSIZE(Size);
3502 NO_LOCK_PREFIX();
3503
3504 /* Pop all the registers in reverse order */
3505 for (i = FAST486_NUM_GEN_REGS - 1; i >= 0; i--)
3506 {
3507 /* Pop the value */
3508 if (!Fast486StackPop(State, &Value))
3509 {
3510 /* Exception occurred */
3511 return FALSE;
3512 }
3513
3514 /* Don't modify ESP */
3515 if (i != FAST486_REG_ESP)
3516 {
3517 if (Size) State->GeneralRegs[i].Long = Value;
3518 else State->GeneralRegs[i].LowWord = LOWORD(Value);
3519 }
3520 }
3521
3522 return TRUE;
3523 }
3524
3525 FAST486_OPCODE_HANDLER(Fast486OpcodeBound)
3526 {
3527 BOOLEAN OperandSize, AddressSize;
3528 FAST486_MOD_REG_RM ModRegRm;
3529 FAST486_SEG_REGS Segment = FAST486_REG_DS;
3530
3531 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3532
3533 NO_LOCK_PREFIX();
3534 TOGGLE_OPSIZE(OperandSize);
3535 TOGGLE_ADSIZE(AddressSize);
3536
3537 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3538 {
3539 /* Exception occurred */
3540 return FALSE;
3541 }
3542
3543 if (!ModRegRm.Memory)
3544 {
3545 /* Invalid */
3546 Fast486Exception(State, FAST486_EXCEPTION_UD);
3547 return FALSE;
3548 }
3549
3550 /* Check for the segment override */
3551 if (State->PrefixFlags & FAST486_PREFIX_SEG)
3552 {
3553 /* Use the override segment instead */
3554 Segment = State->SegmentOverride;
3555 }
3556
3557 if (OperandSize)
3558 {
3559 LONG Index, LowerBound, UpperBound;
3560
3561 /* Read the operands */
3562 if (!Fast486ReadModrmDwordOperands(State,
3563 &ModRegRm,
3564 (PULONG)&Index,
3565 (PULONG)&LowerBound))
3566 {
3567 /* Exception occurred */
3568 return FALSE;
3569 }
3570
3571 if (!Fast486ReadMemory(State,
3572 Segment,
3573 ModRegRm.MemoryAddress + sizeof(ULONG),
3574 FALSE,
3575 &UpperBound,
3576 sizeof(ULONG)))
3577 {
3578 /* Exception occurred */
3579 return FALSE;
3580 }
3581
3582 if ((Index < LowerBound) || (Index > UpperBound))
3583 {
3584 /* Out of bounds */
3585 Fast486Exception(State, FAST486_EXCEPTION_BR);
3586 return FALSE;
3587 }
3588 }
3589 else
3590 {
3591 SHORT Index, LowerBound, UpperBound;
3592
3593 /* Read the operands */
3594 if (!Fast486ReadModrmWordOperands(State,
3595 &ModRegRm,
3596 (PUSHORT)&Index,
3597 (PUSHORT)&LowerBound))
3598 {
3599 /* Exception occurred */
3600 return FALSE;
3601 }
3602
3603 if (!Fast486ReadMemory(State,
3604 Segment,
3605 ModRegRm.MemoryAddress + sizeof(USHORT),
3606 FALSE,
3607 &UpperBound,
3608 sizeof(USHORT)))
3609 {
3610 /* Exception occurred */
3611 return FALSE;
3612 }
3613
3614 if ((Index < LowerBound) || (Index > UpperBound))
3615 {
3616 /* Out of bounds */
3617 Fast486Exception(State, FAST486_EXCEPTION_BR);
3618 return FALSE;
3619 }
3620 }
3621
3622 return TRUE;
3623 }
3624
3625 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl)
3626 {
3627 USHORT FirstValue, SecondValue;
3628 FAST486_MOD_REG_RM ModRegRm;
3629 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3630
3631 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
3632 || State->Flags.Vm
3633 || (State->PrefixFlags & FAST486_PREFIX_LOCK))
3634 {
3635 /* Cannot be used in real mode or with a LOCK prefix */
3636 Fast486Exception(State, FAST486_EXCEPTION_UD);
3637 return FALSE;
3638 }
3639
3640 TOGGLE_ADSIZE(AddressSize);
3641
3642 /* Get the operands */
3643 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3644 {
3645 /* Exception occurred */
3646 return FALSE;
3647 }
3648
3649 /* Read the operands */
3650 if (!Fast486ReadModrmWordOperands(State,
3651 &ModRegRm,
3652 &FirstValue,
3653 &SecondValue))
3654 {
3655 /* Exception occurred */
3656 return FALSE;
3657 }
3658
3659 /* Check if the RPL needs adjusting */
3660 if ((SecondValue & 3) < (FirstValue & 3))
3661 {
3662 /* Adjust the RPL */
3663 SecondValue &= ~3;
3664 SecondValue |= FirstValue & 3;
3665
3666 /* Set ZF */
3667 State->Flags.Zf = TRUE;
3668
3669 /* Write back the result */
3670 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
3671 }
3672 else
3673 {
3674 /* Clear ZF */
3675 State->Flags.Zf = FALSE;
3676 return TRUE;
3677 }
3678 }
3679
3680 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm)
3681 {
3682 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3683
3684 /* Make sure this is the right instruction */
3685 ASSERT(Opcode == 0x68);
3686
3687 NO_LOCK_PREFIX();
3688 TOGGLE_OPSIZE(Size);
3689
3690 if (Size)
3691 {
3692 ULONG Data;
3693
3694 if (!Fast486FetchDword(State, &Data))
3695 {
3696 /* Exception occurred */
3697 return FALSE;
3698 }
3699
3700 /* Call the internal API */
3701 return Fast486StackPush(State, Data);
3702 }
3703 else
3704 {
3705 SHORT Data;
3706
3707 if (!Fast486FetchWord(State, (PUSHORT)&Data))
3708 {
3709 /* Exception occurred */
3710 return FALSE;
3711 }
3712
3713 /* Call the internal API */
3714 return Fast486StackPush(State, Data);
3715 }
3716 }
3717
3718 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm)
3719 {
3720 BOOLEAN OperandSize, AddressSize;
3721 FAST486_MOD_REG_RM ModRegRm;
3722 LONG Multiplier;
3723
3724 /* Make sure this is the right instruction */
3725 ASSERT((Opcode & 0xFD) == 0x69);
3726
3727 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3728
3729 TOGGLE_ADSIZE(AddressSize);
3730 TOGGLE_OPSIZE(OperandSize);
3731
3732 /* Fetch the parameters */
3733 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3734 {
3735 /* Exception occurred */
3736 return FALSE;
3737 }
3738
3739 if (Opcode == 0x6B)
3740 {
3741 CHAR Byte;
3742
3743 /* Fetch the immediate operand */
3744 if (!Fast486FetchByte(State, (PUCHAR)&Byte))
3745 {
3746 /* Exception occurred */
3747 return FALSE;
3748 }
3749
3750 Multiplier = (LONG)Byte;
3751 }
3752 else
3753 {
3754 if (OperandSize)
3755 {
3756 LONG Dword;
3757
3758 /* Fetch the immediate operand */
3759 if (!Fast486FetchDword(State, (PULONG)&Dword))
3760 {
3761 /* Exception occurred */
3762 return FALSE;
3763 }
3764
3765 Multiplier = Dword;
3766 }
3767 else
3768 {
3769 SHORT Word;
3770
3771 /* Fetch the immediate operand */
3772 if (!Fast486FetchWord(State, (PUSHORT)&Word))
3773 {
3774 /* Exception occurred */
3775 return FALSE;
3776 }
3777
3778 Multiplier = (LONG)Word;
3779 }
3780 }
3781
3782 if (OperandSize)
3783 {
3784 LONG RegValue, Multiplicand;
3785 LONGLONG Product;
3786
3787 /* Read the operands */
3788 if (!Fast486ReadModrmDwordOperands(State,
3789 &ModRegRm,
3790 (PULONG)&RegValue,
3791 (PULONG)&Multiplicand))
3792 {
3793 /* Exception occurred */
3794 return FALSE;
3795 }
3796
3797 /* Multiply */
3798 Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
3799
3800 /* Check for carry/overflow */
3801 State->Flags.Cf = State->Flags.Of = ((Product < MINLONG) || (Product > MAXLONG));
3802
3803 /* Write-back the result */
3804 return Fast486WriteModrmDwordOperands(State,
3805 &ModRegRm,
3806 TRUE,
3807 (ULONG)((LONG)Product));
3808 }
3809 else
3810 {
3811 SHORT RegValue, Multiplicand;
3812 LONG Product;
3813
3814 /* Read the operands */
3815 if (!Fast486ReadModrmWordOperands(State,
3816 &ModRegRm,
3817 (PUSHORT)&RegValue,
3818 (PUSHORT)&Multiplicand))
3819 {
3820 /* Exception occurred */
3821 return FALSE;
3822 }
3823
3824 /* Multiply */
3825 Product = (LONG)Multiplicand * (LONG)Multiplier;
3826
3827 /* Check for carry/overflow */
3828 State->Flags.Cf = State->Flags.Of = ((Product < MINSHORT) || (Product > MAXSHORT));
3829
3830 /* Write-back the result */
3831 return Fast486WriteModrmWordOperands(State,
3832 &ModRegRm,
3833 TRUE,
3834 (USHORT)((SHORT)Product));
3835 }
3836 }
3837
3838 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm)
3839 {
3840 CHAR Data;
3841
3842 /* Make sure this is the right instruction */
3843 ASSERT(Opcode == 0x6A);
3844
3845 if (!Fast486FetchByte(State, (PUCHAR)&Data))
3846 {
3847 /* Exception occurred */
3848 return FALSE;
3849 }
3850
3851 /* Call the internal API */
3852 return Fast486StackPush(State, Data);
3853 }
3854
3855 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm)
3856 {
3857 UCHAR FirstValue, SecondValue, Result;
3858 FAST486_MOD_REG_RM ModRegRm;
3859 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3860
3861 /* Make sure this is the right instruction */
3862 ASSERT((Opcode & 0xFD) == 0x88);
3863
3864 TOGGLE_ADSIZE(AddressSize);
3865
3866 /* Get the operands */
3867 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3868 {
3869 /* Exception occurred */
3870 return FALSE;
3871 }
3872
3873 if (!Fast486ReadModrmByteOperands(State,
3874 &ModRegRm,
3875 &FirstValue,
3876 &SecondValue))
3877 {
3878 /* Exception occurred */
3879 return FALSE;
3880 }
3881
3882 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3883 else Result = FirstValue;
3884
3885 /* Write back the result */
3886 return Fast486WriteModrmByteOperands(State,
3887 &ModRegRm,
3888 Opcode & FAST486_OPCODE_WRITE_REG,
3889 Result);
3890
3891 }
3892
3893 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm)
3894 {
3895 FAST486_MOD_REG_RM ModRegRm;
3896 BOOLEAN OperandSize, AddressSize;
3897
3898 /* Make sure this is the right instruction */
3899 ASSERT((Opcode & 0xFD) == 0x89);
3900
3901 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3902
3903 TOGGLE_ADSIZE(AddressSize);
3904 TOGGLE_OPSIZE(OperandSize);
3905
3906 /* Get the operands */
3907 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3908 {
3909 /* Exception occurred */
3910 return FALSE;
3911 }
3912
3913 /* Check the operand size */
3914 if (OperandSize)
3915 {
3916 ULONG FirstValue, SecondValue, Result;
3917
3918 if (!Fast486ReadModrmDwordOperands(State,
3919 &ModRegRm,
3920 &FirstValue,
3921 &SecondValue))
3922 {
3923 /* Exception occurred */
3924 return FALSE;
3925 }
3926
3927 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3928 else Result = FirstValue;
3929
3930 /* Write back the result */
3931 return Fast486WriteModrmDwordOperands(State,
3932 &ModRegRm,
3933 Opcode & FAST486_OPCODE_WRITE_REG,
3934 Result);
3935 }
3936 else
3937 {
3938 USHORT FirstValue, SecondValue, Result;
3939
3940 if (!Fast486ReadModrmWordOperands(State,
3941 &ModRegRm,
3942 &FirstValue,
3943 &SecondValue))
3944 {
3945 /* Exception occurred */
3946 return FALSE;
3947 }
3948
3949 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3950 else Result = FirstValue;
3951
3952 /* Write back the result */
3953 return Fast486WriteModrmWordOperands(State,
3954 &ModRegRm,
3955 Opcode & FAST486_OPCODE_WRITE_REG,
3956 Result);
3957 }
3958 }
3959
3960 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
3961 {
3962 BOOLEAN OperandSize, AddressSize;
3963 FAST486_MOD_REG_RM ModRegRm;
3964
3965 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3966
3967 /* Make sure this is the right instruction */
3968 ASSERT(Opcode == 0x8C);
3969
3970 TOGGLE_ADSIZE(AddressSize);
3971 TOGGLE_OPSIZE(OperandSize);
3972
3973 /* Get the operands */
3974 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3975 {
3976 /* Exception occurred */
3977 return FALSE;
3978 }
3979
3980 if (ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3981 {
3982 /* Invalid */
3983 Fast486Exception(State, FAST486_EXCEPTION_UD);
3984 return FALSE;
3985 }
3986
3987 if (OperandSize)
3988 {
3989 return Fast486WriteModrmDwordOperands(State,
3990 &ModRegRm,
3991 FALSE,
3992 State->SegmentRegs[ModRegRm.Register].Selector);
3993 }
3994 else
3995 {
3996 return Fast486WriteModrmWordOperands(State,
3997 &ModRegRm,
3998 FALSE,
3999 State->SegmentRegs[ModRegRm.Register].Selector);
4000 }
4001 }
4002
4003 FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
4004 {
4005 FAST486_MOD_REG_RM ModRegRm;
4006 BOOLEAN OperandSize, AddressSize;
4007
4008 /* Make sure this is the right instruction */
4009 ASSERT(Opcode == 0x8D);
4010
4011 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4012
4013 TOGGLE_ADSIZE(AddressSize);
4014 TOGGLE_OPSIZE(OperandSize);
4015
4016 /* Get the operands */
4017 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4018 {
4019 /* Exception occurred */
4020 return FALSE;
4021 }
4022
4023 /* The second operand must be memory */
4024 if (!ModRegRm.Memory)
4025 {
4026 /* Invalid */
4027 Fast486Exception(State, FAST486_EXCEPTION_UD);
4028 return FALSE;
4029 }
4030
4031 /* Write the address to the register */
4032 if (OperandSize)
4033 {
4034 return Fast486WriteModrmDwordOperands(State,
4035 &ModRegRm,
4036 TRUE,
4037 ModRegRm.MemoryAddress);
4038 }
4039 else
4040 {
4041 return Fast486WriteModrmWordOperands(State,
4042 &ModRegRm,
4043 TRUE,
4044 ModRegRm.MemoryAddress);
4045
4046 }
4047 }
4048
4049 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
4050 {
4051 BOOLEAN OperandSize, AddressSize;
4052 FAST486_MOD_REG_RM ModRegRm;
4053
4054 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4055
4056 /* Make sure this is the right instruction */
4057 ASSERT(Opcode == 0x8E);
4058
4059 TOGGLE_ADSIZE(AddressSize);
4060 TOGGLE_OPSIZE(OperandSize);
4061
4062 /* Get the operands */
4063 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4064 {
4065 /* Exception occurred */
4066 return FALSE;
4067 }
4068
4069 if ((ModRegRm.Register >= FAST486_NUM_SEG_REGS)
4070 || ((FAST486_SEG_REGS)ModRegRm.Register == FAST486_REG_CS))
4071 {
4072 /* Invalid */
4073 Fast486Exception(State, FAST486_EXCEPTION_UD);
4074 return FALSE;
4075 }
4076
4077 if (OperandSize)
4078 {
4079 ULONG Selector;
4080
4081 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Selector))
4082 {
4083 /* Exception occurred */
4084 return FALSE;
4085 }
4086
4087 return Fast486LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
4088 }
4089 else
4090 {
4091 USHORT Selector;
4092
4093 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
4094 {
4095 /* Exception occurred */
4096 return FALSE;
4097 }
4098
4099 return Fast486LoadSegment(State, ModRegRm.Register, Selector);
4100 }
4101 }
4102
4103 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde)
4104 {
4105 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4106
4107 /* Make sure this is the right instruction */
4108 ASSERT(Opcode == 0x98);
4109
4110 TOGGLE_OPSIZE(Size);
4111 NO_LOCK_PREFIX();
4112
4113 if (Size)
4114 {
4115 /* Sign extend AX to EAX */
4116 State->GeneralRegs[FAST486_REG_EAX].Long = MAKELONG
4117 (
4118 State->GeneralRegs[FAST486_REG_EAX].LowWord,
4119 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4120 ? 0xFFFF : 0x0000
4121 );
4122 }
4123 else
4124 {
4125 /* Sign extend AL to AX */
4126 State->GeneralRegs[FAST486_REG_EAX].HighByte =
4127 (State->GeneralRegs[FAST486_REG_EAX].LowByte & SIGN_FLAG_BYTE)
4128 ? 0xFF : 0x00;
4129 }
4130
4131 return TRUE;
4132 }
4133
4134 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq)
4135 {
4136 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4137
4138 /* Make sure this is the right instruction */
4139 ASSERT(Opcode == 0x99);
4140
4141 TOGGLE_OPSIZE(Size);
4142 NO_LOCK_PREFIX();
4143
4144 if (Size)
4145 {
4146 /* Sign extend EAX to EDX:EAX */
4147 State->GeneralRegs[FAST486_REG_EDX].Long =
4148 (State->GeneralRegs[FAST486_REG_EAX].Long & SIGN_FLAG_LONG)
4149 ? 0xFFFFFFFF : 0x00000000;
4150 }
4151 else
4152 {
4153 /* Sign extend AX to DX:AX */
4154 State->GeneralRegs[FAST486_REG_EDX].LowWord =
4155 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4156 ? 0xFFFF : 0x0000;
4157 }
4158
4159 return TRUE;
4160 }
4161
4162 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
4163 {
4164 USHORT Segment = 0;
4165 ULONG Offset = 0;
4166 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4167
4168 /* Make sure this is the right instruction */
4169 ASSERT(Opcode == 0x9A);
4170
4171 TOGGLE_OPSIZE(Size);
4172 NO_LOCK_PREFIX();
4173
4174 /* Fetch the offset */
4175 if (Size)
4176 {
4177 if (!Fast486FetchDword(State, &Offset))
4178 {
4179 /* Exception occurred */
4180 return FALSE;
4181 }
4182 }
4183 else
4184 {
4185 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
4186 {
4187 /* Exception occurred */
4188 return FALSE;
4189 }
4190 }
4191
4192 /* Fetch the segment */
4193 if (!Fast486FetchWord(State, &Segment))
4194 {
4195 /* Exception occurred */
4196 return FALSE;
4197 }
4198
4199 /* Push the current code segment selector */
4200 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
4201 {
4202 /* Exception occurred */
4203 return FALSE;
4204 }
4205
4206 /* Push the current value of the instruction pointer */
4207 if (!Fast486StackPush(State, State->InstPtr.Long))
4208 {
4209 /* Exception occurred */
4210 return FALSE;
4211 }
4212
4213 /* Load the new CS */
4214 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4215 {
4216 /* Exception occurred */
4217 return FALSE;
4218 }
4219
4220 /* Load new (E)IP */
4221 if (Size) State->InstPtr.Long = Offset;
4222 else State->InstPtr.LowWord = LOWORD(Offset);
4223
4224 return TRUE;
4225 }
4226
4227 FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
4228 {
4229 // TODO: NOT IMPLEMENTED
4230 UNIMPLEMENTED;
4231
4232 return FALSE;
4233 }
4234
4235 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
4236 {
4237 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4238
4239 NO_LOCK_PREFIX();
4240 TOGGLE_OPSIZE(Size);
4241
4242 /* Check for VM86 mode when IOPL is not 3 */
4243 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4244 {
4245 /* Call the VM86 monitor */
4246 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4247 return FALSE;
4248 }
4249
4250 /* Push the flags */
4251 if (Size) return Fast486StackPush(State, State->Flags.Long);
4252 else return Fast486StackPush(State, LOWORD(State->Flags.Long));
4253 }
4254
4255 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
4256 {
4257 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4258 INT Cpl = Fast486GetCurrentPrivLevel(State);
4259 FAST486_FLAGS_REG NewFlags;
4260
4261 NO_LOCK_PREFIX();
4262 TOGGLE_OPSIZE(Size);
4263
4264 /* Pop the new flags */
4265 if (!Fast486StackPop(State, &NewFlags.Long))
4266 {
4267 /* Exception occurred */
4268 return FALSE;
4269 }
4270
4271 /* Check for VM86 mode when IOPL is not 3 */
4272 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4273 {
4274 /* Call the VM86 monitor */
4275 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4276 return FALSE;
4277 }
4278
4279 State->Flags.Cf = NewFlags.Cf;
4280 State->Flags.Pf = NewFlags.Pf;
4281 State->Flags.Af = NewFlags.Af;
4282 State->Flags.Zf = NewFlags.Zf;
4283 State->Flags.Sf = NewFlags.Sf;
4284 State->Flags.Tf = NewFlags.Tf;
4285 State->Flags.Df = NewFlags.Df;
4286 State->Flags.Of = NewFlags.Of;
4287 State->Flags.Nt = NewFlags.Nt;
4288 State->Flags.Ac = NewFlags.Ac;
4289
4290 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4291 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4292
4293 return TRUE;
4294 }
4295
4296 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf)
4297 {
4298 /* Make sure this is the right instruction */
4299 ASSERT(Opcode == 0x9E);
4300
4301 /* Set the low-order byte of FLAGS to AH */
4302 State->Flags.Long &= 0xFFFFFF00;
4303 State->Flags.Long |= State->GeneralRegs[FAST486_REG_EAX].HighByte;
4304
4305 /* Restore the reserved bits of FLAGS */
4306 State->Flags.AlwaysSet = TRUE;
4307 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4308
4309 return TRUE;
4310 }
4311
4312 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf)
4313 {
4314 /* Make sure this is the right instruction */
4315 ASSERT(Opcode == 0x9F);
4316
4317 /* Set AH to the low-order byte of FLAGS */
4318 State->GeneralRegs[FAST486_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4319
4320 return TRUE;
4321 }
4322
4323 FAST486_OPCODE_HANDLER(Fast486OpcodeRet)
4324 {
4325 ULONG ReturnAddress;
4326 USHORT BytesToPop = 0;
4327 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4328
4329 /* Make sure this is the right instruction */
4330 ASSERT((Opcode & 0xFE) == 0xC2);
4331
4332 NO_LOCK_PREFIX();
4333 TOGGLE_OPSIZE(Size);
4334
4335 if (Opcode == 0xC2)
4336 {
4337 /* Fetch the number of bytes to pop after the return */
4338 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4339 }
4340
4341 /* Pop the return address */
4342 if (!Fast486StackPop(State, &ReturnAddress)) return FALSE;
4343
4344 /* Return to the calling procedure, and if necessary, pop the parameters */
4345 if (Size)
4346 {
4347 State->InstPtr.Long = ReturnAddress;
4348 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4349 }
4350 else
4351 {
4352 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4353 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4354 }
4355
4356 return TRUE;
4357 }
4358
4359 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
4360 {
4361 UCHAR FarPointer[6];
4362 BOOLEAN OperandSize, AddressSize;
4363 FAST486_MOD_REG_RM ModRegRm;
4364
4365 /* Make sure this is the right instruction */
4366 ASSERT((Opcode & 0xFE) == 0xC4);
4367
4368 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4369
4370 TOGGLE_OPSIZE(OperandSize);
4371 TOGGLE_ADSIZE(AddressSize);
4372
4373 /* Get the operands */
4374 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4375 {
4376 /* Exception occurred */
4377 return FALSE;
4378 }
4379
4380 if (!ModRegRm.Memory)
4381 {
4382 /* Check if this is a BOP and the host supports BOPs */
4383 if ((Opcode == 0xC4)
4384 && (ModRegRm.Register == FAST486_REG_EAX)
4385 && (ModRegRm.SecondRegister == FAST486_REG_ESP)
4386 && (State->BopCallback != NULL))
4387 {
4388 UCHAR BopCode;
4389
4390 /* Fetch the BOP code */
4391 if (!Fast486FetchByte(State, &BopCode))
4392 {
4393 /* Exception occurred */
4394 return FALSE;
4395 }
4396
4397 /* Call the BOP handler */
4398 State->BopCallback(State, BopCode);
4399
4400 /*
4401 * If an interrupt should occur at this time, delay it.
4402 * We must do this because if an interrupt begins and the BOP callback
4403 * changes the CS:IP, the interrupt handler won't execute and the
4404 * stack pointer will never be restored.
4405 */
4406 if (State->IntStatus == FAST486_INT_EXECUTE)
4407 {
4408 State->IntStatus = FAST486_INT_DELAYED;
4409 }
4410
4411 /* Return success */
4412 return TRUE;
4413 }
4414
4415 /* Invalid */
4416 Fast486Exception(State, FAST486_EXCEPTION_UD);
4417 return FALSE;
4418 }
4419
4420 if (!Fast486ReadMemory(State,
4421 (State->PrefixFlags & FAST486_PREFIX_SEG)
4422 ? State->SegmentOverride : FAST486_REG_DS,
4423 ModRegRm.MemoryAddress,
4424 FALSE,
4425 FarPointer,
4426 OperandSize ? 6 : 4))
4427 {
4428 /* Exception occurred */
4429 return FALSE;
4430 }
4431
4432 if (OperandSize)
4433 {
4434 ULONG Offset = *((PULONG)FarPointer);
4435 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4436
4437 /* Set the register to the offset */
4438 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4439
4440 /* Load the segment */
4441 return Fast486LoadSegment(State,
4442 (Opcode == 0xC4)
4443 ? FAST486_REG_ES : FAST486_REG_DS,
4444 Segment);
4445 }
4446 else
4447 {
4448 USHORT Offset = *((PUSHORT)FarPointer);
4449 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4450
4451 /* Set the register to the offset */
4452 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4453
4454 /* Load the segment */
4455 return Fast486LoadSegment(State,
4456 (Opcode == 0xC4)
4457 ? FAST486_REG_ES : FAST486_REG_DS,
4458 Segment);
4459 }
4460 }
4461
4462 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
4463 {
4464 INT i;
4465 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4466 USHORT FrameSize;
4467 UCHAR NestingLevel;
4468 FAST486_REG FramePointer;
4469
4470 /* Make sure this is the right instruction */
4471 ASSERT(Opcode == 0xC8);
4472
4473 NO_LOCK_PREFIX();
4474 TOGGLE_OPSIZE(Size);
4475
4476 if (!Fast486FetchWord(State, &FrameSize))
4477 {
4478 /* Exception occurred */
4479 return FALSE;
4480 }
4481
4482 if (!Fast486FetchByte(State, &NestingLevel))
4483 {
4484 /* Exception occurred */
4485 return FALSE;
4486 }
4487
4488 /* Push EBP */
4489 if (!Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long))
4490 {
4491 /* Exception occurred */
4492 return FALSE;
4493 }
4494
4495 /* Save ESP */
4496 FramePointer = State->GeneralRegs[FAST486_REG_ESP];
4497
4498 /* Set up the nested procedure stacks */
4499 for (i = 1; i < NestingLevel; i++)
4500 {
4501 if (Size)
4502 {
4503 State->GeneralRegs[FAST486_REG_EBP].Long -= 4;
4504 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long);
4505 }
4506 else
4507 {
4508 State->GeneralRegs[FAST486_REG_EBP].LowWord -= 2;
4509 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].LowWord);
4510 }
4511 }
4512
4513 if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
4514
4515 /* Set EBP to the frame pointer */
4516 State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
4517
4518 /* Reserve space for the frame */
4519 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
4520 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
4521
4522 return TRUE;
4523 }
4524
4525 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
4526 {
4527 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4528
4529 /* Make sure this is the right instruction */
4530 ASSERT(Opcode == 0xC9);
4531
4532 NO_LOCK_PREFIX();
4533 TOGGLE_OPSIZE(Size);
4534
4535 if (Size)
4536 {
4537 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4538 State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
4539
4540 /* Pop the saved base pointer from the stack */
4541 return Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
4542 }
4543 else
4544 {
4545 ULONG Value;
4546
4547 /* Set the stack pointer (SP) to the base pointer (BP) */
4548 State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
4549
4550 /* Pop the saved base pointer from the stack */
4551 if (Fast486StackPop(State, &Value))
4552 {
4553 State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
4554 return TRUE;
4555 }
4556 else return FALSE;
4557 }
4558 }
4559
4560 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
4561 {
4562 ULONG Segment = 0;
4563 ULONG Offset = 0;
4564 USHORT BytesToPop = 0;
4565 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4566
4567 /* Make sure this is the right instruction */
4568 ASSERT((Opcode & 0xFE) == 0xCA);
4569
4570 TOGGLE_OPSIZE(Size);
4571 NO_LOCK_PREFIX();
4572
4573 if (Opcode == 0xCA)
4574 {
4575 /* Fetch the number of bytes to pop after the return */
4576 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4577 }
4578
4579 /* Pop the offset */
4580 if (!Fast486StackPop(State, &Offset))
4581 {
4582 /* Exception occurred */
4583 return FALSE;
4584 }
4585
4586 /* Pop the segment */
4587 if (!Fast486StackPop(State, &Segment))
4588 {
4589 /* Exception occurred */
4590 return FALSE;
4591 }
4592
4593 /* Load the new CS */
4594 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4595 {
4596 /* Exception occurred */
4597 return FALSE;
4598 }
4599
4600 /* Load new (E)IP, and if necessary, pop the parameters */
4601 if (Size)
4602 {
4603 State->InstPtr.Long = Offset;
4604 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4605 }
4606 else
4607 {
4608 State->InstPtr.LowWord = LOWORD(Offset);
4609 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4610 }
4611
4612 return TRUE;
4613 }
4614
4615 FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
4616 {
4617 UCHAR IntNum;
4618 FAST486_IDT_ENTRY IdtEntry;
4619
4620 switch (Opcode)
4621 {
4622 case 0xCC:
4623 {
4624 /* This is the INT3 instruction */
4625 IntNum = 3;
4626 break;
4627 }
4628
4629 case 0xCD:
4630 {
4631 /* Fetch the interrupt number */
4632 if (!Fast486FetchByte(State, &IntNum))
4633 {
4634 /* Exception occurred */
4635 return FALSE;
4636 }
4637
4638 break;
4639 }
4640
4641 case 0xCE:
4642 {
4643 /* Don't do anything if OF is cleared */
4644 if (!State->Flags.Of) return TRUE;
4645
4646 /* Exception #OF */
4647 IntNum = FAST486_EXCEPTION_OF;
4648
4649 break;
4650 }
4651
4652 default:
4653 {
4654 /* Should not happen */
4655 ASSERT(FALSE);
4656 }
4657 }
4658
4659 /* Get the interrupt vector */
4660 if (!Fast486GetIntVector(State, IntNum, &IdtEntry))
4661 {
4662 /* Exception occurred */
4663 return FALSE;
4664 }
4665
4666 /* Perform the interrupt */
4667 if (!Fast486InterruptInternal(State,
4668 IdtEntry.Selector,
4669 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
4670 IdtEntry.Type))
4671 {
4672 /* Exception occurred */
4673 return FALSE;
4674 }
4675
4676 return TRUE;
4677 }
4678
4679 FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
4680 {
4681 FAST486_SEG_REGS i;
4682 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4683 FAST486_FLAGS_REG NewFlags;
4684 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4685
4686 /* Make sure this is the right instruction */
4687 ASSERT(Opcode == 0xCF);
4688
4689 NO_LOCK_PREFIX();
4690 TOGGLE_OPSIZE(Size);
4691
4692 /* Pop EIP */
4693 if (!Fast486StackPop(State, &InstPtr))
4694 {
4695 /* Exception occurred */
4696 return FALSE;
4697 }
4698
4699 /* Pop CS */
4700 if (!Fast486StackPop(State, &CodeSel))
4701 {
4702 /* Exception occurred */
4703 return FALSE;
4704 }
4705
4706 /* Pop EFLAGS */
4707 if (!Fast486StackPop(State, &NewFlags.Long))
4708 {
4709 /* Exception occurred */
4710 return FALSE;
4711 }
4712
4713 /* Check for protected mode */
4714 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4715 {
4716 INT Cpl = Fast486GetCurrentPrivLevel(State);
4717
4718 if (State->Flags.Vm)
4719 {
4720 /* Return from VM86 mode */
4721
4722 /* Check the IOPL */
4723 if (State->Flags.Iopl == 3)
4724 {
4725 /* Set new EIP */
4726 State->InstPtr.Long = LOWORD(InstPtr);
4727
4728 /* Load new CS */
4729 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4730 {
4731 /* Exception occurred */
4732 return FALSE;
4733 }
4734
4735 /* Set the new flags */
4736 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4737 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4738 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4739 State->Flags.Iopl = 3;
4740 }
4741 else
4742 {
4743 /* Call the VM86 monitor */
4744 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4745 return FALSE;
4746 }
4747
4748 return TRUE;
4749 }
4750
4751 if (State->Flags.Nt)
4752 {
4753 /* Nested task return */
4754
4755 UNIMPLEMENTED;
4756 return FALSE;
4757 }
4758
4759 if (NewFlags.Vm)
4760 {
4761 /* Return to VM86 mode */
4762 ULONG Es, Ds, Fs, Gs;
4763
4764 /* Pop ESP, SS, ES, FS, GS */
4765 if (!Fast486StackPop(State, &StackPtr)) return FALSE;
4766 if (!Fast486StackPop(State, &StackSel)) return FALSE;
4767 if (!Fast486StackPop(State, &Es)) return FALSE;
4768 if (!Fast486StackPop(State, &Ds)) return FALSE;
4769 if (!Fast486StackPop(State, &Fs)) return FALSE;
4770 if (!Fast486StackPop(State, &Gs)) return FALSE;
4771
4772 /* Set the new IP */
4773 State->InstPtr.Long = LOWORD(InstPtr);
4774
4775 /* Set the new flags */
4776 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4777 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4778 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4779
4780 /* Load the new segments */
4781 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel)) return FALSE;
4782 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) return FALSE;
4783 if (!Fast486LoadSegment(State, FAST486_REG_ES, Es)) return FALSE;
4784 if (!Fast486LoadSegment(State, FAST486_REG_DS, Ds)) return FALSE;
4785 if (!Fast486LoadSegment(State, FAST486_REG_FS, Fs)) return FALSE;
4786 if (!Fast486LoadSegment(State, FAST486_REG_GS, Gs)) return FALSE;
4787
4788 return TRUE;
4789 }
4790
4791 /* Load the new CS */
4792 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4793 {
4794 /* Exception occurred */
4795 return FALSE;
4796 }
4797
4798 /* Set EIP */
4799 if (Size) State->InstPtr.Long = InstPtr;
4800 else State->InstPtr.LowWord = LOWORD(InstPtr);
4801
4802 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4803 {
4804 /* Pop ESP */
4805 if (!Fast486StackPop(State, &StackPtr))
4806 {
4807 /* Exception */
4808 return FALSE;
4809 }
4810
4811 /* Pop SS */
4812 if (!Fast486StackPop(State, &StackSel))
4813 {
4814 /* Exception */
4815 return FALSE;
4816 }
4817
4818 /* Load new SS */
4819 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4820 {
4821 /* Exception */
4822 return FALSE;
4823 }
4824
4825 /* Set ESP */
4826 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4827 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4828 }
4829
4830 /* Set the new flags */
4831 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
4832 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
4833 State->Flags.AlwaysSet = TRUE;
4834
4835 /* Set additional flags */
4836 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4837 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4838
4839 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4840 {
4841 /* Update the CPL */
4842 Cpl = Fast486GetCurrentPrivLevel(State);
4843
4844 /* Check segment security */
4845 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
4846 {
4847 /* Don't check CS or SS */
4848 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4849
4850 if ((Cpl > State->SegmentRegs[i].Dpl)
4851 && (!State->SegmentRegs[i].Executable
4852 || !State->SegmentRegs[i].DirConf))
4853 {
4854 /* Load the NULL descriptor in the segment */
4855 if (!Fast486LoadSegment(State, i, 0)) return FALSE;
4856 }
4857 }
4858 }
4859 }
4860 else
4861 {
4862 if (Size && (InstPtr & 0xFFFF0000))
4863 {
4864 /* Invalid */
4865 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4866 return FALSE;
4867 }
4868
4869 /* Set new EIP */
4870 State->InstPtr.Long = InstPtr;
4871
4872 /* Load new CS */
4873 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4874 {
4875 /* Exception occurred */
4876 return FALSE;
4877 }
4878
4879 /* Set the new flags */
4880 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4881 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4882 State->Flags.AlwaysSet = TRUE;
4883 }
4884
4885 return TRUE;
4886 }
4887
4888 FAST486_OPCODE_HANDLER(Fast486OpcodeAam)
4889 {
4890 UCHAR Base;
4891 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4892
4893 NO_LOCK_PREFIX();
4894
4895 /* Fetch the base */
4896 if (!Fast486FetchByte(State, &Base))
4897 {
4898 /* Exception occurred */
4899 return FALSE;
4900 }
4901
4902 /* Check if the base is zero */
4903 if (Base == 0)
4904 {
4905 /* Divide error */
4906 Fast486Exception(State, FAST486_EXCEPTION_DE);
4907 return FALSE;
4908 }
4909
4910 /* Adjust */
4911 State->GeneralRegs[FAST486_REG_EAX].HighByte = Value / Base;
4912 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value %= Base;
4913
4914 /* Update flags */
4915 State->Flags.Af = FALSE;
4916 State->Flags.Zf = (Value == 0);
4917 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4918 State->Flags.Pf = Fast486CalculateParity(Value);
4919
4920 return TRUE;
4921 }
4922
4923 FAST486_OPCODE_HANDLER(Fast486OpcodeAad)
4924 {
4925 UCHAR Base;
4926 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4927
4928 NO_LOCK_PREFIX();
4929
4930 /* Fetch the base */
4931 if (!Fast486FetchByte(State, &Base))
4932 {
4933 /* Exception occurred */
4934 return FALSE;
4935 }
4936
4937 /* Adjust */
4938 Value += State->GeneralRegs[FAST486_REG_EAX].HighByte * Base;
4939 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
4940
4941 /* Update flags */
4942 State->Flags.Af = FALSE;
4943 State->Flags.Zf = (Value == 0);
4944 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4945 State->Flags.Pf = Fast486CalculateParity(Value);
4946
4947 return TRUE;
4948 }
4949
4950 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat)
4951 {
4952 UCHAR Value;
4953 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4954
4955 TOGGLE_ADSIZE(AddressSize);
4956
4957 /* Read a byte from DS:[(E)BX + AL] */
4958 if (!Fast486ReadMemory(State,
4959 FAST486_REG_DS,
4960 (AddressSize ? State->GeneralRegs[FAST486_REG_EBX].Long
4961 : State->GeneralRegs[FAST486_REG_EBX].LowWord)
4962 + State->GeneralRegs[FAST486_REG_EAX].LowByte,
4963 FALSE,
4964 &Value,
4965 sizeof(UCHAR)))
4966 {
4967 /* Exception occurred */
4968 return FALSE;
4969 }
4970
4971 /* Set AL to the result */
4972 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4973
4974 /* Return success */
4975 return TRUE;
4976 }
4977
4978 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop)
4979 {
4980 BOOLEAN Condition;
4981 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4982 CHAR Offset = 0;
4983
4984 /* Make sure this is the right instruction */
4985 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
4986
4987 NO_LOCK_PREFIX();
4988 TOGGLE_ADSIZE(Size);
4989
4990 if (Size) Condition = ((--State->GeneralRegs[FAST486_REG_ECX].Long) != 0);
4991 else Condition = ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) != 0);
4992
4993 if (Opcode == 0xE0)
4994 {
4995 /* Additional rule for LOOPNZ */
4996 if (State->Flags.Zf) Condition = FALSE;
4997 }
4998
4999 if (Opcode == 0xE1)
5000 {
5001 /* Additional rule for LOOPZ */
5002 if (!State->Flags.Zf) Condition = FALSE;
5003 }
5004
5005 /* Fetch the offset */
5006 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
5007 {
5008 /* An exception occurred */
5009 return FALSE;
5010 }
5011
5012 if (Condition)
5013 {
5014 /* Move the instruction pointer */
5015 if (Size) State->InstPtr.Long += Offset;
5016 else State->InstPtr.LowWord += Offset;
5017 }
5018
5019 return TRUE;
5020 }
5021
5022 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz)
5023 {
5024 BOOLEAN Condition;
5025 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5026 CHAR Offset = 0;
5027
5028 /* Make sure this is the right instruction */
5029 ASSERT(Opcode == 0xE3);
5030
5031 NO_LOCK_PREFIX();
5032 TOGGLE_ADSIZE(Size);
5033
5034 if (Size) Condition = (State->GeneralRegs[FAST486_REG_ECX].Long == 0);
5035 else Condition = (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0);
5036
5037 /* Fetch the offset */
5038 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
5039 {
5040 /* An exception occurred */
5041 return FALSE;
5042 }
5043
5044 if (Condition)
5045 {
5046 /* Move the instruction pointer */
5047 if (Size) State->InstPtr.Long += Offset;
5048 else State->InstPtr.LowWord += Offset;
5049 }
5050
5051 return TRUE;
5052 }
5053
5054 FAST486_OPCODE_HANDLER(Fast486OpcodeCall)
5055 {
5056 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5057
5058 /* Make sure this is the right instruction */
5059 ASSERT(Opcode == 0xE8);
5060
5061 TOGGLE_OPSIZE(Size);
5062 NO_LOCK_PREFIX();
5063
5064 if (Size)
5065 {
5066 LONG Offset = 0;
5067
5068 /* Fetch the offset */
5069 if (!Fast486FetchDword(State, (PULONG)&Offset))
5070 {
5071 /* An exception occurred */
5072 return FALSE;
5073 }
5074
5075 /* Push the current value of the instruction pointer */
5076 if (!Fast486StackPush(State, State->InstPtr.Long))
5077 {
5078 /* Exception occurred */
5079 return FALSE;
5080 }
5081
5082 /* Move the instruction pointer */
5083 State->InstPtr.Long += Offset;
5084 }
5085 else
5086 {
5087 SHORT Offset = 0;
5088
5089 /* Fetch the offset */
5090 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5091 {
5092 /* An exception occurred */
5093 return FALSE;
5094 }
5095
5096 /* Push the current value of the instruction pointer */
5097 if (!Fast486StackPush(State, State->InstPtr.Long))
5098 {
5099 /* Exception occurred */
5100 return FALSE;
5101 }
5102
5103 /* Move the instruction pointer */
5104 State->InstPtr.LowWord += Offset;
5105 }
5106
5107 return TRUE;
5108 }
5109
5110 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp)
5111 {
5112 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5113
5114 /* Make sure this is the right instruction */
5115 ASSERT(Opcode == 0xE9);
5116
5117 TOGGLE_OPSIZE(Size);
5118 NO_LOCK_PREFIX();
5119
5120 if (Size)
5121 {
5122 LONG Offset = 0;
5123
5124 /* Fetch the offset */
5125 if (!Fast486FetchDword(State, (PULONG)&Offset))
5126 {
5127 /* An exception occurred */
5128 return FALSE;
5129 }
5130
5131 /* Move the instruction pointer */
5132 State->InstPtr.Long += Offset;
5133 }
5134 else
5135 {
5136 SHORT Offset = 0;
5137
5138 /* Fetch the offset */
5139 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5140 {
5141 /* An exception occurred */
5142 return FALSE;
5143 }
5144
5145 /* Move the instruction pointer */
5146 State->InstPtr.Long += Offset;
5147
5148 /* Clear the top half of EIP */
5149 State->InstPtr.Long &= 0xFFFF;
5150 }
5151
5152 return TRUE;
5153 }
5154
5155 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
5156 {
5157 USHORT Segment = 0;
5158 ULONG Offset = 0;
5159 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5160
5161 /* Make sure this is the right instruction */
5162 ASSERT(Opcode == 0xEA);
5163
5164 TOGGLE_OPSIZE(Size);
5165 NO_LOCK_PREFIX();
5166
5167 /* Fetch the offset */
5168 if (Size)
5169 {
5170 if (!Fast486FetchDword(State, &Offset))
5171 {
5172 /* Exception occurred */
5173 return FALSE;
5174 }
5175 }
5176 else
5177 {
5178 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5179 {
5180 /* Exception occurred */
5181 return FALSE;
5182 }
5183 }
5184
5185 /* Fetch the segment */
5186 if (!Fast486FetchWord(State, &Segment))
5187 {
5188 /* Exception occurred */
5189 return FALSE;
5190 }
5191
5192 /* Load the new CS */
5193 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
5194 {
5195 /* Exception occurred */
5196 return FALSE;
5197 }
5198
5199 /* Load new EIP */
5200 State->InstPtr.Long = Offset;
5201
5202 return TRUE;
5203 }
5204
5205 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset)
5206 {
5207 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5208 ULONG Offset;
5209
5210 /* Make sure this is the right instruction */
5211 ASSERT(Opcode == 0xA0);
5212
5213 TOGGLE_ADSIZE(AddressSize);
5214
5215 if (AddressSize)
5216 {
5217 if (!Fast486FetchDword(State, &Offset))
5218 {
5219 /* Exception occurred */
5220 return FALSE;
5221 }
5222 }
5223 else
5224 {
5225 USHORT WordOffset;
5226
5227 if (!Fast486FetchWord(State, &WordOffset))
5228 {
5229 /* Exception occurred */
5230 return FALSE;
5231 }
5232
5233 Offset = (ULONG)WordOffset;
5234 }
5235
5236 /* Read from memory */
5237 return Fast486ReadMemory(State,
5238 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5239 State->SegmentOverride : FAST486_REG_DS,
5240 Offset,
5241 FALSE,
5242 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5243 sizeof(UCHAR));
5244 }
5245
5246 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset)
5247 {
5248 BOOLEAN OperandSize, AddressSize;
5249
5250 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5251
5252 /* Make sure this is the right instruction */
5253 ASSERT(Opcode == 0xA1);
5254
5255 TOGGLE_OPSIZE(OperandSize);
5256 TOGGLE_ADSIZE(AddressSize);
5257
5258 if (AddressSize)
5259 {
5260 ULONG Offset;
5261
5262 if (!Fast486FetchDword(State, &Offset))
5263 {
5264 /* Exception occurred */
5265 return FALSE;
5266 }
5267
5268 /* Read from memory */
5269 if (OperandSize)
5270 {
5271 return Fast486ReadMemory(State,
5272 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5273 State->SegmentOverride : FAST486_REG_DS,
5274 Offset,
5275 FALSE,
5276 &State->GeneralRegs[FAST486_REG_EAX].Long,
5277 sizeof(ULONG));
5278 }
5279 else
5280 {
5281 return Fast486ReadMemory(State,
5282 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5283 State->SegmentOverride : FAST486_REG_DS,
5284 Offset,
5285 FALSE,
5286 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5287 sizeof(USHORT));
5288 }
5289 }
5290 else
5291 {
5292 USHORT Offset;
5293
5294 if (!Fast486FetchWord(State, &Offset))
5295 {
5296 /* Exception occurred */
5297 return FALSE;
5298 }
5299
5300 /* Read from memory */
5301 if (OperandSize)
5302 {
5303 return Fast486ReadMemory(State,
5304 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5305 State->SegmentOverride : FAST486_REG_DS,
5306 Offset,
5307 FALSE,
5308 &State->GeneralRegs[FAST486_REG_EAX].Long,
5309 sizeof(ULONG));
5310 }
5311 else
5312 {
5313 return Fast486ReadMemory(State,
5314 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5315 State->SegmentOverride : FAST486_REG_DS,
5316 Offset,
5317 FALSE,
5318 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5319 sizeof(USHORT));
5320 }
5321 }
5322 }
5323
5324 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
5325 {
5326 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5327 ULONG Offset;
5328
5329 /* Make sure this is the right instruction */
5330 ASSERT(Opcode == 0xA2);
5331
5332 TOGGLE_ADSIZE(AddressSize);
5333
5334 if (AddressSize)
5335 {
5336 if (!Fast486FetchDword(State, &Offset))
5337 {
5338 /* Exception occurred */
5339 return FALSE;
5340 }
5341 }
5342 else
5343 {
5344 USHORT WordOffset;
5345
5346 if (!Fast486FetchWord(State, &WordOffset))
5347 {
5348 /* Exception occurred */
5349 return FALSE;
5350 }
5351
5352 Offset = (ULONG)WordOffset;
5353 }
5354
5355 /* Write to memory */
5356 return Fast486WriteMemory(State,
5357 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5358 State->SegmentOverride : FAST486_REG_DS,
5359 Offset,
5360 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5361 sizeof(UCHAR));
5362 }
5363
5364 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
5365 {
5366 BOOLEAN OperandSize, AddressSize;
5367
5368 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5369
5370 /* Make sure this is the right instruction */
5371 ASSERT(Opcode == 0xA3);
5372
5373 TOGGLE_OPSIZE(OperandSize);
5374 TOGGLE_ADSIZE(AddressSize);
5375
5376 if (AddressSize)
5377 {
5378 ULONG Offset;
5379
5380 if (!Fast486FetchDword(State, &Offset))
5381 {
5382 /* Exception occurred */
5383 return FALSE;
5384 }
5385
5386 /* Write to memory */
5387 if (OperandSize)
5388 {
5389 return Fast486WriteMemory(State,
5390 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5391 State->SegmentOverride : FAST486_REG_DS,
5392 Offset,
5393 &State->GeneralRegs[FAST486_REG_EAX].Long,
5394 sizeof(ULONG));
5395 }
5396 else
5397 {
5398 return Fast486WriteMemory(State,
5399 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5400 State->SegmentOverride : FAST486_REG_DS,
5401 Offset,
5402 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5403 sizeof(USHORT));
5404 }
5405 }
5406 else
5407 {
5408 USHORT Offset;
5409
5410 if (!Fast486FetchWord(State, &Offset))
5411 {
5412 /* Exception occurred */
5413 return FALSE;
5414 }
5415
5416 /* Write to memory */
5417 if (OperandSize)
5418 {
5419 return Fast486WriteMemory(State,
5420 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5421 State->SegmentOverride : FAST486_REG_DS,
5422 Offset,
5423 &State->GeneralRegs[FAST486_REG_EAX].Long,
5424 sizeof(ULONG));
5425 }
5426 else
5427 {
5428 return Fast486WriteMemory(State,
5429 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5430 State->SegmentOverride : FAST486_REG_DS,
5431 Offset,
5432 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5433 sizeof(USHORT));
5434 }
5435 }
5436 }
5437
5438 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc)
5439 {
5440 /* Make sure this is the right instruction */
5441 ASSERT(Opcode == 0xD6);
5442
5443 NO_LOCK_PREFIX();
5444
5445 /* Set all the bits of AL to CF */
5446 State->GeneralRegs[FAST486_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
5447
5448 return TRUE;
5449 }
5450
5451 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs)
5452 {
5453 ULONG Data, DataSize;
5454 BOOLEAN OperandSize, AddressSize;
5455 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5456
5457 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5458
5459 /* Make sure this is the right instruction */
5460 ASSERT((Opcode & 0xFE) == 0xA4);
5461
5462 TOGGLE_OPSIZE(OperandSize);
5463 TOGGLE_ADSIZE(AddressSize);
5464
5465 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5466 {
5467 /* Use the override segment instead of DS */
5468 Segment = State->SegmentOverride;
5469 }
5470
5471 if (State->PrefixFlags & FAST486_PREFIX_REP)
5472 {
5473 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5474 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5475 {
5476 /* Do nothing */
5477 return TRUE;
5478 }
5479 }
5480
5481 /* Calculate the size */
5482 if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
5483 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5484
5485 /* Read from the source operand */
5486 if (!Fast486ReadMemory(State,
5487 Segment,
5488 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5489 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5490 FALSE,
5491 &Data,
5492 DataSize))
5493 {
5494 /* Exception occurred */
5495 return FALSE;
5496 }
5497
5498 /* Write to the destination operand */
5499 if (!Fast486WriteMemory(State,
5500 FAST486_REG_ES,
5501 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5502 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5503 &Data,
5504 DataSize))
5505 {
5506 /* Exception occurred */
5507 return FALSE;
5508 }
5509
5510 /* Increment/decrement ESI and EDI */
5511 if (AddressSize)
5512 {
5513 if (!State->Flags.Df)
5514 {
5515 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5516 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5517 }
5518 else
5519 {
5520 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5521 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5522 }
5523 }
5524 else
5525 {
5526 if (!State->Flags.Df)
5527 {
5528 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5529 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5530 }
5531 else
5532 {
5533 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5534 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5535 }
5536 }
5537
5538 // FIXME: This method is slow!
5539 if (State->PrefixFlags & FAST486_PREFIX_REP)
5540 {
5541 if (AddressSize)
5542 {
5543 if (--State->GeneralRegs[FAST486_REG_ECX].Long)
5544 {
5545 /* Repeat the instruction */
5546 State->InstPtr = State->SavedInstPtr;
5547 }
5548 }
5549 else
5550 {
5551 if (--State->GeneralRegs[FAST486_REG_ECX].LowWord)
5552 {
5553 /* Repeat the instruction */
5554 State->InstPtr = State->SavedInstPtr;
5555 }
5556 }
5557 }
5558
5559 /* Return success */
5560 return TRUE;
5561 }
5562
5563 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps)
5564 {
5565 ULONG FirstValue = 0, SecondValue = 0, Result;
5566 ULONG DataSize, DataMask, SignFlag;
5567 BOOLEAN OperandSize, AddressSize;
5568 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5569
5570 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5571
5572 /* Make sure this is the right instruction */
5573 ASSERT((Opcode & 0xFE) == 0xA6);
5574
5575 TOGGLE_OPSIZE(OperandSize);
5576 TOGGLE_ADSIZE(AddressSize);
5577
5578 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5579 {
5580 /* Use the override segment instead of DS */
5581 Segment = State->SegmentOverride;
5582 }
5583
5584 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5585 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5586 {
5587 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5588 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5589 {
5590 /* Do nothing */
5591 return TRUE;
5592 }
5593 }
5594
5595 /* Calculate the size */
5596 if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
5597 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5598
5599 /* Calculate the mask and sign flag */
5600 SignFlag = 1 << ((DataSize * 8) - 1);
5601 DataMask = SignFlag | (SignFlag - 1);
5602
5603 /* Read from the first source operand */
5604 if (!Fast486ReadMemory(State,
5605 Segment,
5606 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5607 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5608 FALSE,
5609 &FirstValue,
5610 DataSize))
5611 {
5612 /* Exception occurred */
5613 return FALSE;
5614 }
5615
5616 /* Read from the second source operand */
5617 if (!Fast486ReadMemory(State,
5618 FAST486_REG_ES,
5619 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5620 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5621 FALSE,
5622 &SecondValue,
5623 DataSize))
5624 {
5625 /* Exception occurred */
5626 return FALSE;
5627 }
5628
5629 /* Calculate the result */
5630 FirstValue &= DataMask;
5631 SecondValue &= DataMask;
5632 Result = (FirstValue - SecondValue) & DataMask;
5633
5634 /* Update the flags */
5635 State->Flags.Cf = (FirstValue < SecondValue);
5636 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5637 && ((FirstValue & SignFlag) != (Result & SignFlag));
5638 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5639 State->Flags.Zf = (Result == 0);
5640 State->Flags.Sf = ((Result & SignFlag) != 0);
5641 State->Flags.Pf = Fast486CalculateParity(Result);
5642
5643 /* Increment/decrement ESI and EDI */
5644 if (AddressSize)
5645 {
5646 if (!State->Flags.Df)
5647 {
5648 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5649 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5650 }
5651 else
5652 {
5653 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5654 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5655 }
5656 }
5657 else
5658 {
5659 if (!State->Flags.Df)
5660 {
5661 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5662 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5663 }
5664 else
5665 {
5666 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5667 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5668 }
5669 }
5670
5671 // FIXME: This method is slow!
5672 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5673 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5674 {
5675 BOOLEAN Repeat = TRUE;
5676
5677 if (AddressSize)
5678 {
5679 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5680 {
5681 /* ECX is 0 */
5682 Repeat = FALSE;
5683 }
5684 }
5685 else
5686 {
5687 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5688 {
5689 /* CX is 0 */
5690 Repeat = FALSE;
5691 }
5692 }
5693
5694 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5695 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5696 {
5697 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5698 Repeat = FALSE;
5699 }
5700
5701 if (Repeat)
5702 {
5703 /* Repeat the instruction */
5704 State->InstPtr = State->SavedInstPtr;
5705 }
5706 }
5707
5708 /* Return success */
5709 return TRUE;
5710 }
5711
5712 FAST486_OPCODE_HANDLER(Fast486OpcodeStos)
5713 {
5714 ULONG DataSize;
5715 BOOLEAN OperandSize, AddressSize;
5716
5717 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5718
5719 /* Make sure this is the right instruction */
5720 ASSERT((Opcode & 0xFE) == 0xAA);
5721
5722 TOGGLE_OPSIZE(OperandSize);
5723 TOGGLE_ADSIZE(AddressSize);
5724
5725 /* Calculate the size */
5726 if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
5727 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5728
5729 if (State->PrefixFlags & FAST486_PREFIX_REP)
5730 {
5731 UCHAR Block[STRING_BLOCK_SIZE];
5732 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5733 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5734
5735 /* Fill the memory block with the data */
5736 if (DataSize == sizeof(UCHAR))
5737 {
5738 RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[FAST486_REG_EAX].LowByte);
5739 }
5740 else
5741 {
5742 ULONG i;
5743
5744 for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
5745 {
5746 if (DataSize == sizeof(USHORT))
5747 {
5748 ((PUSHORT)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].LowWord;
5749 }
5750 else
5751 {
5752 ((PULONG)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].Long;
5753 }
5754 }
5755 }
5756
5757 /* Transfer until finished */
5758 while (Count)
5759 {
5760 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5761
5762 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5763 if (!AddressSize)
5764 {
5765 ULONG MaxBytes = State->Flags.Df
5766 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5767 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5768
5769 Processed = min(Processed, MaxBytes / DataSize);
5770 if (Processed == 0) Processed = 1;
5771 }
5772
5773 if (State->Flags.Df)
5774 {
5775 /* Set EDI to the starting location */
5776 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= (Processed - 1) * DataSize;
5777 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= (Processed - 1) * DataSize;
5778 }
5779
5780 /* Write to memory */
5781 if (!Fast486WriteMemory(State,
5782 FAST486_REG_ES,
5783 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5784 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5785 Block,
5786 Processed * DataSize))
5787 {
5788 /* Set ECX */
5789 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5790 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5791
5792 /* Exception occurred */
5793 return FALSE;
5794 }
5795
5796 if (!State->Flags.Df)
5797 {
5798 /* Increase EDI by the number of bytes transfered */
5799 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5800 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5801 }
5802 else
5803 {
5804 /* Reduce EDI */
5805 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5806 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5807 }
5808
5809 /* Reduce the total count by the number processed in this run */
5810 Count -= Processed;
5811 }
5812
5813 /* Clear ECX */
5814 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5815 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5816 }
5817 else
5818 {
5819 /* Write to the destination operand */
5820 if (!Fast486WriteMemory(State,
5821 FAST486_REG_ES,
5822 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5823 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5824 &State->GeneralRegs[FAST486_REG_EAX].Long,
5825 DataSize))
5826 {
5827 /* Exception occurred */
5828 return FALSE;
5829 }
5830
5831 /* Increment/decrement EDI */
5832 if (AddressSize)
5833 {
5834 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5835 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5836 }
5837 else
5838 {
5839 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5840 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5841 }
5842 }
5843
5844 /* Return success */
5845 return TRUE;
5846 }
5847
5848 FAST486_OPCODE_HANDLER(Fast486OpcodeLods)
5849 {
5850 ULONG DataSize;
5851 BOOLEAN OperandSize, AddressSize;
5852 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5853
5854 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5855
5856 /* Make sure this is the right instruction */
5857 ASSERT((Opcode & 0xFE) == 0xAC);
5858
5859 TOGGLE_OPSIZE(OperandSize);
5860 TOGGLE_ADSIZE(AddressSize);
5861
5862 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5863 {
5864 /* Use the override segment instead of DS */
5865 Segment = State->SegmentOverride;
5866 }
5867
5868 /* Calculate the size */
5869 if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
5870 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5871
5872 if (State->PrefixFlags & FAST486_PREFIX_REP)
5873 {
5874 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5875 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5876
5877 /* If the count is 0, do nothing */
5878 if (Count == 0) return TRUE;
5879
5880 /* Only the last entry will be loaded */
5881 if (!State->Flags.Df)
5882 {
5883 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += (Count - 1) * DataSize;
5884 else State->GeneralRegs[FAST486_REG_ESI].LowWord += (Count - 1) * DataSize;
5885 }
5886 else
5887 {
5888 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= (Count - 1) * DataSize;
5889 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= (Count - 1) * DataSize;
5890 }
5891
5892 /* Clear ECX */
5893 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5894 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5895 }
5896
5897 /* Read from the source operand */
5898 if (!Fast486ReadMemory(State,
5899 Segment,
5900 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5901 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5902 FALSE,
5903 &State->GeneralRegs[FAST486_REG_EAX].Long,
5904 DataSize))
5905 {
5906 /* Exception occurred */
5907 return FALSE;
5908 }
5909
5910 /* Increment/decrement ESI */
5911 if (AddressSize)
5912 {
5913 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5914 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5915 }
5916 else
5917 {
5918 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5919 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5920 }
5921
5922 /* Return success */
5923 return TRUE;
5924 }
5925
5926 FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
5927 {
5928 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
5929 ULONG SecondValue = 0;
5930 ULONG Result;
5931 ULONG DataSize, DataMask, SignFlag;
5932 BOOLEAN OperandSize, AddressSize;
5933
5934 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5935
5936 /* Make sure this is the right instruction */
5937 ASSERT((Opcode & 0xFE) == 0xAE);
5938
5939 TOGGLE_OPSIZE(OperandSize);
5940 TOGGLE_ADSIZE(AddressSize);
5941
5942 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5943 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5944 {
5945 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5946 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5947 {
5948 /* Do nothing */
5949 return TRUE;
5950 }
5951 }
5952
5953 /* Calculate the size */
5954 if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
5955 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5956
5957 /* Calculate the mask and sign flag */
5958 SignFlag = 1 << ((DataSize * 8) - 1);
5959 DataMask = SignFlag | (SignFlag - 1);
5960
5961 /* Read from the source operand */
5962 if (!Fast486ReadMemory(State,
5963 FAST486_REG_ES,
5964 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5965 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5966 FALSE,
5967 &SecondValue,
5968 DataSize))
5969 {
5970 /* Exception occurred */
5971 return FALSE;
5972 }
5973
5974 /* Calculate the result */
5975 FirstValue &= DataMask;
5976 SecondValue &= DataMask;
5977 Result = (FirstValue - SecondValue) & DataMask;
5978
5979 /* Update the flags */
5980 State->Flags.Cf = (FirstValue < SecondValue);
5981 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5982 && ((FirstValue & SignFlag) != (Result & SignFlag));
5983 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5984 State->Flags.Zf = (Result == 0);
5985 State->Flags.Sf = ((Result & SignFlag) != 0);
5986 State->Flags.Pf = Fast486CalculateParity(Result);
5987
5988 /* Increment/decrement EDI */
5989 if (AddressSize)
5990 {
5991 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5992 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5993 }
5994 else
5995 {
5996 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5997 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5998 }
5999
6000 // FIXME: This method is slow!
6001 if ((State->PrefixFlags & FAST486_PREFIX_REP)
6002 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
6003 {
6004 BOOLEAN Repeat = TRUE;
6005
6006 if (AddressSize)
6007 {
6008 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
6009 {
6010 /* ECX is 0 */
6011 Repeat = FALSE;
6012 }
6013 }
6014 else
6015 {
6016 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
6017 {
6018 /* CX is 0 */
6019 Repeat = FALSE;
6020 }
6021 }
6022
6023 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
6024 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
6025 {
6026 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6027 Repeat = FALSE;
6028 }
6029
6030 if (Repeat)
6031 {
6032 /* Repeat the instruction */
6033 State->InstPtr = State->SavedInstPtr;
6034 }
6035 }
6036
6037 /* Return success */
6038 return TRUE;
6039 }
6040
6041 FAST486_OPCODE_HANDLER(Fast486OpcodeIns)
6042 {
6043 ULONG DataSize;
6044 BOOLEAN OperandSize, AddressSize;
6045
6046 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6047
6048 /* Make sure this is the right instruction */
6049 ASSERT((Opcode & 0xFE) == 0x6C);
6050
6051 TOGGLE_OPSIZE(OperandSize);
6052 TOGGLE_ADSIZE(AddressSize);
6053
6054 /* Calculate the size */
6055 if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
6056 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6057
6058 if (State->PrefixFlags & FAST486_PREFIX_REP)
6059 {
6060 UCHAR Block[STRING_BLOCK_SIZE];
6061 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6062 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6063
6064 /* Clear the memory block */
6065 RtlZeroMemory(Block, sizeof(Block));
6066
6067 /* Transfer until finished */
6068 while (Count)
6069 {
6070 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6071
6072 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6073 if (!AddressSize)
6074 {
6075 ULONG MaxBytes = State->Flags.Df
6076 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6077 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6078
6079 Processed = min(Processed, MaxBytes / DataSize);
6080 if (Processed == 0) Processed = 1;
6081 }
6082
6083 /* Read from the I/O port */
6084 State->IoReadCallback(State,
6085 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6086 Block,
6087 Processed,
6088 DataSize);
6089
6090 if (State->Flags.Df)
6091 {
6092 ULONG i, j;
6093
6094 /* Reduce EDI by the number of bytes to transfer */
6095 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6096 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6097
6098 /* Reverse the block data */
6099 for (i = 0; i < Processed / 2; i++)
6100 {
6101 /* Swap the values */
6102 for (j = 0; j < DataSize; j++)
6103 {
6104 UCHAR Temp = Block[i * DataSize + j];
6105 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6106 Block[(Processed - i - 1) * DataSize + j] = Temp;
6107 }
6108 }
6109 }
6110
6111 /* Write to memory */
6112 if (!Fast486WriteMemory(State,
6113 FAST486_REG_ES,
6114 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6115 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6116 Block,
6117 Processed * DataSize))
6118 {
6119 /* Set ECX */
6120 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6121 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6122
6123 /* Exception occurred */
6124 return FALSE;
6125 }
6126
6127 if (!State->Flags.Df)
6128 {
6129 /* Increase EDI by the number of bytes transfered */
6130 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6131 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6132 }
6133
6134 /* Reduce the total count by the number processed in this run */
6135 Count -= Processed;
6136 }
6137
6138 /* Clear ECX */
6139 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6140 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6141 }
6142 else
6143 {
6144 ULONG Data = 0;
6145
6146 /* Read from the I/O port */
6147 State->IoReadCallback(State,
6148 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6149 &Data,
6150 1,
6151 DataSize);
6152
6153 /* Write to the destination operand */
6154 if (!Fast486WriteMemory(State,
6155 FAST486_REG_ES,
6156 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6157 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6158 &Data,
6159 DataSize))
6160 {
6161 /* Exception occurred */
6162 return FALSE;
6163 }
6164
6165 /* Increment/decrement EDI */
6166 if (AddressSize)
6167 {
6168 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6169 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6170 }
6171 else
6172 {
6173 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6174 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6175 }
6176 }
6177
6178 /* Return success */
6179 return TRUE;
6180 }
6181
6182 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts)
6183 {
6184 ULONG DataSize;
6185 BOOLEAN OperandSize, AddressSize;
6186
6187 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6188
6189 /* Make sure this is the right instruction */
6190 ASSERT((Opcode & 0xFE) == 0x6E);
6191
6192 TOGGLE_OPSIZE(OperandSize);
6193 TOGGLE_ADSIZE(AddressSize);
6194
6195 /* Calculate the size */
6196 if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
6197 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6198
6199 if (State->PrefixFlags & FAST486_PREFIX_REP)
6200 {
6201 UCHAR Block[STRING_BLOCK_SIZE];
6202 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6203 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6204
6205 /* Clear the memory block */
6206 RtlZeroMemory(Block, sizeof(Block));
6207
6208 /* Transfer until finished */
6209 while (Count)
6210 {
6211 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6212
6213 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6214 if (!AddressSize)
6215 {
6216 ULONG MaxBytes = State->Flags.Df
6217 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6218 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6219
6220 Processed = min(Processed, MaxBytes / DataSize);
6221 if (Processed == 0) Processed = 1;
6222 }
6223
6224 /* Read from memory */
6225 if (!Fast486ReadMemory(State,
6226 FAST486_REG_ES,
6227 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6228 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6229 FALSE,
6230 Block,
6231 Processed * DataSize))
6232 {
6233 /* Set ECX */
6234 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6235 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6236
6237 /* Exception occurred */
6238 return FALSE;
6239 }
6240
6241 if (State->Flags.Df)
6242 {
6243 ULONG i, j;
6244
6245 /* Reduce EDI by the number of bytes to transfer */
6246 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6247 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6248
6249 /* Reverse the block data */
6250 for (i = 0; i < Processed / 2; i++)
6251 {
6252 /* Swap the values */
6253 for (j = 0; j < DataSize; j++)
6254 {
6255 UCHAR Temp = Block[i * DataSize + j];
6256 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6257 Block[(Processed - i - 1) * DataSize + j] = Temp;
6258 }
6259 }
6260 }
6261
6262 /* Write to the I/O port */
6263 State->IoWriteCallback(State,
6264 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6265 Block,
6266 Processed,
6267 DataSize);
6268
6269 if (!State->Flags.Df)
6270 {
6271 /* Increase EDI by the number of bytes transfered */
6272 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6273 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6274 }
6275
6276 /* Reduce the total count by the number processed in this run */
6277 Count -= Processed;
6278 }
6279
6280 /* Clear ECX */
6281 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6282 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6283 }
6284 else
6285 {
6286 ULONG Data = 0;
6287
6288 /* Read from the source operand */
6289 if (!Fast486ReadMemory(State,
6290 FAST486_REG_DS,
6291 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6292 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6293 FALSE,
6294 &Data,
6295 DataSize))
6296 {
6297 /* Exception occurred */
6298 return FALSE;
6299 }
6300
6301 /* Write to the I/O port */
6302 State->IoWriteCallback(State,
6303 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6304 &Data,
6305 1,
6306 DataSize);
6307
6308 /* Increment/decrement ESI */
6309 if (AddressSize)
6310 {
6311 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
6312 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
6313 }
6314 else
6315 {
6316 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
6317 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
6318 }
6319 }
6320
6321 /* Return success */
6322 return TRUE;
6323 }