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