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