ReactOS  0.4.14-dev-98-gb0d4763
opcodes.c
Go to the documentation of this file.
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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,
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,
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,
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();
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,
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,
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,
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();
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,
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,
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,
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();
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,
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,
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,
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();
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();
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,
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,
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,
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();
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 */
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,
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 */
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,
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 */
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,
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();
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 */
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,
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 */
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,
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 */
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,
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();
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 
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 
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();
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 
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,
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 
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,
3689  Result);
3690  }
3691  else
3692  {
3693  USHORT Result;
3694 
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,
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 
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 
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 
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();
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();
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();
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();
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();
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 
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();
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 */
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 {
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();
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 {
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();
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 
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 
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 
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 */
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  {
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  {
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  {
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  {
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 */
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  {
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  {
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  {
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  {
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 */
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 */
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 */
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 */
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 */
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