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