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