* Sync up to trunk head (r64995).
[reactos.git] / lib / fast486 / opcodes.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opcodes.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "opgroups.h"
32 #include "extraops.h"
33 #include "common.h"
34 #include "fpu.h"
35
36 /* PUBLIC VARIABLES ***********************************************************/
37
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS] =
40 {
41 Fast486OpcodeAddByteModrm, /* 0x00 - 0x03 */
42 Fast486OpcodeAddModrm,
43 Fast486OpcodeAddByteModrm,
44 Fast486OpcodeAddModrm,
45 Fast486OpcodeAddAl, /* 0x04 */
46 Fast486OpcodeAddEax, /* 0x05 */
47 Fast486OpcodePushEs, /* 0x06 */
48 Fast486OpcodePopEs, /* 0x07 */
49 Fast486OpcodeOrByteModrm, /* 0x08 - 0x0B */
50 Fast486OpcodeOrModrm,
51 Fast486OpcodeOrByteModrm,
52 Fast486OpcodeOrModrm,
53 Fast486OpcodeOrAl, /* 0x0C */
54 Fast486OpcodeOrEax, /* 0x0D */
55 Fast486OpcodePushCs, /* 0x0E */
56 Fast486OpcodeExtended, /* 0x0F */
57 Fast486OpcodeAdcByteModrm, /* 0x10 - 0x13 */
58 Fast486OpcodeAdcModrm,
59 Fast486OpcodeAdcByteModrm,
60 Fast486OpcodeAdcModrm,
61 Fast486OpcodeAdcAl, /* 0x14 */
62 Fast486OpcodeAdcEax, /* 0x15 */
63 Fast486OpcodePushSs, /* 0x16 */
64 Fast486OpcodePopSs, /* 0x17 */
65 Fast486OpcodeSbbByteModrm, /* 0x18 - 0x1B */
66 Fast486OpcodeSbbModrm,
67 Fast486OpcodeSbbByteModrm,
68 Fast486OpcodeSbbModrm,
69 Fast486OpcodeSbbAl, /* 0x1C */
70 Fast486OpcodeSbbEax, /* 0x1D */
71 Fast486OpcodePushDs, /* 0x1E */
72 Fast486OpcodePopDs, /* 0x1F */
73 Fast486OpcodeAndByteModrm, /* 0x20 - 0x23 */
74 Fast486OpcodeAndModrm,
75 Fast486OpcodeAndByteModrm,
76 Fast486OpcodeAndModrm,
77 Fast486OpcodeAndAl, /* 0x24 */
78 Fast486OpcodeAndEax, /* 0x25 */
79 Fast486OpcodePrefix, /* 0x26 */
80 Fast486OpcodeDaa, /* 0x27 */
81 Fast486OpcodeCmpSubByteModrm, /* 0x28 - 0x2B */
82 Fast486OpcodeCmpSubModrm,
83 Fast486OpcodeCmpSubByteModrm,
84 Fast486OpcodeCmpSubModrm,
85 Fast486OpcodeCmpSubAl, /* 0x2C */
86 Fast486OpcodeCmpSubEax, /* 0x2D */
87 Fast486OpcodePrefix, /* 0x2E */
88 Fast486OpcodeDas, /* 0x2F */
89 Fast486OpcodeXorByteModrm, /* 0x30 - 0x33 */
90 Fast486OpcodeXorModrm,
91 Fast486OpcodeXorByteModrm,
92 Fast486OpcodeXorModrm,
93 Fast486OpcodeXorAl, /* 0x34 */
94 Fast486OpcodeXorEax, /* 0x35 */
95 Fast486OpcodePrefix, /* 0x36 */
96 Fast486OpcodeAaa, /* 0x37 */
97 Fast486OpcodeCmpSubByteModrm, /* 0x38 - 0x3B */
98 Fast486OpcodeCmpSubModrm,
99 Fast486OpcodeCmpSubByteModrm,
100 Fast486OpcodeCmpSubModrm,
101 Fast486OpcodeCmpSubAl, /* 0x3C */
102 Fast486OpcodeCmpSubEax, /* 0x3D */
103 Fast486OpcodePrefix, /* 0x3E */
104 Fast486OpcodeAas, /* 0x3F */
105 Fast486OpcodeIncrement, /* 0x40 - 0x47 */
106 Fast486OpcodeIncrement,
107 Fast486OpcodeIncrement,
108 Fast486OpcodeIncrement,
109 Fast486OpcodeIncrement,
110 Fast486OpcodeIncrement,
111 Fast486OpcodeIncrement,
112 Fast486OpcodeIncrement,
113 Fast486OpcodeDecrement, /* 0x48 - 0x4F */
114 Fast486OpcodeDecrement,
115 Fast486OpcodeDecrement,
116 Fast486OpcodeDecrement,
117 Fast486OpcodeDecrement,
118 Fast486OpcodeDecrement,
119 Fast486OpcodeDecrement,
120 Fast486OpcodeDecrement,
121 Fast486OpcodePushReg, /* 0x50 - 0x57 */
122 Fast486OpcodePushReg,
123 Fast486OpcodePushReg,
124 Fast486OpcodePushReg,
125 Fast486OpcodePushReg,
126 Fast486OpcodePushReg,
127 Fast486OpcodePushReg,
128 Fast486OpcodePushReg,
129 Fast486OpcodePopReg, /* 0x58 - 0x5F */
130 Fast486OpcodePopReg,
131 Fast486OpcodePopReg,
132 Fast486OpcodePopReg,
133 Fast486OpcodePopReg,
134 Fast486OpcodePopReg,
135 Fast486OpcodePopReg,
136 Fast486OpcodePopReg,
137 Fast486OpcodePushAll, /* 0x60 */
138 Fast486OpcodePopAll, /* 0x61 */
139 Fast486OpcodeBound, /* 0x62 */
140 Fast486OpcodeArpl, /* 0x63 */
141 Fast486OpcodePrefix, /* 0x64 - 0x67 */
142 Fast486OpcodePrefix,
143 Fast486OpcodePrefix,
144 Fast486OpcodePrefix,
145 Fast486OpcodePushImm, /* 0x68 */
146 Fast486OpcodeImulModrmImm, /* 0x69 */
147 Fast486OpcodePushByteImm, /* 0x6A */
148 Fast486OpcodeImulModrmImm, /* 0x6B */
149 Fast486OpcodeIns, /* 0x6C */
150 Fast486OpcodeIns, /* 0x6D */
151 Fast486OpcodeOuts, /* 0x6E */
152 Fast486OpcodeOuts, /* 0x6F */
153 Fast486OpcodeShortConditionalJmp, /* 0x70 - 0x7F */
154 Fast486OpcodeShortConditionalJmp,
155 Fast486OpcodeShortConditionalJmp,
156 Fast486OpcodeShortConditionalJmp,
157 Fast486OpcodeShortConditionalJmp,
158 Fast486OpcodeShortConditionalJmp,
159 Fast486OpcodeShortConditionalJmp,
160 Fast486OpcodeShortConditionalJmp,
161 Fast486OpcodeShortConditionalJmp,
162 Fast486OpcodeShortConditionalJmp,
163 Fast486OpcodeShortConditionalJmp,
164 Fast486OpcodeShortConditionalJmp,
165 Fast486OpcodeShortConditionalJmp,
166 Fast486OpcodeShortConditionalJmp,
167 Fast486OpcodeShortConditionalJmp,
168 Fast486OpcodeShortConditionalJmp,
169 Fast486OpcodeGroup8082, /* 0x80 */
170 Fast486OpcodeGroup81, /* 0x81 */
171 Fast486OpcodeGroup8082, /* 0x82 */
172 Fast486OpcodeGroup83, /* 0x83 */
173 Fast486OpcodeTestByteModrm, /* 0x84 */
174 Fast486OpcodeTestModrm, /* 0x85 */
175 Fast486OpcodeXchgByteModrm, /* 0x86 */
176 Fast486OpcodeXchgModrm, /* 0x87 */
177 Fast486OpcodeMovByteModrm, /* 0x88 */
178 Fast486OpcodeMovModrm, /* 0x89 */
179 Fast486OpcodeMovByteModrm, /* 0x8A */
180 Fast486OpcodeMovModrm, /* 0x8B */
181 Fast486OpcodeMovStoreSeg, /* 0x8C */
182 Fast486OpcodeLea, /* 0x8D */
183 Fast486OpcodeMovLoadSeg, /* 0x8E */
184 Fast486OpcodeGroup8F, /* 0x8F */
185 Fast486OpcodeNop, /* 0x90 */
186 Fast486OpcodeExchangeEax, /* 0x91 - 0x97 */
187 Fast486OpcodeExchangeEax,
188 Fast486OpcodeExchangeEax,
189 Fast486OpcodeExchangeEax,
190 Fast486OpcodeExchangeEax,
191 Fast486OpcodeExchangeEax,
192 Fast486OpcodeExchangeEax,
193 Fast486OpcodeCwde, /* 0x98 */
194 Fast486OpcodeCdq, /* 0x99 */
195 Fast486OpcodeCallAbs, /* 0x9A */
196 Fast486OpcodeWait, /* 0x9B */
197 Fast486OpcodePushFlags, /* 0x9C */
198 Fast486OpcodePopFlags, /* 0x9D */
199 Fast486OpcodeSahf, /* 0x9E */
200 Fast486OpcodeLahf, /* 0x9F */
201 Fast486OpcodeMovAlOffset, /* 0xA0 */
202 Fast486OpcodeMovEaxOffset, /* 0xA1 */
203 Fast486OpcodeMovOffsetAl, /* 0xA2 */
204 Fast486OpcodeMovOffsetEax, /* 0xA3 */
205 Fast486OpcodeMovs, /* 0xA4 */
206 Fast486OpcodeMovs, /* 0xA5 */
207 Fast486OpcodeCmps, /* 0xA6 */
208 Fast486OpcodeCmps, /* 0xA7 */
209 Fast486OpcodeTestAl, /* 0xA8 */
210 Fast486OpcodeTestEax, /* 0xA9 */
211 Fast486OpcodeStos, /* 0xAA */
212 Fast486OpcodeStos, /* 0xAB */
213 Fast486OpcodeLods, /* 0xAC */
214 Fast486OpcodeLods, /* 0xAD */
215 Fast486OpcodeScas, /* 0xAE */
216 Fast486OpcodeScas, /* 0xAF */
217 Fast486OpcodeMovByteRegImm, /* 0xB0 - 0xB7 */
218 Fast486OpcodeMovByteRegImm,
219 Fast486OpcodeMovByteRegImm,
220 Fast486OpcodeMovByteRegImm,
221 Fast486OpcodeMovByteRegImm,
222 Fast486OpcodeMovByteRegImm,
223 Fast486OpcodeMovByteRegImm,
224 Fast486OpcodeMovByteRegImm,
225 Fast486OpcodeMovRegImm, /* 0xB8 - 0xBF */
226 Fast486OpcodeMovRegImm,
227 Fast486OpcodeMovRegImm,
228 Fast486OpcodeMovRegImm,
229 Fast486OpcodeMovRegImm,
230 Fast486OpcodeMovRegImm,
231 Fast486OpcodeMovRegImm,
232 Fast486OpcodeMovRegImm,
233 Fast486OpcodeGroupC0, /* 0xC0 */
234 Fast486OpcodeGroupC1, /* 0xC1 */
235 Fast486OpcodeRet, /* 0xC2 */
236 Fast486OpcodeRet, /* 0xC3 */
237 Fast486OpcodeLdsLes, /* 0xC4 */
238 Fast486OpcodeLdsLes, /* 0xC5 */
239 Fast486OpcodeGroupC6, /* 0xC6 */
240 Fast486OpcodeGroupC7, /* 0xC7 */
241 Fast486OpcodeEnter, /* 0xC8 */
242 Fast486OpcodeLeave, /* 0xC9 */
243 Fast486OpcodeRetFar, /* 0xCA */
244 Fast486OpcodeRetFar, /* 0xCB */
245 Fast486OpcodeInt, /* 0xCC */
246 Fast486OpcodeInt, /* 0xCD */
247 Fast486OpcodeInt, /* 0xCE */
248 Fast486OpcodeIret, /* 0xCF */
249 Fast486OpcodeGroupD0, /* 0xD0 - 0xD3 */
250 Fast486OpcodeGroupD1,
251 Fast486OpcodeGroupD2,
252 Fast486OpcodeGroupD3,
253 Fast486OpcodeAam, /* 0xD4 */
254 Fast486OpcodeAad, /* 0xD5 */
255 Fast486OpcodeSalc, /* 0xD6 */
256 Fast486OpcodeXlat, /* 0xD7 */
257 Fast486FpuOpcodeD8DC, /* 0xD8 - 0xDF */
258 Fast486FpuOpcodeD9,
259 Fast486FpuOpcodeDA,
260 Fast486FpuOpcodeDB,
261 Fast486FpuOpcodeD8DC,
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 BOOLEAN Valid = FALSE;
315
316 switch (Opcode)
317 {
318 /* ES: */
319 case 0x26:
320 {
321 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
322 {
323 State->PrefixFlags |= FAST486_PREFIX_SEG;
324 State->SegmentOverride = FAST486_REG_ES;
325 Valid = TRUE;
326 }
327
328 break;
329 }
330
331 /* CS: */
332 case 0x2E:
333 {
334 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
335 {
336 State->PrefixFlags |= FAST486_PREFIX_SEG;
337 State->SegmentOverride = FAST486_REG_CS;
338 Valid = TRUE;
339 }
340
341 break;
342 }
343
344 /* SS: */
345 case 0x36:
346 {
347 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
348 {
349 State->PrefixFlags |= FAST486_PREFIX_SEG;
350 State->SegmentOverride = FAST486_REG_SS;
351 Valid = TRUE;
352 }
353
354 break;
355 }
356
357 /* DS: */
358 case 0x3E:
359 {
360 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
361 {
362 State->PrefixFlags |= FAST486_PREFIX_SEG;
363 State->SegmentOverride = FAST486_REG_DS;
364 Valid = TRUE;
365 }
366
367 break;
368 }
369
370 /* FS: */
371 case 0x64:
372 {
373 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
374 {
375 State->PrefixFlags |= FAST486_PREFIX_SEG;
376 State->SegmentOverride = FAST486_REG_FS;
377 Valid = TRUE;
378 }
379
380 break;
381 }
382
383 /* GS: */
384 case 0x65:
385 {
386 if (!(State->PrefixFlags & FAST486_PREFIX_SEG))
387 {
388 State->PrefixFlags |= FAST486_PREFIX_SEG;
389 State->SegmentOverride = FAST486_REG_GS;
390 Valid = TRUE;
391 }
392
393 break;
394 }
395
396 /* OPSIZE */
397 case 0x66:
398 {
399 if (!(State->PrefixFlags & FAST486_PREFIX_OPSIZE))
400 {
401 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
402 Valid = TRUE;
403 }
404
405 break;
406 }
407
408 /* ADSIZE */
409 case 0x67:
410 {
411 if (!(State->PrefixFlags & FAST486_PREFIX_ADSIZE))
412 {
413 State->PrefixFlags |= FAST486_PREFIX_ADSIZE;
414 Valid = TRUE;
415 }
416 break;
417 }
418
419 /* LOCK */
420 case 0xF0:
421 {
422 if (!(State->PrefixFlags & FAST486_PREFIX_LOCK))
423 {
424 State->PrefixFlags |= FAST486_PREFIX_LOCK;
425 Valid = TRUE;
426 }
427
428 break;
429 }
430
431 /* REPNZ */
432 case 0xF2:
433 {
434 /* Mutually exclusive with REP */
435 if (!(State->PrefixFlags
436 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
437 {
438 State->PrefixFlags |= FAST486_PREFIX_REPNZ;
439 Valid = TRUE;
440 }
441
442 break;
443 }
444
445 /* REP / REPZ */
446 case 0xF3:
447 {
448 /* Mutually exclusive with REPNZ */
449 if (!(State->PrefixFlags
450 & (FAST486_PREFIX_REPNZ | FAST486_PREFIX_REP)))
451 {
452 State->PrefixFlags |= FAST486_PREFIX_REP;
453 Valid = TRUE;
454 }
455
456 break;
457 }
458 }
459
460 if (!Valid)
461 {
462 /* Clear all prefixes */
463 State->PrefixFlags = 0;
464
465 /* Throw an exception */
466 Fast486Exception(State, FAST486_EXCEPTION_UD);
467 }
468 }
469
470 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement)
471 {
472 ULONG Value;
473 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
474
475 TOGGLE_OPSIZE(Size);
476 NO_LOCK_PREFIX();
477
478 /* Make sure this is the right instruction */
479 ASSERT((Opcode & 0xF8) == 0x40);
480
481 if (Size)
482 {
483 Value = ++State->GeneralRegs[Opcode & 0x07].Long;
484
485 State->Flags.Of = (Value == SIGN_FLAG_LONG);
486 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
487 }
488 else
489 {
490 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
491
492 State->Flags.Of = (Value == SIGN_FLAG_WORD);
493 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
494 }
495
496 State->Flags.Zf = (Value == 0);
497 State->Flags.Af = ((Value & 0x0F) == 0);
498 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
499 }
500
501 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement)
502 {
503 ULONG Value;
504 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
505
506 TOGGLE_OPSIZE(Size);
507 NO_LOCK_PREFIX();
508
509 /* Make sure this is the right instruction */
510 ASSERT((Opcode & 0xF8) == 0x48);
511
512 if (Size)
513 {
514 Value = --State->GeneralRegs[Opcode & 0x07].Long;
515
516 State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1));
517 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
518 }
519 else
520 {
521 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
522
523 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1));
524 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
525 }
526
527 State->Flags.Zf = (Value == 0);
528 State->Flags.Af = ((Value & 0x0F) == 0x0F);
529 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Value));
530 }
531
532 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg)
533 {
534 NO_LOCK_PREFIX();
535
536 /* Make sure this is the right instruction */
537 ASSERT((Opcode & 0xF8) == 0x50);
538
539 /* Call the internal function */
540 Fast486StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
541 }
542
543 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg)
544 {
545 ULONG Value;
546 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
547
548 TOGGLE_OPSIZE(Size);
549 NO_LOCK_PREFIX();
550
551 /* Make sure this is the right instruction */
552 ASSERT((Opcode & 0xF8) == 0x58);
553
554 /* Call the internal function */
555 if (!Fast486StackPop(State, &Value)) return;
556
557 /* Store the value */
558 if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value;
559 else State->GeneralRegs[Opcode & 0x07].LowWord = Value;
560 }
561
562 FAST486_OPCODE_HANDLER(Fast486OpcodeNop)
563 {
564 }
565
566 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax)
567 {
568 INT Reg = Opcode & 0x07;
569 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
570
571 TOGGLE_OPSIZE(Size);
572 NO_LOCK_PREFIX();
573
574 /* Make sure this is the right instruction */
575 ASSERT((Opcode & 0xF8) == 0x90);
576
577 /* Exchange the values */
578 if (Size)
579 {
580 ULONG Value;
581
582 Value = State->GeneralRegs[Reg].Long;
583 State->GeneralRegs[Reg].Long = State->GeneralRegs[FAST486_REG_EAX].Long;
584 State->GeneralRegs[FAST486_REG_EAX].Long = Value;
585 }
586 else
587 {
588 USHORT Value;
589
590 Value = State->GeneralRegs[Reg].LowWord;
591 State->GeneralRegs[Reg].LowWord = State->GeneralRegs[FAST486_REG_EAX].LowWord;
592 State->GeneralRegs[FAST486_REG_EAX].LowWord = Value;
593 }
594 }
595
596 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp)
597 {
598 BOOLEAN Jump = FALSE;
599 CHAR Offset = 0;
600 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
601
602 /* Make sure this is the right instruction */
603 ASSERT((Opcode & 0xF0) == 0x70);
604
605 TOGGLE_OPSIZE(Size);
606
607 /* Fetch the offset */
608 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
609 {
610 /* An exception occurred */
611 return;
612 }
613
614 switch ((Opcode & 0x0F) >> 1)
615 {
616 /* JO / JNO */
617 case 0:
618 {
619 Jump = State->Flags.Of;
620 break;
621 }
622
623 /* JC / JNC */
624 case 1:
625 {
626 Jump = State->Flags.Cf;
627 break;
628 }
629
630 /* JZ / JNZ */
631 case 2:
632 {
633 Jump = State->Flags.Zf;
634 break;
635 }
636
637 /* JBE / JNBE */
638 case 3:
639 {
640 Jump = State->Flags.Cf || State->Flags.Zf;
641 break;
642 }
643
644 /* JS / JNS */
645 case 4:
646 {
647 Jump = State->Flags.Sf;
648 break;
649 }
650
651 /* JP / JNP */
652 case 5:
653 {
654 Jump = State->Flags.Pf;
655 break;
656 }
657
658 /* JL / JNL */
659 case 6:
660 {
661 Jump = State->Flags.Sf != State->Flags.Of;
662 break;
663 }
664
665 /* JLE / JNLE */
666 case 7:
667 {
668 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
669 break;
670 }
671 }
672
673 if (Opcode & 1)
674 {
675 /* Invert the result */
676 Jump = !Jump;
677 }
678
679 if (Jump)
680 {
681 /* Move the instruction pointer */
682 State->InstPtr.Long += Offset;
683
684 if (!Size)
685 {
686 /* Clear the top half of EIP */
687 State->InstPtr.Long &= 0xFFFF;
688 }
689 }
690 }
691
692 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry)
693 {
694 /* Make sure this is the right instruction */
695 ASSERT(Opcode == 0xF8);
696
697 /* No prefixes allowed */
698 if (State->PrefixFlags)
699 {
700 Fast486Exception(State, FAST486_EXCEPTION_UD);
701 return;
702 }
703
704 /* Clear CF and return success */
705 State->Flags.Cf = FALSE;
706 }
707
708 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry)
709 {
710 /* Make sure this is the right instruction */
711 ASSERT(Opcode == 0xF9);
712
713 /* No prefixes allowed */
714 if (State->PrefixFlags)
715 {
716 Fast486Exception(State, FAST486_EXCEPTION_UD);
717 return;
718 }
719
720 /* Set CF and return success*/
721 State->Flags.Cf = TRUE;
722 }
723
724 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry)
725 {
726 /* Make sure this is the right instruction */
727 ASSERT(Opcode == 0xF5);
728
729 /* No prefixes allowed */
730 if (State->PrefixFlags)
731 {
732 Fast486Exception(State, FAST486_EXCEPTION_UD);
733 return;
734 }
735
736 /* Toggle CF and return success */
737 State->Flags.Cf = !State->Flags.Cf;
738 return;
739 }
740
741 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt)
742 {
743 /* Make sure this is the right instruction */
744 ASSERT(Opcode == 0xFA);
745
746 /* No prefixes allowed */
747 if (State->PrefixFlags)
748 {
749 Fast486Exception(State, FAST486_EXCEPTION_UD);
750 return;
751 }
752
753 /* Check for protected mode */
754 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
755 {
756 /* Check IOPL */
757 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
758 {
759 /* Clear the interrupt flag */
760 State->Flags.If = FALSE;
761 }
762 else
763 {
764 /* General Protection Fault */
765 Fast486Exception(State, FAST486_EXCEPTION_GP);
766 return;
767 }
768 }
769 else
770 {
771 /* Just clear the interrupt flag */
772 State->Flags.If = FALSE;
773 }
774 }
775
776 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt)
777 {
778 /* Make sure this is the right instruction */
779 ASSERT(Opcode == 0xFB);
780
781 /* No prefixes allowed */
782 if (State->PrefixFlags)
783 {
784 Fast486Exception(State, FAST486_EXCEPTION_UD);
785 return;
786 }
787
788 /* Check for protected mode */
789 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
790 {
791 /* Check IOPL */
792 if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
793 {
794 /* Set the interrupt flag */
795 State->Flags.If = TRUE;
796 }
797 else
798 {
799 /* General Protection Fault */
800 Fast486Exception(State, FAST486_EXCEPTION_GP);
801 return;
802 }
803 }
804 else
805 {
806 /* Just set the interrupt flag */
807 State->Flags.If = TRUE;
808 }
809 }
810
811 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir)
812 {
813 /* Make sure this is the right instruction */
814 ASSERT(Opcode == 0xFC);
815
816 /* No prefixes allowed */
817 if (State->PrefixFlags)
818 {
819 Fast486Exception(State, FAST486_EXCEPTION_UD);
820 return;
821 }
822
823 /* Clear DF */
824 State->Flags.Df = FALSE;
825 }
826
827 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir)
828 {
829 /* Make sure this is the right instruction */
830 ASSERT(Opcode == 0xFD);
831
832 /* No prefixes allowed */
833 if (State->PrefixFlags)
834 {
835 Fast486Exception(State, FAST486_EXCEPTION_UD);
836 return;
837 }
838
839 /* Set DF */
840 State->Flags.Df = TRUE;
841 }
842
843 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
844 {
845 /* Make sure this is the right instruction */
846 ASSERT(Opcode == 0xF4);
847
848 /* No prefixes allowed */
849 if (State->PrefixFlags)
850 {
851 Fast486Exception(State, FAST486_EXCEPTION_UD);
852 return;
853 }
854
855 /* Privileged instructions can only be executed under CPL = 0 */
856 if (State->SegmentRegs[FAST486_REG_CS].Dpl != 0)
857 {
858 Fast486Exception(State, FAST486_EXCEPTION_GP);
859 return;
860 }
861
862 /* Halt */
863 State->Halted = TRUE;
864 }
865
866 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte)
867 {
868 UCHAR Data;
869 ULONG Port;
870
871 /* Make sure this is the right instruction */
872 ASSERT((Opcode & 0xF7) == 0xE4);
873
874 if (Opcode == 0xE4)
875 {
876 /* Fetch the parameter */
877 if (!Fast486FetchByte(State, &Data))
878 {
879 /* Exception occurred */
880 return;
881 }
882
883 /* Set the port number to the parameter */
884 Port = Data;
885 }
886 else
887 {
888 /* The port number is in DX */
889 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
890 }
891
892 /* Read a byte from the I/O port */
893 State->IoReadCallback(State, Port, &Data, 1, sizeof(UCHAR));
894
895 /* Store the result in AL */
896 State->GeneralRegs[FAST486_REG_EAX].LowByte = Data;
897 }
898
899 FAST486_OPCODE_HANDLER(Fast486OpcodeIn)
900 {
901 ULONG Port;
902 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
903
904 /* Make sure this is the right instruction */
905 ASSERT((Opcode & 0xF7) == 0xE5);
906
907 TOGGLE_OPSIZE(Size);
908 NO_LOCK_PREFIX();
909
910 if (Opcode == 0xE5)
911 {
912 UCHAR Data;
913
914 /* Fetch the parameter */
915 if (!Fast486FetchByte(State, &Data))
916 {
917 /* Exception occurred */
918 return;
919 }
920
921 /* Set the port number to the parameter */
922 Port = Data;
923 }
924 else
925 {
926 /* The port number is in DX */
927 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
928 }
929
930 if (Size)
931 {
932 ULONG Data;
933
934 /* Read a dword from the I/O port */
935 State->IoReadCallback(State, Port, &Data, 1, sizeof(ULONG));
936
937 /* Store the value in EAX */
938 State->GeneralRegs[FAST486_REG_EAX].Long = Data;
939 }
940 else
941 {
942 USHORT Data;
943
944 /* Read a word from the I/O port */
945 State->IoReadCallback(State, Port, &Data, 1, sizeof(USHORT));
946
947 /* Store the value in AX */
948 State->GeneralRegs[FAST486_REG_EAX].LowWord = Data;
949 }
950 }
951
952 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte)
953 {
954 UCHAR Data;
955 ULONG Port;
956
957 /* Make sure this is the right instruction */
958 ASSERT((Opcode & 0xF7) == 0xE6);
959
960 if (Opcode == 0xE6)
961 {
962 /* Fetch the parameter */
963 if (!Fast486FetchByte(State, &Data))
964 {
965 /* Exception occurred */
966 return;
967 }
968
969 /* Set the port number to the parameter */
970 Port = Data;
971 }
972 else
973 {
974 /* The port number is in DX */
975 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
976 }
977
978 /* Read the value from AL */
979 Data = State->GeneralRegs[FAST486_REG_EAX].LowByte;
980
981 /* Write the byte to the I/O port */
982 State->IoWriteCallback(State, Port, &Data, 1, sizeof(UCHAR));
983 }
984
985 FAST486_OPCODE_HANDLER(Fast486OpcodeOut)
986 {
987 ULONG Port;
988 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
989
990 /* Make sure this is the right instruction */
991 ASSERT((Opcode & 0xF7) == 0xE7);
992
993 TOGGLE_OPSIZE(Size);
994 NO_LOCK_PREFIX();
995
996 if (Opcode == 0xE7)
997 {
998 UCHAR Data;
999
1000 /* Fetch the parameter */
1001 if (!Fast486FetchByte(State, &Data))
1002 {
1003 /* Exception occurred */
1004 return;
1005 }
1006
1007 /* Set the port number to the parameter */
1008 Port = Data;
1009 }
1010 else
1011 {
1012 /* The port number is in DX */
1013 Port = State->GeneralRegs[FAST486_REG_EDX].LowWord;
1014 }
1015
1016 if (Size)
1017 {
1018 /* Get the value from EAX */
1019 ULONG Data = State->GeneralRegs[FAST486_REG_EAX].Long;
1020
1021 /* Write a dword to the I/O port */
1022 State->IoWriteCallback(State, Port, &Data, 1, sizeof(ULONG));
1023 }
1024 else
1025 {
1026 /* Get the value from AX */
1027 USHORT Data = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1028
1029 /* Write a word to the I/O port */
1030 State->IoWriteCallback(State, Port, &Data, 1, sizeof(USHORT));
1031 }
1032 }
1033
1034 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump)
1035 {
1036 CHAR Offset = 0;
1037 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1038
1039 TOGGLE_OPSIZE(Size);
1040
1041 /* Make sure this is the right instruction */
1042 ASSERT(Opcode == 0xEB);
1043
1044 /* Fetch the offset */
1045 if (!Fast486FetchByte(State, (PUCHAR)&Offset))
1046 {
1047 /* An exception occurred */
1048 return;
1049 }
1050
1051 /* Move the instruction pointer */
1052 State->InstPtr.Long += Offset;
1053
1054 if (!Size)
1055 {
1056 /* Clear the top half of EIP */
1057 State->InstPtr.Long &= 0xFFFF;
1058 }
1059 }
1060
1061 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm)
1062 {
1063 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1064
1065 /* Make sure this is the right instruction */
1066 ASSERT((Opcode & 0xF8) == 0xB8);
1067
1068 TOGGLE_OPSIZE(Size);
1069 NO_LOCK_PREFIX();
1070
1071 if (Size)
1072 {
1073 ULONG Value;
1074
1075 /* Fetch the dword */
1076 if (!Fast486FetchDword(State, &Value))
1077 {
1078 /* Exception occurred */
1079 return;
1080 }
1081
1082 /* Store the value in the register */
1083 State->GeneralRegs[Opcode & 0x07].Long = Value;
1084 }
1085 else
1086 {
1087 USHORT Value;
1088
1089 /* Fetch the word */
1090 if (!Fast486FetchWord(State, &Value))
1091 {
1092 /* Exception occurred */
1093 return;
1094 }
1095
1096 /* Store the value in the register */
1097 State->GeneralRegs[Opcode & 0x07].LowWord = Value;
1098 }
1099 }
1100
1101 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm)
1102 {
1103 UCHAR Value;
1104
1105 /* Make sure this is the right instruction */
1106 ASSERT((Opcode & 0xF8) == 0xB0);
1107
1108 if (State->PrefixFlags != 0)
1109 {
1110 /* Invalid prefix */
1111 Fast486Exception(State, FAST486_EXCEPTION_UD);
1112 return;
1113 }
1114
1115 /* Fetch the byte */
1116 if (!Fast486FetchByte(State, &Value))
1117 {
1118 /* Exception occurred */
1119 return;
1120 }
1121
1122 if (Opcode & 0x04)
1123 {
1124 /* AH, CH, DH or BH */
1125 State->GeneralRegs[Opcode & 0x03].HighByte = Value;
1126 }
1127 else
1128 {
1129 /* AL, CL, DL or BL */
1130 State->GeneralRegs[Opcode & 0x03].LowByte = Value;
1131 }
1132 }
1133
1134 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm)
1135 {
1136 UCHAR FirstValue, SecondValue, Result;
1137 FAST486_MOD_REG_RM ModRegRm;
1138 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1139
1140 /* Make sure this is the right instruction */
1141 ASSERT((Opcode & 0xFD) == 0x00);
1142
1143 TOGGLE_ADSIZE(AddressSize);
1144
1145 /* Get the operands */
1146 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1147 {
1148 /* Exception occurred */
1149 return;
1150 }
1151
1152 if (!Fast486ReadModrmByteOperands(State,
1153 &ModRegRm,
1154 &FirstValue,
1155 &SecondValue))
1156 {
1157 /* Exception occurred */
1158 return;
1159 }
1160
1161 /* Calculate the result */
1162 Result = FirstValue + SecondValue;
1163
1164 /* Update the flags */
1165 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1166 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1167 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1168 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1169 State->Flags.Zf = (Result == 0);
1170 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1171 State->Flags.Pf = Fast486CalculateParity(Result);
1172
1173 /* Write back the result */
1174 Fast486WriteModrmByteOperands(State,
1175 &ModRegRm,
1176 Opcode & FAST486_OPCODE_WRITE_REG,
1177 Result);
1178 }
1179
1180 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm)
1181 {
1182 FAST486_MOD_REG_RM ModRegRm;
1183 BOOLEAN OperandSize, AddressSize;
1184
1185 /* Make sure this is the right instruction */
1186 ASSERT((Opcode & 0xFD) == 0x01);
1187
1188 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1189
1190 TOGGLE_ADSIZE(AddressSize);
1191 TOGGLE_OPSIZE(OperandSize);
1192
1193 /* Get the operands */
1194 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1195 {
1196 /* Exception occurred */
1197 return;
1198 }
1199
1200 /* Check the operand size */
1201 if (OperandSize)
1202 {
1203 ULONG FirstValue, SecondValue, Result;
1204
1205 if (!Fast486ReadModrmDwordOperands(State,
1206 &ModRegRm,
1207 &FirstValue,
1208 &SecondValue))
1209 {
1210 /* Exception occurred */
1211 return;
1212 }
1213
1214 /* Calculate the result */
1215 Result = FirstValue + SecondValue;
1216
1217 /* Update the flags */
1218 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1219 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1220 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1221 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1222 State->Flags.Zf = (Result == 0);
1223 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1224 State->Flags.Pf = Fast486CalculateParity(Result);
1225
1226 /* Write back the result */
1227 Fast486WriteModrmDwordOperands(State,
1228 &ModRegRm,
1229 Opcode & FAST486_OPCODE_WRITE_REG,
1230 Result);
1231 }
1232 else
1233 {
1234 USHORT FirstValue, SecondValue, Result;
1235
1236 if (!Fast486ReadModrmWordOperands(State,
1237 &ModRegRm,
1238 &FirstValue,
1239 &SecondValue))
1240 {
1241 /* Exception occurred */
1242 return;
1243 }
1244
1245 /* Calculate the result */
1246 Result = FirstValue + SecondValue;
1247
1248 /* Update the flags */
1249 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1250 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1251 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1252 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1253 State->Flags.Zf = (Result == 0);
1254 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1255 State->Flags.Pf = Fast486CalculateParity(Result);
1256
1257 /* Write back the result */
1258 Fast486WriteModrmWordOperands(State,
1259 &ModRegRm,
1260 Opcode & FAST486_OPCODE_WRITE_REG,
1261 Result);
1262 }
1263 }
1264
1265 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl)
1266 {
1267 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1268 UCHAR SecondValue, Result;
1269
1270 /* Make sure this is the right instruction */
1271 ASSERT(Opcode == 0x04);
1272
1273 if (State->PrefixFlags)
1274 {
1275 /* This opcode doesn't take any prefixes */
1276 Fast486Exception(State, FAST486_EXCEPTION_UD);
1277 return;
1278 }
1279
1280 if (!Fast486FetchByte(State, &SecondValue))
1281 {
1282 /* Exception occurred */
1283 return;
1284 }
1285
1286 /* Calculate the result */
1287 Result = FirstValue + SecondValue;
1288
1289 /* Update the flags */
1290 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1291 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1292 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1293 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1294 State->Flags.Zf = (Result == 0);
1295 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1296 State->Flags.Pf = Fast486CalculateParity(Result);
1297
1298 /* Write back the result */
1299 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1300 }
1301
1302 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax)
1303 {
1304 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1305
1306 /* Make sure this is the right instruction */
1307 ASSERT(Opcode == 0x05);
1308
1309 NO_LOCK_PREFIX();
1310 TOGGLE_OPSIZE(Size);
1311
1312 if (Size)
1313 {
1314 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1315 ULONG SecondValue, Result;
1316
1317 if (!Fast486FetchDword(State, &SecondValue))
1318 {
1319 /* Exception occurred */
1320 return;
1321 }
1322
1323 /* Calculate the result */
1324 Result = FirstValue + SecondValue;
1325
1326 /* Update the flags */
1327 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1328 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1329 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1330 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1331 State->Flags.Zf = (Result == 0);
1332 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1333 State->Flags.Pf = Fast486CalculateParity(Result);
1334
1335 /* Write back the result */
1336 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1337 }
1338 else
1339 {
1340 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1341 USHORT SecondValue, Result;
1342
1343 if (!Fast486FetchWord(State, &SecondValue))
1344 {
1345 /* Exception occurred */
1346 return;
1347 }
1348
1349 /* Calculate the result */
1350 Result = FirstValue + SecondValue;
1351
1352 /* Update the flags */
1353 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1354 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1355 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1356 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
1357 State->Flags.Zf = (Result == 0);
1358 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1359 State->Flags.Pf = Fast486CalculateParity(Result);
1360
1361 /* Write back the result */
1362 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1363 }
1364 }
1365
1366 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm)
1367 {
1368 UCHAR FirstValue, SecondValue, Result;
1369 FAST486_MOD_REG_RM ModRegRm;
1370 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1371
1372 /* Make sure this is the right instruction */
1373 ASSERT((Opcode & 0xFD) == 0x08);
1374
1375 TOGGLE_ADSIZE(AddressSize);
1376
1377 /* Get the operands */
1378 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1379 {
1380 /* Exception occurred */
1381 return;
1382 }
1383
1384 if (!Fast486ReadModrmByteOperands(State,
1385 &ModRegRm,
1386 &FirstValue,
1387 &SecondValue))
1388 {
1389 /* Exception occurred */
1390 return;
1391 }
1392
1393 /* Calculate the result */
1394 Result = FirstValue | SecondValue;
1395
1396 /* Update the flags */
1397 State->Flags.Cf = FALSE;
1398 State->Flags.Of = FALSE;
1399 State->Flags.Zf = (Result == 0);
1400 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1401 State->Flags.Pf = Fast486CalculateParity(Result);
1402
1403 /* Write back the result */
1404 Fast486WriteModrmByteOperands(State,
1405 &ModRegRm,
1406 Opcode & FAST486_OPCODE_WRITE_REG,
1407 Result);
1408 }
1409
1410 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm)
1411 {
1412 FAST486_MOD_REG_RM ModRegRm;
1413 BOOLEAN OperandSize, AddressSize;
1414
1415 /* Make sure this is the right instruction */
1416 ASSERT((Opcode & 0xFD) == 0x09);
1417
1418 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1419
1420 TOGGLE_ADSIZE(AddressSize);
1421 TOGGLE_OPSIZE(OperandSize);
1422
1423 /* Get the operands */
1424 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1425 {
1426 /* Exception occurred */
1427 return;
1428 }
1429
1430 /* Check the operand size */
1431 if (OperandSize)
1432 {
1433 ULONG FirstValue, SecondValue, Result;
1434
1435 if (!Fast486ReadModrmDwordOperands(State,
1436 &ModRegRm,
1437 &FirstValue,
1438 &SecondValue))
1439 {
1440 /* Exception occurred */
1441 return;
1442 }
1443
1444 /* Calculate the result */
1445 Result = FirstValue | SecondValue;
1446
1447 /* Update the flags */
1448 State->Flags.Cf = FALSE;
1449 State->Flags.Of = FALSE;
1450 State->Flags.Zf = (Result == 0);
1451 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1452 State->Flags.Pf = Fast486CalculateParity(Result);
1453
1454 /* Write back the result */
1455 Fast486WriteModrmDwordOperands(State,
1456 &ModRegRm,
1457 Opcode & FAST486_OPCODE_WRITE_REG,
1458 Result);
1459 }
1460 else
1461 {
1462 USHORT FirstValue, SecondValue, Result;
1463
1464 if (!Fast486ReadModrmWordOperands(State,
1465 &ModRegRm,
1466 &FirstValue,
1467 &SecondValue))
1468 {
1469 /* Exception occurred */
1470 return;
1471 }
1472
1473 /* Calculate the result */
1474 Result = FirstValue | SecondValue;
1475
1476 /* Update the flags */
1477 State->Flags.Cf = FALSE;
1478 State->Flags.Of = FALSE;
1479 State->Flags.Zf = (Result == 0);
1480 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1481 State->Flags.Pf = Fast486CalculateParity(Result);
1482
1483 /* Write back the result */
1484 Fast486WriteModrmWordOperands(State,
1485 &ModRegRm,
1486 Opcode & FAST486_OPCODE_WRITE_REG,
1487 Result);
1488 }
1489 }
1490
1491 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl)
1492 {
1493 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1494 UCHAR SecondValue, Result;
1495
1496 /* Make sure this is the right instruction */
1497 ASSERT(Opcode == 0x0C);
1498
1499 if (State->PrefixFlags)
1500 {
1501 /* This opcode doesn't take any prefixes */
1502 Fast486Exception(State, FAST486_EXCEPTION_UD);
1503 return;
1504 }
1505
1506 if (!Fast486FetchByte(State, &SecondValue))
1507 {
1508 /* Exception occurred */
1509 return;
1510 }
1511
1512 /* Calculate the result */
1513 Result = FirstValue | SecondValue;
1514
1515 /* Update the flags */
1516 State->Flags.Cf = FALSE;
1517 State->Flags.Of = FALSE;
1518 State->Flags.Zf = (Result == 0);
1519 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1520 State->Flags.Pf = Fast486CalculateParity(Result);
1521
1522 /* Write back the result */
1523 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1524 }
1525
1526 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax)
1527 {
1528 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1529
1530 /* Make sure this is the right instruction */
1531 ASSERT(Opcode == 0x0D);
1532
1533 NO_LOCK_PREFIX();
1534 TOGGLE_OPSIZE(Size);
1535
1536 if (Size)
1537 {
1538 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1539 ULONG SecondValue, Result;
1540
1541 if (!Fast486FetchDword(State, &SecondValue))
1542 {
1543 /* Exception occurred */
1544 return;
1545 }
1546
1547 /* Calculate the result */
1548 Result = FirstValue | SecondValue;
1549
1550 /* Update the flags */
1551 State->Flags.Cf = FALSE;
1552 State->Flags.Of = FALSE;
1553 State->Flags.Zf = (Result == 0);
1554 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1555 State->Flags.Pf = Fast486CalculateParity(Result);
1556
1557 /* Write back the result */
1558 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1559 }
1560 else
1561 {
1562 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1563 USHORT SecondValue, Result;
1564
1565 if (!Fast486FetchWord(State, &SecondValue))
1566 {
1567 /* Exception occurred */
1568 return;
1569 }
1570
1571 /* Calculate the result */
1572 Result = FirstValue | SecondValue;
1573
1574 /* Update the flags */
1575 State->Flags.Cf = FALSE;
1576 State->Flags.Of = FALSE;
1577 State->Flags.Zf = (Result == 0);
1578 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1579 State->Flags.Pf = Fast486CalculateParity(Result);
1580
1581 /* Write back the result */
1582 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1583 }
1584 }
1585
1586 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm)
1587 {
1588 UCHAR FirstValue, SecondValue, Result;
1589 FAST486_MOD_REG_RM ModRegRm;
1590 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1591
1592 /* Make sure this is the right instruction */
1593 ASSERT((Opcode & 0xFD) == 0x20);
1594
1595 TOGGLE_ADSIZE(AddressSize);
1596
1597 /* Get the operands */
1598 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1599 {
1600 /* Exception occurred */
1601 return;
1602 }
1603
1604 if (!Fast486ReadModrmByteOperands(State,
1605 &ModRegRm,
1606 &FirstValue,
1607 &SecondValue))
1608 {
1609 /* Exception occurred */
1610 return;
1611 }
1612
1613 /* Calculate the result */
1614 Result = FirstValue & SecondValue;
1615
1616 /* Update the flags */
1617 State->Flags.Cf = FALSE;
1618 State->Flags.Of = FALSE;
1619 State->Flags.Zf = (Result == 0);
1620 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1621 State->Flags.Pf = Fast486CalculateParity(Result);
1622
1623 /* Write back the result */
1624 Fast486WriteModrmByteOperands(State,
1625 &ModRegRm,
1626 Opcode & FAST486_OPCODE_WRITE_REG,
1627 Result);
1628 }
1629
1630 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm)
1631 {
1632 FAST486_MOD_REG_RM ModRegRm;
1633 BOOLEAN OperandSize, AddressSize;
1634
1635 /* Make sure this is the right instruction */
1636 ASSERT((Opcode & 0xFD) == 0x21);
1637
1638 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1639
1640 TOGGLE_ADSIZE(AddressSize);
1641 TOGGLE_OPSIZE(OperandSize);
1642
1643 /* Get the operands */
1644 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1645 {
1646 /* Exception occurred */
1647 return;
1648 }
1649
1650 /* Check the operand size */
1651 if (OperandSize)
1652 {
1653 ULONG FirstValue, SecondValue, Result;
1654
1655 if (!Fast486ReadModrmDwordOperands(State,
1656 &ModRegRm,
1657 &FirstValue,
1658 &SecondValue))
1659 {
1660 /* Exception occurred */
1661 return;
1662 }
1663
1664 /* Calculate the result */
1665 Result = FirstValue & SecondValue;
1666
1667 /* Update the flags */
1668 State->Flags.Cf = FALSE;
1669 State->Flags.Of = FALSE;
1670 State->Flags.Zf = (Result == 0);
1671 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1672 State->Flags.Pf = Fast486CalculateParity(Result);
1673
1674 /* Write back the result */
1675 Fast486WriteModrmDwordOperands(State,
1676 &ModRegRm,
1677 Opcode & FAST486_OPCODE_WRITE_REG,
1678 Result);
1679 }
1680 else
1681 {
1682 USHORT FirstValue, SecondValue, Result;
1683
1684 if (!Fast486ReadModrmWordOperands(State,
1685 &ModRegRm,
1686 &FirstValue,
1687 &SecondValue))
1688 {
1689 /* Exception occurred */
1690 return;
1691 }
1692
1693 /* Calculate the result */
1694 Result = FirstValue & SecondValue;
1695
1696 /* Update the flags */
1697 State->Flags.Cf = FALSE;
1698 State->Flags.Of = FALSE;
1699 State->Flags.Zf = (Result == 0);
1700 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1701 State->Flags.Pf = Fast486CalculateParity(Result);
1702
1703 /* Write back the result */
1704 Fast486WriteModrmWordOperands(State,
1705 &ModRegRm,
1706 Opcode & FAST486_OPCODE_WRITE_REG,
1707 Result);
1708 }
1709 }
1710
1711 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl)
1712 {
1713 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1714 UCHAR SecondValue, Result;
1715
1716 /* Make sure this is the right instruction */
1717 ASSERT(Opcode == 0x24);
1718
1719 NO_LOCK_PREFIX();
1720
1721 if (!Fast486FetchByte(State, &SecondValue))
1722 {
1723 /* Exception occurred */
1724 return;
1725 }
1726
1727 /* Calculate the result */
1728 Result = FirstValue & SecondValue;
1729
1730 /* Update the flags */
1731 State->Flags.Cf = FALSE;
1732 State->Flags.Of = FALSE;
1733 State->Flags.Zf = (Result == 0);
1734 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1735 State->Flags.Pf = Fast486CalculateParity(Result);
1736
1737 /* Write back the result */
1738 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1739 }
1740
1741 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax)
1742 {
1743 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1744
1745 /* Make sure this is the right instruction */
1746 ASSERT(Opcode == 0x25);
1747
1748 NO_LOCK_PREFIX();
1749 TOGGLE_OPSIZE(Size);
1750
1751 if (Size)
1752 {
1753 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1754 ULONG SecondValue, Result;
1755
1756 if (!Fast486FetchDword(State, &SecondValue))
1757 {
1758 /* Exception occurred */
1759 return;
1760 }
1761
1762 /* Calculate the result */
1763 Result = FirstValue & SecondValue;
1764
1765 /* Update the flags */
1766 State->Flags.Cf = FALSE;
1767 State->Flags.Of = FALSE;
1768 State->Flags.Zf = (Result == 0);
1769 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1770 State->Flags.Pf = Fast486CalculateParity(Result);
1771
1772 /* Write back the result */
1773 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1774 }
1775 else
1776 {
1777 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1778 USHORT SecondValue, Result;
1779
1780 if (!Fast486FetchWord(State, &SecondValue))
1781 {
1782 /* Exception occurred */
1783 return;
1784 }
1785
1786 /* Calculate the result */
1787 Result = FirstValue & SecondValue;
1788
1789 /* Update the flags */
1790 State->Flags.Cf = FALSE;
1791 State->Flags.Of = FALSE;
1792 State->Flags.Zf = (Result == 0);
1793 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1794 State->Flags.Pf = Fast486CalculateParity(Result);
1795
1796 /* Write back the result */
1797 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
1798 }
1799 }
1800
1801 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm)
1802 {
1803 UCHAR FirstValue, SecondValue, Result;
1804 FAST486_MOD_REG_RM ModRegRm;
1805 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1806
1807 /* Make sure this is the right instruction */
1808 ASSERT((Opcode & 0xFD) == 0x30);
1809
1810 TOGGLE_ADSIZE(AddressSize);
1811
1812 /* Get the operands */
1813 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1814 {
1815 /* Exception occurred */
1816 return;
1817 }
1818
1819 if (!Fast486ReadModrmByteOperands(State,
1820 &ModRegRm,
1821 &FirstValue,
1822 &SecondValue))
1823 {
1824 /* Exception occurred */
1825 return;
1826 }
1827
1828 /* Calculate the result */
1829 Result = FirstValue ^ SecondValue;
1830
1831 /* Update the flags */
1832 State->Flags.Cf = FALSE;
1833 State->Flags.Of = FALSE;
1834 State->Flags.Zf = (Result == 0);
1835 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1836 State->Flags.Pf = Fast486CalculateParity(Result);
1837
1838 /* Write back the result */
1839 Fast486WriteModrmByteOperands(State,
1840 &ModRegRm,
1841 Opcode & FAST486_OPCODE_WRITE_REG,
1842 Result);
1843 }
1844
1845 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm)
1846 {
1847 FAST486_MOD_REG_RM ModRegRm;
1848 BOOLEAN OperandSize, AddressSize;
1849
1850 /* Make sure this is the right instruction */
1851 ASSERT((Opcode & 0xFD) == 0x31);
1852
1853 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1854
1855 TOGGLE_ADSIZE(AddressSize);
1856 TOGGLE_OPSIZE(OperandSize);
1857
1858 /* Get the operands */
1859 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1860 {
1861 /* Exception occurred */
1862 return;
1863 }
1864
1865 /* Check the operand size */
1866 if (OperandSize)
1867 {
1868 ULONG FirstValue, SecondValue, Result;
1869
1870 if (!Fast486ReadModrmDwordOperands(State,
1871 &ModRegRm,
1872 &FirstValue,
1873 &SecondValue))
1874 {
1875 /* Exception occurred */
1876 return;
1877 }
1878
1879 /* Calculate the result */
1880 Result = FirstValue ^ SecondValue;
1881
1882 /* Update the flags */
1883 State->Flags.Cf = FALSE;
1884 State->Flags.Of = FALSE;
1885 State->Flags.Zf = (Result == 0);
1886 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1887 State->Flags.Pf = Fast486CalculateParity(Result);
1888
1889 /* Write back the result */
1890 Fast486WriteModrmDwordOperands(State,
1891 &ModRegRm,
1892 Opcode & FAST486_OPCODE_WRITE_REG,
1893 Result);
1894 }
1895 else
1896 {
1897 USHORT FirstValue, SecondValue, Result;
1898
1899 if (!Fast486ReadModrmWordOperands(State,
1900 &ModRegRm,
1901 &FirstValue,
1902 &SecondValue))
1903 {
1904 /* Exception occurred */
1905 return;
1906 }
1907
1908 /* Calculate the result */
1909 Result = FirstValue ^ SecondValue;
1910
1911 /* Update the flags */
1912 State->Flags.Cf = FALSE;
1913 State->Flags.Of = FALSE;
1914 State->Flags.Zf = (Result == 0);
1915 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1916 State->Flags.Pf = Fast486CalculateParity(Result);
1917
1918 /* Write back the result */
1919 Fast486WriteModrmWordOperands(State,
1920 &ModRegRm,
1921 Opcode & FAST486_OPCODE_WRITE_REG,
1922 Result);
1923 }
1924 }
1925
1926 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl)
1927 {
1928 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
1929 UCHAR SecondValue, Result;
1930
1931 /* Make sure this is the right instruction */
1932 ASSERT(Opcode == 0x34);
1933
1934 if (State->PrefixFlags)
1935 {
1936 /* This opcode doesn't take any prefixes */
1937 Fast486Exception(State, FAST486_EXCEPTION_UD);
1938 return;
1939 }
1940
1941 if (!Fast486FetchByte(State, &SecondValue))
1942 {
1943 /* Exception occurred */
1944 return;
1945 }
1946
1947 /* Calculate the result */
1948 Result = FirstValue ^ SecondValue;
1949
1950 /* Update the flags */
1951 State->Flags.Cf = FALSE;
1952 State->Flags.Of = FALSE;
1953 State->Flags.Zf = (Result == 0);
1954 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1955 State->Flags.Pf = Fast486CalculateParity(Result);
1956
1957 /* Write back the result */
1958 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
1959 }
1960
1961 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax)
1962 {
1963 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1964
1965 /* Make sure this is the right instruction */
1966 ASSERT(Opcode == 0x35);
1967
1968 NO_LOCK_PREFIX();
1969 TOGGLE_OPSIZE(Size);
1970
1971 if (Size)
1972 {
1973 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
1974 ULONG SecondValue, Result;
1975
1976 if (!Fast486FetchDword(State, &SecondValue))
1977 {
1978 /* Exception occurred */
1979 return;
1980 }
1981
1982 /* Calculate the result */
1983 Result = FirstValue ^ SecondValue;
1984
1985 /* Update the flags */
1986 State->Flags.Cf = FALSE;
1987 State->Flags.Of = FALSE;
1988 State->Flags.Zf = (Result == 0);
1989 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1990 State->Flags.Pf = Fast486CalculateParity(Result);
1991
1992 /* Write back the result */
1993 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
1994 }
1995 else
1996 {
1997 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
1998 USHORT SecondValue, Result;
1999
2000 if (!Fast486FetchWord(State, &SecondValue))
2001 {
2002 /* Exception occurred */
2003 return;
2004 }
2005
2006 /* Calculate the result */
2007 Result = FirstValue ^ SecondValue;
2008
2009 /* Update the flags */
2010 State->Flags.Cf = FALSE;
2011 State->Flags.Of = FALSE;
2012 State->Flags.Zf = (Result == 0);
2013 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2014 State->Flags.Pf = Fast486CalculateParity(Result);
2015
2016 /* Write back the result */
2017 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2018 }
2019 }
2020
2021 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm)
2022 {
2023 UCHAR FirstValue, SecondValue, Result;
2024 FAST486_MOD_REG_RM ModRegRm;
2025 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2026
2027 /* Make sure this is the right instruction */
2028 ASSERT(Opcode == 0x84);
2029
2030 TOGGLE_ADSIZE(AddressSize);
2031
2032 /* Get the operands */
2033 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2034 {
2035 /* Exception occurred */
2036 return;
2037 }
2038
2039 if (!Fast486ReadModrmByteOperands(State,
2040 &ModRegRm,
2041 &FirstValue,
2042 &SecondValue))
2043 {
2044 /* Exception occurred */
2045 return;
2046 }
2047 /* Calculate the result */
2048 Result = FirstValue & SecondValue;
2049
2050 /* Update the flags */
2051 State->Flags.Cf = FALSE;
2052 State->Flags.Of = FALSE;
2053 State->Flags.Zf = (Result == 0);
2054 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2055 State->Flags.Pf = Fast486CalculateParity(Result);
2056 }
2057
2058 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm)
2059 {
2060 FAST486_MOD_REG_RM ModRegRm;
2061 BOOLEAN OperandSize, AddressSize;
2062
2063 /* Make sure this is the right instruction */
2064 ASSERT(Opcode == 0x85);
2065
2066 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2067
2068 TOGGLE_ADSIZE(AddressSize);
2069 TOGGLE_OPSIZE(OperandSize);
2070
2071 /* Get the operands */
2072 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2073 {
2074 /* Exception occurred */
2075 return;
2076 }
2077
2078 /* Check the operand size */
2079 if (OperandSize)
2080 {
2081 ULONG FirstValue, SecondValue, Result;
2082
2083 if (!Fast486ReadModrmDwordOperands(State,
2084 &ModRegRm,
2085 &FirstValue,
2086 &SecondValue))
2087 {
2088 /* Exception occurred */
2089 return;
2090 }
2091
2092 /* Calculate the result */
2093 Result = FirstValue & SecondValue;
2094
2095 /* Update the flags */
2096 State->Flags.Cf = FALSE;
2097 State->Flags.Of = FALSE;
2098 State->Flags.Zf = (Result == 0);
2099 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2100 State->Flags.Pf = Fast486CalculateParity(Result);
2101 }
2102 else
2103 {
2104 USHORT FirstValue, SecondValue, Result;
2105
2106 if (!Fast486ReadModrmWordOperands(State,
2107 &ModRegRm,
2108 &FirstValue,
2109 &SecondValue))
2110 {
2111 /* Exception occurred */
2112 return;
2113 }
2114
2115 /* Calculate the result */
2116 Result = FirstValue & SecondValue;
2117
2118 /* Update the flags */
2119 State->Flags.Cf = FALSE;
2120 State->Flags.Of = FALSE;
2121 State->Flags.Zf = (Result == 0);
2122 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2123 State->Flags.Pf = Fast486CalculateParity(Result);
2124 }
2125 }
2126
2127 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl)
2128 {
2129 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2130 UCHAR SecondValue, Result;
2131
2132 /* Make sure this is the right instruction */
2133 ASSERT(Opcode == 0xA8);
2134
2135 if (State->PrefixFlags)
2136 {
2137 /* This opcode doesn't take any prefixes */
2138 Fast486Exception(State, FAST486_EXCEPTION_UD);
2139 return;
2140 }
2141
2142 if (!Fast486FetchByte(State, &SecondValue))
2143 {
2144 /* Exception occurred */
2145 return;
2146 }
2147
2148 /* Calculate the result */
2149 Result = FirstValue & SecondValue;
2150
2151 /* Update the flags */
2152 State->Flags.Cf = FALSE;
2153 State->Flags.Of = FALSE;
2154 State->Flags.Zf = (Result == 0);
2155 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2156 State->Flags.Pf = Fast486CalculateParity(Result);
2157 }
2158
2159 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax)
2160 {
2161 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2162
2163 /* Make sure this is the right instruction */
2164 ASSERT(Opcode == 0xA9);
2165
2166 NO_LOCK_PREFIX();
2167 TOGGLE_OPSIZE(Size);
2168
2169 if (Size)
2170 {
2171 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2172 ULONG SecondValue, Result;
2173
2174 if (!Fast486FetchDword(State, &SecondValue))
2175 {
2176 /* Exception occurred */
2177 return;
2178 }
2179
2180 /* Calculate the result */
2181 Result = FirstValue & SecondValue;
2182
2183 /* Update the flags */
2184 State->Flags.Cf = FALSE;
2185 State->Flags.Of = FALSE;
2186 State->Flags.Zf = (Result == 0);
2187 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2188 State->Flags.Pf = Fast486CalculateParity(Result);
2189 }
2190 else
2191 {
2192 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2193 USHORT SecondValue, Result;
2194
2195 if (!Fast486FetchWord(State, &SecondValue))
2196 {
2197 /* Exception occurred */
2198 return;
2199 }
2200
2201 /* Calculate the result */
2202 Result = FirstValue & SecondValue;
2203
2204 /* Update the flags */
2205 State->Flags.Cf = FALSE;
2206 State->Flags.Of = FALSE;
2207 State->Flags.Zf = (Result == 0);
2208 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2209 State->Flags.Pf = Fast486CalculateParity(Result);
2210 }
2211 }
2212
2213 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm)
2214 {
2215 UCHAR FirstValue, SecondValue;
2216 FAST486_MOD_REG_RM ModRegRm;
2217 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2218
2219 /* Make sure this is the right instruction */
2220 ASSERT(Opcode == 0x86);
2221
2222 TOGGLE_ADSIZE(AddressSize);
2223
2224 /* Get the operands */
2225 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2226 {
2227 /* Exception occurred */
2228 return;
2229 }
2230
2231 if (!Fast486ReadModrmByteOperands(State,
2232 &ModRegRm,
2233 &FirstValue,
2234 &SecondValue))
2235 {
2236 /* Exception occurred */
2237 return;
2238 }
2239
2240 /* Write the value from the register to the R/M */
2241 if (!Fast486WriteModrmByteOperands(State,
2242 &ModRegRm,
2243 FALSE,
2244 FirstValue))
2245 {
2246 /* Exception occurred */
2247 return;
2248 }
2249
2250 /* Write the value from the R/M to the register */
2251 Fast486WriteModrmByteOperands(State,
2252 &ModRegRm,
2253 TRUE,
2254 SecondValue);
2255 }
2256
2257 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm)
2258 {
2259 FAST486_MOD_REG_RM ModRegRm;
2260 BOOLEAN OperandSize, AddressSize;
2261
2262 /* Make sure this is the right instruction */
2263 ASSERT(Opcode == 0x87);
2264
2265 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2266
2267 TOGGLE_ADSIZE(AddressSize);
2268 TOGGLE_OPSIZE(OperandSize);
2269
2270 /* Get the operands */
2271 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2272 {
2273 /* Exception occurred */
2274 return;
2275 }
2276
2277 /* Check the operand size */
2278 if (OperandSize)
2279 {
2280 ULONG FirstValue, SecondValue;
2281
2282 if (!Fast486ReadModrmDwordOperands(State,
2283 &ModRegRm,
2284 &FirstValue,
2285 &SecondValue))
2286 {
2287 /* Exception occurred */
2288 return;
2289 }
2290
2291 /* Write the value from the register to the R/M */
2292 if (!Fast486WriteModrmDwordOperands(State,
2293 &ModRegRm,
2294 FALSE,
2295 FirstValue))
2296 {
2297 /* Exception occurred */
2298 return;
2299 }
2300
2301 /* Write the value from the R/M to the register */
2302 Fast486WriteModrmDwordOperands(State,
2303 &ModRegRm,
2304 TRUE,
2305 SecondValue);
2306 }
2307 else
2308 {
2309 USHORT FirstValue, SecondValue;
2310
2311 if (!Fast486ReadModrmWordOperands(State,
2312 &ModRegRm,
2313 &FirstValue,
2314 &SecondValue))
2315 {
2316 /* Exception occurred */
2317 return;
2318 }
2319
2320 /* Write the value from the register to the R/M */
2321 if (!Fast486WriteModrmWordOperands(State,
2322 &ModRegRm,
2323 FALSE,
2324 FirstValue))
2325 {
2326 /* Exception occurred */
2327 return;
2328 }
2329
2330 /* Write the value from the R/M to the register */
2331 Fast486WriteModrmWordOperands(State,
2332 &ModRegRm,
2333 TRUE,
2334 SecondValue);
2335 }
2336 }
2337
2338 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs)
2339 {
2340 /* Call the internal API */
2341 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector);
2342 }
2343
2344 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs)
2345 {
2346 ULONG NewSelector;
2347
2348 if (!Fast486StackPop(State, &NewSelector))
2349 {
2350 /* Exception occurred */
2351 return;
2352 }
2353
2354 /* Call the internal API */
2355 Fast486LoadSegment(State, FAST486_REG_ES, LOWORD(NewSelector));
2356 }
2357
2358 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs)
2359 {
2360 /* Call the internal API */
2361 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector);
2362 }
2363
2364 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm)
2365 {
2366 UCHAR FirstValue, SecondValue, Result;
2367 FAST486_MOD_REG_RM ModRegRm;
2368 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2369
2370 /* Make sure this is the right instruction */
2371 ASSERT((Opcode & 0xFD) == 0x10);
2372
2373 TOGGLE_ADSIZE(AddressSize);
2374
2375 /* Get the operands */
2376 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2377 {
2378 /* Exception occurred */
2379 return;
2380 }
2381
2382 if (!Fast486ReadModrmByteOperands(State,
2383 &ModRegRm,
2384 &FirstValue,
2385 &SecondValue))
2386 {
2387 /* Exception occurred */
2388 return;
2389 }
2390
2391 /* Calculate the result */
2392 Result = FirstValue + SecondValue + State->Flags.Cf;
2393
2394 /* Special exception for CF */
2395 State->Flags.Cf = State->Flags.Cf
2396 && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2397
2398 /* Update the flags */
2399 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2400 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2401 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2402 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2403 State->Flags.Zf = (Result == 0);
2404 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2405 State->Flags.Pf = Fast486CalculateParity(Result);
2406
2407 /* Write back the result */
2408 Fast486WriteModrmByteOperands(State,
2409 &ModRegRm,
2410 Opcode & FAST486_OPCODE_WRITE_REG,
2411 Result);
2412 }
2413
2414 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm)
2415 {
2416 FAST486_MOD_REG_RM ModRegRm;
2417 BOOLEAN OperandSize, AddressSize;
2418
2419 /* Make sure this is the right instruction */
2420 ASSERT((Opcode & 0xFD) == 0x11);
2421
2422 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2423
2424 TOGGLE_ADSIZE(AddressSize);
2425 TOGGLE_OPSIZE(OperandSize);
2426
2427 /* Get the operands */
2428 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2429 {
2430 /* Exception occurred */
2431 return;
2432 }
2433
2434 /* Check the operand size */
2435 if (OperandSize)
2436 {
2437 ULONG FirstValue, SecondValue, Result;
2438
2439 if (!Fast486ReadModrmDwordOperands(State,
2440 &ModRegRm,
2441 &FirstValue,
2442 &SecondValue))
2443 {
2444 /* Exception occurred */
2445 return;
2446 }
2447
2448 /* Calculate the result */
2449 Result = FirstValue + SecondValue + State->Flags.Cf;
2450
2451 /* Special exception for CF */
2452 State->Flags.Cf = State->Flags.Cf
2453 && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2454
2455 /* Update the flags */
2456 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2457 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2458 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2459 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2460 State->Flags.Zf = (Result == 0);
2461 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2462 State->Flags.Pf = Fast486CalculateParity(Result);
2463
2464 /* Write back the result */
2465 Fast486WriteModrmDwordOperands(State,
2466 &ModRegRm,
2467 Opcode & FAST486_OPCODE_WRITE_REG,
2468 Result);
2469 }
2470 else
2471 {
2472 USHORT FirstValue, SecondValue, Result;
2473
2474 if (!Fast486ReadModrmWordOperands(State,
2475 &ModRegRm,
2476 &FirstValue,
2477 &SecondValue))
2478 {
2479 /* Exception occurred */
2480 return;
2481 }
2482
2483 /* Calculate the result */
2484 Result = FirstValue + SecondValue + State->Flags.Cf;
2485
2486 /* Special exception for CF */
2487 State->Flags.Cf = State->Flags.Cf
2488 && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2489
2490 /* Update the flags */
2491 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2492 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2493 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2494 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2495 State->Flags.Zf = (Result == 0);
2496 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2497 State->Flags.Pf = Fast486CalculateParity(Result);
2498
2499 /* Write back the result */
2500 Fast486WriteModrmWordOperands(State,
2501 &ModRegRm,
2502 Opcode & FAST486_OPCODE_WRITE_REG,
2503 Result);
2504 }
2505
2506 }
2507
2508 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl)
2509 {
2510 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2511 UCHAR SecondValue, Result;
2512
2513 /* Make sure this is the right instruction */
2514 ASSERT(Opcode == 0x14);
2515
2516 if (State->PrefixFlags)
2517 {
2518 /* This opcode doesn't take any prefixes */
2519 Fast486Exception(State, FAST486_EXCEPTION_UD);
2520 return;
2521 }
2522
2523 if (!Fast486FetchByte(State, &SecondValue))
2524 {
2525 /* Exception occurred */
2526 return;
2527 }
2528
2529 /* Calculate the result */
2530 Result = FirstValue + SecondValue + State->Flags.Cf;
2531
2532 /* Special exception for CF */
2533 State->Flags.Cf = State->Flags.Cf &&
2534 ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2535
2536 /* Update the flags */
2537 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2538 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2539 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2540 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2541 State->Flags.Zf = (Result == 0);
2542 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2543 State->Flags.Pf = Fast486CalculateParity(Result);
2544
2545 /* Write back the result */
2546 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2547 }
2548
2549 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax)
2550 {
2551 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2552
2553 /* Make sure this is the right instruction */
2554 ASSERT(Opcode == 0x15);
2555
2556 NO_LOCK_PREFIX();
2557 TOGGLE_OPSIZE(Size);
2558
2559 if (Size)
2560 {
2561 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2562 ULONG SecondValue, Result;
2563
2564 if (!Fast486FetchDword(State, &SecondValue))
2565 {
2566 /* Exception occurred */
2567 return;
2568 }
2569
2570 /* Calculate the result */
2571 Result = FirstValue + SecondValue + State->Flags.Cf;
2572
2573 /* Special exception for CF */
2574 State->Flags.Cf = State->Flags.Cf &&
2575 ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2576
2577 /* Update the flags */
2578 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2579 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2580 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2581 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2582 State->Flags.Zf = (Result == 0);
2583 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2584 State->Flags.Pf = Fast486CalculateParity(Result);
2585
2586 /* Write back the result */
2587 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2588 }
2589 else
2590 {
2591 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2592 USHORT SecondValue, Result;
2593
2594 if (!Fast486FetchWord(State, &SecondValue))
2595 {
2596 /* Exception occurred */
2597 return;
2598 }
2599
2600 /* Calculate the result */
2601 Result = FirstValue + SecondValue + State->Flags.Cf;
2602
2603 /* Special exception for CF */
2604 State->Flags.Cf = State->Flags.Cf &&
2605 ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2606
2607 /* Update the flags */
2608 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2609 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2610 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2611 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2612 State->Flags.Zf = (Result == 0);
2613 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2614 State->Flags.Pf = Fast486CalculateParity(Result);
2615
2616 /* Write back the result */
2617 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2618 }
2619 }
2620
2621 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs)
2622 {
2623 /* Call the internal API */
2624 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_SS].Selector);
2625 }
2626
2627 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs)
2628 {
2629 ULONG NewSelector;
2630
2631 if (!Fast486StackPop(State, &NewSelector))
2632 {
2633 /* Exception occurred */
2634 return;
2635 }
2636
2637 /* Call the internal API */
2638 Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector));
2639 }
2640
2641 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
2642 {
2643 UCHAR FirstValue, SecondValue, Result;
2644 FAST486_MOD_REG_RM ModRegRm;
2645 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2646 INT Carry = State->Flags.Cf ? 1 : 0;
2647
2648 /* Make sure this is the right instruction */
2649 ASSERT((Opcode & 0xFD) == 0x18);
2650
2651 TOGGLE_ADSIZE(AddressSize);
2652
2653 /* Get the operands */
2654 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2655 {
2656 /* Exception occurred */
2657 return;
2658 }
2659
2660 if (!Fast486ReadModrmByteOperands(State,
2661 &ModRegRm,
2662 &FirstValue,
2663 &SecondValue))
2664 {
2665 /* Exception occurred */
2666 return;
2667 }
2668
2669 /* Check if this is the instruction that writes to R/M */
2670 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2671 {
2672 /* Swap the order */
2673 SWAP(FirstValue, SecondValue);
2674 }
2675
2676 /* Calculate the result */
2677 Result = FirstValue - SecondValue - Carry;
2678
2679 /* Update the flags */
2680 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2681 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2682 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2683 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2684 State->Flags.Zf = (Result == 0);
2685 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2686 State->Flags.Pf = Fast486CalculateParity(Result);
2687
2688 /* Write back the result */
2689 Fast486WriteModrmByteOperands(State,
2690 &ModRegRm,
2691 Opcode & FAST486_OPCODE_WRITE_REG,
2692 Result);
2693 }
2694
2695 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm)
2696 {
2697 FAST486_MOD_REG_RM ModRegRm;
2698 BOOLEAN OperandSize, AddressSize;
2699 INT Carry = State->Flags.Cf ? 1 : 0;
2700
2701 /* Make sure this is the right instruction */
2702 ASSERT((Opcode & 0xFD) == 0x19);
2703
2704 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2705
2706 TOGGLE_ADSIZE(AddressSize);
2707 TOGGLE_OPSIZE(OperandSize);
2708
2709 /* Get the operands */
2710 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2711 {
2712 /* Exception occurred */
2713 return;
2714 }
2715
2716 /* Check the operand size */
2717 if (OperandSize)
2718 {
2719 ULONG FirstValue, SecondValue, Result;
2720
2721 if (!Fast486ReadModrmDwordOperands(State,
2722 &ModRegRm,
2723 &FirstValue,
2724 &SecondValue))
2725 {
2726 /* Exception occurred */
2727 return;
2728 }
2729
2730 /* Check if this is the instruction that writes to R/M */
2731 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2732 {
2733 /* Swap the order */
2734 SWAP(FirstValue, SecondValue);
2735 }
2736
2737 /* Calculate the result */
2738 Result = FirstValue - SecondValue - Carry;
2739
2740 /* Update the flags */
2741 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2742 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2743 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2744 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2745 State->Flags.Zf = (Result == 0);
2746 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2747 State->Flags.Pf = Fast486CalculateParity(Result);
2748
2749 /* Write back the result */
2750 Fast486WriteModrmDwordOperands(State,
2751 &ModRegRm,
2752 Opcode & FAST486_OPCODE_WRITE_REG,
2753 Result);
2754 }
2755 else
2756 {
2757 USHORT FirstValue, SecondValue, Result;
2758
2759 if (!Fast486ReadModrmWordOperands(State,
2760 &ModRegRm,
2761 &FirstValue,
2762 &SecondValue))
2763 {
2764 /* Exception occurred */
2765 return;
2766 }
2767
2768 /* Check if this is the instruction that writes to R/M */
2769 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2770 {
2771 /* Swap the order */
2772 SWAP(FirstValue, SecondValue);
2773 }
2774
2775 /* Calculate the result */
2776 Result = FirstValue - SecondValue - Carry;
2777
2778 /* Update the flags */
2779 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2780 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2781 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2782 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2783 State->Flags.Zf = (Result == 0);
2784 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2785 State->Flags.Pf = Fast486CalculateParity(Result);
2786
2787 /* Write back the result */
2788 Fast486WriteModrmWordOperands(State,
2789 &ModRegRm,
2790 Opcode & FAST486_OPCODE_WRITE_REG,
2791 Result);
2792 }
2793 }
2794
2795 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl)
2796 {
2797 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2798 UCHAR SecondValue, Result;
2799 INT Carry = State->Flags.Cf ? 1 : 0;
2800
2801 /* Make sure this is the right instruction */
2802 ASSERT(Opcode == 0x1C);
2803
2804 if (State->PrefixFlags)
2805 {
2806 /* This opcode doesn't take any prefixes */
2807 Fast486Exception(State, FAST486_EXCEPTION_UD);
2808 return;
2809 }
2810
2811 if (!Fast486FetchByte(State, &SecondValue))
2812 {
2813 /* Exception occurred */
2814 return;
2815 }
2816
2817 /* Calculate the result */
2818 Result = FirstValue - SecondValue - Carry;
2819
2820 /* Update the flags */
2821 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2822 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2823 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2824 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2825 State->Flags.Zf = (Result == 0);
2826 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
2827 State->Flags.Pf = Fast486CalculateParity(Result);
2828
2829 /* Write back the result */
2830 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
2831 }
2832
2833 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax)
2834 {
2835 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
2836 INT Carry = State->Flags.Cf ? 1 : 0;
2837
2838 /* Make sure this is the right instruction */
2839 ASSERT(Opcode == 0x1D);
2840
2841 NO_LOCK_PREFIX();
2842 TOGGLE_OPSIZE(Size);
2843
2844 if (Size)
2845 {
2846 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
2847 ULONG SecondValue, Result;
2848
2849 if (!Fast486FetchDword(State, &SecondValue))
2850 {
2851 /* Exception occurred */
2852 return;
2853 }
2854
2855 /* Calculate the result */
2856 Result = FirstValue - SecondValue - Carry;
2857
2858 /* Update the flags */
2859 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2860 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
2861 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2862 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2863 State->Flags.Zf = (Result == 0);
2864 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
2865 State->Flags.Pf = Fast486CalculateParity(Result);
2866
2867 /* Write back the result */
2868 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
2869 }
2870 else
2871 {
2872 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
2873 USHORT SecondValue, Result;
2874
2875 if (!Fast486FetchWord(State, &SecondValue))
2876 {
2877 /* Exception occurred */
2878 return;
2879 }
2880
2881 /* Calculate the result */
2882 Result = FirstValue - SecondValue - Carry;
2883
2884 /* Update the flags */
2885 State->Flags.Cf = Carry ? (FirstValue <= SecondValue) : (FirstValue < SecondValue);
2886 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
2887 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2888 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
2889 State->Flags.Zf = (Result == 0);
2890 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
2891 State->Flags.Pf = Fast486CalculateParity(Result);
2892
2893 /* Write back the result */
2894 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
2895 }
2896 }
2897
2898 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs)
2899 {
2900 /* Call the internal API */
2901 Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector);
2902 }
2903
2904 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs)
2905 {
2906 ULONG NewSelector;
2907
2908 if (!Fast486StackPop(State, &NewSelector))
2909 {
2910 /* Exception occurred */
2911 return;
2912 }
2913
2914 /* Call the internal API */
2915 Fast486LoadSegment(State, FAST486_REG_DS, LOWORD(NewSelector));
2916 }
2917
2918 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa)
2919 {
2920 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2921 BOOLEAN Carry = State->Flags.Cf;
2922
2923 /* Clear the carry flag */
2924 State->Flags.Cf = FALSE;
2925
2926 /* Check if the first BCD digit is invalid or there was a carry from it */
2927 if (((Value & 0x0F) > 9) || State->Flags.Af)
2928 {
2929 /* Correct it */
2930 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x06;
2931 if (State->GeneralRegs[FAST486_REG_EAX].LowByte < 0x06)
2932 {
2933 /* A carry occurred */
2934 State->Flags.Cf = TRUE;
2935 }
2936
2937 /* Set the adjust flag */
2938 State->Flags.Af = TRUE;
2939 }
2940
2941 /* Check if the second BCD digit is invalid or there was a carry from it */
2942 if ((Value > 0x99) || Carry)
2943 {
2944 /* Correct it */
2945 State->GeneralRegs[FAST486_REG_EAX].LowByte += 0x60;
2946
2947 /* There was a carry */
2948 State->Flags.Cf = TRUE;
2949 }
2950
2951 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
2952
2953 /* Update the flags */
2954 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
2955 State->Flags.Zf = (Value == 0);
2956 State->Flags.Pf = Fast486CalculateParity(Value);
2957 }
2958
2959 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm)
2960 {
2961 UCHAR FirstValue, SecondValue, Result;
2962 FAST486_MOD_REG_RM ModRegRm;
2963 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2964
2965 /* Make sure this is the right instruction */
2966 ASSERT((Opcode & 0xED) == 0x28);
2967
2968 TOGGLE_ADSIZE(AddressSize);
2969
2970 /* Get the operands */
2971 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2972 {
2973 /* Exception occurred */
2974 return;
2975 }
2976
2977 if (!Fast486ReadModrmByteOperands(State,
2978 &ModRegRm,
2979 &FirstValue,
2980 &SecondValue))
2981 {
2982 /* Exception occurred */
2983 return;
2984 }
2985
2986 /* Check if this is the instruction that writes to R/M */
2987 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
2988 {
2989 /* Swap the order */
2990 SWAP(FirstValue, SecondValue);
2991 }
2992
2993 /* Calculate the result */
2994 Result = FirstValue - SecondValue;
2995
2996 /* Update the flags */
2997 State->Flags.Cf = (FirstValue < SecondValue);
2998 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
2999 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3000 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3001 State->Flags.Zf = (Result == 0);
3002 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3003 State->Flags.Pf = Fast486CalculateParity(Result);
3004
3005 /* Check if this is not a CMP */
3006 if (!(Opcode & 0x10))
3007 {
3008 /* Write back the result */
3009 Fast486WriteModrmByteOperands(State,
3010 &ModRegRm,
3011 Opcode & FAST486_OPCODE_WRITE_REG,
3012 Result);
3013 }
3014 }
3015
3016 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm)
3017 {
3018 FAST486_MOD_REG_RM ModRegRm;
3019 BOOLEAN OperandSize, AddressSize;
3020
3021 /* Make sure this is the right instruction */
3022 ASSERT((Opcode & 0xED) == 0x29);
3023
3024 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3025
3026 TOGGLE_ADSIZE(AddressSize);
3027 TOGGLE_OPSIZE(OperandSize);
3028
3029 /* Get the operands */
3030 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3031 {
3032 /* Exception occurred */
3033 return;
3034 }
3035
3036 /* Check the operand size */
3037 if (OperandSize)
3038 {
3039 ULONG FirstValue, SecondValue, Result;
3040
3041 if (!Fast486ReadModrmDwordOperands(State,
3042 &ModRegRm,
3043 &FirstValue,
3044 &SecondValue))
3045 {
3046 /* Exception occurred */
3047 return;
3048 }
3049
3050 /* Check if this is the instruction that writes to R/M */
3051 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3052 {
3053 /* Swap the order */
3054 SWAP(FirstValue, SecondValue);
3055 }
3056
3057 /* Calculate the result */
3058 Result = FirstValue - SecondValue;
3059
3060 /* Update the flags */
3061 State->Flags.Cf = (FirstValue < SecondValue);
3062 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3063 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3064 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3065 State->Flags.Zf = (Result == 0);
3066 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3067 State->Flags.Pf = Fast486CalculateParity(Result);
3068
3069 /* Check if this is not a CMP */
3070 if (!(Opcode & 0x10))
3071 {
3072 /* Write back the result */
3073 Fast486WriteModrmDwordOperands(State,
3074 &ModRegRm,
3075 Opcode & FAST486_OPCODE_WRITE_REG,
3076 Result);
3077 }
3078 }
3079 else
3080 {
3081 USHORT FirstValue, SecondValue, Result;
3082
3083 if (!Fast486ReadModrmWordOperands(State,
3084 &ModRegRm,
3085 &FirstValue,
3086 &SecondValue))
3087 {
3088 /* Exception occurred */
3089 return;
3090 }
3091
3092 /* Check if this is the instruction that writes to R/M */
3093 if (!(Opcode & FAST486_OPCODE_WRITE_REG))
3094 {
3095 /* Swap the order */
3096 SWAP(FirstValue, SecondValue);
3097 }
3098
3099 /* Calculate the result */
3100 Result = FirstValue - SecondValue;
3101
3102 /* Update the flags */
3103 State->Flags.Cf = (FirstValue < SecondValue);
3104 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3105 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3106 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3107 State->Flags.Zf = (Result == 0);
3108 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3109 State->Flags.Pf = Fast486CalculateParity(Result);
3110
3111 /* Check if this is not a CMP */
3112 if (!(Opcode & 0x10))
3113 {
3114 /* Write back the result */
3115 Fast486WriteModrmWordOperands(State,
3116 &ModRegRm,
3117 Opcode & FAST486_OPCODE_WRITE_REG,
3118 Result);
3119 }
3120 }
3121 }
3122
3123 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl)
3124 {
3125 UCHAR FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3126 UCHAR SecondValue, Result;
3127
3128 /* Make sure this is the right instruction */
3129 ASSERT((Opcode & 0xEF) == 0x2C);
3130
3131 if (State->PrefixFlags)
3132 {
3133 /* This opcode doesn't take any prefixes */
3134 Fast486Exception(State, FAST486_EXCEPTION_UD);
3135 return;
3136 }
3137
3138 if (!Fast486FetchByte(State, &SecondValue))
3139 {
3140 /* Exception occurred */
3141 return;
3142 }
3143
3144 /* Calculate the result */
3145 Result = FirstValue - SecondValue;
3146
3147 /* Update the flags */
3148 State->Flags.Cf = (FirstValue < SecondValue);
3149 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3150 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3151 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3152 State->Flags.Zf = (Result == 0);
3153 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
3154 State->Flags.Pf = Fast486CalculateParity(Result);
3155
3156 /* Check if this is not a CMP */
3157 if (!(Opcode & 0x10))
3158 {
3159 /* Write back the result */
3160 State->GeneralRegs[FAST486_REG_EAX].LowByte = Result;
3161 }
3162 }
3163
3164 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax)
3165 {
3166 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3167
3168 /* Make sure this is the right instruction */
3169 ASSERT((Opcode & 0xEF) == 0x2D);
3170
3171 NO_LOCK_PREFIX();
3172 TOGGLE_OPSIZE(Size);
3173
3174 if (Size)
3175 {
3176 ULONG FirstValue = State->GeneralRegs[FAST486_REG_EAX].Long;
3177 ULONG SecondValue, Result;
3178
3179 if (!Fast486FetchDword(State, &SecondValue))
3180 {
3181 /* Exception occurred */
3182 return;
3183 }
3184
3185 /* Calculate the result */
3186 Result = FirstValue - SecondValue;
3187
3188 /* Update the flags */
3189 State->Flags.Cf = (FirstValue < SecondValue);
3190 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3191 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3192 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3193 State->Flags.Zf = (Result == 0);
3194 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
3195 State->Flags.Pf = Fast486CalculateParity(Result);
3196
3197 /* Check if this is not a CMP */
3198 if (!(Opcode & 0x10))
3199 {
3200 /* Write back the result */
3201 State->GeneralRegs[FAST486_REG_EAX].Long = Result;
3202 }
3203 }
3204 else
3205 {
3206 USHORT FirstValue = State->GeneralRegs[FAST486_REG_EAX].LowWord;
3207 USHORT SecondValue, Result;
3208
3209 if (!Fast486FetchWord(State, &SecondValue))
3210 {
3211 /* Exception occurred */
3212 return;
3213 }
3214
3215 /* Calculate the result */
3216 Result = FirstValue - SecondValue;
3217
3218 /* Update the flags */
3219 State->Flags.Cf = (FirstValue < SecondValue);
3220 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3221 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3222 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3223 State->Flags.Zf = (Result == 0);
3224 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
3225 State->Flags.Pf = Fast486CalculateParity(Result);
3226
3227 /* Check if this is not a CMP */
3228 if (!(Opcode & 0x10))
3229 {
3230 /* Write back the result */
3231 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
3232 }
3233 }
3234 }
3235
3236 FAST486_OPCODE_HANDLER(Fast486OpcodeDas)
3237 {
3238 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3239 BOOLEAN Carry = State->Flags.Cf;
3240
3241 /* Clear the carry flag */
3242 State->Flags.Cf = FALSE;
3243
3244 /* Check if the first BCD digit is invalid or there was a borrow */
3245 if (((Value & 0x0F) > 9) || State->Flags.Af)
3246 {
3247 /* Correct it */
3248 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x06;
3249 if (State->GeneralRegs[FAST486_REG_EAX].LowByte > 0xFB)
3250 {
3251 /* A borrow occurred */
3252 State->Flags.Cf = TRUE;
3253 }
3254
3255 /* Set the adjust flag */
3256 State->Flags.Af = TRUE;
3257 }
3258
3259 /* Check if the second BCD digit is invalid or there was a borrow */
3260 if ((Value > 0x99) || Carry)
3261 {
3262 /* Correct it */
3263 State->GeneralRegs[FAST486_REG_EAX].LowByte -= 0x60;
3264
3265 /* There was a borrow */
3266 State->Flags.Cf = TRUE;
3267 }
3268
3269 Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3270
3271 /* Update the flags */
3272 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) != 0;
3273 State->Flags.Zf = (Value == 0);
3274 State->Flags.Pf = Fast486CalculateParity(Value);
3275 }
3276
3277 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa)
3278 {
3279 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3280
3281 /*
3282 * Check if the value in AL is not a valid BCD digit,
3283 * or there was a carry from the lowest 4 bits of AL
3284 */
3285 if (((Value & 0x0F) > 9) || State->Flags.Af)
3286 {
3287 /* Correct it */
3288 State->GeneralRegs[FAST486_REG_EAX].LowWord += 0x06;
3289 State->GeneralRegs[FAST486_REG_EAX].HighByte++;
3290
3291 /* Set CF and AF */
3292 State->Flags.Cf = State->Flags.Af = TRUE;
3293 }
3294 else
3295 {
3296 /* Clear CF and AF */
3297 State->Flags.Cf = State->Flags.Af = FALSE;
3298 }
3299
3300 /* Keep only the lowest 4 bits of AL */
3301 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3302 }
3303
3304 FAST486_OPCODE_HANDLER(Fast486OpcodeAas)
3305 {
3306 UCHAR Value = State->GeneralRegs[FAST486_REG_EAX].LowByte;
3307
3308 /*
3309 * Check if the value in AL is not a valid BCD digit,
3310 * or there was a borrow from the lowest 4 bits of AL
3311 */
3312 if (((Value & 0x0F) > 9) || State->Flags.Af)
3313 {
3314 /* Correct it */
3315 State->GeneralRegs[FAST486_REG_EAX].LowWord -= 0x06;
3316 State->GeneralRegs[FAST486_REG_EAX].HighByte--;
3317
3318 /* Set CF and AF */
3319 State->Flags.Cf = State->Flags.Af = TRUE;
3320 }
3321 else
3322 {
3323 /* Clear CF and AF */
3324 State->Flags.Cf = State->Flags.Af = FALSE;
3325 }
3326
3327 /* Keep only the lowest 4 bits of AL */
3328 State->GeneralRegs[FAST486_REG_EAX].LowByte &= 0x0F;
3329 }
3330
3331 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll)
3332 {
3333 INT i;
3334 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3335 FAST486_REG SavedEsp = State->GeneralRegs[FAST486_REG_ESP];
3336
3337 /* Make sure this is the right instruction */
3338 ASSERT(Opcode == 0x60);
3339
3340 TOGGLE_OPSIZE(Size);
3341 NO_LOCK_PREFIX();
3342
3343 /* Push all the registers in order */
3344 for (i = 0; i < FAST486_NUM_GEN_REGS; i++)
3345 {
3346 if (i == FAST486_REG_ESP)
3347 {
3348 /* Use the saved ESP instead */
3349 if (!Fast486StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
3350 {
3351 /* Exception occurred */
3352 return;
3353 }
3354 }
3355 else
3356 {
3357 /* Push the register */
3358 if (!Fast486StackPush(State, Size ? State->GeneralRegs[i].Long
3359 : State->GeneralRegs[i].LowWord))
3360 {
3361 /* Exception occurred */
3362 return;
3363 }
3364 }
3365 }
3366 }
3367
3368 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll)
3369 {
3370 INT i;
3371 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
3372 ULONG Value;
3373
3374 /* Make sure this is the right instruction */
3375 ASSERT(Opcode == 0x61);
3376
3377 TOGGLE_OPSIZE(Size);
3378 NO_LOCK_PREFIX();
3379
3380 /* Pop all the registers in reverse order */
3381 for (i = FAST486_NUM_GEN_REGS - 1; i >= 0; i--)
3382 {
3383 /* Pop the value */
3384 if (!Fast486StackPop(State, &Value))
3385 {
3386 /* Exception occurred */
3387 return;
3388 }
3389
3390 /* Don't modify ESP */
3391 if (i != FAST486_REG_ESP)
3392 {
3393 if (Size) State->GeneralRegs[i].Long = Value;
3394 else State->GeneralRegs[i].LowWord = LOWORD(Value);
3395 }
3396 }
3397 }
3398
3399 FAST486_OPCODE_HANDLER(Fast486OpcodeBound)
3400 {
3401 BOOLEAN OperandSize, AddressSize;
3402 FAST486_MOD_REG_RM ModRegRm;
3403 FAST486_SEG_REGS Segment = FAST486_REG_DS;
3404
3405 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
3406
3407 NO_LOCK_PREFIX();
3408 TOGGLE_OPSIZE(OperandSize);
3409 TOGGLE_ADSIZE(AddressSize);
3410
3411 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
3412 {
3413 /* Exception occurred */
3414 return;
3415 }
3416
3417 if (!ModRegRm.Memory)
3418 {
3419 /* Invalid */
3420 Fast486Exception(State, FAST486_EXCEPTION_UD);
3421 return;
3422 }
3423
3424 /* Check for the segment override */
3425 if (State->PrefixFlags & FAST486_PREFIX_SEG)
3426 {
3427 /* Use the override segment instead */
3428 Segment = State->SegmentOverride;
3429 }
3430
3431 if (OperandSize)
3432 {
3433 LONG Index, LowerBound, UpperBound;
3434
3435 /* Read the operands */
3436 if (!Fast486ReadModrmDwordOperands(State,
3437 &ModRegRm,
3438 (PULONG)&Index,
3439 (PULONG)&LowerBound))
3440 {
3441 /* Exception occurred */
3442 return;
3443 }
3444
3445 if (!Fast486ReadMemory(State,
3446 Segment,
3447 ModRegRm.MemoryAddress + sizeof(ULONG),
3448 FALSE,
3449 &UpperBound,
3450 sizeof(ULONG)))
3451 {
3452 /* Exception occurred */
3453 return;
3454 }
3455
3456 if ((Index < LowerBound) || (Index > UpperBound))
3457 {
3458 /* Out of bounds */
3459 Fast486Exception(State, FAST486_EXCEPTION_BR);
3460 }
3461 }
3462 else
3463 {
3464 SHORT Index, LowerBound, UpperBound;
3465
3466 /* Read the operands */
3467 if (!Fast486ReadModrmWordOperands(State,
3468 &ModRegRm,
3469 (PUSHORT)&Index,
3470 (PUSHORT)&LowerBound))
3471 {
3472 /* Exception occurred */
3473 return;
3474 }
3475
3476 if (!Fast486ReadMemory(State,
3477 Segment,
3478 ModRegRm.MemoryAddress + sizeof(USHORT),
3479 FALSE,