[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 ^ SecondValue ^ Result) & 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 ^ SecondValue ^ Result) & 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 ^ SecondValue ^ Result) & 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 ^ SecondValue ^ Result) & 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 ^ SecondValue ^ Result) & 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 ^ SecondValue ^ Result) & 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 = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
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 ^ SecondValue ^ Result) & 0x10) != 0;
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 = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
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 ^ SecondValue ^ Result) & 0x10) != 0;
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 = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
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 ^ SecondValue ^ Result) & 0x10) != 0;
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 = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
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 ^ SecondValue ^ Result) & 0x10) != 0;
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 = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
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 ^ SecondValue ^ Result) & 0x10) != 0;
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 = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
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 ^ SecondValue ^ Result) & 0x10) != 0;
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 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3046
3047 /* Update the flags */
3048 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3049 State->Flags.Zf = (Value == 0);
3050 State->Flags.Pf = Fast486CalculateParity(Value);
3051
3052 return TRUE;
3053 }
3054
3055 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm)
3056 {
3057 UCHAR FirstValue, SecondValue, Result;
3058 FAST486_MOD_REG_RM ModRegRm;
3059 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3060
3061 /* Make sure this is the right instruction */
3062 ASSERT((Opcode & 0xED) == 0x28);
3063
3064 TOGGLE_ADSIZE(AddressSize);
3065
3066 /* Get the operands */
3067 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3068 {
3069 /* Exception occurred */
3070 return FALSE;
3071 }
3072
3073 if (!Fast486ReadModrmByteOperands(State,
3074 &ModRegRm,
3075 &FirstValue,
3076 &SecondValue))
3077 {
3078 /* Exception occurred */
3079 return FALSE;
3080 }
3081
3082 /* Check if this is the instruction that writes to R/M */
3083 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3084 {
3085 /* Swap the order */
3086 SWAP(FirstValue, SecondValue);
3087 }
3088
3089 /* Calculate the result */
3090 Result = FirstValue - SecondValue;
3091
3092 /* Update the flags */
3093 State->Flags.Cf = (FirstValue < SecondValue);
3094 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3095 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3096 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3097 State->Flags.Zf = (Result == 0);
3098 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3099 State->Flags.Pf = Fast486CalculateParity(Result);
3100
3101 /* Check if this is not a CMP */
3102 if (!(Opcode & 0x10))
3103 {
3104 /* Write back the result */
3105 return Fast486WriteModrmByteOperands(State,
3106 &ModRegRm,
3107 Opcode & FAST486_OPCODE_WRITE_REG,
3108 Result);
3109 }
3110 else
3111 {
3112 /* Discard the result */
3113 return TRUE;
3114 }
3115 }
3116
3117 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm)
3118 {
3119 FAST486_MOD_REG_RM ModRegRm;
3120 BOOLEAN OperandSize, AddressSize;
3121
3122 /* Make sure this is the right instruction */
3123 ASSERT((Opcode & 0xED) == 0x29);
3124
3125 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3126
3127 TOGGLE_ADSIZE(AddressSize);
3128 TOGGLE_OPSIZE(OperandSize);
3129
3130 /* Get the operands */
3131 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3132 {
3133 /* Exception occurred */
3134 return FALSE;
3135 }
3136
3137 /* Check the operand size */
3138 if (OperandSize)
3139 {
3140 ULONG FirstValue, SecondValue, Result;
3141
3142 if (!Fast486ReadModrmDwordOperands(State,
3143 &ModRegRm,
3144 &FirstValue,
3145 &SecondValue))
3146 {
3147 /* Exception occurred */
3148 return FALSE;
3149 }
3150
3151 /* Check if this is the instruction that writes to R/M */
3152 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3153 {
3154 /* Swap the order */
3155 SWAP(FirstValue, SecondValue);
3156 }
3157
3158 /* Calculate the result */
3159 Result = FirstValue - SecondValue;
3160
3161 /* Update the flags */
3162 State->Flags.Cf = (FirstValue < SecondValue);
3163 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3164 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3165 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3166 State->Flags.Zf = (Result == 0);
3167 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3168 State->Flags.Pf = Fast486CalculateParity(Result);
3169
3170 /* Check if this is not a CMP */
3171 if (!(Opcode & 0x10))
3172 {
3173 /* Write back the result */
3174 return Fast486WriteModrmDwordOperands(State,
3175 &ModRegRm,
3176 Opcode & FAST486_OPCODE_WRITE_REG,
3177 Result);
3178 }
3179 else
3180 {
3181 /* Discard the result */
3182 return TRUE;
3183 }
3184 }
3185 else
3186 {
3187 USHORT FirstValue, SecondValue, Result;
3188
3189 if (!Fast486ReadModrmWordOperands(State,
3190 &ModRegRm,
3191 &FirstValue,
3192 &SecondValue))
3193 {
3194 /* Exception occurred */
3195 return FALSE;
3196 }
3197
3198 /* Check if this is the instruction that writes to R/M */
3199 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3200 {
3201 /* Swap the order */
3202 SWAP(FirstValue, SecondValue);
3203 }
3204
3205 /* Calculate the result */
3206 Result = FirstValue - SecondValue;
3207
3208 /* Update the flags */
3209 State->Flags.Cf = (FirstValue < SecondValue);
3210 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3211 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3212 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3213 State->Flags.Zf = (Result == 0);
3214 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3215 State->Flags.Pf = Fast486CalculateParity(Result);
3216
3217 /* Check if this is not a CMP */
3218 if (!(Opcode & 0x10))
3219 {
3220 /* Write back the result */
3221 return Fast486WriteModrmWordOperands(State,
3222 &ModRegRm,
3223 Opcode & FAST486_OPCODE_WRITE_REG,
3224 Result);
3225 }
3226 else
3227 {
3228 /* Discard the result */
3229 return TRUE;
3230 }
3231 }
3232 }
3233
3234 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl)
3235 {
3236 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3237 UCHAR SecondValue, Result;
3238
3239 /* Make sure this is the right instruction */
3240 ASSERT((Opcode & 0xEF) == 0x2C);
3241
3242 if (State->PrefixFlags)
3243 {
3244 /* This opcode doesn't take any prefixes */
3245 Fast486Exception(State, FAST486_EXCEPTION_UD);
3246 return FALSE;
3247 }
3248
3249 if (!Fast486FetchByte(State, &SecondValue))
3250 {
3251 /* Exception occurred */
3252 return FALSE;
3253 }
3254
3255 /* Calculate the result */
3256 Result = FirstValue - SecondValue;
3257
3258 /* Update the flags */
3259 State->Flags.Cf = (FirstValue < SecondValue);
3260 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3261 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3262 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3263 State->Flags.Zf = (Result == 0);
3264 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3265 State->Flags.Pf = Fast486CalculateParity(Result);
3266
3267 /* Check if this is not a CMP */
3268 if (!(Opcode & 0x10))
3269 {
3270 /* Write back the result */
3271 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
3272 }
3273
3274 return TRUE;
3275 }
3276
3277 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax)
3278 {
3279 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3280
3281 /* Make sure this is the right instruction */
3282 ASSERT((Opcode & 0xEF) == 0x2D);
3283
3284 NO_LOCK_PREFIX();
3285 TOGGLE_OPSIZE(Size);
3286
3287 if (Size)
3288 {
3289 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
3290 ULONG SecondValue, Result;
3291
3292 if (!Fast486FetchDword(State, &SecondValue))
3293 {
3294 /* Exception occurred */
3295 return FALSE;
3296 }
3297
3298 /* Calculate the result */
3299 Result = FirstValue - SecondValue;
3300
3301 /* Update the flags */
3302 State->Flags.Cf = (FirstValue < SecondValue);
3303 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3304 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3305 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3306 State->Flags.Zf = (Result == 0);
3307 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3308 State->Flags.Pf = Fast486CalculateParity(Result);
3309
3310 /* Check if this is not a CMP */
3311 if (!(Opcode & 0x10))
3312 {
3313 /* Write back the result */
3314 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
3315 }
3316 }
3317 else
3318 {
3319 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
3320 USHORT SecondValue, Result;
3321
3322 if (!Fast486FetchWord(State, &SecondValue))
3323 {
3324 /* Exception occurred */
3325 return FALSE;
3326 }
3327
3328 /* Calculate the result */
3329 Result = FirstValue - SecondValue;
3330
3331 /* Update the flags */
3332 State->Flags.Cf = (FirstValue < SecondValue);
3333 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3334 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3335 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3336 State->Flags.Zf = (Result == 0);
3337 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3338 State->Flags.Pf = Fast486CalculateParity(Result);
3339
3340 /* Check if this is not a CMP */
3341 if (!(Opcode & 0x10))
3342 {
3343 /* Write back the result */
3344 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
3345 }
3346 }
3347
3348 return TRUE;
3349 }
3350
3351 FAST486_OPCODE_HANDLER(Fast486OpcodeDas)
3352 {
3353 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3354 BOOLEAN Carry = State->Flags.Cf;
3355
3356 /* Clear the carry flag */
3357 State->Flags.Cf = FALSE;
3358
3359 /* Check if the first BCD digit is invalid or there was a borrow */
3360 if (((Value & 0x0F) > 9) || State->Flags.Af)
3361 {
3362 /* Correct it */
3363 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x06;
3364 if (State->GeneralRegs[FAST486_REG_EAX].LowByte > 0xFB)
3365 {
3366 /* A borrow occurred */
3367 State->Flags.Cf = TRUE;
3368 }
3369
3370 /* Set the adjust flag */
3371 State->Flags.Af = TRUE;
3372 }
3373
3374 /* Check if the second BCD digit is invalid or there was a borrow */
3375 if ((Value > 0x99) || Carry)
3376 {
3377 /* Correct it */
3378 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x60;
3379
3380 /* There was a borrow */
3381 State->Flags.Cf = TRUE;
3382 }
3383
3384 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3385
3386 /* Update the flags */
3387 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3388 State->Flags.Zf = (Value == 0);
3389 State->Flags.Pf = Fast486CalculateParity(Value);
3390
3391 return TRUE;
3392 }
3393
3394 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa)
3395 {
3396 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3397
3398 /*
3399 * Check if the value in AL is not a valid BCD digit,
3400 * or there was a carry from the lowest 4 bits of AL
3401 */
3402 if (((Value & 0x0F) > 9) || State->Flags.Af)
3403 {
3404 /* Correct it */
3405 State->GeneralRegs[FAST486_REG_EAX].LowWord += 0x06;
3406 State->GeneralRegs[FAST486_REG_EAX].HighByte++;
3407
3408 /* Set CF and AF */
3409 State->Flags.Cf = State->Flags.Af = TRUE;
3410 }
3411 else
3412 {
3413 /* Clear CF and AF */
3414 State->Flags.Cf = State->Flags.Af = FALSE;
3415 }
3416
3417 /* Keep only the lowest 4 bits of AL */
3418 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3419
3420 return TRUE;
3421 }
3422
3423 FAST486_OPCODE_HANDLER(Fast486OpcodeAas)
3424 {
3425 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3426
3427 /*
3428 * Check if the value in AL is not a valid BCD digit,
3429 * or there was a borrow from the lowest 4 bits of AL
3430 */
3431 if (((Value & 0x0F) > 9) || State->Flags.Af)
3432 {
3433 /* Correct it */
3434 State->GeneralRegs[FAST486_REG_EAX].LowWord -= 0x06;
3435 State->GeneralRegs[FAST486_REG_EAX].HighByte--;
3436
3437 /* Set CF and AF */
3438 State->Flags.Cf = State->Flags.Af = TRUE;
3439 }
3440 else
3441 {
3442 /* Clear CF and AF */
3443 State->Flags.Cf = State->Flags.Af = FALSE;
3444 }
3445
3446 /* Keep only the lowest 4 bits of AL */
3447 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3448
3449 return TRUE;
3450 }
3451
3452 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll)
3453 {
3454 INT i;
3455 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3456 FAST486_REG SavedEsp = State->GeneralRegs[FAST486_REG_ESP];
3457
3458 /* Make sure this is the right instruction */
3459 ASSERT(Opcode == 0x60);
3460
3461 TOGGLE_OPSIZE(Size);
3462 NO_LOCK_PREFIX();
3463
3464 /* Push all the registers in order */
3465 for (i = 0; i < FAST486_NUM_GEN_REGS; i++)
3466 {
3467 if (i == FAST486_REG_ESP)
3468 {
3469 /* Use the saved ESP instead */
3470 if (!Fast486StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
3471 {
3472 /* Exception occurred */
3473 return FALSE;
3474 }
3475 }
3476 else
3477 {
3478 /* Push the register */
3479 if (!Fast486StackPush(State, Size ? State->GeneralRegs[i].Long
3480 : State->GeneralRegs[i].LowWord))
3481 {
3482 /* Exception occurred */
3483 return FALSE;
3484 }
3485 }
3486 }
3487
3488 return TRUE;
3489 }
3490
3491 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll)
3492 {
3493 INT i;
3494 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3495 ULONG Value;
3496
3497 /* Make sure this is the right instruction */
3498 ASSERT(Opcode == 0x61);
3499
3500 TOGGLE_OPSIZE(Size);
3501 NO_LOCK_PREFIX();
3502
3503 /* Pop all the registers in reverse order */
3504 for (i = FAST486_NUM_GEN_REGS - 1; i >= 0; i--)
3505 {
3506 /* Pop the value */
3507 if (!Fast486StackPop(State, &Value))
3508 {
3509 /* Exception occurred */
3510 return FALSE;
3511 }
3512
3513 /* Don't modify ESP */
3514 if (i != FAST486_REG_ESP)
3515 {
3516 if (Size) State->GeneralRegs[i].Long = Value;
3517 else State->GeneralRegs[i].LowWord = LOWORD(Value);
3518 }
3519 }
3520
3521 return TRUE;
3522 }
3523
3524 FAST486_OPCODE_HANDLER(Fast486OpcodeBound)
3525 {
3526 // TODO: NOT IMPLEMENTED
3527 UNIMPLEMENTED;
3528
3529 return FALSE;
3530 }
3531
3532 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl)
3533 {
3534 USHORT FirstValue, SecondValue;
3535 FAST486_MOD_REG_RM ModRegRm;
3536 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3537
3538 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
3539 || State->Flags.Vm
3540 || (State->PrefixFlags & FAST486_PREFIX_LOCK))
3541 {
3542 /* Cannot be used in real mode or with a LOCK prefix */
3543 Fast486Exception(State, FAST486_EXCEPTION_UD);
3544 return FALSE;
3545 }
3546
3547 TOGGLE_ADSIZE(AddressSize);
3548
3549 /* Get the operands */
3550 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3551 {
3552 /* Exception occurred */
3553 return FALSE;
3554 }
3555
3556 /* Read the operands */
3557 if (!Fast486ReadModrmWordOperands(State,
3558 &ModRegRm,
3559 &FirstValue,
3560 &SecondValue))
3561 {
3562 /* Exception occurred */
3563 return FALSE;
3564 }
3565
3566 /* Check if the RPL needs adjusting */
3567 if ((SecondValue & 3) < (FirstValue & 3))
3568 {
3569 /* Adjust the RPL */
3570 SecondValue &= ~3;
3571 SecondValue |= FirstValue & 3;
3572
3573 /* Set ZF */
3574 State->Flags.Zf = TRUE;
3575
3576 /* Write back the result */
3577 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
3578 }
3579 else
3580 {
3581 /* Clear ZF */
3582 State->Flags.Zf = FALSE;
3583 return TRUE;
3584 }
3585 }
3586
3587 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm)
3588 {
3589 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3590
3591 /* Make sure this is the right instruction */
3592 ASSERT(Opcode == 0x68);
3593
3594 NO_LOCK_PREFIX();
3595 TOGGLE_OPSIZE(Size);
3596
3597 if (Size)
3598 {
3599 ULONG Data;
3600
3601 if (!Fast486FetchDword(State, &Data))
3602 {
3603 /* Exception occurred */
3604 return FALSE;
3605 }
3606
3607 /* Call the internal API */
3608 return Fast486StackPush(State, Data);
3609 }
3610 else
3611 {
3612 USHORT Data;
3613
3614 if (!Fast486FetchWord(State, &Data))
3615 {
3616 /* Exception occurred */
3617 return FALSE;
3618 }
3619
3620 /* Call the internal API */
3621 return Fast486StackPush(State, Data);
3622 }
3623 }
3624
3625 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm)
3626 {
3627 BOOLEAN OperandSize, AddressSize;
3628 FAST486_MOD_REG_RM ModRegRm;
3629 LONG Multiplier;
3630
3631 /* Make sure this is the right instruction */
3632 ASSERT((Opcode & 0xFD) == 0x69);
3633
3634 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3635
3636 TOGGLE_ADSIZE(AddressSize);
3637 TOGGLE_OPSIZE(OperandSize);
3638
3639 /* Fetch the parameters */
3640 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3641 {
3642 /* Exception occurred */
3643 return FALSE;
3644 }
3645
3646 if (Opcode == 0x6B)
3647 {
3648 CHAR Byte;
3649
3650 /* Fetch the immediate operand */
3651 if (!Fast486FetchByte(State, (PUCHAR)&Byte))
3652 {
3653 /* Exception occurred */
3654 return FALSE;
3655 }
3656
3657 Multiplier = (LONG)Byte;
3658 }
3659 else
3660 {
3661 if (OperandSize)
3662 {
3663 LONG Dword;
3664
3665 /* Fetch the immediate operand */
3666 if (!Fast486FetchDword(State, (PULONG)&Dword))
3667 {
3668 /* Exception occurred */
3669 return FALSE;
3670 }
3671
3672 Multiplier = Dword;
3673 }
3674 else
3675 {
3676 SHORT Word;
3677
3678 /* Fetch the immediate operand */
3679 if (!Fast486FetchWord(State, (PUSHORT)&Word))
3680 {
3681 /* Exception occurred */
3682 return FALSE;
3683 }
3684
3685 Multiplier = (LONG)Word;
3686 }
3687 }
3688
3689 if (OperandSize)
3690 {
3691 LONG RegValue, Multiplicand;
3692 LONGLONG Product;
3693
3694 /* Read the operands */
3695 if (!Fast486ReadModrmDwordOperands(State,
3696 &ModRegRm,
3697 (PULONG)&RegValue,
3698 (PULONG)&Multiplicand))
3699 {
3700 /* Exception occurred */
3701 return FALSE;
3702 }
3703
3704 /* Multiply */
3705 Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
3706
3707 /* Check for carry/overflow */
3708 State->Flags.Cf = State->Flags.Of = ((Product < MINLONG) || (Product > MAXLONG));
3709
3710 /* Write-back the result */
3711 return Fast486WriteModrmDwordOperands(State,
3712 &ModRegRm,
3713 TRUE,
3714 (ULONG)((LONG)Product));
3715 }
3716 else
3717 {
3718 SHORT RegValue, Multiplicand;
3719 LONG Product;
3720
3721 /* Read the operands */
3722 if (!Fast486ReadModrmWordOperands(State,
3723 &ModRegRm,
3724 (PUSHORT)&RegValue,
3725 (PUSHORT)&Multiplicand))
3726 {
3727 /* Exception occurred */
3728 return FALSE;
3729 }
3730
3731 /* Multiply */
3732 Product = (LONG)Multiplicand * (LONG)Multiplier;
3733
3734 /* Check for carry/overflow */
3735 State->Flags.Cf = State->Flags.Of = ((Product < MINSHORT) || (Product > MAXSHORT));
3736
3737 /* Write-back the result */
3738 return Fast486WriteModrmWordOperands(State,
3739 &ModRegRm,
3740 TRUE,
3741 (USHORT)((SHORT)Product));
3742 }
3743 }
3744
3745 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm)
3746 {
3747 UCHAR Data;
3748
3749 /* Make sure this is the right instruction */
3750 ASSERT(Opcode == 0x6A);
3751
3752 if (!Fast486FetchByte(State, &Data))
3753 {
3754 /* Exception occurred */
3755 return FALSE;
3756 }
3757
3758 /* Call the internal API */
3759 return Fast486StackPush(State, Data);
3760 }
3761
3762 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm)
3763 {
3764 UCHAR FirstValue, SecondValue, Result;
3765 FAST486_MOD_REG_RM ModRegRm;
3766 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3767
3768 /* Make sure this is the right instruction */
3769 ASSERT((Opcode & 0xFD) == 0x88);
3770
3771 TOGGLE_ADSIZE(AddressSize);
3772
3773 /* Get the operands */
3774 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3775 {
3776 /* Exception occurred */
3777 return FALSE;
3778 }
3779
3780 if (!Fast486ReadModrmByteOperands(State,
3781 &ModRegRm,
3782 &FirstValue,
3783 &SecondValue))
3784 {
3785 /* Exception occurred */
3786 return FALSE;
3787 }
3788
3789 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3790 else Result = FirstValue;
3791
3792 /* Write back the result */
3793 return Fast486WriteModrmByteOperands(State,
3794 &ModRegRm,
3795 Opcode & FAST486_OPCODE_WRITE_REG,
3796 Result);
3797
3798 }
3799
3800 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm)
3801 {
3802 FAST486_MOD_REG_RM ModRegRm;
3803 BOOLEAN OperandSize, AddressSize;
3804
3805 /* Make sure this is the right instruction */
3806 ASSERT((Opcode & 0xFD) == 0x89);
3807
3808 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3809
3810 TOGGLE_ADSIZE(AddressSize);
3811 TOGGLE_OPSIZE(OperandSize);
3812
3813 /* Get the operands */
3814 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3815 {
3816 /* Exception occurred */
3817 return FALSE;
3818 }
3819
3820 /* Check the operand size */
3821 if (OperandSize)
3822 {
3823 ULONG FirstValue, SecondValue, Result;
3824
3825 if (!Fast486ReadModrmDwordOperands(State,
3826 &ModRegRm,
3827 &FirstValue,
3828 &SecondValue))
3829 {
3830 /* Exception occurred */
3831 return FALSE;
3832 }
3833
3834 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3835 else Result = FirstValue;
3836
3837 /* Write back the result */
3838 return Fast486WriteModrmDwordOperands(State,
3839 &ModRegRm,
3840 Opcode & FAST486_OPCODE_WRITE_REG,
3841 Result);
3842 }
3843 else
3844 {
3845 USHORT FirstValue, SecondValue, Result;
3846
3847 if (!Fast486ReadModrmWordOperands(State,
3848 &ModRegRm,
3849 &FirstValue,
3850 &SecondValue))
3851 {
3852 /* Exception occurred */
3853 return FALSE;
3854 }
3855
3856 if (Opcode & FAST486_OPCODE_WRITE_REG) Result = SecondValue;
3857 else Result = FirstValue;
3858
3859 /* Write back the result */
3860 return Fast486WriteModrmWordOperands(State,
3861 &ModRegRm,
3862 Opcode & FAST486_OPCODE_WRITE_REG,
3863 Result);
3864 }
3865 }
3866
3867 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
3868 {
3869 BOOLEAN OperandSize, AddressSize;
3870 FAST486_MOD_REG_RM ModRegRm;
3871
3872 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3873
3874 /* Make sure this is the right instruction */
3875 ASSERT(Opcode == 0x8C);
3876
3877 TOGGLE_ADSIZE(AddressSize);
3878 TOGGLE_OPSIZE(OperandSize);
3879
3880 /* Get the operands */
3881 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3882 {
3883 /* Exception occurred */
3884 return FALSE;
3885 }
3886
3887 if (ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3888 {
3889 /* Invalid */
3890 Fast486Exception(State, FAST486_EXCEPTION_UD);
3891 return FALSE;
3892 }
3893
3894 if (OperandSize)
3895 {
3896 return Fast486WriteModrmDwordOperands(State,
3897 &ModRegRm,
3898 FALSE,
3899 State->SegmentRegs[ModRegRm.Register].Selector);
3900 }
3901 else
3902 {
3903 return Fast486WriteModrmWordOperands(State,
3904 &ModRegRm,
3905 FALSE,
3906 State->SegmentRegs[ModRegRm.Register].Selector);
3907 }
3908 }
3909
3910 FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
3911 {
3912 FAST486_MOD_REG_RM ModRegRm;
3913 BOOLEAN OperandSize, AddressSize;
3914
3915 /* Make sure this is the right instruction */
3916 ASSERT(Opcode == 0x8D);
3917
3918 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3919
3920 TOGGLE_ADSIZE(AddressSize);
3921 TOGGLE_OPSIZE(OperandSize);
3922
3923 /* Get the operands */
3924 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3925 {
3926 /* Exception occurred */
3927 return FALSE;
3928 }
3929
3930 /* The second operand must be memory */
3931 if (!ModRegRm.Memory)
3932 {
3933 /* Invalid */
3934 Fast486Exception(State, FAST486_EXCEPTION_UD);
3935 return FALSE;
3936 }
3937
3938 /* Write the address to the register */
3939 if (OperandSize)
3940 {
3941 return Fast486WriteModrmDwordOperands(State,
3942 &ModRegRm,
3943 TRUE,
3944 ModRegRm.MemoryAddress);
3945 }
3946 else
3947 {
3948 return Fast486WriteModrmWordOperands(State,
3949 &ModRegRm,
3950 TRUE,
3951 ModRegRm.MemoryAddress);
3952
3953 }
3954 }
3955
3956 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
3957 {
3958 BOOLEAN OperandSize, AddressSize;
3959 FAST486_MOD_REG_RM ModRegRm;
3960
3961 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3962
3963 /* Make sure this is the right instruction */
3964 ASSERT(Opcode == 0x8E);
3965
3966 TOGGLE_ADSIZE(AddressSize);
3967 TOGGLE_OPSIZE(OperandSize);
3968
3969 /* Get the operands */
3970 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3971 {
3972 /* Exception occurred */
3973 return FALSE;
3974 }
3975
3976 if ((ModRegRm.Register >= FAST486_NUM_SEG_REGS)
3977 || ((FAST486_SEG_REGS)ModRegRm.Register == FAST486_REG_CS))
3978 {
3979 /* Invalid */
3980 Fast486Exception(State, FAST486_EXCEPTION_UD);
3981 return FALSE;
3982 }
3983
3984 if (OperandSize)
3985 {
3986 ULONG Selector;
3987
3988 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Selector))
3989 {
3990 /* Exception occurred */
3991 return FALSE;
3992 }
3993
3994 return Fast486LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
3995 }
3996 else
3997 {
3998 USHORT Selector;
3999
4000 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
4001 {
4002 /* Exception occurred */
4003 return FALSE;
4004 }
4005
4006 return Fast486LoadSegment(State, ModRegRm.Register, Selector);
4007 }
4008 }
4009
4010 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde)
4011 {
4012 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4013
4014 /* Make sure this is the right instruction */
4015 ASSERT(Opcode == 0x98);
4016
4017 TOGGLE_OPSIZE(Size);
4018 NO_LOCK_PREFIX();
4019
4020 if (Size)
4021 {
4022 /* Sign extend AX to EAX */
4023 State->GeneralRegs[FAST486_REG_EAX].Long = MAKELONG
4024 (
4025 State->GeneralRegs[FAST486_REG_EAX].LowWord,
4026 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4027 ? 0xFFFF : 0x0000
4028 );
4029 }
4030 else
4031 {
4032 /* Sign extend AL to AX */
4033 State->GeneralRegs[FAST486_REG_EAX].HighByte =
4034 (State->GeneralRegs[FAST486_REG_EAX].LowByte & SIGN_FLAG_BYTE)
4035 ? 0xFF : 0x00;
4036 }
4037
4038 return TRUE;
4039 }
4040
4041 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq)
4042 {
4043 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4044
4045 /* Make sure this is the right instruction */
4046 ASSERT(Opcode == 0x99);
4047
4048 TOGGLE_OPSIZE(Size);
4049 NO_LOCK_PREFIX();
4050
4051 if (Size)
4052 {
4053 /* Sign extend EAX to EDX:EAX */
4054 State->GeneralRegs[FAST486_REG_EDX].Long =
4055 (State->GeneralRegs[FAST486_REG_EAX].Long & SIGN_FLAG_LONG)
4056 ? 0xFFFFFFFF : 0x00000000;
4057 }
4058 else
4059 {
4060 /* Sign extend AX to DX:AX */
4061 State->GeneralRegs[FAST486_REG_EDX].LowWord =
4062 (State->GeneralRegs[FAST486_REG_EAX].LowWord & SIGN_FLAG_WORD)
4063 ? 0xFFFF : 0x0000;
4064 }
4065
4066 return TRUE;
4067 }
4068
4069 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
4070 {
4071 USHORT Segment = 0;
4072 ULONG Offset = 0;
4073 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4074
4075 /* Make sure this is the right instruction */
4076 ASSERT(Opcode == 0x9A);
4077
4078 TOGGLE_OPSIZE(Size);
4079 NO_LOCK_PREFIX();
4080
4081 /* Fetch the offset */
4082 if (Size)
4083 {
4084 if (!Fast486FetchDword(State, &Offset))
4085 {
4086 /* Exception occurred */
4087 return FALSE;
4088 }
4089 }
4090 else
4091 {
4092 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
4093 {
4094 /* Exception occurred */
4095 return FALSE;
4096 }
4097 }
4098
4099 /* Fetch the segment */
4100 if (!Fast486FetchWord(State, &Segment))
4101 {
4102 /* Exception occurred */
4103 return FALSE;
4104 }
4105
4106 /* Push the current code segment selector */
4107 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
4108 {
4109 /* Exception occurred */
4110 return FALSE;
4111 }
4112
4113 /* Push the current value of the instruction pointer */
4114 if (!Fast486StackPush(State, State->InstPtr.Long))
4115 {
4116 /* Exception occurred */
4117 return FALSE;
4118 }
4119
4120 /* Load the new CS */
4121 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4122 {
4123 /* Exception occurred */
4124 return FALSE;
4125 }
4126
4127 /* Load new (E)IP */
4128 if (Size) State->InstPtr.Long = Offset;
4129 else State->InstPtr.LowWord = LOWORD(Offset);
4130
4131 return TRUE;
4132 }
4133
4134 FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
4135 {
4136 // TODO: NOT IMPLEMENTED
4137 UNIMPLEMENTED;
4138
4139 return FALSE;
4140 }
4141
4142 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
4143 {
4144 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4145
4146 NO_LOCK_PREFIX();
4147 TOGGLE_OPSIZE(Size);
4148
4149 /* Check for VM86 mode when IOPL is not 3 */
4150 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4151 {
4152 /* Call the VM86 monitor */
4153 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4154 return FALSE;
4155 }
4156
4157 /* Push the flags */
4158 if (Size) return Fast486StackPush(State, State->Flags.Long);
4159 else return Fast486StackPush(State, LOWORD(State->Flags.Long));
4160 }
4161
4162 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
4163 {
4164 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4165 INT Cpl = Fast486GetCurrentPrivLevel(State);
4166 ULONG NewFlags;
4167
4168 NO_LOCK_PREFIX();
4169 TOGGLE_OPSIZE(Size);
4170
4171 /* Pop the new flags */
4172 if (!Fast486StackPop(State, &NewFlags))
4173 {
4174 /* Exception occurred */
4175 return FALSE;
4176 }
4177
4178 if (!State->Flags.Vm)
4179 {
4180 /* Check the current privilege level */
4181 if (Cpl == 0)
4182 {
4183 /* Supervisor */
4184
4185 /* Set the flags */
4186 if (Size)
4187 {
4188 /* Memorize the old state of RF */
4189 BOOLEAN OldRf = State->Flags.Rf;
4190
4191 State->Flags.Long = NewFlags;
4192
4193 /* Restore VM and RF */
4194 State->Flags.Vm = FALSE;
4195 State->Flags.Rf = OldRf;
4196
4197 /* Clear VIF and VIP */
4198 State->Flags.Vif = State->Flags.Vip = FALSE;
4199 }
4200 else State->Flags.LowWord = LOWORD(NewFlags);
4201
4202 /* Restore the reserved bits */
4203 State->Flags.AlwaysSet = TRUE;
4204 State->Flags.Reserved0 = FALSE;
4205 State->Flags.Reserved1 = FALSE;
4206 }
4207 else
4208 {
4209 /* User */
4210
4211 /* Memorize the old state of IF and IOPL */
4212 BOOLEAN OldIf = State->Flags.If;
4213 UINT OldIopl = State->Flags.Iopl;
4214
4215 /* Set the flags */
4216 if (Size)
4217 {
4218 /* Memorize the old state of RF */
4219 BOOLEAN OldRf = State->Flags.Rf;
4220
4221 State->Flags.Long = NewFlags;
4222
4223 /* Restore VM and RF */
4224 State->Flags.Vm = FALSE;
4225 State->Flags.Rf = OldRf;
4226
4227 /* Clear VIF and VIP */
4228 State->Flags.Vif = State->Flags.Vip = FALSE;
4229 }
4230 else State->Flags.LowWord = LOWORD(NewFlags);
4231
4232 /* Restore the reserved bits and IOPL */
4233 State->Flags.AlwaysSet = TRUE;
4234 State->Flags.Reserved0 = FALSE;
4235 State->Flags.Reserved1 = FALSE;
4236 State->Flags.Iopl = OldIopl;
4237
4238 /* Check if the user doesn't have the privilege to change IF */
4239 if (Cpl > State->Flags.Iopl)
4240 {
4241 /* Restore IF */
4242 State->Flags.If = OldIf;
4243 }
4244 }
4245 }
4246 else
4247 {
4248 /* Check the IOPL */
4249 if (State->Flags.Iopl == 3)
4250 {
4251 if (Size)
4252 {
4253 /* Memorize the old state of RF, VIF and VIP */
4254 BOOLEAN OldRf = State->Flags.Rf;
4255 BOOLEAN OldVif = State->Flags.Vif;
4256 BOOLEAN OldVip = State->Flags.Vip;
4257
4258 State->Flags.Long = NewFlags;
4259
4260 /* Restore VM, RF, VIF and VIP */
4261 State->Flags.Vm = TRUE;
4262 State->Flags.Rf = OldRf;
4263 State->Flags.Vif = OldVif;
4264 State->Flags.Vip = OldVip;
4265 }
4266 else State->Flags.LowWord = LOWORD(NewFlags);
4267
4268 /* Restore the reserved bits and IOPL */
4269 State->Flags.AlwaysSet = TRUE;
4270 State->Flags.Reserved0 = FALSE;
4271 State->Flags.Reserved1 = FALSE;
4272 State->Flags.Iopl = 3;
4273 }
4274 else
4275 {
4276 /* Call the VM86 monitor */
4277 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4278 }
4279
4280 }
4281
4282 return TRUE;
4283 }
4284
4285 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf)
4286 {
4287 /* Make sure this is the right instruction */
4288 ASSERT(Opcode == 0x9E);
4289
4290 /* Set the low-order byte of FLAGS to AH */
4291 State->Flags.Long &= 0xFFFFFF00;
4292 State->Flags.Long |= State->GeneralRegs[FAST486_REG_EAX].HighByte;
4293
4294 /* Restore the reserved bits of FLAGS */
4295 State->Flags.AlwaysSet = TRUE;
4296 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4297
4298 return FALSE;
4299 }
4300
4301 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf)
4302 {
4303 /* Make sure this is the right instruction */
4304 ASSERT(Opcode == 0x9F);
4305
4306 /* Set AH to the low-order byte of FLAGS */
4307 State->GeneralRegs[FAST486_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4308
4309 return FALSE;
4310 }
4311
4312 FAST486_OPCODE_HANDLER(Fast486OpcodeRet)
4313 {
4314 ULONG ReturnAddress;
4315 USHORT BytesToPop = 0;
4316 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4317
4318 /* Make sure this is the right instruction */
4319 ASSERT((Opcode & 0xFE) == 0xC2);
4320
4321 NO_LOCK_PREFIX();
4322 TOGGLE_OPSIZE(Size);
4323
4324 if (Opcode == 0xC2)
4325 {
4326 /* Fetch the number of bytes to pop after the return */
4327 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4328 }
4329
4330 /* Pop the return address */
4331 if (!Fast486StackPop(State, &ReturnAddress)) return FALSE;
4332
4333 /* Return to the calling procedure, and if necessary, pop the parameters */
4334 if (Size)
4335 {
4336 State->InstPtr.Long = ReturnAddress;
4337 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4338 }
4339 else
4340 {
4341 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4342 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4343 }
4344
4345 return TRUE;
4346 }
4347
4348 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
4349 {
4350 UCHAR FarPointer[6];
4351 BOOLEAN OperandSize, AddressSize;
4352 FAST486_MOD_REG_RM ModRegRm;
4353
4354 /* Make sure this is the right instruction */
4355 ASSERT((Opcode & 0xFE) == 0xC4);
4356
4357 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4358
4359 TOGGLE_OPSIZE(OperandSize);
4360 TOGGLE_ADSIZE(AddressSize);
4361
4362 /* Get the operands */
4363 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
4364 {
4365 /* Exception occurred */
4366 return FALSE;
4367 }
4368
4369 if (!ModRegRm.Memory)
4370 {
4371 /* Check if this is a BOP and the host supports BOPs */
4372 if ((Opcode == 0xC4)
4373 && (ModRegRm.Register == FAST486_REG_EAX)
4374 && (ModRegRm.SecondRegister == FAST486_REG_ESP)
4375 && (State->BopCallback != NULL))
4376 {
4377 UCHAR BopCode;
4378
4379 /* Fetch the BOP code */
4380 if (!Fast486FetchByte(State, &BopCode))
4381 {
4382 /* Exception occurred */
4383 return FALSE;
4384 }
4385
4386 /* Call the BOP handler */
4387 State->BopCallback(State, BopCode);
4388
4389 /* Return success */
4390 return TRUE;
4391 }
4392
4393 /* Invalid */
4394 Fast486Exception(State, FAST486_EXCEPTION_UD);
4395 return FALSE;
4396 }
4397
4398 if (!Fast486ReadMemory(State,
4399 (State->PrefixFlags & FAST486_PREFIX_SEG)
4400 ? State->SegmentOverride : FAST486_REG_DS,
4401 ModRegRm.MemoryAddress,
4402 FALSE,
4403 FarPointer,
4404 OperandSize ? 6 : 4))
4405 {
4406 /* Exception occurred */
4407 return FALSE;
4408 }
4409
4410 if (OperandSize)
4411 {
4412 ULONG Offset = *((PULONG)FarPointer);
4413 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4414
4415 /* Set the register to the offset */
4416 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4417
4418 /* Load the segment */
4419 return Fast486LoadSegment(State,
4420 (Opcode == 0xC4)
4421 ? FAST486_REG_ES : FAST486_REG_DS,
4422 Segment);
4423 }
4424 else
4425 {
4426 USHORT Offset = *((PUSHORT)FarPointer);
4427 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4428
4429 /* Set the register to the offset */
4430 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4431
4432 /* Load the segment */
4433 return Fast486LoadSegment(State,
4434 (Opcode == 0xC4)
4435 ? FAST486_REG_ES : FAST486_REG_DS,
4436 Segment);
4437 }
4438 }
4439
4440 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
4441 {
4442 INT i;
4443 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4444 USHORT FrameSize;
4445 UCHAR NestingLevel;
4446 FAST486_REG FramePointer;
4447
4448 /* Make sure this is the right instruction */
4449 ASSERT(Opcode == 0xC8);
4450
4451 NO_LOCK_PREFIX();
4452 TOGGLE_OPSIZE(Size);
4453
4454 if (!Fast486FetchWord(State, &FrameSize))
4455 {
4456 /* Exception occurred */
4457 return FALSE;
4458 }
4459
4460 if (!Fast486FetchByte(State, &NestingLevel))
4461 {
4462 /* Exception occurred */
4463 return FALSE;
4464 }
4465
4466 /* Push EBP */
4467 if (!Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long))
4468 {
4469 /* Exception occurred */
4470 return FALSE;
4471 }
4472
4473 /* Save ESP */
4474 FramePointer = State->GeneralRegs[FAST486_REG_ESP];
4475
4476 /* Set up the nested procedure stacks */
4477 for (i = 1; i < NestingLevel; i++)
4478 {
4479 if (Size)
4480 {
4481 State->GeneralRegs[FAST486_REG_EBP].Long -= 4;
4482 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].Long);
4483 }
4484 else
4485 {
4486 State->GeneralRegs[FAST486_REG_EBP].LowWord -= 2;
4487 Fast486StackPush(State, State->GeneralRegs[FAST486_REG_EBP].LowWord);
4488 }
4489 }
4490
4491 if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
4492
4493 /* Set EBP to the frame pointer */
4494 State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
4495
4496 /* Reserve space for the frame */
4497 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
4498 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
4499
4500 return TRUE;
4501 }
4502
4503 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
4504 {
4505 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4506
4507 /* Make sure this is the right instruction */
4508 ASSERT(Opcode == 0xC9);
4509
4510 NO_LOCK_PREFIX();
4511 TOGGLE_OPSIZE(Size);
4512
4513 if (Size)
4514 {
4515 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4516 State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
4517
4518 /* Pop the saved base pointer from the stack */
4519 return Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
4520 }
4521 else
4522 {
4523 ULONG Value;
4524
4525 /* Set the stack pointer (SP) to the base pointer (BP) */
4526 State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
4527
4528 /* Pop the saved base pointer from the stack */
4529 if (Fast486StackPop(State, &Value))
4530 {
4531 State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
4532 return TRUE;
4533 }
4534 else return FALSE;
4535 }
4536 }
4537
4538 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
4539 {
4540 ULONG Segment = 0;
4541 ULONG Offset = 0;
4542 USHORT BytesToPop = 0;
4543 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4544
4545 /* Make sure this is the right instruction */
4546 ASSERT((Opcode & 0xFE) == 0xCA);
4547
4548 TOGGLE_OPSIZE(Size);
4549 NO_LOCK_PREFIX();
4550
4551 if (Opcode == 0xCA)
4552 {
4553 /* Fetch the number of bytes to pop after the return */
4554 if (!Fast486FetchWord(State, &BytesToPop)) return FALSE;
4555 }
4556
4557 /* Pop the offset */
4558 if (!Fast486StackPop(State, &Offset))
4559 {
4560 /* Exception occurred */
4561 return FALSE;
4562 }
4563
4564 /* Pop the segment */
4565 if (!Fast486StackPop(State, &Segment))
4566 {
4567 /* Exception occurred */
4568 return FALSE;
4569 }
4570
4571 /* Load the new CS */
4572 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
4573 {
4574 /* Exception occurred */
4575 return FALSE;
4576 }
4577
4578 /* Load new (E)IP, and if necessary, pop the parameters */
4579 if (Size)
4580 {
4581 State->InstPtr.Long = Offset;
4582 State->GeneralRegs[FAST486_REG_ESP].Long += BytesToPop;
4583 }
4584 else
4585 {
4586 State->InstPtr.LowWord = LOWORD(Offset);
4587 State->GeneralRegs[FAST486_REG_ESP].LowWord += BytesToPop;
4588 }
4589
4590 return TRUE;
4591 }
4592
4593 FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
4594 {
4595 UCHAR IntNum;
4596 FAST486_IDT_ENTRY IdtEntry;
4597
4598 switch (Opcode)
4599 {
4600 case 0xCC:
4601 {
4602 /* This is the INT3 instruction */
4603 IntNum = 3;
4604 break;
4605 }
4606
4607 case 0xCD:
4608 {
4609 /* Fetch the interrupt number */
4610 if (!Fast486FetchByte(State, &IntNum))
4611 {
4612 /* Exception occurred */
4613 return FALSE;
4614 }
4615
4616 break;
4617 }
4618
4619 case 0xCE:
4620 {
4621 /* Don't do anything if OF is cleared */
4622 if (!State->Flags.Of) return TRUE;
4623
4624 /* Exception #OF */
4625 IntNum = FAST486_EXCEPTION_OF;
4626
4627 break;
4628 }
4629
4630 default:
4631 {
4632 /* Should not happen */
4633 ASSERT(FALSE);
4634 }
4635 }
4636
4637 /* Get the interrupt vector */
4638 if (!Fast486GetIntVector(State, IntNum, &IdtEntry))
4639 {
4640 /* Exception occurred */
4641 return FALSE;
4642 }
4643
4644 /* Perform the interrupt */
4645 if (!Fast486InterruptInternal(State,
4646 IdtEntry.Selector,
4647 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
4648 IdtEntry.Type))
4649 {
4650 /* Exception occurred */
4651 return FALSE;
4652 }
4653
4654 return TRUE;
4655 }
4656
4657 FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
4658 {
4659 FAST486_SEG_REGS i;
4660 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4661 FAST486_FLAGS_REG NewFlags;
4662 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4663
4664 /* Make sure this is the right instruction */
4665 ASSERT(Opcode == 0xCF);
4666
4667 NO_LOCK_PREFIX();
4668 TOGGLE_OPSIZE(Size);
4669
4670 /* Pop EIP */
4671 if (!Fast486StackPop(State, &InstPtr))
4672 {
4673 /* Exception occurred */
4674 return FALSE;
4675 }
4676
4677 /* Pop CS */
4678 if (!Fast486StackPop(State, &CodeSel))
4679 {
4680 /* Exception occurred */
4681 return FALSE;
4682 }
4683
4684 /* Pop EFLAGS */
4685 if (!Fast486StackPop(State, &NewFlags.Long))
4686 {
4687 /* Exception occurred */
4688 return FALSE;
4689 }
4690
4691 /* Check for protected mode */
4692 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
4693 {
4694 INT Cpl = Fast486GetCurrentPrivLevel(State);
4695
4696 if (State->Flags.Vm)
4697 {
4698 /* Return from VM86 mode */
4699
4700 /* Check the IOPL */
4701 if (State->Flags.Iopl == 3)
4702 {
4703 /* Set new EIP */
4704 State->InstPtr.Long = LOWORD(InstPtr);
4705
4706 /* Load new CS */
4707 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4708 {
4709 /* Exception occurred */
4710 return FALSE;
4711 }
4712
4713 /* Set the new flags */
4714 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4715 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4716 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4717 State->Flags.Iopl = 3;
4718 }
4719 else
4720 {
4721 /* Call the VM86 monitor */
4722 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4723 return FALSE;
4724 }
4725
4726 return TRUE;
4727 }
4728
4729 if (State->Flags.Nt)
4730 {
4731 /* Nested task return */
4732
4733 UNIMPLEMENTED;
4734 return FALSE;
4735 }
4736
4737 if (NewFlags.Vm)
4738 {
4739 /* Return to VM86 mode */
4740 ULONG Es, Ds, Fs, Gs;
4741
4742 /* Pop ESP, SS, ES, FS, GS */
4743 if (!Fast486StackPop(State, &StackPtr)) return FALSE;
4744 if (!Fast486StackPop(State, &StackSel)) return FALSE;
4745 if (!Fast486StackPop(State, &Es)) return FALSE;
4746 if (!Fast486StackPop(State, &Ds)) return FALSE;
4747 if (!Fast486StackPop(State, &Fs)) return FALSE;
4748 if (!Fast486StackPop(State, &Gs)) return FALSE;
4749
4750 /* Set the new IP */
4751 State->InstPtr.Long = LOWORD(InstPtr);
4752
4753 /* Set the new flags */
4754 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4755 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4756 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4757
4758 /* Load the new segments */
4759 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel)) return FALSE;
4760 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) return FALSE;
4761 if (!Fast486LoadSegment(State, FAST486_REG_ES, Es)) return FALSE;
4762 if (!Fast486LoadSegment(State, FAST486_REG_DS, Ds)) return FALSE;
4763 if (!Fast486LoadSegment(State, FAST486_REG_FS, Fs)) return FALSE;
4764 if (!Fast486LoadSegment(State, FAST486_REG_GS, Gs)) return FALSE;
4765
4766 return TRUE;
4767 }
4768
4769 /* Load the new CS */
4770 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4771 {
4772 /* Exception occurred */
4773 return FALSE;
4774 }
4775
4776 /* Set EIP */
4777 if (Size) State->InstPtr.Long = InstPtr;
4778 else State->InstPtr.LowWord = LOWORD(InstPtr);
4779
4780 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4781 {
4782 /* Pop ESP */
4783 if (!Fast486StackPop(State, &StackPtr))
4784 {
4785 /* Exception */
4786 return FALSE;
4787 }
4788
4789 /* Pop SS */
4790 if (!Fast486StackPop(State, &StackSel))
4791 {
4792 /* Exception */
4793 return FALSE;
4794 }
4795
4796 /* Load new SS */
4797 if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
4798 {
4799 /* Exception */
4800 return FALSE;
4801 }
4802
4803 /* Set ESP */
4804 if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
4805 else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
4806 }
4807
4808 /* Set the new flags */
4809 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
4810 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
4811 State->Flags.AlwaysSet = TRUE;
4812
4813 /* Set additional flags */
4814 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
4815 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
4816
4817 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
4818 {
4819 /* Update the CPL */
4820 Cpl = Fast486GetCurrentPrivLevel(State);
4821
4822 /* Check segment security */
4823 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
4824 {
4825 /* Don't check CS or SS */
4826 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
4827
4828 if ((Cpl > State->SegmentRegs[i].Dpl)
4829 && (!State->SegmentRegs[i].Executable
4830 || !State->SegmentRegs[i].DirConf))
4831 {
4832 /* Load the NULL descriptor in the segment */
4833 if (!Fast486LoadSegment(State, i, 0)) return FALSE;
4834 }
4835 }
4836 }
4837 }
4838 else
4839 {
4840 if (Size && (InstPtr & 0xFFFF0000))
4841 {
4842 /* Invalid */
4843 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, 0);
4844 return FALSE;
4845 }
4846
4847 /* Set new EIP */
4848 State->InstPtr.Long = InstPtr;
4849
4850 /* Load new CS */
4851 if (!Fast486LoadSegment(State, FAST486_REG_CS, CodeSel))
4852 {
4853 /* Exception occurred */
4854 return FALSE;
4855 }
4856
4857 /* Set the new flags */
4858 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4859 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4860 State->Flags.AlwaysSet = TRUE;
4861 }
4862
4863 return TRUE;
4864 }
4865
4866 FAST486_OPCODE_HANDLER(Fast486OpcodeAam)
4867 {
4868 UCHAR Base;
4869 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4870
4871 NO_LOCK_PREFIX();
4872
4873 /* Fetch the base */
4874 if (!Fast486FetchByte(State, &Base))
4875 {
4876 /* Exception occurred */
4877 return FALSE;
4878 }
4879
4880 /* Check if the base is zero */
4881 if (Base == 0)
4882 {
4883 /* Divide error */
4884 Fast486Exception(State, FAST486_EXCEPTION_DE);
4885 return FALSE;
4886 }
4887
4888 /* Adjust */
4889 State->GeneralRegs[FAST486_REG_EAX].HighByte = Value / Base;
4890 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value %= Base;
4891
4892 /* Update flags */
4893 State->Flags.Af = FALSE;
4894 State->Flags.Zf = (Value == 0);
4895 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4896 State->Flags.Pf = Fast486CalculateParity(Value);
4897
4898 return TRUE;
4899 }
4900
4901 FAST486_OPCODE_HANDLER(Fast486OpcodeAad)
4902 {
4903 UCHAR Base;
4904 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
4905
4906 NO_LOCK_PREFIX();
4907
4908 /* Fetch the base */
4909 if (!Fast486FetchByte(State, &Base))
4910 {
4911 /* Exception occurred */
4912 return FALSE;
4913 }
4914
4915 /* Adjust */
4916 Value += State->GeneralRegs[FAST486_REG_EAX].HighByte * Base;
4917 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
4918
4919 /* Update flags */
4920 State->Flags.Af = FALSE;
4921 State->Flags.Zf = (Value == 0);
4922 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
4923 State->Flags.Pf = Fast486CalculateParity(Value);
4924
4925 return TRUE;
4926 }
4927
4928 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat)
4929 {
4930 UCHAR Value;
4931 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
4932
4933 TOGGLE_ADSIZE(AddressSize);
4934
4935 /* Read a byte from DS:[(E)BX + AL] */
4936 if (!Fast486ReadMemory(State,
4937 FAST486_REG_DS,
4938 (AddressSize ? State->GeneralRegs[FAST486_REG_EBX].Long
4939 : State->GeneralRegs[FAST486_REG_EBX].LowWord)
4940 + State->GeneralRegs[FAST486_REG_EAX].LowByte,
4941 FALSE,
4942 &Value,
4943 sizeof(UCHAR)))
4944 {
4945 /* Exception occurred */
4946 return FALSE;
4947 }
4948
4949 /* Set AL to the result */
4950 State->GeneralRegs[FAST486_REG_EAX].LowByte = Value;
4951
4952 /* Return success */
4953 return TRUE;
4954 }
4955
4956 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop)
4957 {
4958 BOOLEAN Condition;
4959 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
4960 CHAR Offset = 0;
4961
4962 /* Make sure this is the right instruction */
4963 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
4964
4965 NO_LOCK_PREFIX();
4966 TOGGLE_ADSIZE(Size);
4967
4968 if (Size) Condition = ((--State->GeneralRegs[FAST486_REG_ECX].Long) != 0);
4969 else Condition = ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) != 0);
4970
4971 if (Opcode == 0xE0)
4972 {
4973 /* Additional rule for LOOPNZ */
4974 if (State->Flags.Zf) Condition = FALSE;
4975 }
4976
4977 if (Opcode == 0xE1)
4978 {
4979 /* Additional rule for LOOPZ */
4980 if (!State->Flags.Zf) Condition = FALSE;
4981 }
4982
4983 /* Fetch the offset */
4984 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
4985 {
4986 /* An exception occurred */
4987 return FALSE;
4988 }
4989
4990 if (Condition)
4991 {
4992 /* Move the instruction pointer */
4993 if (Size) State->InstPtr.Long += Offset;
4994 else State->InstPtr.LowWord += Offset;
4995 }
4996
4997 return TRUE;
4998 }
4999
5000 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz)
5001 {
5002 BOOLEAN Condition;
5003 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5004 CHAR Offset = 0;
5005
5006 /* Make sure this is the right instruction */
5007 ASSERT(Opcode == 0xE3);
5008
5009 NO_LOCK_PREFIX();
5010 TOGGLE_ADSIZE(Size);
5011
5012 if (Size) Condition = (State->GeneralRegs[FAST486_REG_ECX].Long == 0);
5013 else Condition = (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0);
5014
5015 /* Fetch the offset */
5016 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
5017 {
5018 /* An exception occurred */
5019 return FALSE;
5020 }
5021
5022 if (Condition)
5023 {
5024 /* Move the instruction pointer */
5025 if (Size) State->InstPtr.Long += Offset;
5026 else State->InstPtr.LowWord += Offset;
5027 }
5028
5029 return TRUE;
5030 }
5031
5032 FAST486_OPCODE_HANDLER(Fast486OpcodeCall)
5033 {
5034 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5035
5036 /* Make sure this is the right instruction */
5037 ASSERT(Opcode == 0xE8);
5038
5039 TOGGLE_OPSIZE(Size);
5040 NO_LOCK_PREFIX();
5041
5042 if (Size)
5043 {
5044 LONG Offset = 0;
5045
5046 /* Fetch the offset */
5047 if (!Fast486FetchDword(State, (PULONG)&Offset))
5048 {
5049 /* An exception occurred */
5050 return FALSE;
5051 }
5052
5053 /* Push the current value of the instruction pointer */
5054 if (!Fast486StackPush(State, State->InstPtr.Long))
5055 {
5056 /* Exception occurred */
5057 return FALSE;
5058 }
5059
5060 /* Move the instruction pointer */
5061 State->InstPtr.Long += Offset;
5062 }
5063 else
5064 {
5065 SHORT Offset = 0;
5066
5067 /* Fetch the offset */
5068 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5069 {
5070 /* An exception occurred */
5071 return FALSE;
5072 }
5073
5074 /* Push the current value of the instruction pointer */
5075 if (!Fast486StackPush(State, State->InstPtr.Long))
5076 {
5077 /* Exception occurred */
5078 return FALSE;
5079 }
5080
5081 /* Move the instruction pointer */
5082 State->InstPtr.LowWord += Offset;
5083 }
5084
5085 return TRUE;
5086 }
5087
5088 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp)
5089 {
5090 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5091
5092 /* Make sure this is the right instruction */
5093 ASSERT(Opcode == 0xE9);
5094
5095 TOGGLE_OPSIZE(Size);
5096 NO_LOCK_PREFIX();
5097
5098 if (Size)
5099 {
5100 LONG Offset = 0;
5101
5102 /* Fetch the offset */
5103 if (!Fast486FetchDword(State, (PULONG)&Offset))
5104 {
5105 /* An exception occurred */
5106 return FALSE;
5107 }
5108
5109 /* Move the instruction pointer */
5110 State->InstPtr.Long += Offset;
5111 }
5112 else
5113 {
5114 SHORT Offset = 0;
5115
5116 /* Fetch the offset */
5117 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5118 {
5119 /* An exception occurred */
5120 return FALSE;
5121 }
5122
5123 /* Move the instruction pointer */
5124 State->InstPtr.Long += Offset;
5125
5126 /* Clear the top half of EIP */
5127 State->InstPtr.Long &= 0xFFFF;
5128 }
5129
5130 return TRUE;
5131 }
5132
5133 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
5134 {
5135 USHORT Segment = 0;
5136 ULONG Offset = 0;
5137 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
5138
5139 /* Make sure this is the right instruction */
5140 ASSERT(Opcode == 0xEA);
5141
5142 TOGGLE_OPSIZE(Size);
5143 NO_LOCK_PREFIX();
5144
5145 /* Fetch the offset */
5146 if (Size)
5147 {
5148 if (!Fast486FetchDword(State, &Offset))
5149 {
5150 /* Exception occurred */
5151 return FALSE;
5152 }
5153 }
5154 else
5155 {
5156 if (!Fast486FetchWord(State, (PUSHORT)&Offset))
5157 {
5158 /* Exception occurred */
5159 return FALSE;
5160 }
5161 }
5162
5163 /* Fetch the segment */
5164 if (!Fast486FetchWord(State, &Segment))
5165 {
5166 /* Exception occurred */
5167 return FALSE;
5168 }
5169
5170 /* Load the new CS */
5171 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
5172 {
5173 /* Exception occurred */
5174 return FALSE;
5175 }
5176
5177 /* Load new EIP */
5178 State->InstPtr.Long = Offset;
5179
5180 return TRUE;
5181 }
5182
5183 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset)
5184 {
5185 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5186 ULONG Offset;
5187
5188 /* Make sure this is the right instruction */
5189 ASSERT(Opcode == 0xA0);
5190
5191 TOGGLE_ADSIZE(AddressSize);
5192
5193 if (AddressSize)
5194 {
5195 if (!Fast486FetchDword(State, &Offset))
5196 {
5197 /* Exception occurred */
5198 return FALSE;
5199 }
5200 }
5201 else
5202 {
5203 USHORT WordOffset;
5204
5205 if (!Fast486FetchWord(State, &WordOffset))
5206 {
5207 /* Exception occurred */
5208 return FALSE;
5209 }
5210
5211 Offset = (ULONG)WordOffset;
5212 }
5213
5214 /* Read from memory */
5215 return Fast486ReadMemory(State,
5216 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5217 State->SegmentOverride : FAST486_REG_DS,
5218 Offset,
5219 FALSE,
5220 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5221 sizeof(UCHAR));
5222 }
5223
5224 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset)
5225 {
5226 BOOLEAN OperandSize, AddressSize;
5227
5228 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5229
5230 /* Make sure this is the right instruction */
5231 ASSERT(Opcode == 0xA1);
5232
5233 TOGGLE_OPSIZE(OperandSize);
5234 TOGGLE_ADSIZE(AddressSize);
5235
5236 if (AddressSize)
5237 {
5238 ULONG Offset;
5239
5240 if (!Fast486FetchDword(State, &Offset))
5241 {
5242 /* Exception occurred */
5243 return FALSE;
5244 }
5245
5246 /* Read from memory */
5247 if (OperandSize)
5248 {
5249 return Fast486ReadMemory(State,
5250 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5251 State->SegmentOverride : FAST486_REG_DS,
5252 Offset,
5253 FALSE,
5254 &State->GeneralRegs[FAST486_REG_EAX].Long,
5255 sizeof(ULONG));
5256 }
5257 else
5258 {
5259 return Fast486ReadMemory(State,
5260 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5261 State->SegmentOverride : FAST486_REG_DS,
5262 Offset,
5263 FALSE,
5264 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5265 sizeof(USHORT));
5266 }
5267 }
5268 else
5269 {
5270 USHORT Offset;
5271
5272 if (!Fast486FetchWord(State, &Offset))
5273 {
5274 /* Exception occurred */
5275 return FALSE;
5276 }
5277
5278 /* Read from memory */
5279 if (OperandSize)
5280 {
5281 return Fast486ReadMemory(State,
5282 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5283 State->SegmentOverride : FAST486_REG_DS,
5284 Offset,
5285 FALSE,
5286 &State->GeneralRegs[FAST486_REG_EAX].Long,
5287 sizeof(ULONG));
5288 }
5289 else
5290 {
5291 return Fast486ReadMemory(State,
5292 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5293 State->SegmentOverride : FAST486_REG_DS,
5294 Offset,
5295 FALSE,
5296 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5297 sizeof(USHORT));
5298 }
5299 }
5300 }
5301
5302 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
5303 {
5304 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5305 ULONG Offset;
5306
5307 /* Make sure this is the right instruction */
5308 ASSERT(Opcode == 0xA2);
5309
5310 TOGGLE_ADSIZE(AddressSize);
5311
5312 if (AddressSize)
5313 {
5314 if (!Fast486FetchDword(State, &Offset))
5315 {
5316 /* Exception occurred */
5317 return FALSE;
5318 }
5319 }
5320 else
5321 {
5322 USHORT WordOffset;
5323
5324 if (!Fast486FetchWord(State, &WordOffset))
5325 {
5326 /* Exception occurred */
5327 return FALSE;
5328 }
5329
5330 Offset = (ULONG)WordOffset;
5331 }
5332
5333 /* Write to memory */
5334 return Fast486WriteMemory(State,
5335 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5336 State->SegmentOverride : FAST486_REG_DS,
5337 Offset,
5338 &State->GeneralRegs[FAST486_REG_EAX].LowByte,
5339 sizeof(UCHAR));
5340 }
5341
5342 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
5343 {
5344 BOOLEAN OperandSize, AddressSize;
5345
5346 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5347
5348 /* Make sure this is the right instruction */
5349 ASSERT(Opcode == 0xA3);
5350
5351 TOGGLE_OPSIZE(OperandSize);
5352 TOGGLE_ADSIZE(AddressSize);
5353
5354 if (AddressSize)
5355 {
5356 ULONG Offset;
5357
5358 if (!Fast486FetchDword(State, &Offset))
5359 {
5360 /* Exception occurred */
5361 return FALSE;
5362 }
5363
5364 /* Write to memory */
5365 if (OperandSize)
5366 {
5367 return Fast486WriteMemory(State,
5368 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5369 State->SegmentOverride : FAST486_REG_DS,
5370 Offset,
5371 &State->GeneralRegs[FAST486_REG_EAX].Long,
5372 sizeof(ULONG));
5373 }
5374 else
5375 {
5376 return Fast486WriteMemory(State,
5377 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5378 State->SegmentOverride : FAST486_REG_DS,
5379 Offset,
5380 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5381 sizeof(USHORT));
5382 }
5383 }
5384 else
5385 {
5386 USHORT Offset;
5387
5388 if (!Fast486FetchWord(State, &Offset))
5389 {
5390 /* Exception occurred */
5391 return FALSE;
5392 }
5393
5394 /* Write to memory */
5395 if (OperandSize)
5396 {
5397 return Fast486WriteMemory(State,
5398 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5399 State->SegmentOverride : FAST486_REG_DS,
5400 Offset,
5401 &State->GeneralRegs[FAST486_REG_EAX].Long,
5402 sizeof(ULONG));
5403 }
5404 else
5405 {
5406 return Fast486WriteMemory(State,
5407 (State->PrefixFlags & FAST486_PREFIX_SEG) ?
5408 State->SegmentOverride : FAST486_REG_DS,
5409 Offset,
5410 &State->GeneralRegs[FAST486_REG_EAX].LowWord,
5411 sizeof(USHORT));
5412 }
5413 }
5414 }
5415
5416 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc)
5417 {
5418 /* Make sure this is the right instruction */
5419 ASSERT(Opcode == 0xD6);
5420
5421 NO_LOCK_PREFIX();
5422
5423 /* Set all the bits of AL to CF */
5424 State->GeneralRegs[FAST486_REG_EAX].LowByte = State->Flags.Cf ? 0xFF : 0x00;
5425
5426 return TRUE;
5427 }
5428
5429 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs)
5430 {
5431 ULONG Data, DataSize;
5432 BOOLEAN OperandSize, AddressSize;
5433 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5434
5435 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5436
5437 /* Make sure this is the right instruction */
5438 ASSERT((Opcode & 0xFE) == 0xA4);
5439
5440 TOGGLE_OPSIZE(OperandSize);
5441 TOGGLE_ADSIZE(AddressSize);
5442
5443 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5444 {
5445 /* Use the override segment instead of DS */
5446 Segment = State->SegmentOverride;
5447 }
5448
5449 /* Calculate the size */
5450 if (Opcode == 0xA4) DataSize = sizeof(UCHAR);
5451 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5452
5453 if (State->PrefixFlags & FAST486_PREFIX_REP)
5454 {
5455 UCHAR Block[STRING_BLOCK_SIZE];
5456 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5457 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5458
5459 /* Clear the memory block */
5460 RtlZeroMemory(Block, sizeof(Block));
5461
5462 /* Transfer until finished */
5463 while (Count)
5464 {
5465 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5466
5467 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5468 if (!AddressSize)
5469 {
5470 ULONG MaxBytesSrc = State->Flags.Df
5471 ? (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord
5472 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_ESI].LowWord);
5473 ULONG MaxBytesDest = State->Flags.Df
5474 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5475 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5476
5477
5478 Processed = min(Processed, min(MaxBytesSrc, MaxBytesDest) / DataSize);
5479 if (Processed == 0) Processed = 1;
5480 }
5481
5482 if (State->Flags.Df)
5483 {
5484 /* Reduce ESI and EDI by the number of bytes to transfer */
5485 if (AddressSize)
5486 {
5487 State->GeneralRegs[FAST486_REG_ESI].Long -= Processed * DataSize;
5488 State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
5489 }
5490 else
5491 {
5492 State->GeneralRegs[FAST486_REG_ESI].LowWord -= Processed * DataSize;
5493 State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
5494 }
5495 }
5496
5497 /* Read from memory */
5498 if (!Fast486ReadMemory(State,
5499 Segment,
5500 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5501 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5502 FALSE,
5503 Block,
5504 Processed * DataSize))
5505 {
5506 /* Set ECX */
5507 if (AddressSize) 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 /* Write to memory */
5515 if (!Fast486WriteMemory(State,
5516 FAST486_REG_ES,
5517 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5518 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5519 Block,
5520 Processed * DataSize))
5521 {
5522 /* Set ECX */
5523 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5524 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5525
5526 /* Exception occurred */
5527 return FALSE;
5528 }
5529
5530 if (!State->Flags.Df)
5531 {
5532 /* Increase ESI and EDI by the number of bytes transfered */
5533 if (AddressSize)
5534 {
5535 State->GeneralRegs[FAST486_REG_ESI].Long += Processed * DataSize;
5536 State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5537 }
5538 else
5539 {
5540 State->GeneralRegs[FAST486_REG_ESI].LowWord += Processed * DataSize;
5541 State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5542 }
5543 }
5544
5545 /* Reduce the total count by the number processed in this run */
5546 Count -= Processed;
5547 }
5548
5549 /* Clear ECX */
5550 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5551 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5552 }
5553 else
5554 {
5555 /* Read from the source operand */
5556 if (!Fast486ReadMemory(State,
5557 FAST486_REG_DS,
5558 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5559 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5560 FALSE,
5561 &Data,
5562 DataSize))
5563 {
5564 /* Exception occurred */
5565 return FALSE;
5566 }
5567
5568 /* Write to the destination operand */
5569 if (!Fast486WriteMemory(State,
5570 FAST486_REG_ES,
5571 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5572 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5573 &Data,
5574 DataSize))
5575 {
5576 /* Exception occurred */
5577 return FALSE;
5578 }
5579
5580 /* Increment/decrement ESI and EDI */
5581 if (AddressSize)
5582 {
5583 if (!State->Flags.Df)
5584 {
5585 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5586 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5587 }
5588 else
5589 {
5590 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5591 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5592 }
5593 }
5594 else
5595 {
5596 if (!State->Flags.Df)
5597 {
5598 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5599 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5600 }
5601 else
5602 {
5603 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5604 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5605 }
5606 }
5607 }
5608
5609 /* Return success */
5610 return TRUE;
5611 }
5612
5613 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps)
5614 {
5615 ULONG FirstValue = 0, SecondValue = 0, Result;
5616 ULONG DataSize, DataMask, SignFlag;
5617 BOOLEAN OperandSize, AddressSize;
5618 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5619
5620 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5621
5622 /* Make sure this is the right instruction */
5623 ASSERT((Opcode & 0xFE) == 0xA6);
5624
5625 TOGGLE_OPSIZE(OperandSize);
5626 TOGGLE_ADSIZE(AddressSize);
5627
5628 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5629 {
5630 /* Use the override segment instead of DS */
5631 Segment = State->SegmentOverride;
5632 }
5633
5634 /* Calculate the size */
5635 if (Opcode == 0xA6) DataSize = sizeof(UCHAR);
5636 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5637
5638 /* Calculate the mask and sign flag */
5639 SignFlag = 1 << ((DataSize * 8) - 1);
5640 DataMask = SignFlag | (SignFlag - 1);
5641
5642 /* Read from the first source operand */
5643 if (!Fast486ReadMemory(State,
5644 Segment,
5645 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5646 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5647 FALSE,
5648 &FirstValue,
5649 DataSize))
5650 {
5651 /* Exception occurred */
5652 return FALSE;
5653 }
5654
5655 /* Read from the second source operand */
5656 if (!Fast486ReadMemory(State,
5657 FAST486_REG_ES,
5658 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5659 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5660 FALSE,
5661 &SecondValue,
5662 DataSize))
5663 {
5664 /* Exception occurred */
5665 return FALSE;
5666 }
5667
5668 /* Calculate the result */
5669 FirstValue &= DataMask;
5670 SecondValue &= DataMask;
5671 Result = (FirstValue - SecondValue) & DataMask;
5672
5673 /* Update the flags */
5674 State->Flags.Cf = (FirstValue < SecondValue);
5675 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
5676 && ((FirstValue & SignFlag) != (Result & SignFlag));
5677 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
5678 State->Flags.Zf = (Result == 0);
5679 State->Flags.Sf = ((Result & SignFlag) != 0);
5680 State->Flags.Pf = Fast486CalculateParity(Result);
5681
5682 /* Increment/decrement ESI and EDI */
5683 if (AddressSize)
5684 {
5685 if (!State->Flags.Df)
5686 {
5687 State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5688 State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5689 }
5690 else
5691 {
5692 State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5693 State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5694 }
5695 }
5696 else
5697 {
5698 if (!State->Flags.Df)
5699 {
5700 State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5701 State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5702 }
5703 else
5704 {
5705 State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5706 State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5707 }
5708 }
5709
5710 // FIXME: This method is slow!
5711 if ((State->PrefixFlags & FAST486_PREFIX_REP)
5712 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
5713 {
5714 BOOLEAN Repeat = TRUE;
5715
5716 if (AddressSize)
5717 {
5718 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
5719 {
5720 /* ECX is 0 */
5721 Repeat = FALSE;
5722 }
5723 }
5724 else
5725 {
5726 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
5727 {
5728 /* CX is 0 */
5729 Repeat = FALSE;
5730 }
5731 }
5732
5733 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
5734 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
5735 {
5736 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5737 Repeat = FALSE;
5738 }
5739
5740 if (Repeat)
5741 {
5742 /* Repeat the instruction */
5743 State->InstPtr = State->SavedInstPtr;
5744 }
5745 }
5746
5747 /* Return success */
5748 return TRUE;
5749 }
5750
5751 FAST486_OPCODE_HANDLER(Fast486OpcodeStos)
5752 {
5753 ULONG DataSize;
5754 BOOLEAN OperandSize, AddressSize;
5755
5756 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5757
5758 /* Make sure this is the right instruction */
5759 ASSERT((Opcode & 0xFE) == 0xAA);
5760
5761 TOGGLE_OPSIZE(OperandSize);
5762 TOGGLE_ADSIZE(AddressSize);
5763
5764 /* Calculate the size */
5765 if (Opcode == 0xAA) DataSize = sizeof(UCHAR);
5766 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5767
5768 if (State->PrefixFlags & FAST486_PREFIX_REP)
5769 {
5770 UCHAR Block[STRING_BLOCK_SIZE];
5771 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5772 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5773
5774 /* Fill the memory block with the data */
5775 if (DataSize == sizeof(UCHAR))
5776 {
5777 RtlFillMemory(Block, sizeof(Block), State->GeneralRegs[FAST486_REG_EAX].LowByte);
5778 }
5779 else
5780 {
5781 ULONG i;
5782
5783 for (i = 0; i < STRING_BLOCK_SIZE / DataSize; i++)
5784 {
5785 if (DataSize == sizeof(USHORT))
5786 {
5787 ((PUSHORT)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].LowWord;
5788 }
5789 else
5790 {
5791 ((PULONG)Block)[i] = State->GeneralRegs[FAST486_REG_EAX].Long;
5792 }
5793 }
5794 }
5795
5796 /* Transfer until finished */
5797 while (Count)
5798 {
5799 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
5800
5801 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5802 if (!AddressSize)
5803 {
5804 ULONG MaxBytes = State->Flags.Df
5805 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
5806 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
5807
5808 Processed = min(Processed, MaxBytes / DataSize);
5809 if (Processed == 0) Processed = 1;
5810 }
5811
5812 if (State->Flags.Df)
5813 {
5814 /* Reduce EDI by the number of bytes to transfer */
5815 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
5816 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
5817 }
5818
5819 /* Write to memory */
5820 if (!Fast486WriteMemory(State,
5821 FAST486_REG_ES,
5822 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5823 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5824 Block,
5825 Processed * DataSize))
5826 {
5827 /* Set ECX */
5828 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
5829 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
5830
5831 /* Exception occurred */
5832 return FALSE;
5833 }
5834
5835 if (!State->Flags.Df)
5836 {
5837 /* Increase EDI by the number of bytes transfered */
5838 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
5839 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
5840 }
5841
5842 /* Reduce the total count by the number processed in this run */
5843 Count -= Processed;
5844 }
5845
5846 /* Clear ECX */
5847 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5848 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5849 }
5850 else
5851 {
5852 /* Write to the destination operand */
5853 if (!Fast486WriteMemory(State,
5854 FAST486_REG_ES,
5855 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5856 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5857 &State->GeneralRegs[FAST486_REG_EAX].Long,
5858 DataSize))
5859 {
5860 /* Exception occurred */
5861 return FALSE;
5862 }
5863
5864 /* Increment/decrement EDI */
5865 if (AddressSize)
5866 {
5867 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
5868 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
5869 }
5870 else
5871 {
5872 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
5873 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
5874 }
5875 }
5876
5877 /* Return success */
5878 return TRUE;
5879 }
5880
5881 FAST486_OPCODE_HANDLER(Fast486OpcodeLods)
5882 {
5883 ULONG DataSize;
5884 BOOLEAN OperandSize, AddressSize;
5885 FAST486_SEG_REGS Segment = FAST486_REG_DS;
5886
5887 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5888
5889 /* Make sure this is the right instruction */
5890 ASSERT((Opcode & 0xFE) == 0xAC);
5891
5892 TOGGLE_OPSIZE(OperandSize);
5893 TOGGLE_ADSIZE(AddressSize);
5894
5895 if (State->PrefixFlags & FAST486_PREFIX_SEG)
5896 {
5897 /* Use the override segment instead of DS */
5898 Segment = State->SegmentOverride;
5899 }
5900
5901 /* Calculate the size */
5902 if (Opcode == 0xAC) DataSize = sizeof(UCHAR);
5903 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5904
5905 if (State->PrefixFlags & FAST486_PREFIX_REP)
5906 {
5907 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
5908 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
5909
5910 /* If the count is 0, do nothing */
5911 if (Count == 0) return TRUE;
5912
5913 /* Only the last entry will be loaded */
5914 if (!State->Flags.Df)
5915 {
5916 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long += (Count - 1) * DataSize;
5917 else State->GeneralRegs[FAST486_REG_ESI].LowWord += (Count - 1) * DataSize;
5918 }
5919 else
5920 {
5921 if (AddressSize) State->GeneralRegs[FAST486_REG_ESI].Long -= (Count - 1) * DataSize;
5922 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= (Count - 1) * DataSize;
5923 }
5924
5925 /* Clear ECX */
5926 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
5927 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
5928 }
5929
5930 /* Read from the source operand */
5931 if (!Fast486ReadMemory(State,
5932 Segment,
5933 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
5934 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
5935 FALSE,
5936 &State->GeneralRegs[FAST486_REG_EAX].Long,
5937 DataSize))
5938 {
5939 /* Exception occurred */
5940 return FALSE;
5941 }
5942
5943 /* Increment/decrement ESI */
5944 if (AddressSize)
5945 {
5946 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
5947 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
5948 }
5949 else
5950 {
5951 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
5952 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
5953 }
5954
5955 /* Return success */
5956 return TRUE;
5957 }
5958
5959 FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
5960 {
5961 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
5962 ULONG SecondValue = 0;
5963 ULONG Result;
5964 ULONG DataSize, DataMask, SignFlag;
5965 BOOLEAN OperandSize, AddressSize;
5966
5967 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
5968
5969 /* Make sure this is the right instruction */
5970 ASSERT((Opcode & 0xFE) == 0xAE);
5971
5972 TOGGLE_OPSIZE(OperandSize);
5973 TOGGLE_ADSIZE(AddressSize);
5974
5975 /* Calculate the size */
5976 if (Opcode == 0xAE) DataSize = sizeof(UCHAR);
5977 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
5978
5979 /* Calculate the mask and sign flag */
5980 SignFlag = 1 << ((DataSize * 8) - 1);
5981 DataMask = SignFlag | (SignFlag - 1);
5982
5983 /* Read from the source operand */
5984 if (!Fast486ReadMemory(State,
5985 FAST486_REG_ES,
5986 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
5987 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
5988 FALSE,
5989 &SecondValue,
5990 DataSize))
5991 {
5992 /* Exception occurred */
5993 return FALSE;
5994 }
5995
5996 /* Calculate the result */
5997 FirstValue &= DataMask;
5998 SecondValue &= DataMask;
5999 Result = (FirstValue - SecondValue) & DataMask;
6000
6001 /* Update the flags */
6002 State->Flags.Cf = (FirstValue < SecondValue);
6003 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
6004 && ((FirstValue & SignFlag) != (Result & SignFlag));
6005 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
6006 State->Flags.Zf = (Result == 0);
6007 State->Flags.Sf = ((Result & SignFlag) != 0);
6008 State->Flags.Pf = Fast486CalculateParity(Result);
6009
6010 /* Increment/decrement EDI */
6011 if (AddressSize)
6012 {
6013 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6014 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6015 }
6016 else
6017 {
6018 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6019 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6020 }
6021
6022 // FIXME: This method is slow!
6023 if ((State->PrefixFlags & FAST486_PREFIX_REP)
6024 || (State->PrefixFlags & FAST486_PREFIX_REPNZ))
6025 {
6026 BOOLEAN Repeat = TRUE;
6027
6028 if (AddressSize)
6029 {
6030 if ((--State->GeneralRegs[FAST486_REG_ECX].Long) == 0)
6031 {
6032 /* ECX is 0 */
6033 Repeat = FALSE;
6034 }
6035 }
6036 else
6037 {
6038 if ((--State->GeneralRegs[FAST486_REG_ECX].LowWord) == 0)
6039 {
6040 /* CX is 0 */
6041 Repeat = FALSE;
6042 }
6043 }
6044
6045 if (((State->PrefixFlags & FAST486_PREFIX_REP) && !State->Flags.Zf)
6046 || ((State->PrefixFlags & FAST486_PREFIX_REPNZ) && State->Flags.Zf))
6047 {
6048 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6049 Repeat = FALSE;
6050 }
6051
6052 if (Repeat)
6053 {
6054 /* Repeat the instruction */
6055 State->InstPtr = State->SavedInstPtr;
6056 }
6057 }
6058
6059 /* Return success */
6060 return TRUE;
6061 }
6062
6063 FAST486_OPCODE_HANDLER(Fast486OpcodeIns)
6064 {
6065 ULONG DataSize;
6066 BOOLEAN OperandSize, AddressSize;
6067
6068 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6069
6070 /* Make sure this is the right instruction */
6071 ASSERT((Opcode & 0xFE) == 0x6C);
6072
6073 TOGGLE_OPSIZE(OperandSize);
6074 TOGGLE_ADSIZE(AddressSize);
6075
6076 /* Calculate the size */
6077 if (Opcode == 0x6C) DataSize = sizeof(UCHAR);
6078 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6079
6080 if (State->PrefixFlags & FAST486_PREFIX_REP)
6081 {
6082 UCHAR Block[STRING_BLOCK_SIZE];
6083 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6084 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6085
6086 /* Clear the memory block */
6087 RtlZeroMemory(Block, sizeof(Block));
6088
6089 /* Transfer until finished */
6090 while (Count)
6091 {
6092 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6093
6094 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6095 if (!AddressSize)
6096 {
6097 ULONG MaxBytes = State->Flags.Df
6098 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6099 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6100
6101 Processed = min(Processed, MaxBytes / DataSize);
6102 if (Processed == 0) Processed = 1;
6103 }
6104
6105 /* Read from the I/O port */
6106 State->IoReadCallback(State,
6107 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6108 Block,
6109 Processed,
6110 DataSize);
6111
6112 if (State->Flags.Df)
6113 {
6114 ULONG i, j;
6115
6116 /* Reduce EDI by the number of bytes to transfer */
6117 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6118 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6119
6120 /* Reverse the block data */
6121 for (i = 0; i < Processed / 2; i++)
6122 {
6123 /* Swap the values */
6124 for (j = 0; j < DataSize; j++)
6125 {
6126 UCHAR Temp = Block[i * DataSize + j];
6127 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6128 Block[(Processed - i - 1) * DataSize + j] = Temp;
6129 }
6130 }
6131 }
6132
6133 /* Write to memory */
6134 if (!Fast486WriteMemory(State,
6135 FAST486_REG_ES,
6136 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6137 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6138 Block,
6139 Processed * DataSize))
6140 {
6141 /* Set ECX */
6142 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6143 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6144
6145 /* Exception occurred */
6146 return FALSE;
6147 }
6148
6149 if (!State->Flags.Df)
6150 {
6151 /* Increase EDI by the number of bytes transfered */
6152 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6153 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6154 }
6155
6156 /* Reduce the total count by the number processed in this run */
6157 Count -= Processed;
6158 }
6159
6160 /* Clear ECX */
6161 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6162 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6163 }
6164 else
6165 {
6166 ULONG Data = 0;
6167
6168 /* Read from the I/O port */
6169 State->IoReadCallback(State,
6170 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6171 &Data,
6172 1,
6173 DataSize);
6174
6175 /* Write to the destination operand */
6176 if (!Fast486WriteMemory(State,
6177 FAST486_REG_ES,
6178 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6179 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6180 &Data,
6181 DataSize))
6182 {
6183 /* Exception occurred */
6184 return FALSE;
6185 }
6186
6187 /* Increment/decrement EDI */
6188 if (AddressSize)
6189 {
6190 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].Long += DataSize;
6191 else State->GeneralRegs[FAST486_REG_EDI].Long -= DataSize;
6192 }
6193 else
6194 {
6195 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_EDI].LowWord += DataSize;
6196 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= DataSize;
6197 }
6198 }
6199
6200 /* Return success */
6201 return TRUE;
6202 }
6203
6204 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts)
6205 {
6206 ULONG DataSize;
6207 BOOLEAN OperandSize, AddressSize;
6208
6209 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
6210
6211 /* Make sure this is the right instruction */
6212 ASSERT((Opcode & 0xFE) == 0x6E);
6213
6214 TOGGLE_OPSIZE(OperandSize);
6215 TOGGLE_ADSIZE(AddressSize);
6216
6217 /* Calculate the size */
6218 if (Opcode == 0x6E) DataSize = sizeof(UCHAR);
6219 else DataSize = OperandSize ? sizeof(ULONG) : sizeof(USHORT);
6220
6221 if (State->PrefixFlags & FAST486_PREFIX_REP)
6222 {
6223 UCHAR Block[STRING_BLOCK_SIZE];
6224 ULONG Count = AddressSize ? State->GeneralRegs[FAST486_REG_ECX].Long
6225 : State->GeneralRegs[FAST486_REG_ECX].LowWord;
6226
6227 /* Clear the memory block */
6228 RtlZeroMemory(Block, sizeof(Block));
6229
6230 /* Transfer until finished */
6231 while (Count)
6232 {
6233 ULONG Processed = min(Count, STRING_BLOCK_SIZE / DataSize);
6234
6235 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6236 if (!AddressSize)
6237 {
6238 ULONG MaxBytes = State->Flags.Df
6239 ? (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord
6240 : (0x10000 - (ULONG)State->GeneralRegs[FAST486_REG_EDI].LowWord);
6241
6242 Processed = min(Processed, MaxBytes / DataSize);
6243 if (Processed == 0) Processed = 1;
6244 }
6245
6246 /* Read from memory */
6247 if (!Fast486ReadMemory(State,
6248 FAST486_REG_ES,
6249 AddressSize ? State->GeneralRegs[FAST486_REG_EDI].Long
6250 : State->GeneralRegs[FAST486_REG_EDI].LowWord,
6251 FALSE,
6252 Block,
6253 Processed * DataSize))
6254 {
6255 /* Set ECX */
6256 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = Count;
6257 else State->GeneralRegs[FAST486_REG_ECX].LowWord = LOWORD(Count);
6258
6259 /* Exception occurred */
6260 return FALSE;
6261 }
6262
6263 if (State->Flags.Df)
6264 {
6265 ULONG i, j;
6266
6267 /* Reduce EDI by the number of bytes to transfer */
6268 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long -= Processed * DataSize;
6269 else State->GeneralRegs[FAST486_REG_EDI].LowWord -= Processed * DataSize;
6270
6271 /* Reverse the block data */
6272 for (i = 0; i < Processed / 2; i++)
6273 {
6274 /* Swap the values */
6275 for (j = 0; j < DataSize; j++)
6276 {
6277 UCHAR Temp = Block[i * DataSize + j];
6278 Block[i * DataSize + j] = Block[(Processed - i - 1) * DataSize + j];
6279 Block[(Processed - i - 1) * DataSize + j] = Temp;
6280 }
6281 }
6282 }
6283
6284 /* Write to the I/O port */
6285 State->IoWriteCallback(State,
6286 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6287 Block,
6288 Processed,
6289 DataSize);
6290
6291 if (!State->Flags.Df)
6292 {
6293 /* Increase EDI by the number of bytes transfered */
6294 if (AddressSize) State->GeneralRegs[FAST486_REG_EDI].Long += Processed * DataSize;
6295 else State->GeneralRegs[FAST486_REG_EDI].LowWord += Processed * DataSize;
6296 }
6297
6298 /* Reduce the total count by the number processed in this run */
6299 Count -= Processed;
6300 }
6301
6302 /* Clear ECX */
6303 if (AddressSize) State->GeneralRegs[FAST486_REG_ECX].Long = 0;
6304 else State->GeneralRegs[FAST486_REG_ECX].LowWord = 0;
6305 }
6306 else
6307 {
6308 ULONG Data = 0;
6309
6310 /* Read from the source operand */
6311 if (!Fast486ReadMemory(State,
6312 FAST486_REG_DS,
6313 AddressSize ? State->GeneralRegs[FAST486_REG_ESI].Long
6314 : State->GeneralRegs[FAST486_REG_ESI].LowWord,
6315 FALSE,
6316 &Data,
6317 DataSize))
6318 {
6319 /* Exception occurred */
6320 return FALSE;
6321 }
6322
6323 /* Write to the I/O port */
6324 State->IoWriteCallback(State,
6325 State->GeneralRegs[FAST486_REG_EDX].LowWord,
6326 &Data,
6327 1,
6328 DataSize);
6329
6330 /* Increment/decrement ESI */
6331 if (AddressSize)
6332 {
6333 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].Long += DataSize;
6334 else State->GeneralRegs[FAST486_REG_ESI].Long -= DataSize;
6335 }
6336 else
6337 {
6338 if (!State->Flags.Df) State->GeneralRegs[FAST486_REG_ESI].LowWord += DataSize;
6339 else State->GeneralRegs[FAST486_REG_ESI].LowWord -= DataSize;
6340 }
6341 }
6342
6343 /* Return success */
6344 return TRUE;
6345 }