* Sync up to trunk HEAD (r62286).
[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 USHORT Data;
3706
3707 if (!Fast486FetchWord(State, &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 UCHAR Data;
3841
3842 /* Make sure this is the right instruction */
3843 ASSERT(Opcode == 0x6A);
3844
3845 if (!Fast486FetchByte(State, &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 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4272 {
4273 /* Call the VM86 monitor */
4274 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4275 return TRUE;
4276 }
4277
4278 State->Flags.Cf = NewFlags.Cf;
4279 State->Flags.Pf = NewFlags.Pf;
4280 State->Flags.Af = NewFlags.Af;
4281 State->Flags.Zf = NewFlags.Zf;
4282 State->Flags.Sf = NewFlags.Sf;
4283 State->Flags.Tf = NewFlags.Tf;
4284 State->Flags.Df = NewFlags.Df;
4285 State->Flags.Of = NewFlags.Of;
4286 State->Flags.Nt = NewFlags.Nt;
4287 State->Flags.Ac = NewFlags.Ac;
4288
4289 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4290 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4291
4292 return TRUE;
4293 }
4294
4295 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf)
4296 {
4297 /* Make sure this is the right instruction */
4298 ASSERT(Opcode == 0x9E);
4299
4300 /* Set the low-order byte of FLAGS to AH */
4301 State->Flags.Long &= 0xFFFFFF00;
4302 State->Flags.Long |= State->GeneralRegs[FAST486_REG_EAX].HighByte;
4303
4304 /* Restore the reserved bits of FLAGS */
4305 State->Flags.AlwaysSet = TRUE;
4306 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4307
4308 return FALSE;
4309 }
4310
4311 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf)
4312 {
4313 /* Make sure this is the right instruction */
4314 ASSERT(Opcode == 0x9F);
4315
4316 /* Set AH to the low-order byte of FLAGS */
4317 State->GeneralRegs[FAST486_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4318
4319 return FALSE;
4320 }
4321
4322 FAST486_OPCODE_HANDLER(Fast486OpcodeRet)
4323 {
4324 ULONG ReturnAddress;
4325 USHORT BytesToPop = 0;
4326 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4327
4328 /* Make sure this is the right instruction */
4329 ASSERT((Opcode & 0xFE) == 0xC2);
4330
4331 NO_LOCK_PREFIX();
4332 TOGGLE_OPSIZE(Size);
4333
4334 if (Opcode == 0xC2)
4335 {
4336 /* Fetch the number of bytes to pop after the return */
4337 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4338 }
4339
4340 /* Pop the return address */
4341 if (!Fast486StackPop(State, &ReturnAddress)) return FALSE;
4342
4343 /* Return to the calling procedure, and if necessary, pop the parameters */
4344 if (Size)
4345 {
4346 State->InstPtr.Long = ReturnAddress;
4347 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4348 }
4349 else
4350 {
4351 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4352 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4353 }
4354
4355 return TRUE;
4356 }
4357
4358 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
4359 {
4360 UCHAR FarPointer[6];
4361 BOOLEAN OperandSize, AddressSize;
4362 FAST486_MOD_REG_RM ModRegRm;
4363
4364 /* Make sure this is the right instruction */
4365 ASSERT((Opcode & 0xFE) == 0xC4);
4366
4367 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4368
4369 TOGGLE_OPSIZE(OperandSize);
4370 TOGGLE_ADSIZE(AddressSize);
4371
4372 /* Get the operands */
4373 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4374 {
4375 /* Exception occurred */
4376 return FALSE;
4377 }
4378
4379 if (!ModRegRm.Memory)
4380 {
4381 /* Check if this is a BOP and the host supports BOPs */
4382 if ((Opcode == 0xC4)
4383 && (ModRegRm.Register == FAST486_REG_EAX)
4384 && (ModRegRm.SecondRegister == FAST486_REG_ESP)
4385 && (State->BopCallback != NULL))
4386 {
4387 UCHAR BopCode;
4388
4389 /* Fetch the BOP code */
4390 if (!Fast486FetchByte(State, &BopCode))
4391 {
4392 /* Exception occurred */
4393 return FALSE;
4394 }
4395
4396 /* Call the BOP handler */
4397 State->BopCallback(State, BopCode);
4398
4399 /* Return success */
4400 return TRUE;
4401 }
4402
4403 /* Invalid */
4404 Fast486Exception(State, FAST486_EXCEPTION_UD);
4405 return FALSE;
4406 }
4407
4408 if (!Fast486ReadMemory(State,
4409 (State->PrefixFlags & FAST486_PREFIX_SEG)
4410 ? State->SegmentOverride : FAST486_REG_DS,
4411 ModRegRm.MemoryAddress,
4412 FALSE,
4413 FarPointer,
4414 OperandSize ? 6 : 4))
4415 {
4416 /* Exception occurred */
4417 return FALSE;
4418 }
4419
4420 if (OperandSize)
4421 {
4422 ULONG Offset = *((PULONG)FarPointer);
4423 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4424
4425 /* Set the register to the offset */
4426 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4427
4428 /* Load the segment */
4429 return Fast486LoadSegment(State,
4430 (Opcode == 0xC4)
4431 ? FAST486_REG_ES : FAST486_REG_DS,
4432 Segment);
4433 }
4434 else
4435 {
4436 USHORT Offset = *((PUSHORT)FarPointer);
4437 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4438
4439 /* Set the register to the offset */
4440 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4441
4442 /* Load the segment */
4443 return Fast486LoadSegment(State,
4444 (Opcode == 0xC4)
4445 ? FAST486_REG_ES : FAST486_REG_DS,
4446 Segment);
4447 }
4448 }
4449
4450 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
4451 {
4452 INT i;
4453 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4454 USHORT FrameSize;
4455 UCHAR NestingLevel;
4456 FAST486_REG FramePointer;
4457
4458 /* Make sure this is the right instruction */
4459 ASSERT(Opcode == 0xC8);
4460
4461 NO_LOCK_PREFIX();
4462 TOGGLE_OPSIZE(Size);
4463
4464 if (!Fast486FetchWord(State, &FrameSize))
4465 {
4466 /* Exception occurred */
4467 return FALSE;
4468 }
4469
4470 if (!Fast486FetchByte(State, &NestingLevel))
4471 {
4472 /* Exception occurred */
4473 return FALSE;
4474 }
4475
4476 /* Push EBP */
4477 if (!Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long))
4478 {
4479 /* Exception occurred */
4480 return FALSE;
4481 }
4482
4483 /* Save ESP */
4484 FramePointer = State->GeneralRegs[FAST486_REG_ESP];
4485
4486 /* Set up the nested procedure stacks */
4487 for (i = 1; i < NestingLevel; i++)
4488 {
4489 if (Size)
4490 {
4491 State->GeneralRegs[FAST486_REG_EBP].Long -= 4;
4492 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long);
4493 }
4494 else
4495 {
4496 State->GeneralRegs[FAST486_REG_EBP].LowWord -= 2;
4497 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].LowWord);
4498 }
4499 }
4500
4501 if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
4502
4503 /* Set EBP to the frame pointer */
4504 State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
4505
4506 /* Reserve space for the frame */
4507 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
4508 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
4509
4510 return TRUE;
4511 }
4512
4513 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
4514 {
4515 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4516
4517 /* Make sure this is the right instruction */
4518 ASSERT(Opcode == 0xC9);
4519
4520 NO_LOCK_PREFIX();
4521 TOGGLE_OPSIZE(Size);
4522
4523 if (Size)
4524 {
4525 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4526 State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
4527
4528 /* Pop the saved base pointer from the stack */
4529 return Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
4530 }
4531 else
4532 {
4533 ULONG Value;
4534
4535 /* Set the stack pointer (SP) to the base pointer (BP) */
4536 State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
4537
4538 /* Pop the saved base pointer from the stack */
4539 if (Fast486StackPop(State, &Value))
4540 {
4541 State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
4542 return TRUE;
4543 }
4544 else return FALSE;
4545 }
4546 }
4547
4548 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
4549 {
4550 ULONG Segment = 0;
4551 ULONG Offset = 0;
4552 USHORT BytesToPop = 0;
4553 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4554
4555 /* Make sure this is the right instruction */
4556 ASSERT((Opcode & 0xFE) == 0xCA);
4557
4558 TOGGLE_OPSIZE(Size);
4559 NO_LOCK_PREFIX();
4560
4561 if (Opcode == 0xCA)
4562 {
4563 /* Fetch the number of bytes to pop after the return */
4564 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4565 }
4566
4567 /* Pop the offset */
4568 if (!Fast486StackPop(State, &Offset))
4569 {
4570 /* Exception occurred */
4571 return FALSE;
4572 }
4573
4574 /* Pop the segment */
4575 if (!Fast486StackPop(State, &Segment))
4576 {
4577 /* Exception occurred */
4578 return FALSE;
4579 }
4580
4581 /* Load the new CS */
4582 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4583 {
4584 /* Exception occurred */
4585 return FALSE;
4586 }
4587
4588 /* Load new (E)IP, and if necessary, pop the parameters */
4589 if (Size)
4590 {
4591 State->InstPtr.Long = Offset;
4592 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4593 }
4594 else
4595 {
4596 State->InstPtr.LowWord = LOWORD(Offset);
4597 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4598 }
4599
4600 return TRUE;
4601 }
4602
4603 FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
4604 {
4605 UCHAR IntNum;
4606 FAST486_IDT_ENTRY IdtEntry;
4607
4608 switch (Opcode)
4609 {
4610 case 0xCC:
4611 {
4612 /* This is the INT3 instruction */
4613 IntNum = 3;
4614 break;
4615 }
4616
4617 case 0xCD:
4618 {
4619 /* Fetch the interrupt number */
4620 if (!Fast486FetchByte(State, &IntNum))
4621 {
4622 /* Exception occurred */
4623 return FALSE;
4624 }
4625
4626 break;
4627 }
4628
4629 case 0xCE:
4630 {
4631 /* Don't do anything if OF is cleared */
4632 if (!State->Flags.Of) return TRUE;
4633
4634 /* Exception #OF */
4635 IntNum = FAST486_EXCEPTION_OF;
4636
4637 break;
4638 }
4639
4640 default:
4641 {
4642 /* Should not happen */
4643 ASSERT(FALSE);
4644 }
4645 }
4646
4647 /* Get the interrupt vector */
4648 if (!Fast486GetIntVector(State, IntNum, &IdtEntry))
4649 {
4650 /* Exception occurred */
4651 return FALSE;
4652 }
4653
4654 /* Perform the interrupt */
4655 if (!Fast486InterruptInternal(State,
4656 IdtEntry.Selector,
4657 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
4658 IdtEntry.Type))
4659 {
4660 /* Exception occurred */
4661 return FALSE;
4662 }
4663
4664 return TRUE;
4665 }
4666
4667 FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
4668 {
4669 FAST486_SEG_REGS i;
4670 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4671 FAST486_FLAGS_REG NewFlags;
4672 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4673
4674 /* Make sure this is the right instruction */
4675 ASSERT(Opcode == 0xCF);
4676
4677 NO_LOCK_PREFIX();
4678 TOGGLE_OPSIZE(Size);
4679
4680 /* Pop EIP */
4681 if (!Fast486StackPop(State, &InstPtr))
4682 {
4683 /* Exception occurred */
4684 return FALSE;
4685 }
4686
4687 /* Pop CS */
4688 if (!Fast486StackPop(State, &CodeSel))
4689 {
4690 /* Exception occurred */
4691 return FALSE;
4692 }
4693
4694 /* Pop EFLAGS */
4695 if (!Fast486StackPop(State, &NewFlags.Long))
4696 {
4697 /* Exception occurred */
4698 return FALSE;
4699 }
4700
4701 /* Check for protected mode */
4702 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4703 {
4704 INT Cpl = Fast486GetCurrentPrivLevel(State);
4705
4706 if (State->Flags.Vm)
4707 {
4708 /* Return from VM86 mode */
4709
4710 /* Check the IOPL */
4711 if (State->Flags.Iopl == 3)
4712 {
4713 /* Set new EIP */
4714 State->InstPtr.Long = LOWORD(InstPtr);
4715
4716 /* Load new CS */
4717 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4718 {
4719 /* Exception occurred */
4720 return FALSE;
4721 }
4722
4723 /* Set the new flags */
4724 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4725 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4726 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4727 State->Flags.Iopl = 3;
4728 }
4729 else
4730 {
4731 /* Call the VM86 monitor */
4732 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4733 return FALSE;
4734 }
4735
4736 return TRUE;
4737 }
4738
4739 if (State->Flags.Nt)
4740 {
4741 /* Nested task return */
4742
4743 UNIMPLEMENTED;
4744 return FALSE;
4745 }
4746
4747 if (NewFlags.Vm)
4748 {
4749 /* Return to VM86 mode */
4750 ULONG Es, Ds, Fs, Gs;
4751
4752 /* Pop ESP, SS, ES, FS, GS */
4753 if (!Fast486StackPop(State, &StackPtr)) return FALSE;
4754 if (!Fast486StackPop(State, &StackSel)) return FALSE;
4755 if (!Fast486StackPop(State, &Es)) return FALSE;
4756 if (!Fast486StackPop(State, &Ds)) return FALSE;
4757 if (!Fast486StackPop(State, &Fs)) return FALSE;
4758 if (!Fast486StackPop(State, &Gs)) return FALSE;
4759
4760 /* Set the new IP */
4761 State->InstPtr.Long = LOWORD(InstPtr);
4762
4763 /* Set the new flags */
4764 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4765 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4766 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4767
4768 /* Load the new segments */
4769 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel)) return FALSE;
4770 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) return FALSE;
4771 if (!Fast486LoadSegment(State, FAST486_REG_ES, Es)) return FALSE;
4772 if (!Fast486LoadSegment(State, FAST486_REG_DS, Ds)) return FALSE;
4773 if (!Fast486LoadSegment(State, FAST486_REG_FS, Fs)) return FALSE;
4774 if (!Fast486LoadSegment(State, FAST486_REG_GS, Gs)) return FALSE;
4775
4776 return TRUE;
4777 }
4778
4779 /* Load the new CS */
4780 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4781 {
4782 /* Exception occurred */
4783 return FALSE;
4784 }
4785
4786 /* Set EIP */
4787 if (Size) State->InstPtr.Long = InstPtr;
4788 else State->InstPtr.LowWord = LOWORD(InstPtr);
4789
4790 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4791 {
4792 /* Pop ESP */
4793 if (!Fast486StackPop(State, &StackPtr))
4794 {
4795 /* Exception */
4796 return FALSE;
4797 }
4798
4799 /* Pop SS */
4800 if (!Fast486StackPop(State, &StackSel))
4801 {
4802 /* Exception */
4803 return FALSE;
4804 }
4805
4806 /* Load new SS */
4807 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4808 {
4809 /* Exception */
4810 return FALSE;
4811 }
4812
4813 /* Set ESP */
4814 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4815 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4816 }
4817
4818 /* Set the new flags */
4819 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
4820 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
4821 State->Flags.AlwaysSet = TRUE;
4822
4823 /* Set additional flags */
4824 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4825 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4826
4827 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4828 {
4829 /* Update the CPL */
4830 Cpl = Fast486GetCurrentPrivLevel(State);
4831
4832 /* Check segment security */
4833 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
4834 {
4835 /* Don't check CS or SS */
4836 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4837
4838 if ((Cpl > State->SegmentRegs[i].Dpl)
4839 && (!State->SegmentRegs[i].Executable
4840 || !State->SegmentRegs[i].DirConf))
4841 {
4842 /* Load the NULL descriptor in the segment */
4843 if (!Fast486LoadSegment(State, i, 0)) return FALSE;
4844 }
4845 }
4846 }
4847 }
4848 else
4849 {
4850 if (Size && (InstPtr & 0xFFFF0000))
4851 {
4852 /* Invalid */
4853 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4854 return FALSE;
4855 }
4856
4857 /* Set new EIP */
4858 State->InstPtr.Long = InstPtr;
4859
4860 /* Load new CS */
4861 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4862 {
4863 /* Exception occurred */
4864 return FALSE;
4865 }
4866
4867 /* Set the new flags */
4868 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4869 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4870 State->Flags.AlwaysSet = TRUE;
4871 }
4872
4873 return TRUE;
4874 }
4875
4876 FAST486_OPCODE_HANDLER(Fast486OpcodeAam)
4877 {
4878 UCHAR Base;
4879 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4880
4881 NO_LOCK_PREFIX();
4882
4883 /* Fetch the base */
4884 if (!Fast486FetchByte(State, &Base))
4885 {
4886 /* Exception occurred */
4887 return FALSE;
4888 }
4889
4890 /* Check if the base is zero */
4891 if (Base == 0)
4892 {
4893 /* Divide error */
4894 Fast486Exception(State, FAST486_EXCEPTION_DE);
4895 return FALSE;
4896 }
4897
4898 /* Adjust */
4899 State->GeneralRegs[FAST486_REG_EAX].HighByte = Value / Base;
4900 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value %= Base;
4901
4902 /* Update flags */
4903 State->Flags.Af = FALSE;
4904 State->Flags.Zf = (Value == 0);
4905 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4906 State->Flags.Pf = Fast486CalculateParity(Value);
4907
4908 return TRUE;
4909 }
4910
4911 FAST486_OPCODE_HANDLER(Fast486OpcodeAad)
4912 {
4913 UCHAR Base;
4914 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4915
4916 NO_LOCK_PREFIX();
4917
4918 /* Fetch the base */
4919 if (!Fast486FetchByte(State, &Base))
4920 {
4921 /* Exception occurred */
4922 return FALSE;
4923 }
4924
4925 /* Adjust */
4926 Value += State->GeneralRegs[FAST486_REG_EAX].HighByte * Base;
4927 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
4928
4929 /* Update flags */
4930 State->Flags.Af = FALSE;
4931 State->Flags.Zf = (Value == 0);
4932 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4933 State->Flags.Pf = Fast486CalculateParity(Value);
4934
4935 return TRUE;
4936 }
4937
4938 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat)
4939 {
4940 UCHAR Value;
4941 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4942
4943 TOGGLE_ADSIZE(AddressSize);
4944
4945 /* Read a byte from DS:[(E)BX + AL] */
4946 if (!Fast486ReadMemory(State,
4947 FAST486_REG_DS,
4948 (AddressSize ? State->GeneralRegs[FAST486_REG_EBX].Long
4949 : State->GeneralRegs[FAST486_REG_EBX].LowWord)
4950 + State->GeneralRegs[FAST486_REG_EAX].LowByte,
4951 FALSE,
4952 &Value,
4953 sizeof(UCHAR)))
4954 {
4955 /* Exception occurred */
4956 return FALSE;
4957 }
4958
4959 /* Set AL to the result */
4960 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4961
4962 /* Return success */
4963 return TRUE;
4964 }
4965
4966 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop)
4967 {
4968 BOOLEAN Condition;
4969 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4970 CHAR Offset = 0;
4971
4972 /* Make sure this is the right instruction */
4973 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
4974
4975 NO_LOCK_PREFIX();
4976 TOGGLE_ADSIZE(Size);
4977
4978 if (Size) Condition = ((--State->GeneralRegs[FAST486_REG_ECX].Long) != 0);
4979 else Condition = ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) != 0);
4980
4981 if (Opcode == 0xE0)
4982 {
4983 /* Additional rule for LOOPNZ */
4984 if (State->Flags.Zf) Condition = FALSE;
4985 }
4986
4987 if (Opcode == 0xE1)
4988 {
4989 /* Additional rule for LOOPZ */
4990 if (!State->Flags.Zf) Condition = FALSE;
4991 }
4992
4993 /* Fetch the offset */
4994 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4995 {
4996 /* An exception occurred */
4997 return FALSE;
4998 }
4999
5000 if (Condition)
5001 {
5002 /* Move the instruction pointer */
5003 if (Size) State->InstPtr.Long += Offset;
5004 else State->InstPtr.LowWord += Offset;
5005 }
5006
5007 return TRUE;
5008 }
5009
5010 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz)
5011 {
5012 BOOLEAN Condition;
5013 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5014 CHAR Offset = 0;
5015
5016 /* Make sure this is the right instruction */
5017 ASSERT(Opcode == 0xE3);
5018
5019 NO_LOCK_PREFIX();
5020 TOGGLE_ADSIZE(Size);
5021
5022 if (Size) Condition = (State->GeneralRegs[FAST486_REG_ECX].Long == 0);
5023 else Condition = (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0);
5024
5025 /* Fetch the offset */
5026 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
5027 {
5028 /* An exception occurred */
5029 return FALSE;
5030 }
5031
5032 if (Condition)
5033 {
5034 /* Move the instruction pointer */
5035 if (Size) State->InstPtr.Long += Offset;
5036 else State->InstPtr.LowWord += Offset;
5037 }
5038
5039 return TRUE;
5040 }
5041
5042 FAST486_OPCODE_HANDLER(Fast486OpcodeCall)
5043 {
5044 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5045
5046 /* Make sure this is the right instruction */
5047 ASSERT(Opcode == 0xE8);
5048
5049 TOGGLE_OPSIZE(Size);
5050 NO_LOCK_PREFIX();
5051
5052 if (Size)
5053 {
5054 LONG Offset = 0;
5055
5056 /* Fetch the offset */
5057 if (!Fast486FetchDword(State, (PULONG)&Offset))
5058 {
5059 /* An exception occurred */
5060 return FALSE;
5061 }
5062
5063 /* Push the current value of the instruction pointer */
5064 if (!Fast486StackPush(State, State->InstPtr.Long))
5065 {
5066 /* Exception occurred */
5067 return FALSE;
5068 }
5069
5070 /* Move the instruction pointer */
5071 State->InstPtr.Long += Offset;
5072 }
5073 else
5074 {
5075 SHORT Offset = 0;
5076
5077 /* Fetch the offset */
5078 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5079 {
5080 /* An exception occurred */
5081 return FALSE;
5082 }
5083
5084 /* Push the current value of the instruction pointer */
5085 if (!Fast486StackPush(State, State->InstPtr.Long))
5086 {
5087 /* Exception occurred */
5088 return FALSE;
5089 }
5090
5091 /* Move the instruction pointer */
5092 State->InstPtr.LowWord += Offset;
5093 }
5094
5095 return TRUE;
5096 }
5097
5098 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp)
5099 {
5100 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5101
5102 /* Make sure this is the right instruction */
5103 ASSERT(Opcode == 0xE9);
5104
5105 TOGGLE_OPSIZE(Size);
5106 NO_LOCK_PREFIX();
5107
5108 if (Size)
5109 {
5110 LONG Offset = 0;
5111
5112 /* Fetch the offset */
5113 if (!Fast486FetchDword(State, (PULONG)&Offset))
5114 {
5115 /* An exception occurred */
5116 return FALSE;
5117 }
5118
5119 /* Move the instruction pointer */
5120 State->InstPtr.Long += Offset;
5121 }
5122 else
5123 {
5124 SHORT Offset = 0;
5125
5126 /* Fetch the offset */
5127 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5128 {
5129 /* An exception occurred */
5130 return FALSE;
5131 }
5132
5133 /* Move the instruction pointer */
5134 State->InstPtr.Long += Offset;
5135
5136 /* Clear the top half of EIP */
5137 State->InstPtr.Long &= 0xFFFF;
5138 }
5139
5140 return TRUE;
5141 }
5142
5143 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
5144 {
5145 USHORT Segment = 0;
5146 ULONG Offset = 0;
5147 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5148
5149 /* Make sure this is the right instruction */
5150 ASSERT(Opcode == 0xEA);
5151
5152 TOGGLE_OPSIZE(Size);
5153 NO_LOCK_PREFIX();
5154
5155 /* Fetch the offset */
5156 if (Size)
5157 {
5158 if (!Fast486FetchDword(State, &Offset))
5159 {
5160 /* Exception occurred */
5161 return FALSE;
5162 }
5163 }
5164 else
5165 {
5166 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5167 {
5168 /* Exception occurred */
5169 return FALSE;
5170 }
5171 }
5172
5173 /* Fetch the segment */
5174 if (!Fast486FetchWord(State, &Segment))
5175 {
5176 /* Exception occurred */
5177 return FALSE;
5178 }
5179
5180 /* Load the new CS */
5181 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
5182 {
5183 /* Exception occurred */
5184 return FALSE;
5185 }
5186
5187 /* Load new EIP */
5188 State->InstPtr.Long = Offset;
5189
5190 return TRUE;
5191 }
5192
5193 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset)
5194 {
5195 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5196 ULONG Offset;
5197
5198 /* Make sure this is the right instruction */
5199 ASSERT(Opcode == 0xA0);
5200
5201 TOGGLE_ADSIZE(AddressSize);
5202
5203 if (AddressSize)
5204 {
5205 if (!Fast486FetchDword(State, &Offset))
5206 {
5207 /* Exception occurred */
5208 return FALSE;
5209 }
5210 }
5211 else
5212 {
5213 USHORT WordOffset;
5214
5215 if (!Fast486FetchWord(State, &WordOffset))
5216 {
5217 /* Exception occurred */
5218 return FALSE;
5219 }
5220
5221 Offset = (ULONG)WordOffset;
5222 }
5223
5224 /* Read from memory */
5225 return Fast486ReadMemory(State,
5226 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5227 State->SegmentOverride : FAST486_REG_DS,
5228 Offset,
5229 FALSE,
5230 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5231 sizeof(UCHAR));
5232 }
5233
5234 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset)
5235 {
5236 BOOLEAN OperandSize, AddressSize;
5237
5238 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5239
5240 /* Make sure this is the right instruction */
5241 ASSERT(Opcode == 0xA1);
5242
5243 TOGGLE_OPSIZE(OperandSize);
5244 TOGGLE_ADSIZE(AddressSize);
5245
5246 if (AddressSize)
5247 {
5248 ULONG Offset;
5249
5250 if (!Fast486FetchDword(State, &Offset))
5251 {
5252 /* Exception occurred */
5253 return FALSE;
5254 }
5255
5256 /* Read from memory */
5257 if (OperandSize)
5258 {
5259 return Fast486ReadMemory(State,
5260 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5261 State->SegmentOverride : FAST486_REG_DS,
5262 Offset,
5263 FALSE,
5264 &State->GeneralRegs[FAST486_REG_EAX].Long,
5265 sizeof(ULONG));
5266 }
5267 else
5268 {
5269 return Fast486ReadMemory(State,
5270 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5271 State->SegmentOverride : FAST486_REG_DS,
5272 Offset,
5273 FALSE,
5274 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5275 sizeof(USHORT));
5276 }
5277 }
5278 else
5279 {
5280 USHORT Offset;
5281
5282 if (!Fast486FetchWord(State, &Offset))
5283 {
5284 /* Exception occurred */
5285 return FALSE;
5286 }
5287
5288 /* Read from memory */
5289 if (OperandSize)
5290 {
5291 return Fast486ReadMemory(State,
5292 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5293 State->SegmentOverride : FAST486_REG_DS,
5294 Offset,
5295 FALSE,
5296 &State->GeneralRegs[FAST486_REG_EAX].Long,
5297 sizeof(ULONG));
5298 }
5299 else
5300 {
5301 return Fast486ReadMemory(State,
5302 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5303 State->SegmentOverride : FAST486_REG_DS,
5304 Offset,
5305 FALSE,
5306 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5307 sizeof(USHORT));
5308 }
5309 }
5310 }
5311
5312 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
5313 {
5314 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5315 ULONG Offset;
5316
5317 /* Make sure this is the right instruction */
5318 ASSERT(Opcode == 0xA2);
5319
5320 TOGGLE_ADSIZE(AddressSize);
5321
5322 if (AddressSize)
5323 {
5324 if (!Fast486FetchDword(State, &Offset))
5325 {
5326 /* Exception occurred */
5327 return FALSE;
5328 }
5329 }
5330 else
5331 {
5332 USHORT WordOffset;
5333
5334 if (!Fast486FetchWord(State, &WordOffset))
5335 {
5336 /* Exception occurred */
5337 return FALSE;
5338 }
5339
5340 Offset = (ULONG)WordOffset;
5341 }
5342
5343 /* Write to memory */
5344 return Fast486WriteMemory(State,
5345 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5346 State->SegmentOverride : FAST486_REG_DS,
5347 Offset,
5348 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5349 sizeof(UCHAR));
5350 }
5351
5352 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
5353 {
5354 BOOLEAN OperandSize, AddressSize;
5355
5356 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5357
5358 /* Make sure this is the right instruction */
5359 ASSERT(Opcode == 0xA3);
5360
5361 TOGGLE_OPSIZE(OperandSize);
5362 TOGGLE_ADSIZE(AddressSize);
5363
5364 if (AddressSize)
5365 {
5366 ULONG Offset;
5367
5368 if (!Fast486FetchDword(State, &Offset))
5369 {
5370 /* Exception occurred */
5371 return FALSE;
5372 }
5373
5374 /* Write to memory */
5375 if (OperandSize)
5376 {
5377 return Fast486WriteMemory(State,
5378 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5379 State->SegmentOverride : FAST486_REG_DS,
5380 Offset,
5381 &State->GeneralRegs[FAST486_REG_EAX].Long,
5382 sizeof(ULONG));
5383 }
5384 else
5385 {
5386 return Fast486WriteMemory(State,
5387 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5388 State->SegmentOverride : FAST486_REG_DS,
5389 Offset,
5390 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5391 sizeof(USHORT));
5392 }
5393 }
5394 else
5395 {
5396 USHORT Offset;
5397
5398 if (!Fast486FetchWord(State, &Offset))
5399 {
5400 /* Exception occurred */
5401 return FALSE;
5402 }
5403
5404 /* Write to memory */
5405 if (OperandSize)
5406 {
5407 return Fast486WriteMemory(State,
5408 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5409 State->SegmentOverride : FAST486_REG_DS,
5410 Offset,
5411 &State->GeneralRegs[FAST486_REG_EAX].Long,
5412 sizeof(ULONG));
5413 }
5414 else
5415 {
5416 return Fast486WriteMemory(State,
5417 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5418 State->SegmentOverride : FAST486_REG_DS,
5419 Offset,
5420 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5421 sizeof(USHORT));
5422 }
5423 }
5424 }
5425
5426 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc)
5427 {
5428 /* Make sure this is the right instruction */
5429 ASSERT(Opcode == 0xD6);
5430
5431 NO_LOCK_PREFIX();
5432
5433 /* Set all the bits of AL to CF */
5434 State->GeneralRegs[FAST486_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
5435
5436 return TRUE;
5437 }
5438
5439 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs)
5440 {
5441 ULONG Data, DataSize;
5442 BOOLEAN OperandSize, AddressSize;
5443 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5444
5445 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5446
5447 /* Make sure this is the right instruction */
5448 ASSERT((Opcode & 0xFE) == 0xA4);
5449
5450 TOGGLE_OPSIZE(OperandSize);
5451 TOGGLE_ADSIZE(AddressSize);
5452
5453 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5454 {
5455 /* Use the override segment instead of DS */
5456 Segment = State->SegmentOverride;
5457 }
5458
5459 if (State->PrefixFlags & FAST486_PREFIX_REP)
5460 {
5461 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5462 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5463 {
5464 /* Do nothing */
5465 return TRUE;
5466 }
5467 }
5468
5469 /* Calculate the size */
5470 if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
5471 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5472
5473 /* Read from the source operand */
5474 if (!Fast486ReadMemory(State,
5475 Segment,
5476 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5477 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5478 FALSE,
5479 &Data,
5480 DataSize))
5481 {
5482 /* Exception occurred */
5483 return FALSE;
5484 }
5485
5486 /* Write to the destination operand */
5487 if (!Fast486WriteMemory(State,
5488 FAST486_REG_ES,
5489 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5490 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5491 &Data,
5492 DataSize))
5493 {
5494 /* Exception occurred */
5495 return FALSE;
5496 }
5497
5498 /* Increment/decrement ESI and EDI */
5499 if (AddressSize)
5500 {
5501 if (!State->Flags.Df)
5502 {
5503 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5504 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5505 }
5506 else
5507 {
5508 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5509 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5510 }
5511 }
5512 else
5513 {
5514 if (!State->Flags.Df)
5515 {
5516 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5517 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5518 }
5519 else
5520 {
5521 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5522 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5523 }
5524 }
5525
5526 // FIXME: This method is slow!
5527 if (State->PrefixFlags & FAST486_PREFIX_REP)
5528 {
5529 if (AddressSize)
5530 {
5531 if (--State->GeneralRegs[FAST486_REG_ECX].Long)
5532 {
5533 /* Repeat the instruction */
5534 State->InstPtr = State->SavedInstPtr;
5535 }
5536 }
5537 else
5538 {
5539 if (--State->GeneralRegs[FAST486_REG_ECX].LowWord)
5540 {
5541 /* Repeat the instruction */
5542 State->InstPtr = State->SavedInstPtr;
5543 }
5544 }
5545 }
5546
5547 /* Return success */
5548 return TRUE;
5549 }
5550
5551 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps)
5552 {
5553 ULONG FirstValue = 0, SecondValue = 0, Result;
5554 ULONG DataSize, DataMask, SignFlag;
5555 BOOLEAN OperandSize, AddressSize;
5556 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5557
5558 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5559
5560 /* Make sure this is the right instruction */
5561 ASSERT((Opcode & 0xFE) == 0xA6);
5562
5563 TOGGLE_OPSIZE(OperandSize);
5564 TOGGLE_ADSIZE(AddressSize);
5565
5566 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5567 {
5568 /* Use the override segment instead of DS */
5569 Segment = State->SegmentOverride;
5570 }
5571
5572 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5573 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5574 {
5575 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5576 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5577 {
5578 /* Do nothing */
5579 return TRUE;
5580 }
5581 }
5582
5583 /* Calculate the size */
5584 if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
5585 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5586
5587 /* Calculate the mask and sign flag */
5588 SignFlag = 1 << ((DataSize * 8) - 1);
5589 DataMask = SignFlag | (SignFlag - 1);
5590
5591 /* Read from the first source operand */
5592 if (!Fast486ReadMemory(State,
5593 Segment,
5594 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5595 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5596 FALSE,
5597 &FirstValue,
5598 DataSize))
5599 {
5600 /* Exception occurred */
5601 return FALSE;
5602 }
5603
5604 /* Read from the second source operand */
5605 if (!Fast486ReadMemory(State,
5606 FAST486_REG_ES,
5607 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5608 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5609 FALSE,
5610 &SecondValue,
5611 DataSize))
5612 {
5613 /* Exception occurred */
5614 return FALSE;
5615 }
5616
5617 /* Calculate the result */
5618 FirstValue &= DataMask;
5619 SecondValue &= DataMask;
5620 Result = (FirstValue - SecondValue) & DataMask;
5621
5622 /* Update the flags */
5623 State->Flags.Cf = (FirstValue < SecondValue);
5624 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5625 && ((FirstValue & SignFlag) != (Result & SignFlag));
5626 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5627 State->Flags.Zf = (Result == 0);
5628 State->Flags.Sf = ((Result & SignFlag) != 0);
5629 State->Flags.Pf = Fast486CalculateParity(Result);
5630
5631 /* Increment/decrement ESI and EDI */
5632 if (AddressSize)
5633 {
5634 if (!State->Flags.Df)
5635 {
5636 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5637 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5638 }
5639 else
5640 {
5641 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5642 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5643 }
5644 }
5645 else
5646 {
5647 if (!State->Flags.Df)
5648 {
5649 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5650 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5651 }
5652 else
5653 {
5654 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5655 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5656 }
5657 }
5658
5659 // FIXME: This method is slow!
5660 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5661 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5662 {
5663 BOOLEAN Repeat = TRUE;
5664
5665 if (AddressSize)
5666 {
5667 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5668 {
5669 /* ECX is 0 */
5670 Repeat = FALSE;
5671 }
5672 }
5673 else
5674 {
5675 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5676 {
5677 /* CX is 0 */
5678 Repeat = FALSE;
5679 }
5680 }
5681
5682 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5683 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5684 {
5685 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5686 Repeat = FALSE;
5687 }
5688
5689 if (Repeat)
5690 {
5691 /* Repeat the instruction */
5692 State->InstPtr = State->SavedInstPtr;
5693 }
5694 }
5695
5696 /* Return success */
5697 return TRUE;
5698 }
5699
5700 FAST486_OPCODE_HANDLER(Fast486OpcodeStos)
5701 {
5702 ULONG DataSize;
5703 BOOLEAN OperandSize, AddressSize;
5704
5705 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5706
5707 /* Make sure this is the right instruction */
5708 ASSERT((Opcode & 0xFE) == 0xAA);
5709
5710 TOGGLE_OPSIZE(OperandSize);
5711 TOGGLE_ADSIZE(AddressSize);
5712
5713 /* Calculate the size */
5714 if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
5715 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5716
5717 if (State->PrefixFlags & FAST486_PREFIX_REP)
5718 {
5719 UCHAR Block[STRING_BLOCK_SIZE];
5720 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5721 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5722
5723 /* Fill the memory block with the data */
5724 if (DataSize == sizeof(UCHAR))
5725 {
5726 RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[FAST486_REG_EAX].LowByte);
5727 }
5728 else
5729 {
5730 ULONG i;
5731
5732 for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
5733 {
5734 if (DataSize == sizeof(USHORT))
5735 {
5736 ((PUSHORT)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].LowWord;
5737 }
5738 else
5739 {
5740 ((PULONG)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].Long;
5741 }
5742 }
5743 }
5744
5745 /* Transfer until finished */
5746 while (Count)
5747 {
5748 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5749
5750 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5751 if (!AddressSize)
5752 {
5753 ULONG MaxBytes = State->Flags.Df
5754 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5755 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5756
5757 Processed = min(Processed, MaxBytes / DataSize);
5758 if (Processed == 0) Processed = 1;
5759 }
5760
5761 if (State->Flags.Df)
5762 {
5763 /* Set EDI to the starting location */
5764 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= (Processed - 1) * DataSize;
5765 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= (Processed - 1) * DataSize;
5766 }
5767
5768 /* Write to memory */
5769 if (!Fast486WriteMemory(State,
5770 FAST486_REG_ES,
5771 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5772 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5773 Block,
5774 Processed * DataSize))
5775 {
5776 /* Set ECX */
5777 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5778 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5779
5780 /* Exception occurred */
5781 return FALSE;
5782 }
5783
5784 if (!State->Flags.Df)
5785 {
5786 /* Increase EDI by the number of bytes transfered */
5787 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5788 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5789 }
5790 else
5791 {
5792 /* Reduce EDI */
5793 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5794 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5795 }
5796
5797 /* Reduce the total count by the number processed in this run */
5798 Count -= Processed;
5799 }
5800
5801 /* Clear ECX */
5802 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5803 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5804 }
5805 else
5806 {
5807 /* Write to the destination operand */
5808 if (!Fast486WriteMemory(State,
5809 FAST486_REG_ES,
5810 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5811 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5812 &State->GeneralRegs[FAST486_REG_EAX].Long,
5813 DataSize))
5814 {
5815 /* Exception occurred */
5816 return FALSE;
5817 }
5818
5819 /* Increment/decrement EDI */
5820 if (AddressSize)
5821 {
5822 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5823 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5824 }
5825 else
5826 {
5827 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5828 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5829 }
5830 }
5831
5832 /* Return success */
5833 return TRUE;
5834 }
5835
5836 FAST486_OPCODE_HANDLER(Fast486OpcodeLods)
5837 {
5838 ULONG DataSize;
5839 BOOLEAN OperandSize, AddressSize;
5840 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5841
5842 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5843
5844 /* Make sure this is the right instruction */
5845 ASSERT((Opcode & 0xFE) == 0xAC);
5846
5847 TOGGLE_OPSIZE(OperandSize);
5848 TOGGLE_ADSIZE(AddressSize);
5849
5850 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5851 {
5852 /* Use the override segment instead of DS */
5853 Segment = State->SegmentOverride;
5854 }
5855
5856 /* Calculate the size */
5857 if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
5858 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5859
5860 if (State->PrefixFlags & FAST486_PREFIX_REP)
5861 {
5862 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5863 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5864
5865 /* If the count is 0, do nothing */
5866 if (Count == 0) return TRUE;
5867
5868 /* Only the last entry will be loaded */
5869 if (!State->Flags.Df)
5870 {
5871 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += (Count - 1) * DataSize;
5872 else State->GeneralRegs[FAST486_REG_ESI].LowWord += (Count - 1) * DataSize;
5873 }
5874 else
5875 {
5876 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= (Count - 1) * DataSize;
5877 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= (Count - 1) * DataSize;
5878 }
5879
5880 /* Clear ECX */
5881 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5882 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5883 }
5884
5885 /* Read from the source operand */
5886 if (!Fast486ReadMemory(State,
5887 Segment,
5888 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5889 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5890 FALSE,
5891 &State->GeneralRegs[FAST486_REG_EAX].Long,
5892 DataSize))
5893 {
5894 /* Exception occurred */
5895 return FALSE;
5896 }
5897
5898 /* Increment/decrement ESI */
5899 if (AddressSize)
5900 {
5901 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5902 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5903 }
5904 else
5905 {
5906 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5907 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5908 }
5909
5910 /* Return success */
5911 return TRUE;
5912 }
5913
5914 FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
5915 {
5916 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
5917 ULONG SecondValue = 0;
5918 ULONG Result;
5919 ULONG DataSize, DataMask, SignFlag;
5920 BOOLEAN OperandSize, AddressSize;
5921
5922 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5923
5924 /* Make sure this is the right instruction */
5925 ASSERT((Opcode & 0xFE) == 0xAE);
5926
5927 TOGGLE_OPSIZE(OperandSize);
5928 TOGGLE_ADSIZE(AddressSize);
5929
5930 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5931 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5932 {
5933 if ((AddressSize && (State->GeneralRegs[FAST486_REG_ECX].Long == 0))
5934 || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
5935 {
5936 /* Do nothing */
5937 return TRUE;
5938 }
5939 }
5940
5941 /* Calculate the size */
5942 if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
5943 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5944
5945 /* Calculate the mask and sign flag */
5946 SignFlag = 1 << ((DataSize * 8) - 1);
5947 DataMask = SignFlag | (SignFlag - 1);
5948
5949 /* Read from the source operand */
5950 if (!Fast486ReadMemory(State,
5951 FAST486_REG_ES,
5952 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5953 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5954 FALSE,
5955 &SecondValue,
5956 DataSize))
5957 {
5958 /* Exception occurred */
5959 return FALSE;
5960 }
5961
5962 /* Calculate the result */
5963 FirstValue &= DataMask;
5964 SecondValue &= DataMask;
5965 Result = (FirstValue - SecondValue) & DataMask;
5966
5967 /* Update the flags */
5968 State->Flags.Cf = (FirstValue < SecondValue);
5969 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5970 && ((FirstValue & SignFlag) != (Result & SignFlag));
5971 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5972 State->Flags.Zf = (Result == 0);
5973 State->Flags.Sf = ((Result & SignFlag) != 0);
5974 State->Flags.Pf = Fast486CalculateParity(Result);
5975
5976 /* Increment/decrement EDI */
5977 if (AddressSize)
5978 {
5979 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5980 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5981 }
5982 else
5983 {
5984 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5985 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5986 }
5987
5988 // FIXME: This method is slow!
5989 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5990 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5991 {
5992 BOOLEAN Repeat = TRUE;
5993
5994 if (AddressSize)
5995 {
5996 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5997 {
5998 /* ECX is 0 */
5999 Repeat = FALSE;
6000 }
6001 }
6002 else
6003 {
6004 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
6005 {
6006 /* CX is 0 */
6007 Repeat = FALSE;
6008 }
6009 }
6010
6011 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
6012 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
6013 {
6014 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6015 Repeat = FALSE;
6016 }
6017
6018 if (Repeat)
6019 {
6020 /* Repeat the instruction */
6021 State->InstPtr = State->SavedInstPtr;
6022 }
6023 }
6024
6025 /* Return success */
6026 return TRUE;
6027 }
6028
6029 FAST486_OPCODE_HANDLER(Fast486OpcodeIns)
6030 {
6031 ULONG DataSize;
6032 BOOLEAN OperandSize, AddressSize;
6033
6034 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6035
6036 /* Make sure this is the right instruction */
6037 ASSERT((Opcode & 0xFE) == 0x6C);
6038
6039 TOGGLE_OPSIZE(OperandSize);
6040 TOGGLE_ADSIZE(AddressSize);
6041
6042 /* Calculate the size */
6043 if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
6044 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6045
6046 if (State->PrefixFlags & FAST486_PREFIX_REP)
6047 {
6048 UCHAR Block[STRING_BLOCK_SIZE];
6049 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6050 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6051
6052 /* Clear the memory block */
6053 RtlZeroMemory(Block, sizeof(Block));
6054
6055 /* Transfer until finished */
6056 while (Count)
6057 {
6058 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6059
6060 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6061 if (!AddressSize)
6062 {
6063 ULONG MaxBytes = State->Flags.Df
6064 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6065 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6066
6067 Processed = min(Processed, MaxBytes / DataSize);
6068 if (Processed == 0) Processed = 1;
6069 }
6070
6071 /* Read from the I/O port */
6072 State->IoReadCallback(State,
6073 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6074 Block,
6075 Processed,
6076 DataSize);
6077
6078 if (State->Flags.Df)
6079 {
6080 ULONG i, j;
6081
6082 /* Reduce EDI by the number of bytes to transfer */
6083 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6084 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6085
6086 /* Reverse the block data */
6087 for (i = 0; i < Processed / 2; i++)
6088 {
6089 /* Swap the values */
6090 for (j = 0; j < DataSize; j++)
6091 {
6092 UCHAR Temp = Block[i * DataSize + j];
6093 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6094 Block[(Processed - i - 1) * DataSize + j] = Temp;
6095 }
6096 }
6097 }
6098
6099 /* Write to memory */
6100 if (!Fast486WriteMemory(State,
6101 FAST486_REG_ES,
6102 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6103 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6104 Block,
6105 Processed * DataSize))
6106 {
6107 /* Set ECX */
6108 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6109 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6110
6111 /* Exception occurred */
6112 return FALSE;
6113 }
6114
6115 if (!State->Flags.Df)
6116 {
6117 /* Increase EDI by the number of bytes transfered */
6118 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6119 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6120 }
6121
6122 /* Reduce the total count by the number processed in this run */
6123 Count -= Processed;
6124 }
6125
6126 /* Clear ECX */
6127 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6128 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6129 }
6130 else
6131 {
6132 ULONG Data = 0;
6133
6134 /* Read from the I/O port */
6135 State->IoReadCallback(State,
6136 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6137 &Data,
6138 1,
6139 DataSize);
6140
6141 /* Write to the destination operand */
6142 if (!Fast486WriteMemory(State,
6143 FAST486_REG_ES,
6144 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6145 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6146 &Data,
6147 DataSize))
6148 {
6149 /* Exception occurred */
6150 return FALSE;
6151 }
6152
6153 /* Increment/decrement EDI */
6154 if (AddressSize)
6155 {
6156 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6157 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6158 }
6159 else
6160 {
6161 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6162 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6163 }
6164 }
6165
6166 /* Return success */
6167 return TRUE;
6168 }
6169
6170 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts)
6171 {
6172 ULONG DataSize;
6173 BOOLEAN OperandSize, AddressSize;
6174
6175 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6176
6177 /* Make sure this is the right instruction */
6178 ASSERT((Opcode & 0xFE) == 0x6E);
6179
6180 TOGGLE_OPSIZE(OperandSize);
6181 TOGGLE_ADSIZE(AddressSize);
6182
6183 /* Calculate the size */
6184 if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
6185 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6186
6187 if (State->PrefixFlags & FAST486_PREFIX_REP)
6188 {
6189 UCHAR Block[STRING_BLOCK_SIZE];
6190 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6191 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6192
6193 /* Clear the memory block */
6194 RtlZeroMemory(Block, sizeof(Block));
6195
6196 /* Transfer until finished */
6197 while (Count)
6198 {
6199 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6200
6201 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6202 if (!AddressSize)
6203 {
6204 ULONG MaxBytes = State->Flags.Df
6205 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6206 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6207
6208 Processed = min(Processed, MaxBytes / DataSize);
6209 if (Processed == 0) Processed = 1;
6210 }
6211
6212 /* Read from memory */
6213 if (!Fast486ReadMemory(State,
6214 FAST486_REG_ES,
6215 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6216 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6217 FALSE,
6218 Block,
6219 Processed * DataSize))
6220 {
6221 /* Set ECX */
6222 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6223 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6224
6225 /* Exception occurred */
6226 return FALSE;
6227 }
6228
6229 if (State->Flags.Df)
6230 {
6231 ULONG i, j;
6232
6233 /* Reduce EDI by the number of bytes to transfer */
6234 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6235 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6236
6237 /* Reverse the block data */
6238 for (i = 0; i < Processed / 2; i++)
6239 {
6240 /* Swap the values */
6241 for (j = 0; j < DataSize; j++)
6242 {
6243 UCHAR Temp = Block[i * DataSize + j];
6244 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6245 Block[(Processed - i - 1) * DataSize + j] = Temp;
6246 }
6247 }
6248 }
6249
6250 /* Write to the I/O port */
6251 State->IoWriteCallback(State,
6252 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6253 Block,
6254 Processed,
6255 DataSize);
6256
6257 if (!State->Flags.Df)
6258 {
6259 /* Increase EDI by the number of bytes transfered */
6260 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6261 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6262 }
6263
6264 /* Reduce the total count by the number processed in this run */
6265 Count -= Processed;
6266 }
6267
6268 /* Clear ECX */
6269 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6270 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6271 }
6272 else
6273 {
6274 ULONG Data = 0;
6275
6276 /* Read from the source operand */
6277 if (!Fast486ReadMemory(State,
6278 FAST486_REG_DS,
6279 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6280 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6281 FALSE,
6282 &Data,
6283 DataSize))
6284 {
6285 /* Exception occurred */
6286 return FALSE;
6287 }
6288
6289 /* Write to the I/O port */
6290 State->IoWriteCallback(State,
6291 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6292 &Data,
6293 1,
6294 DataSize);
6295
6296 /* Increment/decrement ESI */
6297 if (AddressSize)
6298 {
6299 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
6300 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
6301 }
6302 else
6303 {
6304 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
6305 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
6306 }
6307 }
6308
6309 /* Return success */
6310 return TRUE;
6311 }