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