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