[FAST486]
[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 Fast486ExtOpcodeLfsLgs,
221 Fast486ExtOpcodeLfsLgs,
222 Fast486ExtOpcodeMovzxByte,
223 Fast486ExtOpcodeMovzxWord,
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(Fast486ExtOpcodeLfsLgs)
949 {
950 UCHAR FarPointer[6];
951 BOOLEAN OperandSize, AddressSize;
952 FAST486_MOD_REG_RM ModRegRm;
953
954 /* Make sure this is the right instruction */
955 ASSERT((Opcode & 0xFE) == 0xB4);
956
957 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
958
959 TOGGLE_ADSIZE(AddressSize);
960
961 /* Get the operands */
962 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
963 {
964 /* Exception occurred */
965 return FALSE;
966 }
967
968 if (!ModRegRm.Memory)
969 {
970 /* Invalid */
971 Fast486Exception(State, FAST486_EXCEPTION_UD);
972 return FALSE;
973 }
974
975 if (!Fast486ReadMemory(State,
976 (State->PrefixFlags & FAST486_PREFIX_SEG)
977 ? State->SegmentOverride : FAST486_REG_DS,
978 ModRegRm.MemoryAddress,
979 FALSE,
980 FarPointer,
981 OperandSize ? 6 : 4))
982 {
983 /* Exception occurred */
984 return FALSE;
985 }
986
987 if (OperandSize)
988 {
989 ULONG Offset = *((PULONG)FarPointer);
990 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
991
992 /* Set the register to the offset */
993 State->GeneralRegs[ModRegRm.Register].Long = Offset;
994
995 /* Load the segment */
996 return Fast486LoadSegment(State,
997 (Opcode == 0xB4)
998 ? FAST486_REG_FS : FAST486_REG_GS,
999 Segment);
1000 }
1001 else
1002 {
1003 USHORT Offset = *((PUSHORT)FarPointer);
1004 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
1005
1006 /* Set the register to the offset */
1007 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
1008
1009 /* Load the segment */
1010 return Fast486LoadSegment(State,
1011 (Opcode == 0xB4)
1012 ? FAST486_REG_FS : FAST486_REG_GS,
1013 Segment);
1014 }
1015 }
1016
1017 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxByte)
1018 {
1019 UCHAR Dummy, Value;
1020 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1021 FAST486_MOD_REG_RM ModRegRm;
1022
1023 TOGGLE_ADSIZE(AddressSize);
1024
1025 /* Make sure this is the right instruction */
1026 ASSERT(Opcode == 0xB6);
1027
1028 /* Get the operands */
1029 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1030 {
1031 /* Exception occurred */
1032 return FALSE;
1033 }
1034
1035 /* Read the operands */
1036 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
1037 {
1038 /* Exception occurred */
1039 return FALSE;
1040 }
1041
1042 /* Write back the zero-extended value */
1043 return Fast486WriteModrmDwordOperands(State,
1044 &ModRegRm,
1045 TRUE,
1046 (ULONG)Value);
1047 }
1048
1049 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovzxWord)
1050 {
1051 USHORT Dummy, Value;
1052 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1053 FAST486_MOD_REG_RM ModRegRm;
1054
1055 TOGGLE_ADSIZE(AddressSize);
1056
1057 /* Make sure this is the right instruction */
1058 ASSERT(Opcode == 0xB7);
1059
1060 /* Get the operands */
1061 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1062 {
1063 /* Exception occurred */
1064 return FALSE;
1065 }
1066
1067 /* Read the operands */
1068 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1069 {
1070 /* Exception occurred */
1071 return FALSE;
1072 }
1073
1074 /* Write back the zero-extended value */
1075 return Fast486WriteModrmDwordOperands(State,
1076 &ModRegRm,
1077 TRUE,
1078 (ULONG)Value);
1079 }
1080
1081 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBtc)
1082 {
1083 BOOLEAN OperandSize, AddressSize;
1084 FAST486_MOD_REG_RM ModRegRm;
1085 UINT DataSize;
1086 ULONG BitNumber;
1087
1088 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1089 TOGGLE_OPSIZE(OperandSize);
1090 TOGGLE_ADSIZE(AddressSize);
1091
1092 /* Get the number of bits */
1093 if (OperandSize) DataSize = 32;
1094 else DataSize = 16;
1095
1096 /* Get the operands */
1097 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1098 {
1099 /* Exception occurred */
1100 return FALSE;
1101 }
1102
1103 /* Get the bit number */
1104 BitNumber = OperandSize ? State->GeneralRegs[ModRegRm.Register].Long
1105 : (ULONG)State->GeneralRegs[ModRegRm.Register].LowWord;
1106
1107 if (ModRegRm.Memory)
1108 {
1109 /*
1110 * For memory operands, add the bit offset divided by
1111 * the data size to the address
1112 */
1113 ModRegRm.MemoryAddress += BitNumber / DataSize;
1114 }
1115
1116 /* Normalize the bit number */
1117 BitNumber &= (1 << DataSize) - 1;
1118
1119 if (OperandSize)
1120 {
1121 ULONG Dummy, Value;
1122
1123 /* Read the value */
1124 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1125 {
1126 /* Exception occurred */
1127 return FALSE;
1128 }
1129
1130 /* Set CF to the bit value */
1131 State->Flags.Cf = (Value >> BitNumber) & 1;
1132
1133 /* Toggle the bit */
1134 Value ^= 1 << BitNumber;
1135
1136 /* Write back the result */
1137 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1138 {
1139 /* Exception occurred */
1140 return FALSE;
1141 }
1142 }
1143 else
1144 {
1145 USHORT Dummy, Value;
1146
1147 /* Read the value */
1148 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1149 {
1150 /* Exception occurred */
1151 return FALSE;
1152 }
1153
1154 /* Set CF to the bit value */
1155 State->Flags.Cf = (Value >> BitNumber) & 1;
1156
1157 /* Toggle the bit */
1158 Value ^= 1 << BitNumber;
1159
1160 /* Write back the result */
1161 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1162 {
1163 /* Exception occurred */
1164 return FALSE;
1165 }
1166 }
1167
1168 /* Return success */
1169 return TRUE;
1170 }
1171
1172 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsf)
1173 {
1174 INT i;
1175 ULONG Dummy = 0, Value = 0;
1176 BOOLEAN OperandSize, AddressSize;
1177 FAST486_MOD_REG_RM ModRegRm;
1178 ULONG BitNumber;
1179 UINT DataSize;
1180
1181 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1182 TOGGLE_OPSIZE(OperandSize);
1183 TOGGLE_ADSIZE(AddressSize);
1184
1185 /* Make sure this is the right instruction */
1186 ASSERT(Opcode == 0xBC);
1187
1188 /* Get the number of bits */
1189 if (OperandSize) DataSize = 32;
1190 else DataSize = 16;
1191
1192 /* Get the operands */
1193 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1194 {
1195 /* Exception occurred */
1196 return FALSE;
1197 }
1198
1199 /* Read the value */
1200 if (OperandSize)
1201 {
1202 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1203 {
1204 /* Exception occurred */
1205 return FALSE;
1206 }
1207 }
1208 else
1209 {
1210 if (!Fast486ReadModrmWordOperands(State,
1211 &ModRegRm,
1212 (PUSHORT)&Dummy,
1213 (PUSHORT)&Value))
1214 {
1215 /* Exception occurred */
1216 return FALSE;
1217 }
1218 }
1219
1220 /* Clear ZF */
1221 State->Flags.Zf = FALSE;
1222
1223 for (i = 0; i < DataSize; i++)
1224 {
1225 if(Value & (1 << i))
1226 {
1227 /* Set ZF */
1228 State->Flags.Zf = TRUE;
1229
1230 /* Save the bit number */
1231 BitNumber = i;
1232
1233 /* Exit the loop */
1234 break;
1235 }
1236 }
1237
1238 if (State->Flags.Zf)
1239 {
1240 /* Write back the result */
1241 if (OperandSize)
1242 {
1243 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1244 {
1245 /* Exception occurred */
1246 return FALSE;
1247 }
1248 }
1249 else
1250 {
1251 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1252 {
1253 /* Exception occurred */
1254 return FALSE;
1255 }
1256 }
1257 }
1258
1259 return TRUE;
1260 }
1261
1262 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBsr)
1263 {
1264 INT i;
1265 ULONG Dummy = 0, Value = 0;
1266 BOOLEAN OperandSize, AddressSize;
1267 FAST486_MOD_REG_RM ModRegRm;
1268 ULONG BitNumber;
1269 UINT DataSize;
1270
1271 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1272 TOGGLE_OPSIZE(OperandSize);
1273 TOGGLE_ADSIZE(AddressSize);
1274
1275 /* Make sure this is the right instruction */
1276 ASSERT(Opcode == 0xBD);
1277
1278 /* Get the number of bits */
1279 if (OperandSize) DataSize = 32;
1280 else DataSize = 16;
1281
1282 /* Get the operands */
1283 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1284 {
1285 /* Exception occurred */
1286 return FALSE;
1287 }
1288
1289 /* Read the value */
1290 if (OperandSize)
1291 {
1292 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1293 {
1294 /* Exception occurred */
1295 return FALSE;
1296 }
1297 }
1298 else
1299 {
1300 if (!Fast486ReadModrmWordOperands(State,
1301 &ModRegRm,
1302 (PUSHORT)&Dummy,
1303 (PUSHORT)&Value))
1304 {
1305 /* Exception occurred */
1306 return FALSE;
1307 }
1308 }
1309
1310 /* Clear ZF */
1311 State->Flags.Zf = FALSE;
1312
1313 for (i = DataSize - 1; i >= 0; i--)
1314 {
1315 if(Value & (1 << i))
1316 {
1317 /* Set ZF */
1318 State->Flags.Zf = TRUE;
1319
1320 /* Save the bit number */
1321 BitNumber = i;
1322
1323 /* Exit the loop */
1324 break;
1325 }
1326 }
1327
1328 if (State->Flags.Zf)
1329 {
1330 /* Write back the result */
1331 if (OperandSize)
1332 {
1333 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, BitNumber))
1334 {
1335 /* Exception occurred */
1336 return FALSE;
1337 }
1338 }
1339 else
1340 {
1341 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, LOWORD(BitNumber)))
1342 {
1343 /* Exception occurred */
1344 return FALSE;
1345 }
1346 }
1347 }
1348
1349 return TRUE;
1350 }
1351
1352 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxByte)
1353 {
1354 UCHAR Dummy;
1355 CHAR Value;
1356 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1357 FAST486_MOD_REG_RM ModRegRm;
1358
1359 TOGGLE_ADSIZE(AddressSize);
1360
1361 /* Make sure this is the right instruction */
1362 ASSERT(Opcode == 0xBE);
1363
1364 /* Get the operands */
1365 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1366 {
1367 /* Exception occurred */
1368 return FALSE;
1369 }
1370
1371 /* Read the operands */
1372 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, (PUCHAR)&Value))
1373 {
1374 /* Exception occurred */
1375 return FALSE;
1376 }
1377
1378 /* Write back the sign-extended value */
1379 return Fast486WriteModrmDwordOperands(State,
1380 &ModRegRm,
1381 TRUE,
1382 (ULONG)((LONG)Value));
1383 }
1384
1385 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeMovsxWord)
1386 {
1387 USHORT Dummy;
1388 SHORT Value;
1389 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1390 FAST486_MOD_REG_RM ModRegRm;
1391
1392 TOGGLE_ADSIZE(AddressSize);
1393
1394 /* Make sure this is the right instruction */
1395 ASSERT(Opcode == 0xBF);
1396
1397 /* Get the operands */
1398 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1399 {
1400 /* Exception occurred */
1401 return FALSE;
1402 }
1403
1404 /* Read the operands */
1405 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, (PUSHORT)&Value))
1406 {
1407 /* Exception occurred */
1408 return FALSE;
1409 }
1410
1411 /* Write back the sign-extended value */
1412 return Fast486WriteModrmDwordOperands(State,
1413 &ModRegRm,
1414 TRUE,
1415 (ULONG)((LONG)Value));
1416 }
1417
1418 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
1419 {
1420 BOOLEAN Jump = FALSE;
1421 LONG Offset = 0;
1422 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
1423
1424 TOGGLE_OPSIZE(Size);
1425 NO_LOCK_PREFIX();
1426
1427 /* Make sure this is the right instruction */
1428 ASSERT((Opcode & 0xF0) == 0x80);
1429
1430 /* Fetch the offset */
1431 if (Size)
1432 {
1433 if (!Fast486FetchDword(State, (PULONG)&Offset))
1434 {
1435 /* Exception occurred */
1436 return FALSE;
1437 }
1438 }
1439 else
1440 {
1441 SHORT Value;
1442
1443 if (!Fast486FetchWord(State, (PUSHORT)&Value))
1444 {
1445 /* Exception occurred */
1446 return FALSE;
1447 }
1448
1449 /* Sign-extend */
1450 Offset = (LONG)Value;
1451 }
1452
1453 switch ((Opcode & 0x0F) >> 1)
1454 {
1455 /* JO / JNO */
1456 case 0:
1457 {
1458 Jump = State->Flags.Of;
1459 break;
1460 }
1461
1462 /* JC / JNC */
1463 case 1:
1464 {
1465 Jump = State->Flags.Cf;
1466 break;
1467 }
1468
1469 /* JZ / JNZ */
1470 case 2:
1471 {
1472 Jump = State->Flags.Zf;
1473 break;
1474 }
1475
1476 /* JBE / JNBE */
1477 case 3:
1478 {
1479 Jump = State->Flags.Cf || State->Flags.Zf;
1480 break;
1481 }
1482
1483 /* JS / JNS */
1484 case 4:
1485 {
1486 Jump = State->Flags.Sf;
1487 break;
1488 }
1489
1490 /* JP / JNP */
1491 case 5:
1492 {
1493 Jump = State->Flags.Pf;
1494 break;
1495 }
1496
1497 /* JL / JNL */
1498 case 6:
1499 {
1500 Jump = State->Flags.Sf != State->Flags.Of;
1501 break;
1502 }
1503
1504 /* JLE / JNLE */
1505 case 7:
1506 {
1507 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1508 break;
1509 }
1510 }
1511
1512 if (Opcode & 1)
1513 {
1514 /* Invert the result */
1515 Jump = !Jump;
1516 }
1517
1518 if (Jump)
1519 {
1520 /* Move the instruction pointer */
1521 State->InstPtr.Long += Offset;
1522 }
1523
1524 /* Return success */
1525 return TRUE;
1526 }
1527
1528 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
1529 {
1530 BOOLEAN Value = FALSE;
1531 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1532 FAST486_MOD_REG_RM ModRegRm;
1533
1534 TOGGLE_ADSIZE(AddressSize);
1535
1536 /* Get the operands */
1537 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1538 {
1539 /* Exception occurred */
1540 return FALSE;
1541 }
1542
1543 /* Make sure this is the right instruction */
1544 ASSERT((Opcode & 0xF0) == 0x90);
1545
1546 switch ((Opcode & 0x0F) >> 1)
1547 {
1548 /* SETO / SETNO */
1549 case 0:
1550 {
1551 Value = State->Flags.Of;
1552 break;
1553 }
1554
1555 /* SETC / SETNC */
1556 case 1:
1557 {
1558 Value = State->Flags.Cf;
1559 break;
1560 }
1561
1562 /* SETZ / SETNZ */
1563 case 2:
1564 {
1565 Value = State->Flags.Zf;
1566 break;
1567 }
1568
1569 /* SETBE / SETNBE */
1570 case 3:
1571 {
1572 Value = State->Flags.Cf || State->Flags.Zf;
1573 break;
1574 }
1575
1576 /* SETS / SETNS */
1577 case 4:
1578 {
1579 Value = State->Flags.Sf;
1580 break;
1581 }
1582
1583 /* SETP / SETNP */
1584 case 5:
1585 {
1586 Value = State->Flags.Pf;
1587 break;
1588 }
1589
1590 /* SETL / SETNL */
1591 case 6:
1592 {
1593 Value = State->Flags.Sf != State->Flags.Of;
1594 break;
1595 }
1596
1597 /* SETLE / SETNLE */
1598 case 7:
1599 {
1600 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
1601 break;
1602 }
1603 }
1604
1605 if (Opcode & 1)
1606 {
1607 /* Invert the result */
1608 Value = !Value;
1609 }
1610
1611 /* Write back the result */
1612 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1613 }
1614
1615 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXaddByte)
1616 {
1617 UCHAR Source, Destination, Result;
1618 FAST486_MOD_REG_RM ModRegRm;
1619 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1620
1621 /* Make sure this is the right instruction */
1622 ASSERT(Opcode == 0xC0);
1623
1624 TOGGLE_ADSIZE(AddressSize);
1625
1626 /* Get the operands */
1627 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1628 {
1629 /* Exception occurred */
1630 return FALSE;
1631 }
1632
1633 if (!Fast486ReadModrmByteOperands(State,
1634 &ModRegRm,
1635 &Source,
1636 &Destination))
1637 {
1638 /* Exception occurred */
1639 return FALSE;
1640 }
1641
1642 /* Calculate the result */
1643 Result = Source + Destination;
1644
1645 /* Update the flags */
1646 State->Flags.Cf = (Result < Source) && (Result < Destination);
1647 State->Flags.Of = ((Source & SIGN_FLAG_BYTE) == (Destination & SIGN_FLAG_BYTE))
1648 && ((Source & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1649 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1650 State->Flags.Zf = (Result == 0);
1651 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
1652 State->Flags.Pf = Fast486CalculateParity(Result);
1653
1654 /* Write the sum to the destination */
1655 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result))
1656 {
1657 /* Exception occurred */
1658 return FALSE;
1659 }
1660
1661 /* Write the old value of the destination to the source */
1662 if (!Fast486WriteModrmByteOperands(State, &ModRegRm, TRUE, Destination))
1663 {
1664 /* Exception occurred */
1665 return FALSE;
1666 }
1667
1668 return TRUE;
1669 }
1670
1671 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeXadd)
1672 {
1673 FAST486_MOD_REG_RM ModRegRm;
1674 BOOLEAN OperandSize, AddressSize;
1675
1676 /* Make sure this is the right instruction */
1677 ASSERT(Opcode == 0xC1);
1678
1679 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1680
1681 TOGGLE_ADSIZE(AddressSize);
1682 TOGGLE_OPSIZE(OperandSize);
1683
1684 /* Get the operands */
1685 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1686 {
1687 /* Exception occurred */
1688 return FALSE;
1689 }
1690
1691 /* Check the operand size */
1692 if (OperandSize)
1693 {
1694 ULONG Source, Destination, Result;
1695
1696 if (!Fast486ReadModrmDwordOperands(State,
1697 &ModRegRm,
1698 &Source,
1699 &Destination))
1700 {
1701 /* Exception occurred */
1702 return FALSE;
1703 }
1704
1705 /* Calculate the result */
1706 Result = Source + Destination;
1707
1708 /* Update the flags */
1709 State->Flags.Cf = (Result < Source) && (Result < Destination);
1710 State->Flags.Of = ((Source & SIGN_FLAG_LONG) == (Destination & SIGN_FLAG_LONG))
1711 && ((Source & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1712 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1713 State->Flags.Zf = (Result == 0);
1714 State->Flags.Sf = ((Result & SIGN_FLAG_LONG) != 0);
1715 State->Flags.Pf = Fast486CalculateParity(Result);
1716
1717 /* Write the sum to the destination */
1718 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result))
1719 {
1720 /* Exception occurred */
1721 return FALSE;
1722 }
1723
1724 /* Write the old value of the destination to the source */
1725 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, TRUE, Destination))
1726 {
1727 /* Exception occurred */
1728 return FALSE;
1729 }
1730 }
1731 else
1732 {
1733 USHORT Source, Destination, Result;
1734
1735 if (!Fast486ReadModrmWordOperands(State,
1736 &ModRegRm,
1737 &Source,
1738 &Destination))
1739 {
1740 /* Exception occurred */
1741 return FALSE;
1742 }
1743
1744 /* Calculate the result */
1745 Result = Source + Destination;
1746
1747 /* Update the flags */
1748 State->Flags.Cf = (Result < Source) && (Result < Destination);
1749 State->Flags.Of = ((Source & SIGN_FLAG_WORD) == (Destination & SIGN_FLAG_WORD))
1750 && ((Source & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1751 State->Flags.Af = ((((Source & 0x0F) + (Destination & 0x0F)) & 0x10) != 0);
1752 State->Flags.Zf = (Result == 0);
1753 State->Flags.Sf = ((Result & SIGN_FLAG_WORD) != 0);
1754 State->Flags.Pf = Fast486CalculateParity(Result);
1755
1756 /* Write the sum to the destination */
1757 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Result))
1758 {
1759 /* Exception occurred */
1760 return FALSE;
1761 }
1762
1763 /* Write the old value of the destination to the source */
1764 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, TRUE, Destination))
1765 {
1766 /* Exception occurred */
1767 return FALSE;
1768 }
1769 }
1770
1771 return TRUE;
1772 }
1773
1774 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeBswap)
1775 {
1776 PUCHAR Pointer;
1777
1778 NO_LOCK_PREFIX();
1779
1780 /* Get a pointer to the value */
1781 Pointer = (PUCHAR)&State->GeneralRegs[Opcode & 0x07].Long;
1782
1783 /* Swap the byte order */
1784 SWAP(Pointer[0], Pointer[3]);
1785 SWAP(Pointer[1], Pointer[2]);
1786
1787 /* Return success */
1788 return TRUE;
1789 }
1790
1791 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
1792 {
1793 UCHAR SecondOpcode;
1794
1795 /* Fetch the second operation code */
1796 if (!Fast486FetchByte(State, &SecondOpcode))
1797 {
1798 /* Exception occurred */
1799 return FALSE;
1800 }
1801
1802 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
1803 {
1804 /* Call the extended opcode handler */
1805 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
1806 }
1807 else
1808 {
1809 /* This is not a valid opcode */
1810 Fast486Exception(State, FAST486_EXCEPTION_UD);
1811 return FALSE;
1812 }
1813 }
1814