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