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