[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) ? TRUE : FALSE;
477 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
478 }
479 else
480 {
481 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
482
483 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
484 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
485 }
486
487 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
488 State->Flags.Af = ((Value & 0x0F) == 0) ? TRUE : FALSE;
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)) ? TRUE : FALSE;
511 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
512 }
513 else
514 {
515 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
516
517 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1)) ? TRUE : FALSE;
518 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
519 }
520
521 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
522 State->Flags.Af = ((Value & 0x0F) == 0x0F) ? TRUE : FALSE;
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, 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, 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, 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, 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->IoReadCallback(State, Port, &Data, 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, 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) ? TRUE : FALSE;
1190 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1191 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1243 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1244 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1274 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1275 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1315 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1316 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1354 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1355 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1380 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1381 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1425 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1476 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1505 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1544 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1581 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1605 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1649 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1700 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1729 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1763 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1800 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1824 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1868 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1919 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1948 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
1987 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2024 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2048 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2091 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2139 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2162 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2198 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2233 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2254 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2469 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2470 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2526 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2527 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2561 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2562 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2607 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2608 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2650 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2651 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2680 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2681 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2755 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2816 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2854 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2896 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2937 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
2963 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
3073 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
3142 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
3189 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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) ? TRUE : FALSE;
3239 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
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) ? TRUE : FALSE;
3282 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
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) ? TRUE : FALSE;
3312 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
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 LONGLONG Product;
3599
3600 /* Make sure this is the right instruction */
3601 ASSERT((Opcode & 0xFD) == 0x69);
3602
3603 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3604
3605 TOGGLE_ADSIZE(AddressSize);
3606 TOGGLE_OPSIZE(OperandSize);
3607
3608 /* Fetch the parameters */
3609 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3610 {
3611 /* Exception occurred */
3612 return FALSE;
3613 }
3614
3615 if (Opcode == 0x6B)
3616 {
3617 CHAR Byte;
3618
3619 /* Fetch the immediate operand */
3620 if (!Fast486FetchByte(State, (PUCHAR)&Byte))
3621 {
3622 /* Exception occurred */
3623 return FALSE;
3624 }
3625
3626 Multiplier = (LONG)Byte;
3627 }
3628 else
3629 {
3630 if (OperandSize)
3631 {
3632 LONG Dword;
3633
3634 /* Fetch the immediate operand */
3635 if (!Fast486FetchDword(State, (PULONG)&Dword))
3636 {
3637 /* Exception occurred */
3638 return FALSE;
3639 }
3640
3641 Multiplier = Dword;
3642 }
3643 else
3644 {
3645 SHORT Word;
3646
3647 /* Fetch the immediate operand */
3648 if (!Fast486FetchWord(State, (PUSHORT)&Word))
3649 {
3650 /* Exception occurred */
3651 return FALSE;
3652 }
3653
3654 Multiplier = (LONG)Word;
3655 }
3656 }
3657
3658 if (OperandSize)
3659 {
3660 LONG RegValue, Multiplicand;
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 else
3676 {
3677 SHORT RegValue, Multiplicand;
3678
3679 /* Read the operands */
3680 if (!Fast486ReadModrmWordOperands(State,
3681 &ModRegRm,
3682 (PUSHORT)&RegValue,
3683 (PUSHORT)&Multiplicand))
3684 {
3685 /* Exception occurred */
3686 return FALSE;
3687 }
3688
3689 /* Multiply */
3690 Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
3691 }
3692
3693 /* Check for carry/overflow */
3694 State->Flags.Cf = State->Flags.Of = ((Product < MINLONG) || (Product > MAXLONG));
3695
3696 /* Write-back the result */
3697 return Fast486WriteModrmDwordOperands(State,
3698 &ModRegRm,
3699 TRUE,
3700 (ULONG)((LONG)Product));
3701 }
3702
3703 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm)
3704 {
3705 UCHAR Data;
3706
3707 /* Make sure this is the right instruction */
3708 ASSERT(Opcode == 0x6A);
3709
3710 if (!Fast486FetchByte(State, &Data))
3711 {
3712 /* Exception occurred */
3713 return FALSE;
3714 }
3715
3716 /* Call the internal API */
3717 return Fast486StackPush(State, Data);
3718 }
3719
3720 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm)
3721 {
3722 UCHAR FirstValue, SecondValue, Result;
3723 FAST486_MOD_REG_RM ModRegRm;
3724 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3725
3726 /* Make sure this is the right instruction */
3727 ASSERT((Opcode & 0xFD) == 0x88);
3728
3729 TOGGLE_ADSIZE(AddressSize);
3730
3731 /* Get the operands */
3732 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3733 {
3734 /* Exception occurred */
3735 return FALSE;
3736 }
3737
3738 if (!Fast486ReadModrmByteOperands(State,
3739 &ModRegRm,
3740 &FirstValue,
3741 &SecondValue))
3742 {
3743 /* Exception occurred */
3744 return FALSE;
3745 }
3746
3747 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3748 else Result = FirstValue;
3749
3750 /* Write back the result */
3751 return Fast486WriteModrmByteOperands(State,
3752 &ModRegRm,
3753 Opcode & FAST486_OPCODE_WRITE_REG,
3754 Result);
3755
3756 }
3757
3758 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm)
3759 {
3760 FAST486_MOD_REG_RM ModRegRm;
3761 BOOLEAN OperandSize, AddressSize;
3762
3763 /* Make sure this is the right instruction */
3764 ASSERT((Opcode & 0xFD) == 0x89);
3765
3766 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3767
3768 TOGGLE_ADSIZE(AddressSize);
3769 TOGGLE_OPSIZE(OperandSize);
3770
3771 /* Get the operands */
3772 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3773 {
3774 /* Exception occurred */
3775 return FALSE;
3776 }
3777
3778 /* Check the operand size */
3779 if (OperandSize)
3780 {
3781 ULONG FirstValue, SecondValue, Result;
3782
3783 if (!Fast486ReadModrmDwordOperands(State,
3784 &ModRegRm,
3785 &FirstValue,
3786 &SecondValue))
3787 {
3788 /* Exception occurred */
3789 return FALSE;
3790 }
3791
3792 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3793 else Result = FirstValue;
3794
3795 /* Write back the result */
3796 return Fast486WriteModrmDwordOperands(State,
3797 &ModRegRm,
3798 Opcode & FAST486_OPCODE_WRITE_REG,
3799 Result);
3800 }
3801 else
3802 {
3803 USHORT FirstValue, SecondValue, Result;
3804
3805 if (!Fast486ReadModrmWordOperands(State,
3806 &ModRegRm,
3807 &FirstValue,
3808 &SecondValue))
3809 {
3810 /* Exception occurred */
3811 return FALSE;
3812 }
3813
3814 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3815 else Result = FirstValue;
3816
3817 /* Write back the result */
3818 return Fast486WriteModrmWordOperands(State,
3819 &ModRegRm,
3820 Opcode & FAST486_OPCODE_WRITE_REG,
3821 Result);
3822 }
3823 }
3824
3825 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
3826 {
3827 BOOLEAN OperandSize, AddressSize;
3828 FAST486_MOD_REG_RM ModRegRm;
3829
3830 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3831
3832 /* Make sure this is the right instruction */
3833 ASSERT(Opcode == 0x8C);
3834
3835 TOGGLE_ADSIZE(AddressSize);
3836 TOGGLE_OPSIZE(OperandSize);
3837
3838 /* Get the operands */
3839 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3840 {
3841 /* Exception occurred */
3842 return FALSE;
3843 }
3844
3845 if (ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3846 {
3847 /* Invalid */
3848 Fast486Exception(State, FAST486_EXCEPTION_UD);
3849 return FALSE;
3850 }
3851
3852 if (OperandSize)
3853 {
3854 return Fast486WriteModrmDwordOperands(State,
3855 &ModRegRm,
3856 FALSE,
3857 State->SegmentRegs[ModRegRm.Register].Selector);
3858 }
3859 else
3860 {
3861 return Fast486WriteModrmWordOperands(State,
3862 &ModRegRm,
3863 FALSE,
3864 State->SegmentRegs[ModRegRm.Register].Selector);
3865 }
3866 }
3867
3868 FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
3869 {
3870 FAST486_MOD_REG_RM ModRegRm;
3871 BOOLEAN OperandSize, AddressSize;
3872
3873 /* Make sure this is the right instruction */
3874 ASSERT(Opcode == 0x8D);
3875
3876 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3877
3878 TOGGLE_ADSIZE(AddressSize);
3879 TOGGLE_OPSIZE(OperandSize);
3880
3881 /* Get the operands */
3882 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3883 {
3884 /* Exception occurred */
3885 return FALSE;
3886 }
3887
3888 /* The second operand must be memory */
3889 if (!ModRegRm.Memory)
3890 {
3891 /* Invalid */
3892 Fast486Exception(State, FAST486_EXCEPTION_UD);
3893 return FALSE;
3894 }
3895
3896 /* Write the address to the register */
3897 if (OperandSize)
3898 {
3899 return Fast486WriteModrmDwordOperands(State,
3900 &ModRegRm,
3901 TRUE,
3902 ModRegRm.MemoryAddress);
3903 }
3904 else
3905 {
3906 return Fast486WriteModrmWordOperands(State,
3907 &ModRegRm,
3908 TRUE,
3909 ModRegRm.MemoryAddress);
3910
3911 }
3912 }
3913
3914 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
3915 {
3916 BOOLEAN OperandSize, AddressSize;
3917 FAST486_MOD_REG_RM ModRegRm;
3918
3919 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3920
3921 /* Make sure this is the right instruction */
3922 ASSERT(Opcode == 0x8E);
3923
3924 TOGGLE_ADSIZE(AddressSize);
3925 TOGGLE_OPSIZE(OperandSize);
3926
3927 /* Get the operands */
3928 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3929 {
3930 /* Exception occurred */
3931 return FALSE;
3932 }
3933
3934 if ((ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3935 || ((FAST486_SEG_REGS)ModRegRm.Register == FAST486_REG_CS))
3936 {
3937 /* Invalid */
3938 Fast486Exception(State, FAST486_EXCEPTION_UD);
3939 return FALSE;
3940 }
3941
3942 if (OperandSize)
3943 {
3944 ULONG Dummy, Selector;
3945
3946 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Selector))
3947 {
3948 /* Exception occurred */
3949 return FALSE;
3950 }
3951
3952 return Fast486LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
3953 }
3954 else
3955 {
3956 USHORT Dummy, Selector;
3957
3958 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Selector))
3959 {
3960 /* Exception occurred */
3961 return FALSE;
3962 }
3963
3964 return Fast486LoadSegment(State, ModRegRm.Register, Selector);
3965 }
3966 }
3967
3968 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde)
3969 {
3970 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3971
3972 /* Make sure this is the right instruction */
3973 ASSERT(Opcode == 0x98);
3974
3975 TOGGLE_OPSIZE(Size);
3976 NO_LOCK_PREFIX();
3977
3978 if (Size)
3979 {
3980 /* Sign extend AX to EAX */
3981 State->GeneralRegs[FAST486_REG_EAX].Long = MAKELONG
3982 (
3983 State->GeneralRegs[FAST486_REG_EAX].LowWord,
3984 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
3985 ? 0xFFFF : 0x0000
3986 );
3987 }
3988 else
3989 {
3990 /* Sign extend AL to AX */
3991 State->GeneralRegs[FAST486_REG_EAX].HighByte =
3992 (State->GeneralRegs[FAST486_REG_EAX].LowByte & SIGN_FLAG_BYTE)
3993 ? 0xFF : 0x00;
3994 }
3995
3996 return TRUE;
3997 }
3998
3999 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq)
4000 {
4001 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4002
4003 /* Make sure this is the right instruction */
4004 ASSERT(Opcode == 0x99);
4005
4006 TOGGLE_OPSIZE(Size);
4007 NO_LOCK_PREFIX();
4008
4009 if (Size)
4010 {
4011 /* Sign extend EAX to EDX:EAX */
4012 State->GeneralRegs[FAST486_REG_EDX].Long =
4013 (State->GeneralRegs[FAST486_REG_EAX].Long & SIGN_FLAG_LONG)
4014 ? 0xFFFFFFFF : 0x00000000;
4015 }
4016 else
4017 {
4018 /* Sign extend AX to DX:AX */
4019 State->GeneralRegs[FAST486_REG_EDX].LowWord =
4020 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4021 ? 0xFFFF : 0x0000;
4022 }
4023
4024 return TRUE;
4025 }
4026
4027 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
4028 {
4029 USHORT Segment = 0;
4030 ULONG Offset = 0;
4031 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4032
4033 /* Make sure this is the right instruction */
4034 ASSERT(Opcode == 0x9A);
4035
4036 TOGGLE_OPSIZE(Size);
4037 NO_LOCK_PREFIX();
4038
4039 /* Fetch the offset */
4040 if (Size)
4041 {
4042 if (!Fast486FetchDword(State, &Offset))
4043 {
4044 /* Exception occurred */
4045 return FALSE;
4046 }
4047 }
4048 else
4049 {
4050 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
4051 {
4052 /* Exception occurred */
4053 return FALSE;
4054 }
4055 }
4056
4057 /* Fetch the segment */
4058 if (!Fast486FetchWord(State, &Segment))
4059 {
4060 /* Exception occurred */
4061 return FALSE;
4062 }
4063
4064 /* Push the current code segment selector */
4065 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
4066 {
4067 /* Exception occurred */
4068 return FALSE;
4069 }
4070
4071 /* Push the current value of the instruction pointer */
4072 if (!Fast486StackPush(State, State->InstPtr.Long))
4073 {
4074 /* Exception occurred */
4075 return FALSE;
4076 }
4077
4078 /* Load the new CS */
4079 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4080 {
4081 /* Exception occurred */
4082 return FALSE;
4083 }
4084
4085 /* Load new (E)IP */
4086 if (Size) State->InstPtr.Long = Offset;
4087 else State->InstPtr.LowWord = LOWORD(Offset);
4088
4089 return TRUE;
4090 }
4091
4092 FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
4093 {
4094 // TODO: NOT IMPLEMENTED
4095 UNIMPLEMENTED;
4096
4097 return FALSE;
4098 }
4099
4100 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
4101 {
4102 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4103
4104 NO_LOCK_PREFIX();
4105 TOGGLE_OPSIZE(Size);
4106
4107 /* Check for VM86 mode when IOPL is not 3 */
4108 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4109 {
4110 /* Call the VM86 monitor */
4111 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4112 return FALSE;
4113 }
4114
4115 /* Push the flags */
4116 if (Size) return Fast486StackPush(State, State->Flags.Long);
4117 else return Fast486StackPush(State, LOWORD(State->Flags.Long));
4118 }
4119
4120 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
4121 {
4122 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4123 INT Cpl = Fast486GetCurrentPrivLevel(State);
4124 ULONG NewFlags;
4125
4126 NO_LOCK_PREFIX();
4127 TOGGLE_OPSIZE(Size);
4128
4129 /* Pop the new flags */
4130 if (!Fast486StackPop(State, &NewFlags))
4131 {
4132 /* Exception occurred */
4133 return FALSE;
4134 }
4135
4136 if (!State->Flags.Vm)
4137 {
4138 /* Check the current privilege level */
4139 if (Cpl == 0)
4140 {
4141 /* Supervisor */
4142
4143 /* Set the flags */
4144 if (Size)
4145 {
4146 /* Memorize the old state of RF */
4147 BOOLEAN OldRf = State->Flags.Rf;
4148
4149 State->Flags.Long = NewFlags;
4150
4151 /* Restore VM and RF */
4152 State->Flags.Vm = FALSE;
4153 State->Flags.Rf = OldRf;
4154
4155 /* Clear VIF and VIP */
4156 State->Flags.Vif = State->Flags.Vip = FALSE;
4157 }
4158 else State->Flags.LowWord = LOWORD(NewFlags);
4159
4160 /* Restore the reserved bits */
4161 State->Flags.AlwaysSet = TRUE;
4162 State->Flags.Reserved0 = FALSE;
4163 State->Flags.Reserved1 = FALSE;
4164 }
4165 else
4166 {
4167 /* User */
4168
4169 /* Memorize the old state of IF and IOPL */
4170 BOOLEAN OldIf = State->Flags.If;
4171 UINT OldIopl = State->Flags.Iopl;
4172
4173 /* Set the flags */
4174 if (Size)
4175 {
4176 /* Memorize the old state of RF */
4177 BOOLEAN OldRf = State->Flags.Rf;
4178
4179 State->Flags.Long = NewFlags;
4180
4181 /* Restore VM and RF */
4182 State->Flags.Vm = FALSE;
4183 State->Flags.Rf = OldRf;
4184
4185 /* Clear VIF and VIP */
4186 State->Flags.Vif = State->Flags.Vip = FALSE;
4187 }
4188 else State->Flags.LowWord = LOWORD(NewFlags);
4189
4190 /* Restore the reserved bits and IOPL */
4191 State->Flags.AlwaysSet = TRUE;
4192 State->Flags.Reserved0 = FALSE;
4193 State->Flags.Reserved1 = FALSE;
4194 State->Flags.Iopl = OldIopl;
4195
4196 /* Check if the user doesn't have the privilege to change IF */
4197 if (Cpl > State->Flags.Iopl)
4198 {
4199 /* Restore IF */
4200 State->Flags.If = OldIf;
4201 }
4202 }
4203 }
4204 else
4205 {
4206 /* Check the IOPL */
4207 if (State->Flags.Iopl == 3)
4208 {
4209 if (Size)
4210 {
4211 /* Memorize the old state of RF, VIF and VIP */
4212 BOOLEAN OldRf = State->Flags.Rf;
4213 BOOLEAN OldVif = State->Flags.Vif;
4214 BOOLEAN OldVip = State->Flags.Vip;
4215
4216 State->Flags.Long = NewFlags;
4217
4218 /* Restore VM, RF, VIF and VIP */
4219 State->Flags.Vm = TRUE;
4220 State->Flags.Rf = OldRf;
4221 State->Flags.Vif = OldVif;
4222 State->Flags.Vip = OldVip;
4223 }
4224 else State->Flags.LowWord = LOWORD(NewFlags);
4225
4226 /* Restore the reserved bits and IOPL */
4227 State->Flags.AlwaysSet = TRUE;
4228 State->Flags.Reserved0 = FALSE;
4229 State->Flags.Reserved1 = FALSE;
4230 State->Flags.Iopl = 3;
4231 }
4232 else
4233 {
4234 /* Call the VM86 monitor */
4235 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4236 }
4237
4238 }
4239
4240 return TRUE;
4241 }
4242
4243 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf)
4244 {
4245 /* Make sure this is the right instruction */
4246 ASSERT(Opcode == 0x9E);
4247
4248 /* Set the low-order byte of FLAGS to AH */
4249 State->Flags.Long &= 0xFFFFFF00;
4250 State->Flags.Long |= State->GeneralRegs[FAST486_REG_EAX].HighByte;
4251
4252 /* Restore the reserved bits of FLAGS */
4253 State->Flags.AlwaysSet = TRUE;
4254 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4255
4256 return FALSE;
4257 }
4258
4259 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf)
4260 {
4261 /* Make sure this is the right instruction */
4262 ASSERT(Opcode == 0x9F);
4263
4264 /* Set AH to the low-order byte of FLAGS */
4265 State->GeneralRegs[FAST486_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4266
4267 return FALSE;
4268 }
4269
4270 FAST486_OPCODE_HANDLER(Fast486OpcodeRet)
4271 {
4272 ULONG ReturnAddress;
4273 USHORT BytesToPop = 0;
4274 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4275
4276 /* Make sure this is the right instruction */
4277 ASSERT((Opcode & 0xFE) == 0xC2);
4278
4279 NO_LOCK_PREFIX();
4280 TOGGLE_OPSIZE(Size);
4281
4282 if (Opcode == 0xC2)
4283 {
4284 /* Fetch the number of bytes to pop after the return */
4285 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4286 }
4287
4288 /* Pop the return address */
4289 if (!Fast486StackPop(State, &ReturnAddress)) return FALSE;
4290
4291 /* Return to the calling procedure, and if necessary, pop the parameters */
4292 if (Size)
4293 {
4294 State->InstPtr.Long = ReturnAddress;
4295 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4296 }
4297 else
4298 {
4299 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4300 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4301 }
4302
4303 return TRUE;
4304 }
4305
4306 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
4307 {
4308 UCHAR FarPointer[6];
4309 BOOLEAN OperandSize, AddressSize;
4310 FAST486_MOD_REG_RM ModRegRm;
4311
4312 /* Make sure this is the right instruction */
4313 ASSERT((Opcode & 0xFE) == 0xC4);
4314
4315 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4316
4317 TOGGLE_ADSIZE(AddressSize);
4318
4319 /* Get the operands */
4320 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4321 {
4322 /* Exception occurred */
4323 return FALSE;
4324 }
4325
4326 if (!ModRegRm.Memory)
4327 {
4328 /* Check if this is a BOP and the host supports BOPs */
4329 if ((Opcode == 0xC4)
4330 && (ModRegRm.Register == FAST486_REG_EAX)
4331 && (ModRegRm.SecondRegister == FAST486_REG_ESP)
4332 && (State->BopCallback != NULL))
4333 {
4334 USHORT BopCode;
4335
4336 /* Fetch the BOP code */
4337 if (!Fast486FetchWord(State, &BopCode))
4338 {
4339 /* Exception occurred */
4340 return FALSE;
4341 }
4342
4343 /* Call the BOP handler */
4344 State->BopCallback(State, BopCode);
4345
4346 /* Return success */
4347 return TRUE;
4348 }
4349
4350 /* Invalid */
4351 Fast486Exception(State, FAST486_EXCEPTION_UD);
4352 return FALSE;
4353 }
4354
4355 if (!Fast486ReadMemory(State,
4356 (State->PrefixFlags & FAST486_PREFIX_SEG)
4357 ? State->SegmentOverride : FAST486_REG_DS,
4358 ModRegRm.MemoryAddress,
4359 FALSE,
4360 FarPointer,
4361 OperandSize ? 6 : 4))
4362 {
4363 /* Exception occurred */
4364 return FALSE;
4365 }
4366
4367 if (OperandSize)
4368 {
4369 ULONG Offset = *((PULONG)FarPointer);
4370 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4371
4372 /* Set the register to the offset */
4373 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4374
4375 /* Load the segment */
4376 return Fast486LoadSegment(State,
4377 (Opcode == 0xC4)
4378 ? FAST486_REG_ES : FAST486_REG_DS,
4379 Segment);
4380 }
4381 else
4382 {
4383 USHORT Offset = *((PUSHORT)FarPointer);
4384 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4385
4386 /* Set the register to the offset */
4387 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4388
4389 /* Load the segment */
4390 return Fast486LoadSegment(State,
4391 (Opcode == 0xC4)
4392 ? FAST486_REG_ES : FAST486_REG_DS,
4393 Segment);
4394 }
4395 }
4396
4397 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
4398 {
4399 INT i;
4400 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4401 USHORT FrameSize;
4402 UCHAR NestingLevel;
4403 FAST486_REG FramePointer;
4404
4405 /* Make sure this is the right instruction */
4406 ASSERT(Opcode == 0xC8);
4407
4408 NO_LOCK_PREFIX();
4409 TOGGLE_OPSIZE(Size);
4410
4411 if (!Fast486FetchWord(State, &FrameSize))
4412 {
4413 /* Exception occurred */
4414 return FALSE;
4415 }
4416
4417 if (!Fast486FetchByte(State, &NestingLevel))
4418 {
4419 /* Exception occurred */
4420 return FALSE;
4421 }
4422
4423 /* Push EBP */
4424 if (!Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long))
4425 {
4426 /* Exception occurred */
4427 return FALSE;
4428 }
4429
4430 /* Save ESP */
4431 FramePointer = State->GeneralRegs[FAST486_REG_ESP];
4432
4433 /* Set up the nested procedure stacks */
4434 for (i = 1; i < NestingLevel; i++)
4435 {
4436 if (Size)
4437 {
4438 State->GeneralRegs[FAST486_REG_EBP].Long -= 4;
4439 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long);
4440 }
4441 else
4442 {
4443 State->GeneralRegs[FAST486_REG_EBP].LowWord -= 2;
4444 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].LowWord);
4445 }
4446 }
4447
4448 if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
4449
4450 /* Set EBP to the frame pointer */
4451 State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
4452
4453 /* Reserve space for the frame */
4454 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
4455 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
4456
4457 return TRUE;
4458 }
4459
4460 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
4461 {
4462 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4463
4464 /* Make sure this is the right instruction */
4465 ASSERT(Opcode == 0xC9);
4466
4467 NO_LOCK_PREFIX();
4468 TOGGLE_OPSIZE(Size);
4469
4470 if (Size)
4471 {
4472 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4473 State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
4474
4475 /* Pop the saved base pointer from the stack */
4476 return Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
4477 }
4478 else
4479 {
4480 ULONG Value;
4481
4482 /* Set the stack pointer (SP) to the base pointer (BP) */
4483 State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
4484
4485 /* Pop the saved base pointer from the stack */
4486 if (Fast486StackPop(State, &Value))
4487 {
4488 State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
4489 return TRUE;
4490 }
4491 else return FALSE;
4492 }
4493 }
4494
4495 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
4496 {
4497 ULONG Segment = 0;
4498 ULONG Offset = 0;
4499 USHORT BytesToPop = 0;
4500 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4501
4502 /* Make sure this is the right instruction */
4503 ASSERT((Opcode & 0xFE) == 0xCA);
4504
4505 TOGGLE_OPSIZE(Size);
4506 NO_LOCK_PREFIX();
4507
4508 if (Opcode == 0xCA)
4509 {
4510 /* Fetch the number of bytes to pop after the return */
4511 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4512 }
4513
4514 /* Pop the offset */
4515 if (!Fast486StackPop(State, &Offset))
4516 {
4517 /* Exception occurred */
4518 return FALSE;
4519 }
4520
4521 /* Pop the segment */
4522 if (!Fast486StackPop(State, &Segment))
4523 {
4524 /* Exception occurred */
4525 return FALSE;
4526 }
4527
4528 /* Load the new CS */
4529 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4530 {
4531 /* Exception occurred */
4532 return FALSE;
4533 }
4534
4535 /* Load new (E)IP, and if necessary, pop the parameters */
4536 if (Size)
4537 {
4538 State->InstPtr.Long = Offset;
4539 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4540 }
4541 else
4542 {
4543 State->InstPtr.LowWord = LOWORD(Offset);
4544 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4545 }
4546
4547 return TRUE;
4548 }
4549
4550 FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
4551 {
4552 UCHAR IntNum;
4553 FAST486_IDT_ENTRY IdtEntry;
4554
4555 switch (Opcode)
4556 {
4557 case 0xCC:
4558 {
4559 /* This is the INT3 instruction */
4560 IntNum = 3;
4561 break;
4562 }
4563
4564 case 0xCD:
4565 {
4566 /* Fetch the interrupt number */
4567 if (!Fast486FetchByte(State, &IntNum))
4568 {
4569 /* Exception occurred */
4570 return FALSE;
4571 }
4572
4573 break;
4574 }
4575
4576 case 0xCE:
4577 {
4578 /* Don't do anything if OF is cleared */
4579 if (!State->Flags.Of) return TRUE;
4580
4581 /* Exception #OF */
4582 IntNum = FAST486_EXCEPTION_OF;
4583
4584 break;
4585 }
4586
4587 default:
4588 {
4589 /* Should not happen */
4590 ASSERT(FALSE);
4591 }
4592 }
4593
4594 /* Get the interrupt vector */
4595 if (!Fast486GetIntVector(State, IntNum, &IdtEntry))
4596 {
4597 /* Exception occurred */
4598 return FALSE;
4599 }
4600
4601 /* Perform the interrupt */
4602 if (!Fast486InterruptInternal(State,
4603 IdtEntry.Selector,
4604 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
4605 IdtEntry.Type))
4606 {
4607 /* Exception occurred */
4608 return FALSE;
4609 }
4610
4611 return TRUE;
4612 }
4613
4614 FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
4615 {
4616 INT i;
4617 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4618 FAST486_FLAGS_REG NewFlags;
4619 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4620
4621 /* Make sure this is the right instruction */
4622 ASSERT(Opcode == 0xCF);
4623
4624 NO_LOCK_PREFIX();
4625 TOGGLE_OPSIZE(Size);
4626
4627 /* Pop EIP */
4628 if (!Fast486StackPop(State, &InstPtr))
4629 {
4630 /* Exception occurred */
4631 return FALSE;
4632 }
4633
4634 /* Pop CS */
4635 if (!Fast486StackPop(State, &CodeSel))
4636 {
4637 /* Exception occurred */
4638 return FALSE;
4639 }
4640
4641 /* Pop EFLAGS */
4642 if (!Fast486StackPop(State, &NewFlags.Long))
4643 {
4644 /* Exception occurred */
4645 return FALSE;
4646 }
4647
4648 /* Check for protected mode */
4649 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4650 {
4651 INT Cpl = Fast486GetCurrentPrivLevel(State);
4652
4653 if (State->Flags.Vm)
4654 {
4655 /* Return from VM86 mode */
4656
4657 /* Check the IOPL */
4658 if (State->Flags.Iopl == 3)
4659 {
4660 /* Set new EIP */
4661 State->InstPtr.Long = LOWORD(InstPtr);
4662
4663 /* Load new CS */
4664 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4665 {
4666 /* Exception occurred */
4667 return FALSE;
4668 }
4669
4670 /* Set the new flags */
4671 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4672 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4673 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4674 State->Flags.Iopl = 3;
4675 }
4676 else
4677 {
4678 /* Call the VM86 monitor */
4679 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4680 return FALSE;
4681 }
4682
4683 return TRUE;
4684 }
4685
4686 if (State->Flags.Nt)
4687 {
4688 /* Nested task return */
4689
4690 UNIMPLEMENTED;
4691 return FALSE;
4692 }
4693
4694 if (NewFlags.Vm)
4695 {
4696 /* Return to VM86 mode */
4697 ULONG Es, Ds, Fs, Gs;
4698
4699 /* Pop ESP, SS, ES, FS, GS */
4700 if (!Fast486StackPop(State, &StackPtr)) return FALSE;
4701 if (!Fast486StackPop(State, &StackSel)) return FALSE;
4702 if (!Fast486StackPop(State, &Es)) return FALSE;
4703 if (!Fast486StackPop(State, &Ds)) return FALSE;
4704 if (!Fast486StackPop(State, &Fs)) return FALSE;
4705 if (!Fast486StackPop(State, &Gs)) return FALSE;
4706
4707 /* Set the new IP */
4708 State->InstPtr.Long = LOWORD(InstPtr);
4709
4710 /* Set the new flags */
4711 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4712 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4713 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4714
4715 /* Load the new segments */
4716 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel)) return FALSE;
4717 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) return FALSE;
4718 if (!Fast486LoadSegment(State, FAST486_REG_ES, Es)) return FALSE;
4719 if (!Fast486LoadSegment(State, FAST486_REG_DS, Ds)) return FALSE;
4720 if (!Fast486LoadSegment(State, FAST486_REG_FS, Fs)) return FALSE;
4721 if (!Fast486LoadSegment(State, FAST486_REG_GS, Gs)) return FALSE;
4722
4723 return TRUE;
4724 }
4725
4726 /* Load the new CS */
4727 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4728 {
4729 /* Exception occurred */
4730 return FALSE;
4731 }
4732
4733 /* Set EIP */
4734 if (Size) State->InstPtr.Long = InstPtr;
4735 else State->InstPtr.LowWord = LOWORD(InstPtr);
4736
4737 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4738 {
4739 /* Pop ESP */
4740 if (!Fast486StackPop(State, &StackPtr))
4741 {
4742 /* Exception */
4743 return FALSE;
4744 }
4745
4746 /* Pop SS */
4747 if (!Fast486StackPop(State, &StackSel))
4748 {
4749 /* Exception */
4750 return FALSE;
4751 }
4752
4753 /* Load new SS */
4754 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4755 {
4756 /* Exception */
4757 return FALSE;
4758 }
4759
4760 /* Set ESP */
4761 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4762 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4763 }
4764
4765 /* Set the new flags */
4766 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
4767 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
4768 State->Flags.AlwaysSet = TRUE;
4769
4770 /* Set additional flags */
4771 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4772 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4773
4774 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4775 {
4776 /* Update the CPL */
4777 Cpl = Fast486GetCurrentPrivLevel(State);
4778
4779 /* Check segment security */
4780 for (i = 0; i <= FAST486_NUM_SEG_REGS; i++)
4781 {
4782 /* Don't check CS or SS */
4783 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4784
4785 if ((Cpl > State->SegmentRegs[i].Dpl)
4786 && (!State->SegmentRegs[i].Executable
4787 || !State->SegmentRegs[i].DirConf))
4788 {
4789 /* Load the NULL descriptor in the segment */
4790 if (!Fast486LoadSegment(State, i, 0)) return FALSE;
4791 }
4792 }
4793 }
4794 }
4795 else
4796 {
4797 if (Size && (InstPtr & 0xFFFF0000))
4798 {
4799 /* Invalid */
4800 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4801 return FALSE;
4802 }
4803
4804 /* Set new EIP */
4805 State->InstPtr.Long = InstPtr;
4806
4807 /* Load new CS */
4808 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4809 {
4810 /* Exception occurred */
4811 return FALSE;
4812 }
4813
4814 /* Set the new flags */
4815 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4816 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4817 State->Flags.AlwaysSet = TRUE;
4818 }
4819
4820 return TRUE;
4821 }
4822
4823 FAST486_OPCODE_HANDLER(Fast486OpcodeAam)
4824 {
4825 UCHAR Base;
4826 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4827
4828 NO_LOCK_PREFIX();
4829
4830 /* Fetch the base */
4831 if (!Fast486FetchByte(State, &Base))
4832 {
4833 /* Exception occurred */
4834 return FALSE;
4835 }
4836
4837 /* Check if the base is zero */
4838 if (Base == 0)
4839 {
4840 /* Divide error */
4841 Fast486Exception(State, FAST486_EXCEPTION_DE);
4842 return FALSE;
4843 }
4844
4845 /* Adjust */
4846 State->GeneralRegs[FAST486_REG_EAX].HighByte = Value / Base;
4847 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value %= Base;
4848
4849 /* Update flags */
4850 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
4851 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
4852 State->Flags.Pf = Fast486CalculateParity(Value);
4853
4854 return TRUE;
4855 }
4856
4857 FAST486_OPCODE_HANDLER(Fast486OpcodeAad)
4858 {
4859 UCHAR Base;
4860 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4861
4862 NO_LOCK_PREFIX();
4863
4864 /* Fetch the base */
4865 if (!Fast486FetchByte(State, &Base))
4866 {
4867 /* Exception occurred */
4868 return FALSE;
4869 }
4870
4871 /* Adjust */
4872 Value += State->GeneralRegs[FAST486_REG_EAX].HighByte * Base;
4873 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4874
4875 /* Update flags */
4876 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
4877 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
4878 State->Flags.Pf = Fast486CalculateParity(Value);
4879
4880 return TRUE;
4881 }
4882
4883 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat)
4884 {
4885 UCHAR Value;
4886 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4887
4888 TOGGLE_ADSIZE(AddressSize);
4889
4890 /* Read a byte from DS:[(E)BX + AL] */
4891 if (!Fast486ReadMemory(State,
4892 FAST486_REG_DS,
4893 AddressSize ? State->GeneralRegs[FAST486_REG_EBX].Long
4894 : State->GeneralRegs[FAST486_REG_EBX].LowWord
4895 + State->GeneralRegs[FAST486_REG_EAX].LowByte,
4896 FALSE,
4897 &Value,
4898 sizeof(UCHAR)))
4899 {
4900 /* Exception occurred */
4901 return FALSE;
4902 }
4903
4904 /* Set AL to the result */
4905 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4906
4907 /* Return success */
4908 return TRUE;
4909 }
4910
4911 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop)
4912 {
4913 BOOLEAN Condition;
4914 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4915 CHAR Offset = 0;
4916
4917 /* Make sure this is the right instruction */
4918 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
4919
4920 NO_LOCK_PREFIX();
4921 TOGGLE_OPSIZE(Size);
4922
4923 if (Size) Condition = ((--State->GeneralRegs[FAST486_REG_ECX].Long) != 0);
4924 else Condition = ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) != 0);
4925
4926 if (Opcode == 0xE0)
4927 {
4928 /* Additional rule for LOOPNZ */
4929 if (State->Flags.Zf) Condition = FALSE;
4930 }
4931
4932 if (Opcode == 0xE1)
4933 {
4934 /* Additional rule for LOOPZ */
4935 if (!State->Flags.Zf) Condition = FALSE;
4936 }
4937
4938 /* Fetch the offset */
4939 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4940 {
4941 /* An exception occurred */
4942 return FALSE;
4943 }
4944
4945 if (Condition)
4946 {
4947 /* Move the instruction pointer */
4948 State->InstPtr.Long += Offset;
4949 }
4950
4951 return TRUE;
4952 }
4953
4954 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz)
4955 {
4956 BOOLEAN Condition;
4957 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4958 CHAR Offset = 0;
4959
4960 /* Make sure this is the right instruction */
4961 ASSERT(Opcode == 0xE3);
4962
4963 NO_LOCK_PREFIX();
4964 TOGGLE_OPSIZE(Size);
4965
4966 if (Size) Condition = (State->GeneralRegs[FAST486_REG_ECX].Long == 0);
4967 else Condition = (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0);
4968
4969 /* Fetch the offset */
4970 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4971 {
4972 /* An exception occurred */
4973 return FALSE;
4974 }
4975
4976 if (Condition)
4977 {
4978 /* Move the instruction pointer */
4979 State->InstPtr.Long += Offset;
4980 }
4981
4982 return TRUE;
4983 }
4984
4985 FAST486_OPCODE_HANDLER(Fast486OpcodeCall)
4986 {
4987 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4988
4989 /* Make sure this is the right instruction */
4990 ASSERT(Opcode == 0xE8);
4991
4992 TOGGLE_OPSIZE(Size);
4993 NO_LOCK_PREFIX();
4994
4995 if (Size)
4996 {
4997 LONG Offset = 0;
4998
4999 /* Fetch the offset */
5000 if (!Fast486FetchDword(State, (PULONG)&Offset))
5001 {
5002 /* An exception occurred */
5003 return FALSE;
5004 }
5005
5006 /* Push the current value of the instruction pointer */
5007 if (!Fast486StackPush(State, State->InstPtr.Long))
5008 {
5009 /* Exception occurred */
5010 return FALSE;
5011 }
5012
5013 /* Move the instruction pointer */
5014 State->InstPtr.Long += Offset;
5015 }
5016 else
5017 {
5018 SHORT Offset = 0;
5019
5020 /* Fetch the offset */
5021 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5022 {
5023 /* An exception occurred */
5024 return FALSE;
5025 }
5026
5027 /* Push the current value of the instruction pointer */
5028 if (!Fast486StackPush(State, State->InstPtr.Long))
5029 {
5030 /* Exception occurred */
5031 return FALSE;
5032 }
5033
5034 /* Move the instruction pointer */
5035 State->InstPtr.LowWord += Offset;
5036 }
5037
5038 return TRUE;
5039 }
5040
5041 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp)
5042 {
5043 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5044
5045 /* Make sure this is the right instruction */
5046 ASSERT(Opcode == 0xE9);
5047
5048 TOGGLE_OPSIZE(Size);
5049 NO_LOCK_PREFIX();
5050
5051 if (Size)
5052 {
5053 LONG Offset = 0;
5054
5055 /* Fetch the offset */
5056 if (!Fast486FetchDword(State, (PULONG)&Offset))
5057 {
5058 /* An exception occurred */
5059 return FALSE;
5060 }
5061
5062 /* Move the instruction pointer */
5063 State->InstPtr.Long += Offset;
5064 }
5065 else
5066 {
5067 SHORT Offset = 0;
5068
5069 /* Fetch the offset */
5070 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5071 {
5072 /* An exception occurred */
5073 return FALSE;
5074 }
5075
5076 /* Move the instruction pointer */
5077 State->InstPtr.LowWord += Offset;
5078 }
5079
5080 return TRUE;
5081 }
5082
5083 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
5084 {
5085 USHORT Segment = 0;
5086 ULONG Offset = 0;
5087 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5088
5089 /* Make sure this is the right instruction */
5090 ASSERT(Opcode == 0xEA);
5091
5092 TOGGLE_OPSIZE(Size);
5093 NO_LOCK_PREFIX();
5094
5095 /* Fetch the offset */
5096 if (Size)
5097 {
5098 if (!Fast486FetchDword(State, &Offset))
5099 {
5100 /* Exception occurred */
5101 return FALSE;
5102 }
5103 }
5104 else
5105 {
5106 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5107 {
5108 /* Exception occurred */
5109 return FALSE;
5110 }
5111 }
5112
5113 /* Fetch the segment */
5114 if (!Fast486FetchWord(State, &Segment))
5115 {
5116 /* Exception occurred */
5117 return FALSE;
5118 }
5119
5120 /* Load the new CS */
5121 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
5122 {
5123 /* Exception occurred */
5124 return FALSE;
5125 }
5126
5127 /* Load new (E)IP */
5128 if (Size) State->InstPtr.Long = Offset;
5129 else State->InstPtr.LowWord = LOWORD(Offset);
5130
5131 return TRUE;
5132 }
5133
5134 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset)
5135 {
5136 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5137 ULONG Offset;
5138
5139 /* Make sure this is the right instruction */
5140 ASSERT(Opcode == 0xA0);
5141
5142 TOGGLE_OPSIZE(Size);
5143
5144 if (Size)
5145 {
5146 if (!Fast486FetchDword(State, &Offset))
5147 {
5148 /* Exception occurred */
5149 return FALSE;
5150 }
5151 }
5152 else
5153 {
5154 USHORT WordOffset;
5155
5156 if (!Fast486FetchWord(State, &WordOffset))
5157 {
5158 /* Exception occurred */
5159 return FALSE;
5160 }
5161
5162 Offset = (ULONG)WordOffset;
5163 }
5164
5165 /* Read from memory */
5166 return Fast486ReadMemory(State,
5167 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5168 State->SegmentOverride : FAST486_REG_DS,
5169 Offset,
5170 FALSE,
5171 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5172 sizeof(UCHAR));
5173 }
5174
5175 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset)
5176 {
5177 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5178
5179 /* Make sure this is the right instruction */
5180 ASSERT(Opcode == 0xA1);
5181
5182 TOGGLE_OPSIZE(Size);
5183
5184 if (Size)
5185 {
5186 ULONG Offset;
5187
5188 if (!Fast486FetchDword(State, &Offset))
5189 {
5190 /* Exception occurred */
5191 return FALSE;
5192 }
5193
5194 /* Read from memory */
5195 return Fast486ReadMemory(State,
5196 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5197 State->SegmentOverride : FAST486_REG_DS,
5198 Offset,
5199 FALSE,
5200 &State->GeneralRegs[FAST486_REG_EAX].Long,
5201 sizeof(ULONG));
5202 }
5203 else
5204 {
5205 USHORT Offset;
5206
5207 if (!Fast486FetchWord(State, &Offset))
5208 {
5209 /* Exception occurred */
5210 return FALSE;
5211 }
5212
5213 /* Read from memory */
5214 return Fast486ReadMemory(State,
5215 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5216 State->SegmentOverride : FAST486_REG_DS,
5217 Offset,
5218 FALSE,
5219 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5220 sizeof(USHORT));
5221 }
5222 }
5223
5224 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
5225 {
5226 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5227 ULONG Offset;
5228
5229 /* Make sure this is the right instruction */
5230 ASSERT(Opcode == 0xA2);
5231
5232 TOGGLE_OPSIZE(Size);
5233
5234 if (Size)
5235 {
5236 if (!Fast486FetchDword(State, &Offset))
5237 {
5238 /* Exception occurred */
5239 return FALSE;
5240 }
5241 }
5242 else
5243 {
5244 USHORT WordOffset;
5245
5246 if (!Fast486FetchWord(State, &WordOffset))
5247 {
5248 /* Exception occurred */
5249 return FALSE;
5250 }
5251
5252 Offset = (ULONG)WordOffset;
5253 }
5254
5255 /* Write to memory */
5256 return Fast486WriteMemory(State,
5257 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5258 State->SegmentOverride : FAST486_REG_DS,
5259 Offset,
5260 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5261 sizeof(UCHAR));
5262 }
5263
5264 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
5265 {
5266 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5267
5268 /* Make sure this is the right instruction */
5269 ASSERT(Opcode == 0xA3);
5270
5271 TOGGLE_OPSIZE(Size);
5272
5273 if (Size)
5274 {
5275 ULONG Offset;
5276
5277 if (!Fast486FetchDword(State, &Offset))
5278 {
5279 /* Exception occurred */
5280 return FALSE;
5281 }
5282
5283 /* Write to memory */
5284 return Fast486WriteMemory(State,
5285 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5286 State->SegmentOverride : FAST486_REG_DS,
5287 Offset,
5288 &State->GeneralRegs[FAST486_REG_EAX].Long,
5289 sizeof(ULONG));
5290 }
5291 else
5292 {
5293 USHORT Offset;
5294
5295 if (!Fast486FetchWord(State, &Offset))
5296 {
5297 /* Exception occurred */
5298 return FALSE;
5299 }
5300
5301 /* Write to memory */
5302 return Fast486WriteMemory(State,
5303 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5304 State->SegmentOverride : FAST486_REG_DS,
5305 Offset,
5306 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5307 sizeof(USHORT));
5308 }
5309 }
5310
5311 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc)
5312 {
5313 /* Make sure this is the right instruction */
5314 ASSERT(Opcode == 0xD6);
5315
5316 NO_LOCK_PREFIX();
5317
5318 /* Set all the bits of AL to CF */
5319 State->GeneralRegs[FAST486_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
5320
5321 return TRUE;
5322 }
5323
5324 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs)
5325 {
5326 ULONG Data, DataSize;
5327 BOOLEAN OperandSize, AddressSize;
5328 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5329
5330 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5331
5332 /* Make sure this is the right instruction */
5333 ASSERT((Opcode & 0xFE) == 0xA4);
5334
5335 TOGGLE_OPSIZE(OperandSize);
5336 TOGGLE_ADSIZE(AddressSize);
5337
5338 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5339 {
5340 /* Use the override segment instead of DS */
5341 Segment = State->SegmentOverride;
5342 }
5343
5344 /* Calculate the size */
5345 if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
5346 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5347
5348 if (State->PrefixFlags & FAST486_PREFIX_REP)
5349 {
5350 UCHAR Block[STRING_BLOCK_SIZE];
5351 ULONG Count = OperandSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5352 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5353
5354 /* Clear the memory block */
5355 RtlZeroMemory(Block, sizeof(Block));
5356
5357 /* Transfer until finished */
5358 while (Count)
5359 {
5360 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5361
5362 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5363 if (!AddressSize)
5364 {
5365 ULONG MaxBytesSrc = State->Flags.Df
5366 ? (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord
5367 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord);
5368 ULONG MaxBytesDest = State->Flags.Df
5369 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5370 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5371
5372
5373 Processed = min(Processed, min(MaxBytesSrc, MaxBytesDest) / DataSize);
5374 if (Processed == 0) Processed = 1;
5375 }
5376
5377 if (State->Flags.Df)
5378 {
5379 /* Reduce ESI and EDI by the number of bytes to transfer */
5380 if (AddressSize)
5381 {
5382 State->GeneralRegs[FAST486_REG_ESI].Long -= Processed * DataSize;
5383 State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
5384 }
5385 else
5386 {
5387 State->GeneralRegs[FAST486_REG_ESI].LowWord -= Processed * DataSize;
5388 State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
5389 }
5390 }
5391
5392 /* Read from memory */
5393 if (!Fast486ReadMemory(State,
5394 Segment,
5395 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5396 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5397 FALSE,
5398 Block,
5399 Processed * DataSize))
5400 {
5401 /* Set ECX */
5402 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5403 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5404
5405 /* Exception occurred */
5406 return FALSE;
5407 }
5408
5409 /* Write to memory */
5410 if (!Fast486WriteMemory(State,
5411 FAST486_REG_ES,
5412 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5413 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5414 Block,
5415 Processed * DataSize))
5416 {
5417 /* Set ECX */
5418 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5419 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5420
5421 /* Exception occurred */
5422 return FALSE;
5423 }
5424
5425 if (!State->Flags.Df)
5426 {
5427 /* Increase ESI and EDI by the number of bytes transfered */
5428 if (AddressSize)
5429 {
5430 State->GeneralRegs[FAST486_REG_ESI].Long += Processed * DataSize;
5431 State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5432 }
5433 else
5434 {
5435 State->GeneralRegs[FAST486_REG_ESI].LowWord += Processed * DataSize;
5436 State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5437 }
5438 }
5439
5440 /* Reduce the total count by the number processed in this run */
5441 Count -= Processed;
5442 }
5443
5444 /* Clear ECX */
5445 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5446 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5447 }
5448 else
5449 {
5450 /* Read from the source operand */
5451 if (!Fast486ReadMemory(State,
5452 FAST486_REG_DS,
5453 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5454 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5455 FALSE,
5456 &Data,
5457 DataSize))
5458 {
5459 /* Exception occurred */
5460 return FALSE;
5461 }
5462
5463 /* Write to the destination operand */
5464 if (!Fast486WriteMemory(State,
5465 FAST486_REG_ES,
5466 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5467 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5468 &Data,
5469 DataSize))
5470 {
5471 /* Exception occurred */
5472 return FALSE;
5473 }
5474
5475 /* Increment/decrement ESI and EDI */
5476 if (OperandSize)
5477 {
5478 if (!State->Flags.Df)
5479 {
5480 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5481 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5482 }
5483 else
5484 {
5485 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5486 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5487 }
5488 }
5489 else
5490 {
5491 if (!State->Flags.Df)
5492 {
5493 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5494 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5495 }
5496 else
5497 {
5498 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5499 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5500 }
5501 }
5502 }
5503
5504 /* Return success */
5505 return TRUE;
5506 }
5507
5508 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps)
5509 {
5510 ULONG FirstValue = 0, SecondValue = 0, Result;
5511 ULONG DataSize, DataMask, SignFlag;
5512 BOOLEAN OperandSize, AddressSize;
5513 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5514
5515 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5516
5517 /* Make sure this is the right instruction */
5518 ASSERT((Opcode & 0xFE) == 0xA6);
5519
5520 TOGGLE_OPSIZE(OperandSize);
5521 TOGGLE_ADSIZE(AddressSize);
5522
5523 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5524 {
5525 /* Use the override segment instead of DS */
5526 Segment = State->SegmentOverride;
5527 }
5528
5529 /* Calculate the size */
5530 if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
5531 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5532
5533 /* Calculate the mask and sign flag */
5534 DataMask = (1 << (DataSize * 8)) - 1;
5535 SignFlag = 1 << ((DataSize * 8) - 1);
5536
5537 /* Read from the first source operand */
5538 if (!Fast486ReadMemory(State,
5539 Segment,
5540 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5541 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5542 FALSE,
5543 &FirstValue,
5544 DataSize))
5545 {
5546 /* Exception occurred */
5547 return FALSE;
5548 }
5549
5550 /* Read from the second source operand */
5551 if (!Fast486ReadMemory(State,
5552 FAST486_REG_ES,
5553 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5554 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5555 FALSE,
5556 &SecondValue,
5557 DataSize))
5558 {
5559 /* Exception occurred */
5560 return FALSE;
5561 }
5562
5563 /* Calculate the result */
5564 FirstValue &= DataMask;
5565 SecondValue &= DataMask;
5566 Result = (FirstValue - SecondValue) & DataMask;
5567
5568 /* Update the flags */
5569 State->Flags.Cf = FirstValue < SecondValue;
5570 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5571 && ((FirstValue & SignFlag) != (Result & SignFlag));
5572 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5573 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
5574 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
5575 State->Flags.Pf = Fast486CalculateParity(Result);
5576
5577 /* Increment/decrement ESI and EDI */
5578 if (OperandSize)
5579 {
5580 if (!State->Flags.Df)
5581 {
5582 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5583 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5584 }
5585 else
5586 {
5587 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5588 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5589 }
5590 }
5591 else
5592 {
5593 if (!State->Flags.Df)
5594 {
5595 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5596 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5597 }
5598 else
5599 {
5600 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5601 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5602 }
5603 }
5604
5605 // FIXME: This method is slow!
5606 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5607 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5608 {
5609 BOOLEAN Repeat = TRUE;
5610
5611 if (OperandSize)
5612 {
5613 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5614 {
5615 /* ECX is 0 */
5616 Repeat = FALSE;
5617 }
5618 }
5619 else
5620 {
5621 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5622 {
5623 /* CX is 0 */
5624 Repeat = FALSE;
5625 }
5626 }
5627
5628 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5629 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5630 {
5631 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5632 Repeat = FALSE;
5633 }
5634
5635 if (Repeat)
5636 {
5637 /* Repeat the instruction */
5638 State->InstPtr = State->SavedInstPtr;
5639 }
5640 }
5641
5642 /* Return success */
5643 return TRUE;
5644 }
5645
5646 FAST486_OPCODE_HANDLER(Fast486OpcodeStos)
5647 {
5648 ULONG DataSize;
5649 BOOLEAN OperandSize, AddressSize;
5650
5651 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5652
5653 /* Make sure this is the right instruction */
5654 ASSERT((Opcode & 0xFE) == 0xAA);
5655
5656 TOGGLE_OPSIZE(OperandSize);
5657 TOGGLE_ADSIZE(AddressSize);
5658
5659 /* Calculate the size */
5660 if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
5661 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5662
5663 if (State->PrefixFlags & FAST486_PREFIX_REP)
5664 {
5665 UCHAR Block[STRING_BLOCK_SIZE];
5666 ULONG Count = OperandSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5667 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5668
5669 /* Fill the memory block with the data */
5670 if (DataSize == sizeof(UCHAR))
5671 {
5672 RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[FAST486_REG_EAX].LowByte);
5673 }
5674 else
5675 {
5676 ULONG i;
5677
5678 for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
5679 {
5680 if (DataSize == sizeof(USHORT))
5681 {
5682 ((PUSHORT)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].LowWord;
5683 }
5684 else
5685 {
5686 ((PULONG)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].Long;
5687 }
5688 }
5689 }
5690
5691 /* Transfer until finished */
5692 while (Count)
5693 {
5694 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5695
5696 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5697 if (!AddressSize)
5698 {
5699 ULONG MaxBytes = State->Flags.Df
5700 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5701 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5702
5703 Processed = min(Processed, MaxBytes / DataSize);
5704 if (Processed == 0) Processed = 1;
5705 }
5706
5707 if (State->Flags.Df)
5708 {
5709 /* Reduce EDI by the number of bytes to transfer */
5710 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
5711 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
5712 }
5713
5714 /* Write to memory */
5715 if (!Fast486WriteMemory(State,
5716 FAST486_REG_ES,
5717 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5718 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5719 Block,
5720 Processed * DataSize))
5721 {
5722 /* Set ECX */
5723 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5724 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5725
5726 /* Exception occurred */
5727 return FALSE;
5728 }
5729
5730 if (!State->Flags.Df)
5731 {
5732 /* Increase EDI by the number of bytes transfered */
5733 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5734 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5735 }
5736
5737 /* Reduce the total count by the number processed in this run */
5738 Count -= Processed;
5739 }
5740
5741 /* Clear ECX */
5742 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5743 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5744 }
5745 else
5746 {
5747 /* Write to the destination operand */
5748 if (!Fast486WriteMemory(State,
5749 FAST486_REG_ES,
5750 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5751 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5752 &State->GeneralRegs[FAST486_REG_EAX].Long,
5753 DataSize))
5754 {
5755 /* Exception occurred */
5756 return FALSE;
5757 }
5758
5759 /* Increment/decrement EDI */
5760 if (OperandSize)
5761 {
5762 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5763 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5764 }
5765 else
5766 {
5767 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5768 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5769 }
5770 }
5771
5772 /* Return success */
5773 return TRUE;
5774 }
5775
5776 FAST486_OPCODE_HANDLER(Fast486OpcodeLods)
5777 {
5778 ULONG DataSize;
5779 BOOLEAN OperandSize, AddressSize;
5780 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5781
5782 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5783
5784 /* Make sure this is the right instruction */
5785 ASSERT((Opcode & 0xFE) == 0xAC);
5786
5787 TOGGLE_OPSIZE(OperandSize);
5788 TOGGLE_ADSIZE(AddressSize);
5789
5790 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5791 {
5792 /* Use the override segment instead of DS */
5793 Segment = State->SegmentOverride;
5794 }
5795
5796 /* Calculate the size */
5797 if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
5798 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5799
5800 if (State->PrefixFlags & FAST486_PREFIX_REP)
5801 {
5802 ULONG Count = OperandSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5803 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5804
5805 /* If the count is 0, do nothing */
5806 if (Count == 0) return TRUE;
5807
5808 /* Only the last entry will be loaded */
5809 if (!State->Flags.Df)
5810 {
5811 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += (Count - 1) * DataSize;
5812 else State->GeneralRegs[FAST486_REG_ESI].LowWord += (Count - 1) * DataSize;
5813 }
5814 else
5815 {
5816 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= (Count - 1) * DataSize;
5817 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= (Count - 1) * DataSize;
5818 }
5819 }
5820
5821 /* Read from the source operand */
5822 if (!Fast486ReadMemory(State,
5823 Segment,
5824 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5825 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5826 FALSE,
5827 &State->GeneralRegs[FAST486_REG_EAX].Long,
5828 DataSize))
5829 {
5830 /* Exception occurred */
5831 return FALSE;
5832 }
5833
5834 /* Increment/decrement ESI */
5835 if (OperandSize)
5836 {
5837 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5838 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5839 }
5840 else
5841 {
5842 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5843 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5844 }
5845
5846 /* Return success */
5847 return TRUE;
5848 }
5849
5850 FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
5851 {
5852 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
5853 ULONG SecondValue = 0;
5854 ULONG Result;
5855 ULONG DataSize, DataMask, SignFlag;
5856 BOOLEAN OperandSize, AddressSize;
5857
5858 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5859
5860 /* Make sure this is the right instruction */
5861 ASSERT((Opcode & 0xFE) == 0xAE);
5862
5863 TOGGLE_OPSIZE(OperandSize);
5864 TOGGLE_ADSIZE(AddressSize);
5865
5866 /* Calculate the size */
5867 if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
5868 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5869
5870 /* Calculate the mask and sign flag */
5871 DataMask = (1 << (DataSize * 8)) - 1;
5872 SignFlag = 1 << ((DataSize * 8) - 1);
5873
5874 /* Read from the source operand */
5875 if (!Fast486ReadMemory(State,
5876 FAST486_REG_ES,
5877 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5878 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5879 FALSE,
5880 &SecondValue,
5881 DataSize))
5882 {
5883 /* Exception occurred */
5884 return FALSE;
5885 }
5886
5887 /* Calculate the result */
5888 FirstValue &= DataMask;
5889 SecondValue &= DataMask;
5890 Result = (FirstValue - SecondValue) & DataMask;
5891
5892 /* Update the flags */
5893 State->Flags.Cf = FirstValue < SecondValue;
5894 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5895 && ((FirstValue & SignFlag) != (Result & SignFlag));
5896 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5897 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
5898 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
5899 State->Flags.Pf = Fast486CalculateParity(Result);
5900
5901 /* Increment/decrement EDI */
5902 if (OperandSize)
5903 {
5904 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5905 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5906 }
5907 else
5908 {
5909 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5910 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5911 }
5912
5913 // FIXME: This method is slow!
5914 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5915 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5916 {
5917 BOOLEAN Repeat = TRUE;
5918
5919 if (OperandSize)
5920 {
5921 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5922 {
5923 /* ECX is 0 */
5924 Repeat = FALSE;
5925 }
5926 }
5927 else
5928 {
5929 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5930 {
5931 /* CX is 0 */
5932 Repeat = FALSE;
5933 }
5934 }
5935
5936 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5937 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5938 {
5939 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5940 Repeat = FALSE;
5941 }
5942
5943 if (Repeat)
5944 {
5945 /* Repeat the instruction */
5946 State->InstPtr = State->SavedInstPtr;
5947 }
5948 }
5949
5950 /* Return success */
5951 return TRUE;
5952 }
5953
5954 FAST486_OPCODE_HANDLER(Fast486OpcodeIns)
5955 {
5956 ULONG DataSize;
5957 BOOLEAN OperandSize, AddressSize;
5958
5959 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5960
5961 /* Make sure this is the right instruction */
5962 ASSERT((Opcode & 0xFE) == 0x6C);
5963
5964 TOGGLE_OPSIZE(OperandSize);
5965 TOGGLE_ADSIZE(AddressSize);
5966
5967 /* Calculate the size */
5968 if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
5969 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5970
5971 if (State->PrefixFlags & FAST486_PREFIX_REP)
5972 {
5973 UCHAR Block[STRING_BLOCK_SIZE];
5974 ULONG Count = OperandSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5975 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5976
5977 /* Clear the memory block */
5978 RtlZeroMemory(Block, sizeof(Block));
5979
5980 /* Transfer until finished */
5981 while (Count)
5982 {
5983 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5984
5985 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5986 if (!AddressSize)
5987 {
5988 ULONG MaxBytes = State->Flags.Df
5989 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5990 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5991
5992 Processed = min(Processed, MaxBytes / DataSize);
5993 if (Processed == 0) Processed = 1;
5994 }
5995
5996 /* Read from the I/O port */
5997 State->IoReadCallback(State,
5998 State->GeneralRegs[FAST486_REG_EDX].LowWord,
5999 Block,
6000 Processed * DataSize);
6001
6002 if (State->Flags.Df)
6003 {
6004 ULONG i, j;
6005
6006 /* Reduce EDI by the number of bytes to transfer */
6007 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6008 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6009
6010 /* Reverse the block data */
6011 for (i = 0; i < Processed / 2; i++)
6012 {
6013 /* Swap the values */
6014 for (j = 0; j < DataSize; j++)
6015 {
6016 UCHAR Temp = Block[i * DataSize + j];
6017 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6018 Block[(Processed - i - 1) * DataSize + j] = Temp;
6019 }
6020 }
6021 }
6022
6023 /* Write to memory */
6024 if (!Fast486WriteMemory(State,
6025 FAST486_REG_ES,
6026 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6027 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6028 Block,
6029 Processed * DataSize))
6030 {
6031 /* Set ECX */
6032 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6033 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6034
6035 /* Exception occurred */
6036 return FALSE;
6037 }
6038
6039 if (!State->Flags.Df)
6040 {
6041 /* Increase EDI by the number of bytes transfered */
6042 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6043 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6044 }
6045
6046 /* Reduce the total count by the number processed in this run */
6047 Count -= Processed;
6048 }
6049
6050 /* Clear ECX */
6051 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6052 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6053 }
6054 else
6055 {
6056 ULONG Data = 0;
6057
6058 /* Read from the I/O port */
6059 State->IoReadCallback(State,
6060 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6061 &Data,
6062 DataSize);
6063
6064 /* Write to the destination operand */
6065 if (!Fast486WriteMemory(State,
6066 FAST486_REG_ES,
6067 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6068 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6069 &Data,
6070 DataSize))
6071 {
6072 /* Exception occurred */
6073 return FALSE;
6074 }
6075
6076 /* Increment/decrement EDI */
6077 if (OperandSize)
6078 {
6079 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6080 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6081 }
6082 else
6083 {
6084 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6085 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6086 }
6087 }
6088
6089 /* Return success */
6090 return TRUE;
6091 }
6092
6093 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts)
6094 {
6095 ULONG DataSize;
6096 BOOLEAN OperandSize, AddressSize;
6097
6098 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6099
6100 /* Make sure this is the right instruction */
6101 ASSERT((Opcode & 0xFE) == 0x6E);
6102
6103 TOGGLE_OPSIZE(OperandSize);
6104 TOGGLE_ADSIZE(AddressSize);
6105
6106 /* Calculate the size */
6107 if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
6108 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6109
6110 if (State->PrefixFlags & FAST486_PREFIX_REP)
6111 {
6112 UCHAR Block[STRING_BLOCK_SIZE];
6113 ULONG Count = OperandSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6114 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6115
6116 /* Clear the memory block */
6117 RtlZeroMemory(Block, sizeof(Block));
6118
6119 /* Transfer until finished */
6120 while (Count)
6121 {
6122 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6123
6124 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6125 if (!AddressSize)
6126 {
6127 ULONG MaxBytes = State->Flags.Df
6128 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6129 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6130
6131 Processed = min(Processed, MaxBytes / DataSize);
6132 if (Processed == 0) Processed = 1;
6133 }
6134
6135 /* Read from memory */
6136 if (!Fast486ReadMemory(State,
6137 FAST486_REG_ES,
6138 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6139 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6140 FALSE,
6141 Block,
6142 Processed * DataSize))
6143 {
6144 /* Set ECX */
6145 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6146 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6147
6148 /* Exception occurred */
6149 return FALSE;
6150 }
6151
6152 if (State->Flags.Df)
6153 {
6154 ULONG i, j;
6155
6156 /* Reduce EDI by the number of bytes to transfer */
6157 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6158 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6159
6160 /* Reverse the block data */
6161 for (i = 0; i < Processed / 2; i++)
6162 {
6163 /* Swap the values */
6164 for (j = 0; j < DataSize; j++)
6165 {
6166 UCHAR Temp = Block[i * DataSize + j];
6167 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6168 Block[(Processed - i - 1) * DataSize + j] = Temp;
6169 }
6170 }
6171 }
6172
6173 /* Write to the I/O port */
6174 State->IoWriteCallback(State,
6175 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6176 Block,
6177 Processed * DataSize);
6178
6179 if (!State->Flags.Df)
6180 {
6181 /* Increase EDI by the number of bytes transfered */
6182 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6183 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6184 }
6185
6186 /* Reduce the total count by the number processed in this run */
6187 Count -= Processed;
6188 }
6189
6190 /* Clear ECX */
6191 if (OperandSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6192 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6193 }
6194 else
6195 {
6196 ULONG Data = 0;
6197
6198 /* Read from the source operand */
6199 if (!Fast486ReadMemory(State,
6200 FAST486_REG_DS,
6201 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6202 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6203 FALSE,
6204 &Data,
6205 DataSize))
6206 {
6207 /* Exception occurred */
6208 return FALSE;
6209 }
6210
6211 /* Write to the I/O port */
6212 State->IoWriteCallback(State,
6213 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6214 &Data,
6215 DataSize);
6216
6217 /* Increment/decrement ESI */
6218 if (OperandSize)
6219 {
6220 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
6221 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
6222 }
6223 else
6224 {
6225 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
6226 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
6227 }
6228 }
6229
6230 /* Return success */
6231 return TRUE;
6232 }