xref: /reactos/sdk/lib/fast486/extraops.c (revision c2c66aff)
1 /*
2  * Fast486 386/486 CPU Emulation Library
3  * extraops.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 "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34 
35 /* PUBLIC VARIABLES ***********************************************************/
36 
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
40     Fast486ExtOpcodeGroup0F00,          /* 0x00 - 0x01 */
41     Fast486ExtOpcodeGroup0F01,
42     Fast486ExtOpcodeLar,                /* 0x02 */
43     Fast486ExtOpcodeLsl,                /* 0x03 */
44     Fast486ExtOpcodeInvalid,            /* 0x04 - 0x05 */   // Invalid
45     Fast486ExtOpcodeInvalid,                                // Invalid
46     Fast486ExtOpcodeClts,               /* 0x06 */
47     Fast486ExtOpcodeInvalid,            /* 0x07 */          // Invalid
48     Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49     Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50     Fast486ExtOpcodeInvalid,            /* 0x0A */          // Invalid
51     Fast486ExtOpcode0F0B,               /* 0x0B */          // Reserved (UD2)
52     Fast486ExtOpcodeInvalid,            /* 0x0C - 0x1F */   // Invalid
53     Fast486ExtOpcodeInvalid,                                // Invalid
54     Fast486ExtOpcodeInvalid,                                // Invalid
55     Fast486ExtOpcodeInvalid,                                // Invalid
56     Fast486ExtOpcodeInvalid,                                // Invalid
57     Fast486ExtOpcodeInvalid,                                // Invalid
58     Fast486ExtOpcodeInvalid,                                // Invalid
59     Fast486ExtOpcodeInvalid,                                // Invalid
60     Fast486ExtOpcodeInvalid,                                // Invalid
61     Fast486ExtOpcodeInvalid,                                // Invalid
62     Fast486ExtOpcodeInvalid,                                // Invalid
63     Fast486ExtOpcodeInvalid,                                // Invalid
64     Fast486ExtOpcodeInvalid,                                // Invalid
65     Fast486ExtOpcodeInvalid,                                // Invalid
66     Fast486ExtOpcodeInvalid,                                // Invalid
67     Fast486ExtOpcodeInvalid,                                // Invalid
68     Fast486ExtOpcodeInvalid,                                // Invalid
69     Fast486ExtOpcodeInvalid,                                // Invalid
70     Fast486ExtOpcodeInvalid,                                // Invalid
71     Fast486ExtOpcodeInvalid,                                // Invalid
72     Fast486ExtOpcodeStoreControlReg,    /* 0x20 */
73     Fast486ExtOpcodeStoreDebugReg,      /* 0x21 */
74     Fast486ExtOpcodeLoadControlReg,     /* 0x22 */
75     Fast486ExtOpcodeLoadDebugReg,       /* 0x23 */
76     Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77     Fast486ExtOpcodeInvalid,            /* 0x25 */          // Invalid
78     Fast486ExtOpcodeUnimplemented, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79     Fast486ExtOpcodeInvalid,            /* 0x27 - 0x7F */   // Invalid
80     Fast486ExtOpcodeInvalid,                                // Invalid
81     Fast486ExtOpcodeInvalid,                                // Invalid
82     Fast486ExtOpcodeInvalid,                                // Invalid
83     Fast486ExtOpcodeInvalid,                                // Invalid
84     Fast486ExtOpcodeInvalid,                                // Invalid
85     Fast486ExtOpcodeInvalid,                                // Invalid
86     Fast486ExtOpcodeInvalid,                                // Invalid
87     Fast486ExtOpcodeInvalid,                                // Invalid
88     Fast486ExtOpcodeInvalid,                                // Invalid
89     Fast486ExtOpcodeInvalid,                                // Invalid
90     Fast486ExtOpcodeInvalid,                                // Invalid
91     Fast486ExtOpcodeInvalid,                                // Invalid
92     Fast486ExtOpcodeInvalid,                                // Invalid
93     Fast486ExtOpcodeInvalid,                                // Invalid
94     Fast486ExtOpcodeInvalid,                                // Invalid
95     Fast486ExtOpcodeInvalid,                                // Invalid
96     Fast486ExtOpcodeInvalid,                                // Invalid
97     Fast486ExtOpcodeInvalid,                                // Invalid
98     Fast486ExtOpcodeInvalid,                                // Invalid
99     Fast486ExtOpcodeInvalid,                                // Invalid
100     Fast486ExtOpcodeInvalid,                                // Invalid
101     Fast486ExtOpcodeInvalid,                                // Invalid
102     Fast486ExtOpcodeInvalid,                                // Invalid
103     Fast486ExtOpcodeInvalid,                                // Invalid
104     Fast486ExtOpcodeInvalid,                                // Invalid
105     Fast486ExtOpcodeInvalid,                                // Invalid
106     Fast486ExtOpcodeInvalid,                                // Invalid
107     Fast486ExtOpcodeInvalid,                                // Invalid
108     Fast486ExtOpcodeInvalid,                                // Invalid
109     Fast486ExtOpcodeInvalid,                                // Invalid
110     Fast486ExtOpcodeInvalid,                                // Invalid
111     Fast486ExtOpcodeInvalid,                                // Invalid
112     Fast486ExtOpcodeInvalid,                                // Invalid
113     Fast486ExtOpcodeInvalid,                                // Invalid
114     Fast486ExtOpcodeInvalid,                                // Invalid
115     Fast486ExtOpcodeInvalid,                                // Invalid
116     Fast486ExtOpcodeInvalid,                                // Invalid
117     Fast486ExtOpcodeInvalid,                                // Invalid
118     Fast486ExtOpcodeInvalid,                                // Invalid
119     Fast486ExtOpcodeInvalid,                                // Invalid
120     Fast486ExtOpcodeInvalid,                                // Invalid
121     Fast486ExtOpcodeInvalid,                                // Invalid
122     Fast486ExtOpcodeInvalid,                                // Invalid
123     Fast486ExtOpcodeInvalid,                                // Invalid
124     Fast486ExtOpcodeInvalid,                                // Invalid
125     Fast486ExtOpcodeInvalid,                                // Invalid
126     Fast486ExtOpcodeInvalid,                                // Invalid
127     Fast486ExtOpcodeInvalid,                                // Invalid
128     Fast486ExtOpcodeInvalid,                                // Invalid
129     Fast486ExtOpcodeInvalid,                                // Invalid
130     Fast486ExtOpcodeInvalid,                                // Invalid
131     Fast486ExtOpcodeInvalid,                                // Invalid
132     Fast486ExtOpcodeInvalid,                                // Invalid
133     Fast486ExtOpcodeInvalid,                                // Invalid
134     Fast486ExtOpcodeInvalid,                                // Invalid
135     Fast486ExtOpcodeInvalid,                                // Invalid
136     Fast486ExtOpcodeInvalid,                                // Invalid
137     Fast486ExtOpcodeInvalid,                                // Invalid
138     Fast486ExtOpcodeInvalid,                                // Invalid
139     Fast486ExtOpcodeInvalid,                                // Invalid
140     Fast486ExtOpcodeInvalid,                                // Invalid
141     Fast486ExtOpcodeInvalid,                                // Invalid
142     Fast486ExtOpcodeInvalid,                                // Invalid
143     Fast486ExtOpcodeInvalid,                                // Invalid
144     Fast486ExtOpcodeInvalid,                                // Invalid
145     Fast486ExtOpcodeInvalid,                                // Invalid
146     Fast486ExtOpcodeInvalid,                                // Invalid
147     Fast486ExtOpcodeInvalid,                                // Invalid
148     Fast486ExtOpcodeInvalid,                                // Invalid
149     Fast486ExtOpcodeInvalid,                                // Invalid
150     Fast486ExtOpcodeInvalid,                                // Invalid
151     Fast486ExtOpcodeInvalid,                                // Invalid
152     Fast486ExtOpcodeInvalid,                                // Invalid
153     Fast486ExtOpcodeInvalid,                                // Invalid
154     Fast486ExtOpcodeInvalid,                                // Invalid
155     Fast486ExtOpcodeInvalid,                                // Invalid
156     Fast486ExtOpcodeInvalid,                                // Invalid
157     Fast486ExtOpcodeInvalid,                                // Invalid
158     Fast486ExtOpcodeInvalid,                                // Invalid
159     Fast486ExtOpcodeInvalid,                                // Invalid
160     Fast486ExtOpcodeInvalid,                                // Invalid
161     Fast486ExtOpcodeInvalid,                                // Invalid
162     Fast486ExtOpcodeInvalid,                                // Invalid
163     Fast486ExtOpcodeInvalid,                                // Invalid
164     Fast486ExtOpcodeInvalid,                                // Invalid
165     Fast486ExtOpcodeInvalid,                                // Invalid
166     Fast486ExtOpcodeInvalid,                                // Invalid
167     Fast486ExtOpcodeInvalid,                                // Invalid
168     Fast486ExtOpcodeConditionalJmp,     /* 0x80 - 0x8F */
169     Fast486ExtOpcodeConditionalJmp,
170     Fast486ExtOpcodeConditionalJmp,
171     Fast486ExtOpcodeConditionalJmp,
172     Fast486ExtOpcodeConditionalJmp,
173     Fast486ExtOpcodeConditionalJmp,
174     Fast486ExtOpcodeConditionalJmp,
175     Fast486ExtOpcodeConditionalJmp,
176     Fast486ExtOpcodeConditionalJmp,
177     Fast486ExtOpcodeConditionalJmp,
178     Fast486ExtOpcodeConditionalJmp,
179     Fast486ExtOpcodeConditionalJmp,
180     Fast486ExtOpcodeConditionalJmp,
181     Fast486ExtOpcodeConditionalJmp,
182     Fast486ExtOpcodeConditionalJmp,
183     Fast486ExtOpcodeConditionalJmp,
184     Fast486ExtOpcodeConditionalSet,     /* 0x90 - 0x9F */
185     Fast486ExtOpcodeConditionalSet,
186     Fast486ExtOpcodeConditionalSet,
187     Fast486ExtOpcodeConditionalSet,
188     Fast486ExtOpcodeConditionalSet,
189     Fast486ExtOpcodeConditionalSet,
190     Fast486ExtOpcodeConditionalSet,
191     Fast486ExtOpcodeConditionalSet,
192     Fast486ExtOpcodeConditionalSet,
193     Fast486ExtOpcodeConditionalSet,
194     Fast486ExtOpcodeConditionalSet,
195     Fast486ExtOpcodeConditionalSet,
196     Fast486ExtOpcodeConditionalSet,
197     Fast486ExtOpcodeConditionalSet,
198     Fast486ExtOpcodeConditionalSet,
199     Fast486ExtOpcodeConditionalSet,
200     Fast486ExtOpcodePushFs,             /* 0xA0 */
201     Fast486ExtOpcodePopFs,              /* 0xA1 */
202     Fast486ExtOpcodeInvalid,            /* 0xA2 */          // Invalid
203     Fast486ExtOpcodeBitTest,            /* 0xA3 */
204     Fast486ExtOpcodeShld,               /* 0xA4 - 0xA5 */
205     Fast486ExtOpcodeShld,
206     Fast486ExtOpcodeInvalid,            /* 0xA6 - 0xA7 */   // Invalid
207     Fast486ExtOpcodeInvalid,                                // Invalid
208     Fast486ExtOpcodePushGs,             /* 0xA8 - 0xA9 */
209     Fast486ExtOpcodePopGs,
210     Fast486ExtOpcodeInvalid,            /* 0xAA */          // Invalid
211     Fast486ExtOpcodeBts,                /* 0xAB */
212     Fast486ExtOpcodeShrd,               /* 0xAC - 0xAD */
213     Fast486ExtOpcodeShrd,
214     Fast486ExtOpcodeInvalid,            /* 0xAE */          // Invalid
215     Fast486ExtOpcodeImul,               /* 0xAF */
216     Fast486ExtOpcodeCmpXchgByte,        /* 0xB0 */
217     Fast486ExtOpcodeCmpXchg,            /* 0xB1 */
218     Fast486ExtOpcodeLss,                /* 0xB2 */
219     Fast486ExtOpcodeBtr,                /* 0xB3 */
220     Fast486ExtOpcodeLfsLgs,             /* 0xB4 - 0xB5 */
221     Fast486ExtOpcodeLfsLgs,
222     Fast486ExtOpcodeMovzxByte,          /* 0xB6 - 0xB7 */
223     Fast486ExtOpcodeMovzxWord,
224     Fast486ExtOpcodeInvalid,            /* 0xB8 */          // Invalid
225     Fast486ExtOpcodeGroup0FB9,          /* 0xB9 */
226     Fast486ExtOpcodeGroup0FBA,          /* 0xBA */
227     Fast486ExtOpcodeBtc,                /* 0xBB */
228     Fast486ExtOpcodeBsf,                /* 0xBC */
229     Fast486ExtOpcodeBsr,                /* 0xBD */
230     Fast486ExtOpcodeMovsxByte,          /* 0xBE - 0xBF */
231     Fast486ExtOpcodeMovsxWord,
232     Fast486ExtOpcodeXaddByte,           /* 0xC0 - 0xC1 */
233     Fast486ExtOpcodeXadd,
234     Fast486ExtOpcodeInvalid,            /* 0xC2 - 0xC7 */   // Invalid
235     Fast486ExtOpcodeInvalid,                                // Invalid
236     Fast486ExtOpcodeInvalid,                                // Invalid
237     Fast486ExtOpcodeInvalid,                                // Invalid
238     Fast486ExtOpcodeInvalid,                                // Invalid
239     Fast486ExtOpcodeInvalid,                                // Invalid
240     Fast486ExtOpcodeBswap,              /* 0xC8 - 0xCF */
241     Fast486ExtOpcodeBswap,
242     Fast486ExtOpcodeBswap,
243     Fast486ExtOpcodeBswap,
244     Fast486ExtOpcodeBswap,
245     Fast486ExtOpcodeBswap,
246     Fast486ExtOpcodeBswap,
247     Fast486ExtOpcodeBswap,
248     Fast486ExtOpcodeInvalid,            /* 0xD0 - 0xFF */   // Invalid
249     Fast486ExtOpcodeInvalid,                                // Invalid
250     Fast486ExtOpcodeInvalid,                                // Invalid
251     Fast486ExtOpcodeInvalid,                                // Invalid
252     Fast486ExtOpcodeInvalid,                                // Invalid
253     Fast486ExtOpcodeInvalid,                                // Invalid
254     Fast486ExtOpcodeInvalid,                                // Invalid
255     Fast486ExtOpcodeInvalid,                                // Invalid
256     Fast486ExtOpcodeInvalid,                                // Invalid
257     Fast486ExtOpcodeInvalid,                                // Invalid
258     Fast486ExtOpcodeInvalid,                                // Invalid
259     Fast486ExtOpcodeInvalid,                                // Invalid
260     Fast486ExtOpcodeInvalid,                                // Invalid
261     Fast486ExtOpcodeInvalid,                                // Invalid
262     Fast486ExtOpcodeInvalid,                                // Invalid
263     Fast486ExtOpcodeInvalid,                                // Invalid
264     Fast486ExtOpcodeInvalid,                                // Invalid
265     Fast486ExtOpcodeInvalid,                                // Invalid
266     Fast486ExtOpcodeInvalid,                                // Invalid
267     Fast486ExtOpcodeInvalid,                                // Invalid
268     Fast486ExtOpcodeInvalid,                                // Invalid
269     Fast486ExtOpcodeInvalid,                                // Invalid
270     Fast486ExtOpcodeInvalid,                                // Invalid
271     Fast486ExtOpcodeInvalid,                                // Invalid
272     Fast486ExtOpcodeInvalid,                                // Invalid
273     Fast486ExtOpcodeInvalid,                                // Invalid
274     Fast486ExtOpcodeInvalid,                                // Invalid
275     Fast486ExtOpcodeInvalid,                                // Invalid
276     Fast486ExtOpcodeInvalid,                                // Invalid
277     Fast486ExtOpcodeInvalid,                                // Invalid
278     Fast486ExtOpcodeInvalid,                                // Invalid
279     Fast486ExtOpcodeInvalid,                                // Invalid
280     Fast486ExtOpcodeInvalid,                                // Invalid
281     Fast486ExtOpcodeInvalid,                                // Invalid
282     Fast486ExtOpcodeInvalid,                                // Invalid
283     Fast486ExtOpcodeInvalid,                                // Invalid
284     Fast486ExtOpcodeInvalid,                                // Invalid
285     Fast486ExtOpcodeInvalid,                                // Invalid
286     Fast486ExtOpcodeInvalid,                                // Invalid
287     Fast486ExtOpcodeInvalid,                                // Invalid
288     Fast486ExtOpcodeInvalid,                                // Invalid
289     Fast486ExtOpcodeInvalid,                                // Invalid
290     Fast486ExtOpcodeInvalid,                                // Invalid
291     Fast486ExtOpcodeInvalid,                                // Invalid
292     Fast486ExtOpcodeInvalid,                                // Invalid
293     Fast486ExtOpcodeInvalid,                                // Invalid
294     Fast486ExtOpcodeInvalid,                                // Invalid
295     Fast486ExtOpcodeInvalid,                                // Invalid
296 };
297 
298 /* PUBLIC FUNCTIONS ***********************************************************/
299 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid)300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeInvalid)
301 {
302     DPRINT1("FAST486 -- Extended opcode 0x%02X is INVALID!\n", Opcode);
303     Fast486Exception(State, FAST486_EXCEPTION_UD);
304     return;
305 }
306 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented)307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeUnimplemented)
308 {
309     DPRINT1("FAST486 -- Extended opcode 0x%02X is UNIMPLEMENTED\n", Opcode);
310     // Fast486Exception(State, FAST486_EXCEPTION_UD);
311 }
312 
FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B)313 FAST486_OPCODE_HANDLER(Fast486ExtOpcode0F0B)
314 {
315     /* Reserved opcode (UD2) */
316     Fast486Exception(State, FAST486_EXCEPTION_UD);
317 }
318 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)319 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLar)
320 {
321     BOOLEAN OperandSize, AddressSize;
322     FAST486_MOD_REG_RM ModRegRm;
323     BOOLEAN Valid;
324     USHORT Selector;
325     FAST486_GDT_ENTRY GdtEntry;
326     DWORD AccessRights;
327 
328     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
329 
330     if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
331         || State->Flags.Vm)
332     {
333         /* Not recognized */
334         Fast486Exception(State, FAST486_EXCEPTION_UD);
335         return;
336     }
337 
338     NO_LOCK_PREFIX();
339     TOGGLE_OPSIZE(OperandSize);
340     TOGGLE_ADSIZE(AddressSize);
341 
342     /* Get the operands */
343     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
344     {
345         /* Exception occurred */
346         return;
347     }
348 
349     if (OperandSize)
350     {
351         ULONG Value;
352 
353         /* Read the value */
354         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
355         {
356             /* Exception occurred */
357             return;
358         }
359 
360         Selector = LOWORD(Value);
361     }
362     else
363     {
364         /* Read the value */
365         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
366         {
367             /* Exception occurred */
368             return;
369         }
370     }
371 
372     if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
373     {
374         /* Exception occurred */
375         return;
376     }
377 
378     if (!Valid)
379     {
380         State->Flags.Zf = FALSE;
381         return;
382     }
383 
384     /* Privilege check */
385     if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
386         || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
387     {
388         State->Flags.Zf = FALSE;
389         return;
390     }
391 
392     /* Set ZF */
393     State->Flags.Zf = TRUE;
394 
395     /* Get the access rights */
396     AccessRights = ((PDWORD)&GdtEntry)[1] & 0x00F0FF00;
397 
398     /* Return the access rights */
399     if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, AccessRights);
400     else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(AccessRights));
401 }
402 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)403 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
404 {
405     BOOLEAN OperandSize, AddressSize;
406     FAST486_MOD_REG_RM ModRegRm;
407     BOOLEAN Valid;
408     USHORT Selector;
409     ULONG Limit;
410     FAST486_GDT_ENTRY GdtEntry;
411 
412     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
413 
414     if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
415         || State->Flags.Vm)
416     {
417         /* Not recognized */
418         Fast486Exception(State, FAST486_EXCEPTION_UD);
419         return;
420     }
421 
422     NO_LOCK_PREFIX();
423     TOGGLE_OPSIZE(OperandSize);
424     TOGGLE_ADSIZE(AddressSize);
425 
426     /* Get the operands */
427     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
428     {
429         /* Exception occurred */
430         return;
431     }
432 
433     if (OperandSize)
434     {
435         ULONG Value;
436 
437         /* Read the value */
438         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
439         {
440             /* Exception occurred */
441             return;
442         }
443 
444         Selector = LOWORD(Value);
445     }
446     else
447     {
448         /* Read the value */
449         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
450         {
451             /* Exception occurred */
452             return;
453         }
454     }
455 
456     if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
457     {
458         /* Exception occurred */
459         return;
460     }
461 
462     if (!Valid)
463     {
464         State->Flags.Zf = FALSE;
465         return;
466     }
467 
468     /* Privilege check */
469     if (((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl))
470         || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
471     {
472         State->Flags.Zf = FALSE;
473         return;
474     }
475 
476     /* Calculate the limit */
477     Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
478 
479     if (GdtEntry.Granularity)
480     {
481         Limit <<= 12;
482         Limit |= 0x00000FFF;
483     }
484 
485     /* Set ZF */
486     State->Flags.Zf = TRUE;
487 
488     /* Return the limit */
489     if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Limit);
490     else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(Limit));
491 }
492 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)493 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
494 {
495     NO_LOCK_PREFIX();
496 
497     /* The current privilege level must be zero */
498     if (Fast486GetCurrentPrivLevel(State) != 0)
499     {
500         Fast486Exception(State, FAST486_EXCEPTION_GP);
501         return;
502     }
503 
504     /* Clear the task switch bit */
505     State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
506 }
507 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)508 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
509 {
510     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
511     FAST486_MOD_REG_RM ModRegRm;
512 
513     NO_LOCK_PREFIX();
514     TOGGLE_ADSIZE(AddressSize);
515 
516     /* Get the operands */
517     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
518     {
519         /* Exception occurred */
520         return;
521     }
522 
523     /* The current privilege level must be zero */
524     if (Fast486GetCurrentPrivLevel(State) != 0)
525     {
526         Fast486Exception(State, FAST486_EXCEPTION_GP);
527         return;
528     }
529 
530     if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
531     {
532         /* CR1, CR4, CR5, CR6 and CR7 don't exist */
533         Fast486Exception(State, FAST486_EXCEPTION_UD);
534         return;
535     }
536 
537     if (ModRegRm.Register != 0)
538     {
539         /* CR2 and CR3 and are stored in array indexes 1 and 2 */
540         ModRegRm.Register--;
541     }
542 
543     /* Store the value of the control register */
544     State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
545 }
546 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)547 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
548 {
549     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
550     FAST486_MOD_REG_RM ModRegRm;
551 
552     NO_LOCK_PREFIX();
553     TOGGLE_ADSIZE(AddressSize);
554 
555     /* Get the operands */
556     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
557     {
558         /* Exception occurred */
559         return;
560     }
561 
562     /* The current privilege level must be zero */
563     if (Fast486GetCurrentPrivLevel(State) != 0)
564     {
565         Fast486Exception(State, FAST486_EXCEPTION_GP);
566         return;
567     }
568 
569     if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
570     {
571         /* DR6 and DR7 are aliases to DR4 and DR5 */
572         ModRegRm.Register -= 2;
573     }
574 
575     if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
576     {
577         /* Disallow access to debug registers */
578         Fast486Exception(State, FAST486_EXCEPTION_GP);
579         return;
580     }
581 
582     /* Store the value of the debug register */
583     State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
584 }
585 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)586 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
587 {
588     ULONG Value;
589     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
590     FAST486_MOD_REG_RM ModRegRm;
591 
592     NO_LOCK_PREFIX();
593     TOGGLE_ADSIZE(AddressSize);
594 
595     /* Get the operands */
596     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
597     {
598         /* Exception occurred */
599         return;
600     }
601 
602     /* The current privilege level must be zero */
603     if (Fast486GetCurrentPrivLevel(State) != 0)
604     {
605         Fast486Exception(State, FAST486_EXCEPTION_GP);
606         return;
607     }
608 
609     if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
610     {
611         /* CR1, CR4, CR5, CR6 and CR7 don't exist */
612         Fast486Exception(State, FAST486_EXCEPTION_UD);
613         return;
614     }
615 
616     if (ModRegRm.Register != 0)
617     {
618         /* CR2 and CR3 and are stored in array indexes 1 and 2 */
619         ModRegRm.Register--;
620     }
621 
622     /* Get the value */
623     Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
624 
625     if (ModRegRm.Register == (INT)FAST486_REG_CR0)
626     {
627         /* CR0 checks */
628 
629         if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
630             || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
631         {
632             /* Invalid value */
633             Fast486Exception(State, FAST486_EXCEPTION_GP);
634             return;
635         }
636     }
637 
638 #ifndef FAST486_NO_PREFETCH
639     /* Changing CR0 or CR3 can interfere with prefetching (because of paging) */
640     State->PrefetchValid = FALSE;
641 #endif
642 
643     if (ModRegRm.Register == (INT)FAST486_REG_CR3)
644     {
645         /* Flush the TLB */
646         Fast486FlushTlb(State);
647     }
648 
649     /* Load a value to the control register */
650     State->ControlRegisters[ModRegRm.Register] = Value;
651 }
652 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)653 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
654 {
655     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
656     FAST486_MOD_REG_RM ModRegRm;
657 
658     NO_LOCK_PREFIX();
659     TOGGLE_ADSIZE(AddressSize);
660 
661     /* Get the operands */
662     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
663     {
664         /* Exception occurred */
665         return;
666     }
667 
668     /* The current privilege level must be zero */
669     if (Fast486GetCurrentPrivLevel(State) != 0)
670     {
671         Fast486Exception(State, FAST486_EXCEPTION_GP);
672         return;
673     }
674 
675     if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
676     {
677         /* DR6 and DR7 are aliases to DR4 and DR5 */
678         ModRegRm.Register -= 2;
679     }
680 
681     if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
682     {
683         /* Disallow access to debug registers */
684         Fast486Exception(State, FAST486_EXCEPTION_GP);
685         return;
686     }
687 
688     /* Load a value to the debug register */
689     State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
690 
691     if (ModRegRm.Register == (INT)FAST486_REG_DR4)
692     {
693         /* The reserved bits are 1 */
694         State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
695     }
696     else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
697     {
698         /* The reserved bits are 0 */
699         State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
700     }
701 }
702 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)703 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
704 {
705     /* Call the internal API */
706     Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
707 }
708 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)709 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
710 {
711     ULONG NewSelector;
712 
713     if (!Fast486StackPop(State, &NewSelector))
714     {
715         /* Exception occurred */
716         return;
717     }
718 
719     /* Call the internal API */
720     Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
721 }
722 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)723 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
724 {
725     BOOLEAN OperandSize, AddressSize;
726     FAST486_MOD_REG_RM ModRegRm;
727     UINT DataSize;
728     ULONG BitNumber;
729 
730     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
731     TOGGLE_OPSIZE(OperandSize);
732     TOGGLE_ADSIZE(AddressSize);
733 
734     /* Get the number of bits */
735     if (OperandSize) DataSize = 32;
736     else DataSize = 16;
737 
738     /* Get the operands */
739     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
740     {
741         /* Exception occurred */
742         return;
743     }
744 
745     /* Get the bit number */
746     BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
747                             : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
748 
749     if (ModRegRm.Memory)
750     {
751         /*
752          * For memory operands, add the bit offset divided by
753          * the data size to the address
754          */
755         ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8);
756     }
757 
758     /* Normalize the bit number */
759     BitNumber %= DataSize;
760 
761     if (OperandSize)
762     {
763         ULONG Value;
764 
765         /* Read the value */
766         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
767         {
768             /* Exception occurred */
769             return;
770         }
771 
772         /* Set CF to the bit value */
773         State->Flags.Cf = (Value >> BitNumber) & 1;
774     }
775     else
776     {
777         USHORT Value;
778 
779         /* Read the value */
780         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
781         {
782             /* Exception occurred */
783             return;
784         }
785 
786         /* Set CF to the bit value */
787         State->Flags.Cf = (Value >> BitNumber) & 1;
788     }
789 }
790 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)791 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShld)
792 {
793     BOOLEAN OperandSize, AddressSize;
794     FAST486_MOD_REG_RM ModRegRm;
795     UCHAR Count;
796 
797     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
798     TOGGLE_OPSIZE(OperandSize);
799     TOGGLE_ADSIZE(AddressSize);
800 
801     /* Make sure this is the right instruction */
802     ASSERT((Opcode & 0xFE) == 0xA4);
803 
804     /* Get the operands */
805     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
806     {
807         /* Exception occurred */
808         return;
809     }
810 
811     if (Opcode == 0xA4)
812     {
813         /* Fetch the count */
814         if (!Fast486FetchByte(State, &Count))
815         {
816             /* Exception occurred */
817             return;
818         }
819     }
820     else
821     {
822         /* The count is in CL */
823         Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
824     }
825 
826     /* Normalize the count */
827     Count &= 0x1F;
828 
829     /* Do nothing if the count is zero */
830     if (Count == 0) return;
831 
832     if (OperandSize)
833     {
834         ULONG Source, Destination, Result;
835 
836         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
837         {
838             /* Exception occurred */
839             return;
840         }
841 
842         /* Calculate the result */
843         Result = (Destination << Count) | (Source >> (32 - Count));
844 
845         /* Update flags */
846         State->Flags.Cf = (Destination >> (32 - Count)) & 1;
847         if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
848                                           != (Destination & SIGN_FLAG_LONG);
849         State->Flags.Zf = (Result == 0);
850         State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
851         State->Flags.Pf = Fast486CalculateParity(Result);
852 
853         /* Write back the result */
854         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
855     }
856     else
857     {
858         USHORT Source, Destination, Result;
859         ULONG DoubleSource;
860 
861         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
862         {
863             /* Exception occurred */
864             return;
865         }
866 
867         DoubleSource = Source | (Source << 16);
868 
869         /* Calculate the result */
870         Result = (Destination << Count) | (DoubleSource >> (32 - Count));
871 
872         /* Update flags */
873         if (Count <= 16) State->Flags.Cf = (Destination >> (16 - Count)) & 1;
874         else  State->Flags.Cf = (Source >> (32 - Count)) & 1;
875 
876         if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
877                                           != (Destination & SIGN_FLAG_WORD);
878         State->Flags.Zf = (Result == 0);
879         State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
880         State->Flags.Pf = Fast486CalculateParity(Result);
881 
882         /* Write back the result */
883         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
884     }
885 }
886 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)887 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
888 {
889     /* Call the internal API */
890     Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
891 }
892 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)893 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
894 {
895     ULONG NewSelector;
896 
897     if (!Fast486StackPop(State, &NewSelector))
898     {
899         /* Exception occurred */
900         return;
901     }
902 
903     /* Call the internal API */
904     Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
905 }
906 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)907 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
908 {
909     BOOLEAN OperandSize, AddressSize;
910     FAST486_MOD_REG_RM ModRegRm;
911     UINT DataSize;
912     ULONG BitNumber;
913 
914     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
915     TOGGLE_OPSIZE(OperandSize);
916     TOGGLE_ADSIZE(AddressSize);
917 
918     /* Get the number of bits */
919     if (OperandSize) DataSize = 32;
920     else DataSize = 16;
921 
922     /* Get the operands */
923     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
924     {
925         /* Exception occurred */
926         return;
927     }
928 
929     /* Get the bit number */
930     BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
931                             : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
932 
933     if (ModRegRm.Memory)
934     {
935         /*
936          * For memory operands, add the bit offset divided by
937          * the data size to the address
938          */
939         ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8);
940     }
941 
942     /* Normalize the bit number */
943     BitNumber %= DataSize;
944 
945     if (OperandSize)
946     {
947         ULONG Value;
948 
949         /* Read the value */
950         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
951         {
952             /* Exception occurred */
953             return;
954         }
955 
956         /* Set CF to the bit value */
957         State->Flags.Cf = (Value >> BitNumber) & 1;
958 
959         /* Set the bit */
960         Value |= 1 << BitNumber;
961 
962         /* Write back the result */
963         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
964     }
965     else
966     {
967         USHORT Value;
968 
969         /* Read the value */
970         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
971         {
972             /* Exception occurred */
973             return;
974         }
975 
976         /* Set CF to the bit value */
977         State->Flags.Cf = (Value >> BitNumber) & 1;
978 
979         /* Set the bit */
980         Value |= 1 << BitNumber;
981 
982         /* Write back the result */
983         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
984     }
985 }
986 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)987 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeShrd)
988 {
989     BOOLEAN OperandSize, AddressSize;
990     FAST486_MOD_REG_RM ModRegRm;
991     UCHAR Count;
992 
993     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
994     TOGGLE_OPSIZE(OperandSize);
995     TOGGLE_ADSIZE(AddressSize);
996 
997     /* Make sure this is the right instruction */
998     ASSERT((Opcode & 0xFE) == 0xAC);
999 
1000     /* Get the operands */
1001     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1002     {
1003         /* Exception occurred */
1004         return;
1005     }
1006 
1007     if (Opcode == 0xAC)
1008     {
1009         /* Fetch the count */
1010         if (!Fast486FetchByte(State, &Count))
1011         {
1012             /* Exception occurred */
1013             return;
1014         }
1015     }
1016     else
1017     {
1018         /* The count is in CL */
1019         Count = State->GeneralRegs[FAST486_REG_ECX].LowByte;
1020     }
1021 
1022     /* Normalize the count */
1023     Count &= 0x1F;
1024 
1025     /* Do nothing if the count is zero */
1026     if (Count == 0) return;
1027 
1028     if (OperandSize)
1029     {
1030         ULONG Source, Destination, Result;
1031 
1032         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1033         {
1034             /* Exception occurred */
1035             return;
1036         }
1037 
1038         /* Calculate the result */
1039         Result = (Destination >> Count) | (Source << (32 - Count));
1040 
1041         /* Update flags */
1042         State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1043         if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_LONG)
1044                                           != (Destination & SIGN_FLAG_LONG);
1045         State->Flags.Zf = (Result == 0);
1046         State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1047         State->Flags.Pf = Fast486CalculateParity(Result);
1048 
1049         /* Write back the result */
1050         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1051     }
1052     else
1053     {
1054         USHORT Source, Destination, Result;
1055 
1056         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1057         {
1058             /* Exception occurred */
1059             return;
1060         }
1061 
1062         /* Calculate the result */
1063         Result = (Destination >> Count) | (Source << (16 - Count));
1064 
1065         if (Count >= 16) Result |= (ULONG)(Source | (Source << 16)) >> (Count - 16);
1066 
1067         /* Update flags */
1068         if (Count <= 16) State->Flags.Cf = (Destination >> (Count - 1)) & 1;
1069         else State->Flags.Cf = (Source >> (Count - 17)) & 1;
1070 
1071         if (Count == 1) State->Flags.Of = (Result & SIGN_FLAG_WORD)
1072                                           != (Destination & SIGN_FLAG_WORD);
1073         State->Flags.Zf = (Result == 0);
1074         State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1075         State->Flags.Pf = Fast486CalculateParity(Result);
1076 
1077         /* Write back the result */
1078         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
1079     }
1080 }
1081 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)1082 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeImul)
1083 {
1084     BOOLEAN OperandSize, AddressSize;
1085     FAST486_MOD_REG_RM ModRegRm;
1086 
1087     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1088 
1089     TOGGLE_OPSIZE(OperandSize);
1090     TOGGLE_ADSIZE(AddressSize);
1091 
1092     /* Get the operands */
1093     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1094     {
1095         /* Exception occurred */
1096         return;
1097     }
1098 
1099     if (OperandSize)
1100     {
1101         LONG Source, Destination;
1102         LONGLONG Result;
1103 
1104         /* Read the operands */
1105         if (!Fast486ReadModrmDwordOperands(State,
1106                                            &ModRegRm,
1107                                            (PULONG)&Destination,
1108                                            (PULONG)&Source))
1109         {
1110             /* Exception occurred */
1111             return;
1112         }
1113 
1114         /* Calculate the result */
1115         Result = (LONGLONG)Source * (LONGLONG)Destination;
1116 
1117         /* Update the flags */
1118         State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1119 
1120         /* Write back the result */
1121         Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, (ULONG)((LONG)Result));
1122     }
1123     else
1124     {
1125         SHORT Source, Destination;
1126         LONG Result;
1127 
1128         /* Read the operands */
1129         if (!Fast486ReadModrmWordOperands(State,
1130                                           &ModRegRm,
1131                                           (PUSHORT)&Destination,
1132                                           (PUSHORT)&Source))
1133         {
1134             /* Exception occurred */
1135             return;
1136         }
1137 
1138         /* Calculate the result */
1139         Result = (LONG)Source * (LONG)Destination;
1140 
1141         /* Update the flags */
1142         State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1143 
1144         /* Write back the result */
1145         Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, (USHORT)((SHORT)Result));
1146     }
1147 }
1148 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)1149 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
1150 {
1151     FAST486_MOD_REG_RM ModRegRm;
1152     UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1153     UCHAR Source, Destination, Result;
1154     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1155 
1156     TOGGLE_ADSIZE(AddressSize);
1157 
1158     /* Get the operands */
1159     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1160     {
1161         /* Exception occurred */
1162         return;
1163     }
1164 
1165     /* Read the operands */
1166     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
1167     {
1168         /* Exception occurred */
1169         return;
1170     }
1171 
1172     /* Compare AL with the destination */
1173     Result = Accumulator - Destination;
1174 
1175     /* Update the flags */
1176     State->Flags.Cf = (Accumulator < Destination);
1177     State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
1178                       && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1179     State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1180     State->Flags.Zf = (Result == 0);
1181     State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1182     State->Flags.Pf = Fast486CalculateParity(Result);
1183 
1184     if (State->Flags.Zf)
1185     {
1186         /* Load the source operand into the destination */
1187         Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
1188     }
1189     else
1190     {
1191         /* Load the destination into AL */
1192         State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
1193     }
1194 }
1195 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)1196 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
1197 {
1198     FAST486_MOD_REG_RM ModRegRm;
1199     BOOLEAN OperandSize, AddressSize;
1200 
1201     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1202 
1203     TOGGLE_OPSIZE(OperandSize);
1204     TOGGLE_ADSIZE(AddressSize);
1205 
1206     /* Get the operands */
1207     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1208     {
1209         /* Exception occurred */
1210         return;
1211     }
1212 
1213     if (OperandSize)
1214     {
1215         ULONG Source, Destination, Result;
1216         ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
1217 
1218         /* Read the operands */
1219         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
1220         {
1221             /* Exception occurred */
1222             return;
1223         }
1224 
1225         /* Compare EAX with the destination */
1226         Result = Accumulator - Destination;
1227 
1228         /* Update the flags */
1229         State->Flags.Cf = (Accumulator < Destination);
1230         State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
1231                           && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1232         State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1233         State->Flags.Zf = (Result == 0);
1234         State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1235         State->Flags.Pf = Fast486CalculateParity(Result);
1236 
1237         if (State->Flags.Zf)
1238         {
1239             /* Load the source operand into the destination */
1240             Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
1241         }
1242         else
1243         {
1244             /* Load the destination into EAX */
1245             State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
1246         }
1247     }
1248     else
1249     {
1250         USHORT Source, Destination, Result;
1251         USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1252 
1253         /* Read the operands */
1254         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
1255         {
1256             /* Exception occurred */
1257             return;
1258         }
1259 
1260         /* Compare AX with the destination */
1261         Result = Accumulator - Destination;
1262 
1263         /* Update the flags */
1264         State->Flags.Cf = (Accumulator < Destination);
1265         State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
1266                           && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1267         State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
1268         State->Flags.Zf = (Result == 0);
1269         State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1270         State->Flags.Pf = Fast486CalculateParity(Result);
1271 
1272         if (State->Flags.Zf)
1273         {
1274             /* Load the source operand into the destination */
1275             Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
1276         }
1277         else
1278         {
1279             /* Load the destination into AX */
1280             State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
1281         }
1282     }
1283 }
1284 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)1285 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLss)
1286 {
1287     UCHAR FarPointer[6];
1288     BOOLEAN OperandSize, AddressSize;
1289     FAST486_MOD_REG_RM ModRegRm;
1290 
1291     /* Make sure this is the right instruction */
1292     ASSERT(Opcode == 0xB2);
1293 
1294     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1295 
1296     TOGGLE_OPSIZE(OperandSize);
1297     TOGGLE_ADSIZE(AddressSize);
1298 
1299     /* Get the operands */
1300     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1301     {
1302         /* Exception occurred */
1303         return;
1304     }
1305 
1306     if (!ModRegRm.Memory)
1307     {
1308         /* Invalid */
1309         Fast486Exception(State, FAST486_EXCEPTION_UD);
1310         return;
1311     }
1312 
1313     if (!Fast486ReadMemory(State,
1314                            (State->PrefixFlags & FAST486_PREFIX_SEG)
1315                            ? State->SegmentOverride : FAST486_REG_DS,
1316                            ModRegRm.MemoryAddress,
1317                            FALSE,
1318                            FarPointer,
1319                            OperandSize ? 6 : 4))
1320     {
1321         /* Exception occurred */
1322         return;
1323     }
1324 
1325     if (OperandSize)
1326     {
1327         ULONG Offset = *((PULONG)FarPointer);
1328         USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1329 
1330         /* Set the register to the offset */
1331         State->GeneralRegs[ModRegRm.Register].Long = Offset;
1332 
1333         /* Load the segment */
1334         Fast486LoadSegment(State, FAST486_REG_SS, Segment);
1335     }
1336     else
1337     {
1338         USHORT Offset = *((PUSHORT)FarPointer);
1339         USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1340 
1341         /* Set the register to the offset */
1342         State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1343 
1344         /* Load the segment */
1345         Fast486LoadSegment(State, FAST486_REG_SS, Segment);
1346     }
1347 }
1348 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)1349 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
1350 {
1351     BOOLEAN OperandSize, AddressSize;
1352     FAST486_MOD_REG_RM ModRegRm;
1353     UINT DataSize;
1354     ULONG BitNumber;
1355 
1356     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1357     TOGGLE_OPSIZE(OperandSize);
1358     TOGGLE_ADSIZE(AddressSize);
1359 
1360     /* Get the number of bits */
1361     if (OperandSize) DataSize = 32;
1362     else DataSize = 16;
1363 
1364     /* Get the operands */
1365     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1366     {
1367         /* Exception occurred */
1368         return;
1369     }
1370 
1371     /* Get the bit number */
1372     BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1373                             : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1374 
1375     if (ModRegRm.Memory)
1376     {
1377         /*
1378          * For memory operands, add the bit offset divided by
1379          * the data size to the address
1380          */
1381         ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8);
1382     }
1383 
1384     /* Normalize the bit number */
1385     BitNumber %= DataSize;
1386 
1387     if (OperandSize)
1388     {
1389         ULONG Value;
1390 
1391         /* Read the value */
1392         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1393         {
1394             /* Exception occurred */
1395             return;
1396         }
1397 
1398         /* Set CF to the bit value */
1399         State->Flags.Cf = (Value >> BitNumber) & 1;
1400 
1401         /* Clear the bit */
1402         Value &= ~(1 << BitNumber);
1403 
1404         /* Write back the result */
1405         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1406     }
1407     else
1408     {
1409         USHORT Value;
1410 
1411         /* Read the value */
1412         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1413         {
1414             /* Exception occurred */
1415             return;
1416         }
1417 
1418         /* Set CF to the bit value */
1419         State->Flags.Cf = (Value >> BitNumber) & 1;
1420 
1421         /* Clear the bit */
1422         Value &= ~(1 << BitNumber);
1423 
1424         /* Write back the result */
1425         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1426     }
1427 }
1428 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)1429 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLfsLgs)
1430 {
1431     UCHAR FarPointer[6];
1432     BOOLEAN OperandSize, AddressSize;
1433     FAST486_MOD_REG_RM ModRegRm;
1434 
1435     /* Make sure this is the right instruction */
1436     ASSERT((Opcode & 0xFE) == 0xB4);
1437 
1438     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1439 
1440     TOGGLE_OPSIZE(OperandSize);
1441     TOGGLE_ADSIZE(AddressSize);
1442 
1443     /* Get the operands */
1444     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1445     {
1446         /* Exception occurred */
1447         return;
1448     }
1449 
1450     if (!ModRegRm.Memory)
1451     {
1452         /* Invalid */
1453         Fast486Exception(State, FAST486_EXCEPTION_UD);
1454         return;
1455     }
1456 
1457     if (!Fast486ReadMemory(State,
1458                            (State->PrefixFlags & FAST486_PREFIX_SEG)
1459                            ? State->SegmentOverride : FAST486_REG_DS,
1460                            ModRegRm.MemoryAddress,
1461                            FALSE,
1462                            FarPointer,
1463                            OperandSize ? 6 : 4))
1464     {
1465         /* Exception occurred */
1466         return;
1467     }
1468 
1469     if (OperandSize)
1470     {
1471         ULONG Offset = *((PULONG)FarPointer);
1472         USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
1473 
1474         /* Set the register to the offset */
1475         State->GeneralRegs[ModRegRm.Register].Long = Offset;
1476 
1477         /* Load the segment */
1478         Fast486LoadSegment(State,
1479                            (Opcode == 0xB4)
1480                            ? FAST486_REG_FS : FAST486_REG_GS,
1481                            Segment);
1482     }
1483     else
1484     {
1485         USHORT Offset = *((PUSHORT)FarPointer);
1486         USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1487 
1488         /* Set the register to the offset */
1489         State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1490 
1491         /* Load the segment */
1492         Fast486LoadSegment(State,
1493                            (Opcode == 0xB4)
1494                            ? FAST486_REG_FS : FAST486_REG_GS,
1495                            Segment);
1496     }
1497 }
1498 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)1499 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1500 {
1501     UCHAR Value;
1502     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1503     FAST486_MOD_REG_RM ModRegRm;
1504 
1505     TOGGLE_ADSIZE(AddressSize);
1506 
1507     /* Make sure this is the right instruction */
1508     ASSERT(Opcode == 0xB6);
1509 
1510     /* Get the operands */
1511     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1512     {
1513         /* Exception occurred */
1514         return;
1515     }
1516 
1517     /* Read the operands */
1518     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1519     {
1520         /* Exception occurred */
1521         return;
1522     }
1523 
1524     /* Write back the zero-extended value */
1525     Fast486WriteModrmDwordOperands(State,
1526                                    &ModRegRm,
1527                                    TRUE,
1528                                    (ULONG)Value);
1529 }
1530 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)1531 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1532 {
1533     USHORT Value;
1534     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1535     FAST486_MOD_REG_RM ModRegRm;
1536 
1537     TOGGLE_ADSIZE(AddressSize);
1538 
1539     /* Make sure this is the right instruction */
1540     ASSERT(Opcode == 0xB7);
1541 
1542     /* Get the operands */
1543     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1544     {
1545         /* Exception occurred */
1546         return;
1547     }
1548 
1549     /* Read the operands */
1550     if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1551     {
1552         /* Exception occurred */
1553         return;
1554     }
1555 
1556     /* Write back the zero-extended value */
1557     Fast486WriteModrmDwordOperands(State,
1558                                    &ModRegRm,
1559                                    TRUE,
1560                                    (ULONG)Value);
1561 }
1562 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)1563 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1564 {
1565     BOOLEAN OperandSize, AddressSize;
1566     FAST486_MOD_REG_RM ModRegRm;
1567     UINT DataSize;
1568     ULONG BitNumber;
1569 
1570     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1571     TOGGLE_OPSIZE(OperandSize);
1572     TOGGLE_ADSIZE(AddressSize);
1573 
1574     /* Get the number of bits */
1575     if (OperandSize) DataSize = 32;
1576     else DataSize = 16;
1577 
1578     /* Get the operands */
1579     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1580     {
1581         /* Exception occurred */
1582         return;
1583     }
1584 
1585     /* Get the bit number */
1586     BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1587                             : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1588 
1589     if (ModRegRm.Memory)
1590     {
1591         /*
1592          * For memory operands, add the bit offset divided by
1593          * the data size to the address
1594          */
1595         ModRegRm.MemoryAddress += (BitNumber / DataSize) * (DataSize / 8);
1596     }
1597 
1598     /* Normalize the bit number */
1599     BitNumber %= DataSize;
1600 
1601     if (OperandSize)
1602     {
1603         ULONG Value;
1604 
1605         /* Read the value */
1606         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1607         {
1608             /* Exception occurred */
1609             return;
1610         }
1611 
1612         /* Set CF to the bit value */
1613         State->Flags.Cf = (Value >> BitNumber) & 1;
1614 
1615         /* Toggle the bit */
1616         Value ^= 1 << BitNumber;
1617 
1618         /* Write back the result */
1619         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1620     }
1621     else
1622     {
1623         USHORT Value;
1624 
1625         /* Read the value */
1626         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1627         {
1628             /* Exception occurred */
1629             return;
1630         }
1631 
1632         /* Set CF to the bit value */
1633         State->Flags.Cf = (Value >> BitNumber) & 1;
1634 
1635         /* Toggle the bit */
1636         Value ^= 1 << BitNumber;
1637 
1638         /* Write back the result */
1639         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1640     }
1641 }
1642 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)1643 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1644 {
1645     UINT i;
1646     ULONG Value = 0;
1647     BOOLEAN OperandSize, AddressSize;
1648     FAST486_MOD_REG_RM ModRegRm;
1649     ULONG BitNumber;
1650     UINT DataSize;
1651 
1652     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1653     TOGGLE_OPSIZE(OperandSize);
1654     TOGGLE_ADSIZE(AddressSize);
1655 
1656     /* Make sure this is the right instruction */
1657     ASSERT(Opcode == 0xBC);
1658 
1659     /* Get the number of bits */
1660     if (OperandSize) DataSize = 32;
1661     else DataSize = 16;
1662 
1663     /* Get the operands */
1664     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1665     {
1666         /* Exception occurred */
1667         return;
1668     }
1669 
1670     /* Read the value */
1671     if (OperandSize)
1672     {
1673         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1674         {
1675             /* Exception occurred */
1676             return;
1677         }
1678     }
1679     else
1680     {
1681         if (!Fast486ReadModrmWordOperands(State,
1682                                           &ModRegRm,
1683                                           (PUSHORT)NULL,
1684                                           (PUSHORT)&Value))
1685         {
1686             /* Exception occurred */
1687             return;
1688         }
1689     }
1690 
1691     /* Set ZF */
1692     State->Flags.Zf = (Value == 0);
1693     if (State->Flags.Zf) return;
1694 
1695     for (i = 0; i < DataSize; i++)
1696     {
1697         if (Value & (1 << i))
1698         {
1699             /* Save the bit number */
1700             BitNumber = i;
1701 
1702             /* Exit the loop */
1703             break;
1704         }
1705     }
1706 
1707     /* Write back the result */
1708     if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber);
1709     else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));
1710 }
1711 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)1712 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1713 {
1714     INT i;
1715     ULONG Value = 0;
1716     BOOLEAN OperandSize, AddressSize;
1717     FAST486_MOD_REG_RM ModRegRm;
1718     ULONG BitNumber;
1719     UINT DataSize;
1720 
1721     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1722     TOGGLE_OPSIZE(OperandSize);
1723     TOGGLE_ADSIZE(AddressSize);
1724 
1725     /* Make sure this is the right instruction */
1726     ASSERT(Opcode == 0xBD);
1727 
1728     /* Get the number of bits */
1729     if (OperandSize) DataSize = 32;
1730     else DataSize = 16;
1731 
1732     /* Get the operands */
1733     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1734     {
1735         /* Exception occurred */
1736         return;
1737     }
1738 
1739     /* Read the value */
1740     if (OperandSize)
1741     {
1742         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1743         {
1744             /* Exception occurred */
1745             return;
1746         }
1747     }
1748     else
1749     {
1750         if (!Fast486ReadModrmWordOperands(State,
1751                                           &ModRegRm,
1752                                           (PUSHORT)NULL,
1753                                           (PUSHORT)&Value))
1754         {
1755             /* Exception occurred */
1756             return;
1757         }
1758     }
1759 
1760     /* Set ZF according to the value */
1761     State->Flags.Zf = (Value == 0);
1762     if (State->Flags.Zf) return;
1763 
1764     for (i = DataSize - 1; i >= 0; i--)
1765     {
1766         if (Value & (1 << i))
1767         {
1768             /* Save the bit number */
1769             BitNumber = i;
1770 
1771             /* Exit the loop */
1772             break;
1773         }
1774     }
1775 
1776     /* Write back the result */
1777     if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber);
1778     else Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber));
1779 }
1780 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)1781 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1782 {
1783     CHAR Value;
1784     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1785     FAST486_MOD_REG_RM ModRegRm;
1786 
1787     TOGGLE_ADSIZE(AddressSize);
1788 
1789     /* Make sure this is the right instruction */
1790     ASSERT(Opcode == 0xBE);
1791 
1792     /* Get the operands */
1793     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1794     {
1795         /* Exception occurred */
1796         return;
1797     }
1798 
1799     /* Read the operands */
1800     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, (PUCHAR)&Value))
1801     {
1802         /* Exception occurred */
1803         return;
1804     }
1805 
1806     /* Write back the sign-extended value */
1807     Fast486WriteModrmDwordOperands(State,
1808                                    &ModRegRm,
1809                                    TRUE,
1810                                    (ULONG)((LONG)Value));
1811 }
1812 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)1813 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1814 {
1815     SHORT Value;
1816     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1817     FAST486_MOD_REG_RM ModRegRm;
1818 
1819     TOGGLE_ADSIZE(AddressSize);
1820 
1821     /* Make sure this is the right instruction */
1822     ASSERT(Opcode == 0xBF);
1823 
1824     /* Get the operands */
1825     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1826     {
1827         /* Exception occurred */
1828         return;
1829     }
1830 
1831     /* Read the operands */
1832     if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1833     {
1834         /* Exception occurred */
1835         return;
1836     }
1837 
1838     /* Write back the sign-extended value */
1839     Fast486WriteModrmDwordOperands(State,
1840                                    &ModRegRm,
1841                                    TRUE,
1842                                    (ULONG)((LONG)Value));
1843 }
1844 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)1845 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1846 {
1847     BOOLEAN Jump = FALSE;
1848     LONG Offset = 0;
1849     BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1850 
1851     TOGGLE_OPSIZE(Size);
1852     NO_LOCK_PREFIX();
1853 
1854     /* Make sure this is the right instruction */
1855     ASSERT((Opcode & 0xF0) == 0x80);
1856 
1857     /* Fetch the offset */
1858     if (Size)
1859     {
1860         if (!Fast486FetchDword(State, (PULONG)&Offset))
1861         {
1862             /* Exception occurred */
1863             return;
1864         }
1865     }
1866     else
1867     {
1868         SHORT Value;
1869 
1870         if (!Fast486FetchWord(State, (PUSHORT)&Value))
1871         {
1872             /* Exception occurred */
1873             return;
1874         }
1875 
1876         /* Sign-extend */
1877         Offset = (LONG)Value;
1878     }
1879 
1880     switch ((Opcode & 0x0F) >> 1)
1881     {
1882         /* JO / JNO */
1883         case 0:
1884         {
1885             Jump = State->Flags.Of;
1886             break;
1887         }
1888 
1889         /* JC / JNC */
1890         case 1:
1891         {
1892             Jump = State->Flags.Cf;
1893             break;
1894         }
1895 
1896         /* JZ / JNZ */
1897         case 2:
1898         {
1899             Jump = State->Flags.Zf;
1900             break;
1901         }
1902 
1903         /* JBE / JNBE */
1904         case 3:
1905         {
1906             Jump = State->Flags.Cf || State->Flags.Zf;
1907             break;
1908         }
1909 
1910         /* JS / JNS */
1911         case 4:
1912         {
1913             Jump = State->Flags.Sf;
1914             break;
1915         }
1916 
1917         /* JP / JNP */
1918         case 5:
1919         {
1920             Jump = State->Flags.Pf;
1921             break;
1922         }
1923 
1924         /* JL / JNL */
1925         case 6:
1926         {
1927             Jump = State->Flags.Sf != State->Flags.Of;
1928             break;
1929         }
1930 
1931         /* JLE / JNLE */
1932         case 7:
1933         {
1934             Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1935             break;
1936         }
1937     }
1938 
1939     if (Opcode & 1)
1940     {
1941         /* Invert the result */
1942         Jump = !Jump;
1943     }
1944 
1945     if (Jump)
1946     {
1947         /* Move the instruction pointer */
1948         State->InstPtr.Long += Offset;
1949     }
1950 }
1951 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)1952 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1953 {
1954     BOOLEAN Value = FALSE;
1955     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1956     FAST486_MOD_REG_RM ModRegRm;
1957 
1958     TOGGLE_ADSIZE(AddressSize);
1959 
1960     /* Get the operands */
1961     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1962     {
1963         /* Exception occurred */
1964         return;
1965     }
1966 
1967     /* Make sure this is the right instruction */
1968     ASSERT((Opcode & 0xF0) == 0x90);
1969 
1970     switch ((Opcode & 0x0F) >> 1)
1971     {
1972         /* SETO / SETNO */
1973         case 0:
1974         {
1975             Value = State->Flags.Of;
1976             break;
1977         }
1978 
1979         /* SETC / SETNC */
1980         case 1:
1981         {
1982             Value = State->Flags.Cf;
1983             break;
1984         }
1985 
1986         /* SETZ / SETNZ */
1987         case 2:
1988         {
1989             Value = State->Flags.Zf;
1990             break;
1991         }
1992 
1993         /* SETBE / SETNBE */
1994         case 3:
1995         {
1996             Value = State->Flags.Cf || State->Flags.Zf;
1997             break;
1998         }
1999 
2000         /* SETS / SETNS */
2001         case 4:
2002         {
2003             Value = State->Flags.Sf;
2004             break;
2005         }
2006 
2007         /* SETP / SETNP */
2008         case 5:
2009         {
2010             Value = State->Flags.Pf;
2011             break;
2012         }
2013 
2014         /* SETL / SETNL */
2015         case 6:
2016         {
2017             Value = State->Flags.Sf != State->Flags.Of;
2018             break;
2019         }
2020 
2021         /* SETLE / SETNLE */
2022         case 7:
2023         {
2024             Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
2025             break;
2026         }
2027     }
2028 
2029     if (Opcode & 1)
2030     {
2031         /* Invert the result */
2032         Value = !Value;
2033     }
2034 
2035     /* Write back the result */
2036     Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
2037 }
2038 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)2039 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
2040 {
2041     UCHAR Source, Destination, Result;
2042     FAST486_MOD_REG_RM ModRegRm;
2043     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2044 
2045     /* Make sure this is the right instruction */
2046     ASSERT(Opcode == 0xC0);
2047 
2048     TOGGLE_ADSIZE(AddressSize);
2049 
2050     /* Get the operands */
2051     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2052     {
2053         /* Exception occurred */
2054         return;
2055     }
2056 
2057     if (!Fast486ReadModrmByteOperands(State,
2058                                       &ModRegRm,
2059                                       &Source,
2060                                       &Destination))
2061     {
2062         /* Exception occurred */
2063         return;
2064     }
2065 
2066     /* Calculate the result */
2067     Result = Source + Destination;
2068 
2069     /* Update the flags */
2070     State->Flags.Cf = (Result < Source) && (Result < Destination);
2071     State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
2072                       && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2073     State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2074     State->Flags.Zf = (Result == 0);
2075     State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2076     State->Flags.Pf = Fast486CalculateParity(Result);
2077 
2078     /* Write the sum to the destination */
2079     if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
2080     {
2081         /* Exception occurred */
2082         return;
2083     }
2084 
2085     /* Write the old value of the destination to the source */
2086     Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination);
2087 }
2088 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)2089 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
2090 {
2091     FAST486_MOD_REG_RM ModRegRm;
2092     BOOLEAN OperandSize, AddressSize;
2093 
2094     /* Make sure this is the right instruction */
2095     ASSERT(Opcode == 0xC1);
2096 
2097     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2098 
2099     TOGGLE_ADSIZE(AddressSize);
2100     TOGGLE_OPSIZE(OperandSize);
2101 
2102     /* Get the operands */
2103     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2104     {
2105         /* Exception occurred */
2106         return;
2107     }
2108 
2109     /* Check the operand size */
2110     if (OperandSize)
2111     {
2112         ULONG Source, Destination, Result;
2113 
2114         if (!Fast486ReadModrmDwordOperands(State,
2115                                            &ModRegRm,
2116                                            &Source,
2117                                            &Destination))
2118         {
2119             /* Exception occurred */
2120             return;
2121         }
2122 
2123         /* Calculate the result */
2124         Result = Source + Destination;
2125 
2126         /* Update the flags */
2127         State->Flags.Cf = (Result < Source) && (Result < Destination);
2128         State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
2129                           && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2130         State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2131         State->Flags.Zf = (Result == 0);
2132         State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2133         State->Flags.Pf = Fast486CalculateParity(Result);
2134 
2135         /* Write the old value of the destination to the source */
2136         if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
2137         {
2138             /* Exception occurred */
2139             return;
2140         }
2141 
2142         /* Write the sum to the destination */
2143         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
2144     }
2145     else
2146     {
2147         USHORT Source, Destination, Result;
2148 
2149         if (!Fast486ReadModrmWordOperands(State,
2150                                           &ModRegRm,
2151                                           &Source,
2152                                           &Destination))
2153         {
2154             /* Exception occurred */
2155             return;
2156         }
2157 
2158         /* Calculate the result */
2159         Result = Source + Destination;
2160 
2161         /* Update the flags */
2162         State->Flags.Cf = (Result < Source) && (Result < Destination);
2163         State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
2164                           && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2165         State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
2166         State->Flags.Zf = (Result == 0);
2167         State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2168         State->Flags.Pf = Fast486CalculateParity(Result);
2169 
2170         /* Write the old value of the destination to the source */
2171         if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
2172         {
2173             /* Exception occurred */
2174             return;
2175         }
2176 
2177         /* Write the sum to the destination */
2178         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result);
2179     }
2180 }
2181 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)2182 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
2183 {
2184     PUCHAR Pointer;
2185 
2186     NO_LOCK_PREFIX();
2187 
2188     /* Get a pointer to the value */
2189     Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
2190 
2191     /* Swap the byte order */
2192     SWAP(Pointer[0], Pointer[3]);
2193     SWAP(Pointer[1], Pointer[2]);
2194 }
2195 
FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)2196 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
2197 {
2198     UCHAR SecondOpcode;
2199 
2200     /* Fetch the second operation code */
2201     if (!Fast486FetchByte(State, &SecondOpcode))
2202     {
2203         /* Exception occurred */
2204         return;
2205     }
2206 
2207     /* Call the extended opcode handler */
2208     Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
2209 }
2210 
2211 /* EOF */
2212