a36bea1e84175eb0a5b6c69a16adb41549732fdb
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32 #include "opgroups.h"
33 #include "extraops.h"
34
35 /* PUBLIC VARIABLES ***********************************************************/
36
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
39 {
40 NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
41 Fast486OpcodeGroup0F01,
42 NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
43 NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
44 NULL, // TODO: OPCODE 0x04 NOT IMPLEMENTED
45 NULL, // TODO: OPCODE 0x05 NOT IMPLEMENTED
46 Fast486ExtOpcodeClts,
47 NULL, // TODO: OPCODE 0x07 NOT IMPLEMENTED
48 NULL, // TODO: OPCODE 0x08 NOT IMPLEMENTED
49 NULL, // TODO: OPCODE 0x09 NOT IMPLEMENTED
50 NULL, // Invalid
51 NULL, // Reserved (UD1)
52 NULL, // Invalid
53 NULL, // Invalid
54 NULL, // Invalid
55 NULL, // Invalid
56 NULL, // TODO: OPCODE 0x10 NOT IMPLEMENTED
57 NULL, // TODO: OPCODE 0x11 NOT IMPLEMENTED
58 NULL, // TODO: OPCODE 0x12 NOT IMPLEMENTED
59 NULL, // TODO: OPCODE 0x13 NOT IMPLEMENTED
60 NULL, // Invalid
61 NULL, // Invalid
62 NULL, // Invalid
63 NULL, // Invalid
64 NULL, // Invalid
65 NULL, // Invalid
66 NULL, // Invalid
67 NULL, // Invalid
68 NULL, // Invalid
69 NULL, // Invalid
70 NULL, // Invalid
71 NULL, // Invalid
72 Fast486ExtOpcodeStoreControlReg,
73 Fast486ExtOpcodeStoreDebugReg,
74 Fast486ExtOpcodeLoadControlReg,
75 Fast486ExtOpcodeLoadDebugReg,
76 NULL, // TODO: OPCODE 0x24 NOT IMPLEMENTED
77 NULL, // Invalid
78 NULL, // TODO: OPCODE 0x26 NOT IMPLEMENTED
79 NULL, // Invalid
80 NULL, // Invalid
81 NULL, // Invalid
82 NULL, // Invalid
83 NULL, // Invalid
84 NULL, // Invalid
85 NULL, // Invalid
86 NULL, // Invalid
87 NULL, // Invalid
88 NULL, // Invalid
89 NULL, // Invalid
90 NULL, // Invalid
91 NULL, // Invalid
92 NULL, // Invalid
93 NULL, // Invalid
94 NULL, // Invalid
95 NULL, // Invalid
96 NULL, // Invalid
97 NULL, // Invalid
98 NULL, // Invalid
99 NULL, // Invalid
100 NULL, // Invalid
101 NULL, // Invalid
102 NULL, // Invalid
103 NULL, // Invalid
104 NULL, // Invalid
105 NULL, // Invalid
106 NULL, // Invalid
107 NULL, // Invalid
108 NULL, // Invalid
109 NULL, // Invalid
110 NULL, // Invalid
111 NULL, // Invalid
112 NULL, // Invalid
113 NULL, // Invalid
114 NULL, // Invalid
115 NULL, // Invalid
116 NULL, // Invalid
117 NULL, // Invalid
118 NULL, // Invalid
119 NULL, // Invalid
120 NULL, // Invalid
121 NULL, // Invalid
122 NULL, // Invalid
123 NULL, // Invalid
124 NULL, // Invalid
125 NULL, // Invalid
126 NULL, // Invalid
127 NULL, // Invalid
128 NULL, // Invalid
129 NULL, // Invalid
130 NULL, // Invalid
131 NULL, // Invalid
132 NULL, // Invalid
133 NULL, // Invalid
134 NULL, // Invalid
135 NULL, // Invalid
136 NULL, // Invalid
137 NULL, // Invalid
138 NULL, // Invalid
139 NULL, // Invalid
140 NULL, // Invalid
141 NULL, // Invalid
142 NULL, // Invalid
143 NULL, // Invalid
144 NULL, // Invalid
145 NULL, // Invalid
146 NULL, // Invalid
147 NULL, // Invalid
148 NULL, // Invalid
149 NULL, // Invalid
150 NULL, // Invalid
151 NULL, // Invalid
152 NULL, // Invalid
153 NULL, // Invalid
154 NULL, // Invalid
155 NULL, // Invalid
156 NULL, // Invalid
157 NULL, // Invalid
158 NULL, // Invalid
159 NULL, // Invalid
160 NULL, // Invalid
161 NULL, // Invalid
162 NULL, // Invalid
163 NULL, // Invalid
164 NULL, // Invalid
165 NULL, // Invalid
166 NULL, // Invalid
167 NULL, // Invalid
168 Fast486ExtOpcodeConditionalJmp,
169 Fast486ExtOpcodeConditionalJmp,
170 Fast486ExtOpcodeConditionalJmp,
171 Fast486ExtOpcodeConditionalJmp,
172 Fast486ExtOpcodeConditionalJmp,
173 Fast486ExtOpcodeConditionalJmp,
174 Fast486ExtOpcodeConditionalJmp,
175 Fast486ExtOpcodeConditionalJmp,
176 Fast486ExtOpcodeConditionalJmp,
177 Fast486ExtOpcodeConditionalJmp,
178 Fast486ExtOpcodeConditionalJmp,
179 Fast486ExtOpcodeConditionalJmp,
180 Fast486ExtOpcodeConditionalJmp,
181 Fast486ExtOpcodeConditionalJmp,
182 Fast486ExtOpcodeConditionalJmp,
183 Fast486ExtOpcodeConditionalJmp,
184 Fast486ExtOpcodeConditionalSet,
185 Fast486ExtOpcodeConditionalSet,
186 Fast486ExtOpcodeConditionalSet,
187 Fast486ExtOpcodeConditionalSet,
188 Fast486ExtOpcodeConditionalSet,
189 Fast486ExtOpcodeConditionalSet,
190 Fast486ExtOpcodeConditionalSet,
191 Fast486ExtOpcodeConditionalSet,
192 Fast486ExtOpcodeConditionalSet,
193 Fast486ExtOpcodeConditionalSet,
194 Fast486ExtOpcodeConditionalSet,
195 Fast486ExtOpcodeConditionalSet,
196 Fast486ExtOpcodeConditionalSet,
197 Fast486ExtOpcodeConditionalSet,
198 Fast486ExtOpcodeConditionalSet,
199 Fast486ExtOpcodeConditionalSet,
200 Fast486ExtOpcodePushFs,
201 Fast486ExtOpcodePopFs,
202 NULL, // Invalid
203 Fast486ExtOpcodeBitTest,
204 NULL, // TODO: OPCODE 0xA4 NOT IMPLEMENTED
205 NULL, // TODO: OPCODE 0xA5 NOT IMPLEMENTED
206 NULL, // Invalid
207 NULL, // Invalid
208 Fast486ExtOpcodePushGs,
209 Fast486ExtOpcodePopGs,
210 NULL, // Invalid
211 Fast486ExtOpcodeBts,
212 NULL, // TODO: OPCODE 0xAC NOT IMPLEMENTED
213 NULL, // TODO: OPCODE 0xAD NOT IMPLEMENTED
214 NULL, // TODO: OPCODE 0xAE NOT IMPLEMENTED
215 NULL, // TODO: OPCODE 0xAF NOT IMPLEMENTED
216 Fast486ExtOpcodeCmpXchgByte,
217 Fast486ExtOpcodeCmpXchg,
218 NULL, // TODO: OPCODE 0xB2 NOT IMPLEMENTED
219 Fast486ExtOpcodeBtr,
220 NULL, // TODO: OPCODE 0xB4 NOT IMPLEMENTED
221 NULL, // TODO: OPCODE 0xB5 NOT IMPLEMENTED
222 NULL, // TODO: OPCODE 0xB6 NOT IMPLEMENTED
223 NULL, // TODO: OPCODE 0xB7 NOT IMPLEMENTED
224 NULL, // TODO: OPCODE 0xB8 NOT IMPLEMENTED
225 Fast486OpcodeGroup0FB9,
226 Fast486OpcodeGroup0FBA,
227 Fast486ExtOpcodeBtc,
228 Fast486ExtOpcodeBsf,
229 Fast486ExtOpcodeBsr,
230 Fast486ExtOpcodeMovsxByte,
231 Fast486ExtOpcodeMovsxWord,
232 Fast486ExtOpcodeXaddByte,
233 Fast486ExtOpcodeXadd,
234 NULL, // Invalid
235 NULL, // Invalid
236 NULL, // Invalid
237 NULL, // Invalid
238 NULL, // Invalid
239 NULL, // Invalid
240 Fast486ExtOpcodeBswap,
241 Fast486ExtOpcodeBswap,
242 Fast486ExtOpcodeBswap,
243 Fast486ExtOpcodeBswap,
244 Fast486ExtOpcodeBswap,
245 Fast486ExtOpcodeBswap,
246 Fast486ExtOpcodeBswap,
247 Fast486ExtOpcodeBswap,
248 NULL, // Invalid
249 NULL, // Invalid
250 NULL, // Invalid
251 NULL, // Invalid
252 NULL, // Invalid
253 NULL, // Invalid
254 NULL, // Invalid
255 NULL, // Invalid
256 NULL, // Invalid
257 NULL, // Invalid
258 NULL, // Invalid
259 NULL, // Invalid
260 NULL, // Invalid
261 NULL, // Invalid
262 NULL, // Invalid
263 NULL, // Invalid
264 NULL, // Invalid
265 NULL, // Invalid
266 NULL, // Invalid
267 NULL, // Invalid
268 NULL, // Invalid
269 NULL, // Invalid
270 NULL, // Invalid
271 NULL, // Invalid
272 NULL, // Invalid
273 NULL, // Invalid
274 NULL, // Invalid
275 NULL, // Invalid
276 NULL, // Invalid
277 NULL, // Invalid
278 NULL, // Invalid
279 NULL, // Invalid
280 NULL, // Invalid
281 NULL, // Invalid
282 NULL, // Invalid
283 NULL, // Invalid
284 NULL, // Invalid
285 NULL, // Invalid
286 NULL, // Invalid
287 NULL, // Invalid
288 NULL, // Invalid
289 NULL, // Invalid
290 NULL, // Invalid
291 NULL, // Invalid
292 NULL, // Invalid
293 NULL, // Invalid
294 NULL, // Invalid
295 NULL, // Invalid
296 };
297
298 /* PUBLIC FUNCTIONS ***********************************************************/
299
300 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeClts)
301 {
302 NO_LOCK_PREFIX();
303
304 /* The current privilege level must be zero */
305 if (Fast486GetCurrentPrivLevel(State) != 0)
306 {
307 Fast486Exception(State, FAST486_EXCEPTION_GP);
308 return FALSE;
309 }
310
311 /* Clear the task switch bit */
312 State->ControlRegisters[FAST486_REG_CR0] &= ~FAST486_CR0_TS;
313
314 return TRUE;
315 }
316
317 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreControlReg)
318 {
319 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
320 FAST486_MOD_REG_RM ModRegRm;
321
322 NO_LOCK_PREFIX();
323 TOGGLE_ADSIZE(AddressSize);
324
325 /* Get the operands */
326 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
327 {
328 /* Exception occurred */
329 return FALSE;
330 }
331
332 /* The current privilege level must be zero */
333 if (Fast486GetCurrentPrivLevel(State) != 0)
334 {
335 Fast486Exception(State, FAST486_EXCEPTION_GP);
336 return FALSE;
337 }
338
339 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
340 {
341 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
342 Fast486Exception(State, FAST486_EXCEPTION_UD);
343 return FALSE;
344 }
345
346 if (ModRegRm.Register != 0)
347 {
348 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
349 ModRegRm.Register--;
350 }
351
352 /* Store the value of the control register */
353 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->ControlRegisters[ModRegRm.Register];
354
355 /* Return success */
356 return TRUE;
357 }
358
359 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeStoreDebugReg)
360 {
361 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
362 FAST486_MOD_REG_RM ModRegRm;
363
364 NO_LOCK_PREFIX();
365 TOGGLE_ADSIZE(AddressSize);
366
367 /* Get the operands */
368 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
369 {
370 /* Exception occurred */
371 return FALSE;
372 }
373
374 /* The current privilege level must be zero */
375 if (Fast486GetCurrentPrivLevel(State) != 0)
376 {
377 Fast486Exception(State, FAST486_EXCEPTION_GP);
378 return FALSE;
379 }
380
381 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
382 {
383 /* DR6 and DR7 are aliases to DR4 and DR5 */
384 ModRegRm.Register -= 2;
385 }
386
387 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
388 {
389 /* Disallow access to debug registers */
390 Fast486Exception(State, FAST486_EXCEPTION_GP);
391 return FALSE;
392 }
393
394 /* Store the value of the debug register */
395 State->GeneralRegs[ModRegRm.SecondRegister].Long = State->DebugRegisters[ModRegRm.Register];
396
397 /* Return success */
398 return TRUE;
399 }
400
401 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadControlReg)
402 {
403 ULONG Value;
404 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
405 FAST486_MOD_REG_RM ModRegRm;
406
407 NO_LOCK_PREFIX();
408 TOGGLE_ADSIZE(AddressSize);
409
410 /* Get the operands */
411 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
412 {
413 /* Exception occurred */
414 return FALSE;
415 }
416
417 /* The current privilege level must be zero */
418 if (Fast486GetCurrentPrivLevel(State) != 0)
419 {
420 Fast486Exception(State, FAST486_EXCEPTION_GP);
421 return FALSE;
422 }
423
424 if ((ModRegRm.Register == 1) || (ModRegRm.Register > 3))
425 {
426 /* CR1, CR4, CR5, CR6 and CR7 don't exist */
427 Fast486Exception(State, FAST486_EXCEPTION_UD);
428 return FALSE;
429 }
430
431 if (ModRegRm.Register != 0)
432 {
433 /* CR2 and CR3 and are stored in array indexes 1 and 2 */
434 ModRegRm.Register--;
435 }
436
437 /* Get the value */
438 Value = State->GeneralRegs[ModRegRm.SecondRegister].Long;
439
440 if (ModRegRm.Register == (INT)FAST486_REG_CR0)
441 {
442 /* CR0 checks */
443
444 if (((Value & (FAST486_CR0_PG | FAST486_CR0_PE)) == FAST486_CR0_PG)
445 || ((Value & (FAST486_CR0_CD | FAST486_CR0_NW)) == FAST486_CR0_NW))
446 {
447 /* Invalid value */
448 Fast486Exception(State, FAST486_EXCEPTION_GP);
449 return FALSE;
450 }
451 }
452
453 /* Load a value to the control register */
454 State->ControlRegisters[ModRegRm.Register] = Value;
455
456 /* Return success */
457 return TRUE;
458 }
459
460 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLoadDebugReg)
461 {
462 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
463 FAST486_MOD_REG_RM ModRegRm;
464
465 NO_LOCK_PREFIX();
466 TOGGLE_ADSIZE(AddressSize);
467
468 /* Get the operands */
469 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
470 {
471 /* Exception occurred */
472 return FALSE;
473 }
474
475 /* The current privilege level must be zero */
476 if (Fast486GetCurrentPrivLevel(State) != 0)
477 {
478 Fast486Exception(State, FAST486_EXCEPTION_GP);
479 return FALSE;
480 }
481
482 if ((ModRegRm.Register == 6) || (ModRegRm.Register == 7))
483 {
484 /* DR6 and DR7 are aliases to DR4 and DR5 */
485 ModRegRm.Register -= 2;
486 }
487
488 if (State->DebugRegisters[FAST486_REG_DR5] & FAST486_DR5_GD)
489 {
490 /* Disallow access to debug registers */
491 Fast486Exception(State, FAST486_EXCEPTION_GP);
492 return FALSE;
493 }
494
495 /* Load a value to the debug register */
496 State->DebugRegisters[ModRegRm.Register] = State->GeneralRegs[ModRegRm.SecondRegister].Long;
497
498 if (ModRegRm.Register == (INT)FAST486_REG_DR4)
499 {
500 /* The reserved bits are 1 */
501 State->DebugRegisters[ModRegRm.Register] |= FAST486_DR4_RESERVED;
502 }
503 else if (ModRegRm.Register == (INT)FAST486_REG_DR5)
504 {
505 /* The reserved bits are 0 */
506 State->DebugRegisters[ModRegRm.Register] &= ~FAST486_DR5_RESERVED;
507 }
508
509 /* Return success */
510 return TRUE;
511 }
512
513 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
514 {
515 /* Call the internal API */
516 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
517 }
518
519 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
520 {
521 ULONG NewSelector;
522
523 if (!Fast486StackPop(State, &NewSelector))
524 {
525 /* Exception occurred */
526 return FALSE;
527 }
528
529 /* Call the internal API */
530 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
531 }
532
533 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBitTest)
534 {
535 BOOLEAN OperandSize, AddressSize;
536 FAST486_MOD_REG_RM ModRegRm;
537 UINT DataSize;
538 ULONG BitNumber;
539
540 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
541 TOGGLE_OPSIZE(OperandSize);
542 TOGGLE_ADSIZE(AddressSize);
543
544 /* Get the number of bits */
545 if (OperandSize) DataSize = 32;
546 else DataSize = 16;
547
548 /* Get the operands */
549 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
550 {
551 /* Exception occurred */
552 return FALSE;
553 }
554
555 /* Get the bit number */
556 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
557 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
558
559 if (ModRegRm.Memory)
560 {
561 /*
562 * For memory operands, add the bit offset divided by
563 * the data size to the address
564 */
565 ModRegRm.MemoryAddress += BitNumber / DataSize;
566 }
567
568 /* Normalize the bit number */
569 BitNumber &= (1 << DataSize) - 1;
570
571 if (OperandSize)
572 {
573 ULONG Dummy, Value;
574
575 /* Read the value */
576 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
577 {
578 /* Exception occurred */
579 return FALSE;
580 }
581
582 /* Set CF to the bit value */
583 State->Flags.Cf = (Value >> BitNumber) & 1;
584 }
585 else
586 {
587 USHORT Dummy, Value;
588
589 /* Read the value */
590 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
591 {
592 /* Exception occurred */
593 return FALSE;
594 }
595
596 /* Set CF to the bit value */
597 State->Flags.Cf = (Value >> BitNumber) & 1;
598 }
599
600 /* Return success */
601 return TRUE;
602 }
603
604 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
605 {
606 /* Call the internal API */
607 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
608 }
609
610 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
611 {
612 ULONG NewSelector;
613
614 if (!Fast486StackPop(State, &NewSelector))
615 {
616 /* Exception occurred */
617 return FALSE;
618 }
619
620 /* Call the internal API */
621 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
622 }
623
624 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBts)
625 {
626 BOOLEAN OperandSize, AddressSize;
627 FAST486_MOD_REG_RM ModRegRm;
628 UINT DataSize;
629 ULONG BitNumber;
630
631 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
632 TOGGLE_OPSIZE(OperandSize);
633 TOGGLE_ADSIZE(AddressSize);
634
635 /* Get the number of bits */
636 if (OperandSize) DataSize = 32;
637 else DataSize = 16;
638
639 /* Get the operands */
640 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
641 {
642 /* Exception occurred */
643 return FALSE;
644 }
645
646 /* Get the bit number */
647 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
648 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
649
650 if (ModRegRm.Memory)
651 {
652 /*
653 * For memory operands, add the bit offset divided by
654 * the data size to the address
655 */
656 ModRegRm.MemoryAddress += BitNumber / DataSize;
657 }
658
659 /* Normalize the bit number */
660 BitNumber &= (1 << DataSize) - 1;
661
662 if (OperandSize)
663 {
664 ULONG Dummy, Value;
665
666 /* Read the value */
667 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
668 {
669 /* Exception occurred */
670 return FALSE;
671 }
672
673 /* Set CF to the bit value */
674 State->Flags.Cf = (Value >> BitNumber) & 1;
675
676 /* Set the bit */
677 Value |= 1 << BitNumber;
678
679 /* Write back the result */
680 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
681 {
682 /* Exception occurred */
683 return FALSE;
684 }
685 }
686 else
687 {
688 USHORT Dummy, Value;
689
690 /* Read the value */
691 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
692 {
693 /* Exception occurred */
694 return FALSE;
695 }
696
697 /* Set CF to the bit value */
698 State->Flags.Cf = (Value >> BitNumber) & 1;
699
700 /* Set the bit */
701 Value |= 1 << BitNumber;
702
703 /* Write back the result */
704 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
705 {
706 /* Exception occurred */
707 return FALSE;
708 }
709 }
710
711 /* Return success */
712 return TRUE;
713 }
714
715 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchgByte)
716 {
717 FAST486_MOD_REG_RM ModRegRm;
718 UCHAR Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowByte;
719 UCHAR Source, Destination, Result;
720 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
721
722 TOGGLE_ADSIZE(AddressSize);
723
724 /* Get the operands */
725 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
726 {
727 /* Exception occurred */
728 return FALSE;
729 }
730
731 /* Read the operands */
732 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Source, &Destination))
733 {
734 /* Exception occurred */
735 return FALSE;
736 }
737
738 /* Compare AL with the destination */
739 Result = Accumulator - Destination;
740
741 /* Update the flags */
742 State->Flags.Cf = (Accumulator < Destination);
743 State->Flags.Of = ((Accumulator & SIGN_FLAG_BYTE) != (Destination & SIGN_FLAG_BYTE))
744 && ((Accumulator & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
745 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
746 State->Flags.Zf = (Result == 0);
747 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
748 State->Flags.Pf = Fast486CalculateParity(Result);
749
750 if (State->Flags.Zf)
751 {
752 /* Load the source operand into the destination */
753 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Source);
754 }
755 else
756 {
757 /* Load the destination into AL */
758 State->GeneralRegs[FAST486_REG_EAX].LowByte = Destination;
759 }
760
761 /* Return success */
762 return TRUE;
763 }
764
765 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeCmpXchg)
766 {
767 FAST486_MOD_REG_RM ModRegRm;
768 BOOLEAN OperandSize, AddressSize;
769
770 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
771
772 TOGGLE_OPSIZE(OperandSize);
773 TOGGLE_ADSIZE(AddressSize);
774
775 /* Get the operands */
776 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
777 {
778 /* Exception occurred */
779 return FALSE;
780 }
781
782 if (OperandSize)
783 {
784 ULONG Source, Destination, Result;
785 ULONG Accumulator = State->GeneralRegs[FAST486_REG_EAX].Long;
786
787 /* Read the operands */
788 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Source, &Destination))
789 {
790 /* Exception occurred */
791 return FALSE;
792 }
793
794 /* Compare EAX with the destination */
795 Result = Accumulator - Destination;
796
797 /* Update the flags */
798 State->Flags.Cf = (Accumulator < Destination);
799 State->Flags.Of = ((Accumulator & SIGN_FLAG_LONG) != (Destination & SIGN_FLAG_LONG))
800 && ((Accumulator & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
801 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
802 State->Flags.Zf = (Result == 0);
803 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
804 State->Flags.Pf = Fast486CalculateParity(Result);
805
806 if (State->Flags.Zf)
807 {
808 /* Load the source operand into the destination */
809 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Source);
810 }
811 else
812 {
813 /* Load the destination into EAX */
814 State->GeneralRegs[FAST486_REG_EAX].Long = Destination;
815 }
816 }
817 else
818 {
819 USHORT Source, Destination, Result;
820 USHORT Accumulator = State->GeneralRegs[FAST486_REG_EAX].LowWord;
821
822 /* Read the operands */
823 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Source, &Destination))
824 {
825 /* Exception occurred */
826 return FALSE;
827 }
828
829 /* Compare AX with the destination */
830 Result = Accumulator - Destination;
831
832 /* Update the flags */
833 State->Flags.Cf = (Accumulator < Destination);
834 State->Flags.Of = ((Accumulator & SIGN_FLAG_WORD) != (Destination & SIGN_FLAG_WORD))
835 && ((Accumulator & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
836 State->Flags.Af = (Accumulator & 0x0F) < (Destination & 0x0F);
837 State->Flags.Zf = (Result == 0);
838 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
839 State->Flags.Pf = Fast486CalculateParity(Result);
840
841 if (State->Flags.Zf)
842 {
843 /* Load the source operand into the destination */
844 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Source);
845 }
846 else
847 {
848 /* Load the destination into AX */
849 State->GeneralRegs[FAST486_REG_EAX].LowWord = Destination;
850 }
851 }
852
853 /* Return success */
854 return TRUE;
855 }
856
857 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtr)
858 {
859 BOOLEAN OperandSize, AddressSize;
860 FAST486_MOD_REG_RM ModRegRm;
861 UINT DataSize;
862 ULONG BitNumber;
863
864 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
865 TOGGLE_OPSIZE(OperandSize);
866 TOGGLE_ADSIZE(AddressSize);
867
868 /* Get the number of bits */
869 if (OperandSize) DataSize = 32;
870 else DataSize = 16;
871
872 /* Get the operands */
873 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
874 {
875 /* Exception occurred */
876 return FALSE;
877 }
878
879 /* Get the bit number */
880 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
881 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
882
883 if (ModRegRm.Memory)
884 {
885 /*
886 * For memory operands, add the bit offset divided by
887 * the data size to the address
888 */
889 ModRegRm.MemoryAddress += BitNumber / DataSize;
890 }
891
892 /* Normalize the bit number */
893 BitNumber &= (1 << DataSize) - 1;
894
895 if (OperandSize)
896 {
897 ULONG Dummy, Value;
898
899 /* Read the value */
900 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
901 {
902 /* Exception occurred */
903 return FALSE;
904 }
905
906 /* Set CF to the bit value */
907 State->Flags.Cf = (Value >> BitNumber) & 1;
908
909 /* Clear the bit */
910 Value &= ~(1 << BitNumber);
911
912 /* Write back the result */
913 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
914 {
915 /* Exception occurred */
916 return FALSE;
917 }
918 }
919 else
920 {
921 USHORT Dummy, Value;
922
923 /* Read the value */
924 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
925 {
926 /* Exception occurred */
927 return FALSE;
928 }
929
930 /* Set CF to the bit value */
931 State->Flags.Cf = (Value >> BitNumber) & 1;
932
933 /* Clear the bit */
934 Value &= ~(1 << BitNumber);
935
936 /* Write back the result */
937 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
938 {
939 /* Exception occurred */
940 return FALSE;
941 }
942 }
943
944 /* Return success */
945 return TRUE;
946 }
947
948 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
949 {
950 BOOLEAN OperandSize, AddressSize;
951 FAST486_MOD_REG_RM ModRegRm;
952 UINT DataSize;
953 ULONG BitNumber;
954
955 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
956 TOGGLE_OPSIZE(OperandSize);
957 TOGGLE_ADSIZE(AddressSize);
958
959 /* Get the number of bits */
960 if (OperandSize) DataSize = 32;
961 else DataSize = 16;
962
963 /* Get the operands */
964 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
965 {
966 /* Exception occurred */
967 return FALSE;
968 }
969
970 /* Get the bit number */
971 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
972 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
973
974 if (ModRegRm.Memory)
975 {
976 /*
977 * For memory operands, add the bit offset divided by
978 * the data size to the address
979 */
980 ModRegRm.MemoryAddress += BitNumber / DataSize;
981 }
982
983 /* Normalize the bit number */
984 BitNumber &= (1 << DataSize) - 1;
985
986 if (OperandSize)
987 {
988 ULONG Dummy, Value;
989
990 /* Read the value */
991 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
992 {
993 /* Exception occurred */
994 return FALSE;
995 }
996
997 /* Set CF to the bit value */
998 State->Flags.Cf = (Value >> BitNumber) & 1;
999
1000 /* Toggle the bit */
1001 Value ^= 1 << BitNumber;
1002
1003 /* Write back the result */
1004 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1005 {
1006 /* Exception occurred */
1007 return FALSE;
1008 }
1009 }
1010 else
1011 {
1012 USHORT Dummy, Value;
1013
1014 /* Read the value */
1015 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1016 {
1017 /* Exception occurred */
1018 return FALSE;
1019 }
1020
1021 /* Set CF to the bit value */
1022 State->Flags.Cf = (Value >> BitNumber) & 1;
1023
1024 /* Toggle the bit */
1025 Value ^= 1 << BitNumber;
1026
1027 /* Write back the result */
1028 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1029 {
1030 /* Exception occurred */
1031 return FALSE;
1032 }
1033 }
1034
1035 /* Return success */
1036 return TRUE;
1037 }
1038
1039 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1040 {
1041 INT i;
1042 ULONG Dummy = 0, Value = 0;
1043 BOOLEAN OperandSize, AddressSize;
1044 FAST486_MOD_REG_RM ModRegRm;
1045 ULONG BitNumber;
1046 UINT DataSize;
1047
1048 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1049 TOGGLE_OPSIZE(OperandSize);
1050 TOGGLE_ADSIZE(AddressSize);
1051
1052 /* Make sure this is the right instruction */
1053 ASSERT(Opcode == 0xBC);
1054
1055 /* Get the number of bits */
1056 if (OperandSize) DataSize = 32;
1057 else DataSize = 16;
1058
1059 /* Get the operands */
1060 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1061 {
1062 /* Exception occurred */
1063 return FALSE;
1064 }
1065
1066 /* Read the value */
1067 if (OperandSize)
1068 {
1069 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1070 {
1071 /* Exception occurred */
1072 return FALSE;
1073 }
1074 }
1075 else
1076 {
1077 if (!Fast486ReadModrmWordOperands(State,
1078 &ModRegRm,
1079 (PUSHORT)&Dummy,
1080 (PUSHORT)&Value))
1081 {
1082 /* Exception occurred */
1083 return FALSE;
1084 }
1085 }
1086
1087 /* Clear ZF */
1088 State->Flags.Zf = FALSE;
1089
1090 for (i = 0; i < DataSize; i++)
1091 {
1092 if(Value & (1 << i))
1093 {
1094 /* Set ZF */
1095 State->Flags.Zf = TRUE;
1096
1097 /* Save the bit number */
1098 BitNumber = i;
1099
1100 /* Exit the loop */
1101 break;
1102 }
1103 }
1104
1105 if (State->Flags.Zf)
1106 {
1107 /* Write back the result */
1108 if (OperandSize)
1109 {
1110 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1111 {
1112 /* Exception occurred */
1113 return FALSE;
1114 }
1115 }
1116 else
1117 {
1118 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1119 {
1120 /* Exception occurred */
1121 return FALSE;
1122 }
1123 }
1124 }
1125
1126 return TRUE;
1127 }
1128
1129 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1130 {
1131 INT i;
1132 ULONG Dummy = 0, Value = 0;
1133 BOOLEAN OperandSize, AddressSize;
1134 FAST486_MOD_REG_RM ModRegRm;
1135 ULONG BitNumber;
1136 UINT DataSize;
1137
1138 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1139 TOGGLE_OPSIZE(OperandSize);
1140 TOGGLE_ADSIZE(AddressSize);
1141
1142 /* Make sure this is the right instruction */
1143 ASSERT(Opcode == 0xBD);
1144
1145 /* Get the number of bits */
1146 if (OperandSize) DataSize = 32;
1147 else DataSize = 16;
1148
1149 /* Get the operands */
1150 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1151 {
1152 /* Exception occurred */
1153 return FALSE;
1154 }
1155
1156 /* Read the value */
1157 if (OperandSize)
1158 {
1159 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1160 {
1161 /* Exception occurred */
1162 return FALSE;
1163 }
1164 }
1165 else
1166 {
1167 if (!Fast486ReadModrmWordOperands(State,
1168 &ModRegRm,
1169 (PUSHORT)&Dummy,
1170 (PUSHORT)&Value))
1171 {
1172 /* Exception occurred */
1173 return FALSE;
1174 }
1175 }
1176
1177 /* Clear ZF */
1178 State->Flags.Zf = FALSE;
1179
1180 for (i = DataSize - 1; i >= 0; i--)
1181 {
1182 if(Value & (1 << i))
1183 {
1184 /* Set ZF */
1185 State->Flags.Zf = TRUE;
1186
1187 /* Save the bit number */
1188 BitNumber = i;
1189
1190 /* Exit the loop */
1191 break;
1192 }
1193 }
1194
1195 if (State->Flags.Zf)
1196 {
1197 /* Write back the result */
1198 if (OperandSize)
1199 {
1200 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1201 {
1202 /* Exception occurred */
1203 return FALSE;
1204 }
1205 }
1206 else
1207 {
1208 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1209 {
1210 /* Exception occurred */
1211 return FALSE;
1212 }
1213 }
1214 }
1215
1216 return TRUE;
1217 }
1218
1219 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1220 {
1221 UCHAR Dummy;
1222 CHAR Value;
1223 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1224 FAST486_MOD_REG_RM ModRegRm;
1225
1226 TOGGLE_ADSIZE(AddressSize);
1227
1228 /* Make sure this is the right instruction */
1229 ASSERT(Opcode == 0xBE);
1230
1231 /* Get the operands */
1232 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1233 {
1234 /* Exception occurred */
1235 return FALSE;
1236 }
1237
1238 /* Read the operands */
1239 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, (PUCHAR)&Value))
1240 {
1241 /* Exception occurred */
1242 return FALSE;
1243 }
1244
1245 /* Write back the sign-extended value */
1246 return Fast486WriteModrmDwordOperands(State,
1247 &ModRegRm,
1248 TRUE,
1249 (ULONG)((LONG)Value));
1250 }
1251
1252 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1253 {
1254 USHORT Dummy;
1255 SHORT Value;
1256 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1257 FAST486_MOD_REG_RM ModRegRm;
1258
1259 TOGGLE_ADSIZE(AddressSize);
1260
1261 /* Make sure this is the right instruction */
1262 ASSERT(Opcode == 0xBF);
1263
1264 /* Get the operands */
1265 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1266 {
1267 /* Exception occurred */
1268 return FALSE;
1269 }
1270
1271 /* Read the operands */
1272 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, (PUSHORT)&Value))
1273 {
1274 /* Exception occurred */
1275 return FALSE;
1276 }
1277
1278 /* Write back the sign-extended value */
1279 return Fast486WriteModrmDwordOperands(State,
1280 &ModRegRm,
1281 TRUE,
1282 (ULONG)((LONG)Value));
1283 }
1284
1285 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1286 {
1287 BOOLEAN Jump = FALSE;
1288 LONG Offset = 0;
1289 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1290
1291 TOGGLE_OPSIZE(Size);
1292 NO_LOCK_PREFIX();
1293
1294 /* Make sure this is the right instruction */
1295 ASSERT((Opcode & 0xF0) == 0x80);
1296
1297 /* Fetch the offset */
1298 if (Size)
1299 {
1300 if (!Fast486FetchDword(State, (PULONG)&Offset))
1301 {
1302 /* Exception occurred */
1303 return FALSE;
1304 }
1305 }
1306 else
1307 {
1308 SHORT Value;
1309
1310 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1311 {
1312 /* Exception occurred */
1313 return FALSE;
1314 }
1315
1316 /* Sign-extend */
1317 Offset = (LONG)Value;
1318 }
1319
1320 switch ((Opcode & 0x0F) >> 1)
1321 {
1322 /* JO / JNO */
1323 case 0:
1324 {
1325 Jump = State->Flags.Of;
1326 break;
1327 }
1328
1329 /* JC / JNC */
1330 case 1:
1331 {
1332 Jump = State->Flags.Cf;
1333 break;
1334 }
1335
1336 /* JZ / JNZ */
1337 case 2:
1338 {
1339 Jump = State->Flags.Zf;
1340 break;
1341 }
1342
1343 /* JBE / JNBE */
1344 case 3:
1345 {
1346 Jump = State->Flags.Cf || State->Flags.Zf;
1347 break;
1348 }
1349
1350 /* JS / JNS */
1351 case 4:
1352 {
1353 Jump = State->Flags.Sf;
1354 break;
1355 }
1356
1357 /* JP / JNP */
1358 case 5:
1359 {
1360 Jump = State->Flags.Pf;
1361 break;
1362 }
1363
1364 /* JL / JNL */
1365 case 6:
1366 {
1367 Jump = State->Flags.Sf != State->Flags.Of;
1368 break;
1369 }
1370
1371 /* JLE / JNLE */
1372 case 7:
1373 {
1374 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1375 break;
1376 }
1377 }
1378
1379 if (Opcode & 1)
1380 {
1381 /* Invert the result */
1382 Jump = !Jump;
1383 }
1384
1385 if (Jump)
1386 {
1387 /* Move the instruction pointer */
1388 State->InstPtr.Long += Offset;
1389 }
1390
1391 /* Return success */
1392 return TRUE;
1393 }
1394
1395 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1396 {
1397 BOOLEAN Value = FALSE;
1398 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1399 FAST486_MOD_REG_RM ModRegRm;
1400
1401 TOGGLE_ADSIZE(AddressSize);
1402
1403 /* Get the operands */
1404 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1405 {
1406 /* Exception occurred */
1407 return FALSE;
1408 }
1409
1410 /* Make sure this is the right instruction */
1411 ASSERT((Opcode & 0xF0) == 0x90);
1412
1413 switch ((Opcode & 0x0F) >> 1)
1414 {
1415 /* SETO / SETNO */
1416 case 0:
1417 {
1418 Value = State->Flags.Of;
1419 break;
1420 }
1421
1422 /* SETC / SETNC */
1423 case 1:
1424 {
1425 Value = State->Flags.Cf;
1426 break;
1427 }
1428
1429 /* SETZ / SETNZ */
1430 case 2:
1431 {
1432 Value = State->Flags.Zf;
1433 break;
1434 }
1435
1436 /* SETBE / SETNBE */
1437 case 3:
1438 {
1439 Value = State->Flags.Cf || State->Flags.Zf;
1440 break;
1441 }
1442
1443 /* SETS / SETNS */
1444 case 4:
1445 {
1446 Value = State->Flags.Sf;
1447 break;
1448 }
1449
1450 /* SETP / SETNP */
1451 case 5:
1452 {
1453 Value = State->Flags.Pf;
1454 break;
1455 }
1456
1457 /* SETL / SETNL */
1458 case 6:
1459 {
1460 Value = State->Flags.Sf != State->Flags.Of;
1461 break;
1462 }
1463
1464 /* SETLE / SETNLE */
1465 case 7:
1466 {
1467 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1468 break;
1469 }
1470 }
1471
1472 if (Opcode & 1)
1473 {
1474 /* Invert the result */
1475 Value = !Value;
1476 }
1477
1478 /* Write back the result */
1479 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1480 }
1481
1482 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
1483 {
1484 UCHAR Source, Destination, Result;
1485 FAST486_MOD_REG_RM ModRegRm;
1486 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1487
1488 /* Make sure this is the right instruction */
1489 ASSERT(Opcode == 0xC0);
1490
1491 TOGGLE_ADSIZE(AddressSize);
1492
1493 /* Get the operands */
1494 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1495 {
1496 /* Exception occurred */
1497 return FALSE;
1498 }
1499
1500 if (!Fast486ReadModrmByteOperands(State,
1501 &ModRegRm,
1502 &Source,
1503 &Destination))
1504 {
1505 /* Exception occurred */
1506 return FALSE;
1507 }
1508
1509 /* Calculate the result */
1510 Result = Source + Destination;
1511
1512 /* Update the flags */
1513 State->Flags.Cf = (Result < Source) && (Result < Destination);
1514 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
1515 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1516 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1517 State->Flags.Zf = (Result == 0);
1518 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1519 State->Flags.Pf = Fast486CalculateParity(Result);
1520
1521 /* Write the sum to the destination */
1522 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
1523 {
1524 /* Exception occurred */
1525 return FALSE;
1526 }
1527
1528 /* Write the old value of the destination to the source */
1529 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
1530 {
1531 /* Exception occurred */
1532 return FALSE;
1533 }
1534
1535 return TRUE;
1536 }
1537
1538 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
1539 {
1540 FAST486_MOD_REG_RM ModRegRm;
1541 BOOLEAN OperandSize, AddressSize;
1542
1543 /* Make sure this is the right instruction */
1544 ASSERT(Opcode == 0xC1);
1545
1546 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1547
1548 TOGGLE_ADSIZE(AddressSize);
1549 TOGGLE_OPSIZE(OperandSize);
1550
1551 /* Get the operands */
1552 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1553 {
1554 /* Exception occurred */
1555 return FALSE;
1556 }
1557
1558 /* Check the operand size */
1559 if (OperandSize)
1560 {
1561 ULONG Source, Destination, Result;
1562
1563 if (!Fast486ReadModrmDwordOperands(State,
1564 &ModRegRm,
1565 &Source,
1566 &Destination))
1567 {
1568 /* Exception occurred */
1569 return FALSE;
1570 }
1571
1572 /* Calculate the result */
1573 Result = Source + Destination;
1574
1575 /* Update the flags */
1576 State->Flags.Cf = (Result < Source) && (Result < Destination);
1577 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
1578 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1579 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1580 State->Flags.Zf = (Result == 0);
1581 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1582 State->Flags.Pf = Fast486CalculateParity(Result);
1583
1584 /* Write the sum to the destination */
1585 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
1586 {
1587 /* Exception occurred */
1588 return FALSE;
1589 }
1590
1591 /* Write the old value of the destination to the source */
1592 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
1593 {
1594 /* Exception occurred */
1595 return FALSE;
1596 }
1597 }
1598 else
1599 {
1600 USHORT Source, Destination, Result;
1601
1602 if (!Fast486ReadModrmWordOperands(State,
1603 &ModRegRm,
1604 &Source,
1605 &Destination))
1606 {
1607 /* Exception occurred */
1608 return FALSE;
1609 }
1610
1611 /* Calculate the result */
1612 Result = Source + Destination;
1613
1614 /* Update the flags */
1615 State->Flags.Cf = (Result < Source) && (Result < Destination);
1616 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
1617 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1618 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1619 State->Flags.Zf = (Result == 0);
1620 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1621 State->Flags.Pf = Fast486CalculateParity(Result);
1622
1623 /* Write the sum to the destination */
1624 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
1625 {
1626 /* Exception occurred */
1627 return FALSE;
1628 }
1629
1630 /* Write the old value of the destination to the source */
1631 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
1632 {
1633 /* Exception occurred */
1634 return FALSE;
1635 }
1636 }
1637
1638 return TRUE;
1639 }
1640
1641 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
1642 {
1643 PUCHAR Pointer;
1644
1645 NO_LOCK_PREFIX();
1646
1647 /* Get a pointer to the value */
1648 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
1649
1650 /* Swap the byte order */
1651 SWAP(Pointer[0], Pointer[3]);
1652 SWAP(Pointer[1], Pointer[2]);
1653
1654 /* Return success */
1655 return TRUE;
1656 }
1657
1658 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
1659 {
1660 UCHAR SecondOpcode;
1661
1662 /* Fetch the second operation code */
1663 if (!Fast486FetchByte(State, &SecondOpcode))
1664 {
1665 /* Exception occurred */
1666 return FALSE;
1667 }
1668
1669 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
1670 {
1671 /* Call the extended opcode handler */
1672 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
1673 }
1674 else
1675 {
1676 /* This is not a valid opcode */
1677 Fast486Exception(State, FAST486_EXCEPTION_UD);
1678 return FALSE;
1679 }
1680 }
1681