bfc0caa707982e0226202ed17c21dc26e81c62b9
[reactos.git] / lib / fast486 / opgroups.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opgroups.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
33 /* PRIVATE FUNCTIONS **********************************************************/
34
35 inline
36 static
37 ULONG
38 Fast486ArithmeticOperation(PFAST486_STATE State,
39 INT Operation,
40 ULONG FirstValue,
41 ULONG SecondValue,
42 UCHAR Bits)
43 {
44 ULONG Result;
45 ULONG SignFlag = 1 << (Bits - 1);
46 ULONG MaxValue = (SignFlag - 1) | SignFlag;
47
48 /* Make sure the values don't exceed the maximum for their size */
49 FirstValue &= MaxValue;
50 SecondValue &= MaxValue;
51
52 /* Check which operation is this */
53 switch (Operation)
54 {
55 /* ADD */
56 case 0:
57 {
58 Result = (FirstValue + SecondValue) & MaxValue;
59
60 /* Update CF, OF and AF */
61 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
62 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
63 && ((FirstValue & SignFlag) != (Result & SignFlag));
64 State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
65
66 break;
67 }
68
69 /* OR */
70 case 1:
71 {
72 Result = FirstValue | SecondValue;
73 break;
74 }
75
76 /* ADC */
77 case 2:
78 {
79 INT Carry = State->Flags.Cf ? 1 : 0;
80
81 Result = (FirstValue + SecondValue + Carry) & MaxValue;
82
83 /* Update CF, OF and AF */
84 State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1))
85 || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
86 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
87 && ((FirstValue & SignFlag) != (Result & SignFlag));
88 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
89
90 break;
91 }
92
93 /* SBB */
94 case 3:
95 {
96 INT Carry = State->Flags.Cf ? 1 : 0;
97
98 Result = (FirstValue - SecondValue - Carry) & MaxValue;
99
100 /* Update CF, OF and AF */
101 State->Flags.Cf = Carry
102 ? (FirstValue <= SecondValue)
103 : (FirstValue < SecondValue);
104 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
105 && ((FirstValue & SignFlag) != (Result & SignFlag));
106 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
107
108 break;
109 }
110
111 /* AND */
112 case 4:
113 {
114 Result = FirstValue & SecondValue;
115 break;
116 }
117
118 /* SUB or CMP */
119 case 5:
120 case 7:
121 {
122 Result = (FirstValue - SecondValue) & MaxValue;
123
124 /* Update CF, OF and AF */
125 State->Flags.Cf = (FirstValue < SecondValue);
126 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
127 && ((FirstValue & SignFlag) != (Result & SignFlag));
128 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
129
130 break;
131 }
132
133 /* XOR */
134 case 6:
135 {
136 Result = FirstValue ^ SecondValue;
137 break;
138 }
139
140 default:
141 {
142 /* Shouldn't happen */
143 ASSERT(FALSE);
144 }
145 }
146
147 /* Update ZF, SF and PF */
148 State->Flags.Zf = (Result == 0);
149 State->Flags.Sf = ((Result & SignFlag) != 0);
150 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
151
152 /* Return the result */
153 return Result;
154 }
155
156 static
157 inline
158 ULONG
159 Fast486RotateOperation(PFAST486_STATE State,
160 INT Operation,
161 ULONG Value,
162 UCHAR Bits,
163 UCHAR Count)
164 {
165 ULONG HighestBit = 1 << (Bits - 1);
166 ULONG MaxValue = HighestBit | (HighestBit - 1);
167 ULONG Result;
168
169 /* Normalize the count */
170 Count &= 0x1F;
171
172 if ((Operation == 2) || (Operation == 3)) Count %= Bits + 1;
173
174 /* If the count is zero, do nothing */
175 if (Count == 0) return Value;
176
177 /* Check which operation is this */
178 switch (Operation)
179 {
180 /* ROL */
181 case 0:
182 {
183 Count %= Bits;
184 Result = (Value << Count) | (Value >> (Bits - Count));
185
186 /* Update CF and OF */
187 State->Flags.Cf = Result & 1;
188 if (Count == 1) State->Flags.Of = State->Flags.Cf
189 ^ ((Result & HighestBit) != 0);
190
191 break;
192 }
193
194 /* ROR */
195 case 1:
196 {
197 Count %= Bits;
198 Result = (Value >> Count) | (Value << (Bits - Count));
199
200 /* Update CF and OF */
201 State->Flags.Cf = ((Result & HighestBit) != 0);
202 if (Count == 1) State->Flags.Of = State->Flags.Cf
203 ^ ((Result & (HighestBit >> 1)) != 0);
204
205 break;
206 }
207
208 /* RCL */
209 case 2:
210 {
211 Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
212
213 /* Complete the calculation, but make sure we don't shift by too much */
214 if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
215
216 /* Update CF and OF */
217 State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
218 if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
219
220 break;
221 }
222
223 /* RCR */
224 case 3:
225 {
226 /* Update OF */
227 if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Value & HighestBit) != 0);
228
229 Result = (Value >> Count) | (State->Flags.Cf << (Bits - Count));
230
231 /* Complete the calculation, but make sure we don't shift by too much */
232 if ((Bits - Count) < 31) Result |= Value << (Bits - Count + 1);
233
234 /* Update CF */
235 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
236
237 break;
238 }
239
240 /* SHL/SAL */
241 case 4:
242 case 6:
243 {
244 Result = Value << Count;
245
246 /* Update CF and OF */
247 State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
248 if (Count == 1) State->Flags.Of = State->Flags.Cf
249 ^ ((Result & HighestBit) != 0);
250
251 break;
252 }
253
254 /* SHR */
255 case 5:
256 {
257 Result = Value >> Count;
258
259 /* Update CF and OF */
260 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
261 if (Count == 1) State->Flags.Of = ((Value & HighestBit) != 0);
262
263 break;
264 }
265
266 /* SAR */
267 case 7:
268 {
269 Result = Value >> Count;
270
271 /* Fill the top Count bits with the sign bit */
272 if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
273
274 /* Update CF and OF */
275 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
276 if (Count == 1) State->Flags.Of = FALSE;
277
278 break;
279 }
280 }
281
282 if (Operation >= 4)
283 {
284 /* Update ZF, SF and PF */
285 State->Flags.Zf = ((Result & MaxValue) == 0);
286 State->Flags.Sf = ((Result & HighestBit) != 0);
287 State->Flags.Pf = Fast486CalculateParity(Result);
288 }
289
290 /* Return the result */
291 return Result;
292 }
293
294 /* PUBLIC FUNCTIONS ***********************************************************/
295
296 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)
297 {
298 UCHAR Immediate, Value;
299 FAST486_MOD_REG_RM ModRegRm;
300 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
301
302 TOGGLE_ADSIZE(AddressSize);
303
304 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
305 {
306 /* Exception occurred */
307 return FALSE;
308 }
309
310 /* Fetch the immediate operand */
311 if (!Fast486FetchByte(State, &Immediate))
312 {
313 /* Exception occurred */
314 return FALSE;
315 }
316
317 /* Read the operands */
318 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
319 {
320 /* Exception occurred */
321 return FALSE;
322 }
323
324 /* Calculate the result */
325 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
326
327 /* Unless this is CMP, write back the result */
328 if (ModRegRm.Register != 7)
329 {
330 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
331 }
332
333 return TRUE;
334 }
335
336 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
337 {
338 FAST486_MOD_REG_RM ModRegRm;
339 BOOLEAN OperandSize, AddressSize;
340
341 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
342
343 TOGGLE_OPSIZE(OperandSize);
344 TOGGLE_ADSIZE(AddressSize);
345
346 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
347 {
348 /* Exception occurred */
349 return FALSE;
350 }
351
352 if (OperandSize)
353 {
354 ULONG Immediate, Value;
355
356 /* Fetch the immediate operand */
357 if (!Fast486FetchDword(State, &Immediate))
358 {
359 /* Exception occurred */
360 return FALSE;
361 }
362
363 /* Read the operands */
364 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
365 {
366 /* Exception occurred */
367 return FALSE;
368 }
369
370 /* Calculate the result */
371 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
372
373 /* Unless this is CMP, write back the result */
374 if (ModRegRm.Register != 7)
375 {
376 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
377 }
378 }
379 else
380 {
381 USHORT Immediate, Value;
382
383 /* Fetch the immediate operand */
384 if (!Fast486FetchWord(State, &Immediate))
385 {
386 /* Exception occurred */
387 return FALSE;
388 }
389
390 /* Read the operands */
391 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
392 {
393 /* Exception occurred */
394 return FALSE;
395 }
396
397 /* Calculate the result */
398 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
399
400 /* Unless this is CMP, write back the result */
401 if (ModRegRm.Register != 7)
402 {
403 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
404 }
405 }
406
407 return TRUE;
408 }
409
410 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
411 {
412 CHAR ImmByte;
413 FAST486_MOD_REG_RM ModRegRm;
414 BOOLEAN OperandSize, AddressSize;
415
416 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
417
418 TOGGLE_OPSIZE(OperandSize);
419 TOGGLE_ADSIZE(AddressSize);
420
421 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
422 {
423 /* Exception occurred */
424 return FALSE;
425 }
426
427 /* Fetch the immediate operand */
428 if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
429 {
430 /* Exception occurred */
431 return FALSE;
432 }
433
434 if (OperandSize)
435 {
436 ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
437 ULONG Value;
438
439 /* Read the operands */
440 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
441 {
442 /* Exception occurred */
443 return FALSE;
444 }
445
446 /* Calculate the result */
447 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
448
449 /* Unless this is CMP, write back the result */
450 if (ModRegRm.Register != 7)
451 {
452 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
453 }
454 }
455 else
456 {
457 USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
458 USHORT Value;
459
460 /* Read the operands */
461 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
462 {
463 /* Exception occurred */
464 return FALSE;
465 }
466
467 /* Calculate the result */
468 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
469
470 /* Unless this is CMP, write back the result */
471 if (ModRegRm.Register != 7)
472 {
473 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
474 }
475 }
476
477 return TRUE;
478 }
479
480 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
481 {
482 ULONG Value;
483 FAST486_MOD_REG_RM ModRegRm;
484 BOOLEAN OperandSize, AddressSize;
485
486 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
487
488 TOGGLE_OPSIZE(OperandSize);
489 TOGGLE_ADSIZE(AddressSize);
490
491 /* Pop a value from the stack - this must be done first */
492 if (!Fast486StackPop(State, &Value))
493 {
494 /* Exception occurred */
495 return FALSE;
496 }
497
498 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
499 {
500 /* Exception occurred - restore SP */
501 if (OperandSize) State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
502 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
503
504 return FALSE;
505 }
506
507 if (ModRegRm.Register != 0)
508 {
509 /* Invalid */
510 Fast486Exception(State, FAST486_EXCEPTION_UD);
511 return FALSE;
512 }
513
514 if (OperandSize)
515 {
516 return Fast486WriteModrmDwordOperands(State,
517 &ModRegRm,
518 FALSE,
519 Value);
520 }
521 else
522 {
523 return Fast486WriteModrmWordOperands(State,
524 &ModRegRm,
525 FALSE,
526 LOWORD(Value));
527 }
528 }
529
530 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
531 {
532 UCHAR Value, Count;
533 FAST486_MOD_REG_RM ModRegRm;
534 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
535
536 TOGGLE_ADSIZE(AddressSize);
537
538 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
539 {
540 /* Exception occurred */
541 return FALSE;
542 }
543
544 /* Fetch the count */
545 if (!Fast486FetchByte(State, &Count))
546 {
547 /* Exception occurred */
548 return FALSE;
549 }
550
551 /* Read the operands */
552 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
553 {
554 /* Exception occurred */
555 return FALSE;
556 }
557
558 /* Calculate the result */
559 Value = LOBYTE(Fast486RotateOperation(State,
560 ModRegRm.Register,
561 Value,
562 8,
563 Count));
564
565 /* Write back the result */
566 return Fast486WriteModrmByteOperands(State,
567 &ModRegRm,
568 FALSE,
569 Value);
570 }
571
572 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
573 {
574 UCHAR Count;
575 FAST486_MOD_REG_RM ModRegRm;
576 BOOLEAN OperandSize, AddressSize;
577
578 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
579
580 TOGGLE_OPSIZE(OperandSize);
581 TOGGLE_ADSIZE(AddressSize);
582
583 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
584 {
585 /* Exception occurred */
586 return FALSE;
587 }
588
589 /* Fetch the count */
590 if (!Fast486FetchByte(State, &Count))
591 {
592 /* Exception occurred */
593 return FALSE;
594 }
595
596 if (OperandSize)
597 {
598 ULONG Value;
599
600 /* Read the operands */
601 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
602 {
603 /* Exception occurred */
604 return FALSE;
605 }
606
607 /* Calculate the result */
608 Value = Fast486RotateOperation(State,
609 ModRegRm.Register,
610 Value,
611 32,
612 Count);
613
614 /* Write back the result */
615 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
616 }
617 else
618 {
619 USHORT Value;
620
621 /* Read the operands */
622 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
623 {
624 /* Exception occurred */
625 return FALSE;
626 }
627
628 /* Calculate the result */
629 Value = LOWORD(Fast486RotateOperation(State,
630 ModRegRm.Register,
631 Value,
632 16,
633 Count));
634
635 /* Write back the result */
636 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
637 }
638 }
639
640 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)
641 {
642 UCHAR Immediate;
643 FAST486_MOD_REG_RM ModRegRm;
644 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
645
646 TOGGLE_ADSIZE(AddressSize);
647
648 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
649 {
650 /* Exception occurred */
651 return FALSE;
652 }
653
654 if (ModRegRm.Register != 0)
655 {
656 /* Invalid */
657 Fast486Exception(State, FAST486_EXCEPTION_UD);
658 return FALSE;
659 }
660
661 /* Get the immediate operand */
662 if (!Fast486FetchByte(State, &Immediate))
663 {
664 /* Exception occurred */
665 return FALSE;
666 }
667
668 return Fast486WriteModrmByteOperands(State,
669 &ModRegRm,
670 FALSE,
671 Immediate);
672 }
673
674 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
675 {
676 FAST486_MOD_REG_RM ModRegRm;
677 BOOLEAN OperandSize, AddressSize;
678
679 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
680
681 TOGGLE_OPSIZE(OperandSize);
682 TOGGLE_ADSIZE(AddressSize);
683
684 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
685 {
686 /* Exception occurred */
687 return FALSE;
688 }
689
690 if (ModRegRm.Register != 0)
691 {
692 /* Invalid */
693 Fast486Exception(State, FAST486_EXCEPTION_UD);
694 return FALSE;
695 }
696
697 if (OperandSize)
698 {
699 ULONG Immediate;
700
701 /* Get the immediate operand */
702 if (!Fast486FetchDword(State, &Immediate))
703 {
704 /* Exception occurred */
705 return FALSE;
706 }
707
708 return Fast486WriteModrmDwordOperands(State,
709 &ModRegRm,
710 FALSE,
711 Immediate);
712 }
713 else
714 {
715 USHORT Immediate;
716
717 /* Get the immediate operand */
718 if (!Fast486FetchWord(State, &Immediate))
719 {
720 /* Exception occurred */
721 return FALSE;
722 }
723
724 return Fast486WriteModrmWordOperands(State,
725 &ModRegRm,
726 FALSE,
727 Immediate);
728 }
729 }
730
731 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)
732 {
733 UCHAR Value;
734 FAST486_MOD_REG_RM ModRegRm;
735 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
736
737 TOGGLE_ADSIZE(AddressSize);
738
739 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
740 {
741 /* Exception occurred */
742 return FALSE;
743 }
744
745 /* Read the operands */
746 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
747 {
748 /* Exception occurred */
749 return FALSE;
750 }
751
752 /* Calculate the result */
753 Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
754
755 /* Write back the result */
756 return Fast486WriteModrmByteOperands(State,
757 &ModRegRm,
758 FALSE,
759 Value);
760
761 }
762
763 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)
764 {
765 FAST486_MOD_REG_RM ModRegRm;
766 BOOLEAN OperandSize, AddressSize;
767
768 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
769
770 TOGGLE_OPSIZE(OperandSize);
771 TOGGLE_ADSIZE(AddressSize);
772
773 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
774 {
775 /* Exception occurred */
776 return FALSE;
777 }
778
779 if (OperandSize)
780 {
781 ULONG Value;
782
783 /* Read the operands */
784 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
785 {
786 /* Exception occurred */
787 return FALSE;
788 }
789
790 /* Calculate the result */
791 Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
792
793 /* Write back the result */
794 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
795 }
796 else
797 {
798 USHORT Value;
799
800 /* Read the operands */
801 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
802 {
803 /* Exception occurred */
804 return FALSE;
805 }
806
807 /* Calculate the result */
808 Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
809
810 /* Write back the result */
811 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
812 }
813 }
814
815 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)
816 {
817 UCHAR Value;
818 FAST486_MOD_REG_RM ModRegRm;
819 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
820
821 TOGGLE_ADSIZE(AddressSize);
822
823 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
824 {
825 /* Exception occurred */
826 return FALSE;
827 }
828
829 /* Read the operands */
830 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
831 {
832 /* Exception occurred */
833 return FALSE;
834 }
835
836 /* Calculate the result */
837 Value = LOBYTE(Fast486RotateOperation(State,
838 ModRegRm.Register,
839 Value,
840 8,
841 State->GeneralRegs[FAST486_REG_ECX].LowByte));
842
843 /* Write back the result */
844 return Fast486WriteModrmByteOperands(State,
845 &ModRegRm,
846 FALSE,
847 Value);
848 }
849
850 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
851 {
852 FAST486_MOD_REG_RM ModRegRm;
853 BOOLEAN OperandSize, AddressSize;
854
855 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
856
857 TOGGLE_OPSIZE(OperandSize);
858 TOGGLE_ADSIZE(AddressSize);
859
860 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
861 {
862 /* Exception occurred */
863 return FALSE;
864 }
865
866 if (OperandSize)
867 {
868 ULONG Value;
869
870 /* Read the operands */
871 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
872 {
873 /* Exception occurred */
874 return FALSE;
875 }
876
877 /* Calculate the result */
878 Value = Fast486RotateOperation(State,
879 ModRegRm.Register,
880 Value,
881 32,
882 State->GeneralRegs[FAST486_REG_ECX].LowByte);
883
884 /* Write back the result */
885 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
886 }
887 else
888 {
889 USHORT Value;
890
891 /* Read the operands */
892 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
893 {
894 /* Exception occurred */
895 return FALSE;
896 }
897
898 /* Calculate the result */
899 Value = LOWORD(Fast486RotateOperation(State,
900 ModRegRm.Register,
901 Value,
902 16,
903 State->GeneralRegs[FAST486_REG_ECX].LowByte));
904
905 /* Write back the result */
906 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
907 }
908 }
909
910 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
911 {
912 UCHAR Value = 0;
913 FAST486_MOD_REG_RM ModRegRm;
914 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
915
916 TOGGLE_ADSIZE(AddressSize);
917
918 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
919 {
920 /* Exception occurred */
921 return FALSE;
922 }
923
924 /* Read the operands */
925 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
926 {
927 /* Exception occurred */
928 return FALSE;
929 }
930
931 switch (ModRegRm.Register)
932 {
933 /* TEST */
934 case 0:
935 case 1:
936 {
937 UCHAR Immediate, Result;
938
939 /* Fetch the immediate byte */
940 if (!Fast486FetchByte(State, &Immediate))
941 {
942 /* Exception occurred */
943 return FALSE;
944 }
945
946 /* Calculate the result */
947 Result = Value & Immediate;
948
949 /* Update the flags */
950 State->Flags.Cf = FALSE;
951 State->Flags.Of = FALSE;
952 State->Flags.Zf = (Result == 0);
953 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
954 State->Flags.Pf = Fast486CalculateParity(Result);
955
956 break;
957 }
958
959 /* NOT */
960 case 2:
961 {
962 /* Write back the result */
963 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
964 }
965
966 /* NEG */
967 case 3:
968 {
969 /* Calculate the result */
970 UCHAR Result = -Value;
971
972 /* Update the flags */
973 State->Flags.Cf = (Value != 0);
974 State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
975 State->Flags.Af = ((Value & 0x0F) != 0);
976 State->Flags.Zf = (Result == 0);
977 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
978 State->Flags.Pf = Fast486CalculateParity(Result);
979
980 /* Write back the result */
981 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
982 }
983
984 /* MUL */
985 case 4:
986 {
987 USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
988
989 /* Update the flags */
990 State->Flags.Cf = State->Flags.Of = (HIBYTE(Result) != 0);
991
992 /* Write back the result */
993 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
994
995 break;
996 }
997
998 /* IMUL */
999 case 5:
1000 {
1001 SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
1002
1003 /* Update the flags */
1004 State->Flags.Cf = State->Flags.Of = ((Result < -128) || (Result > 127));
1005
1006 /* Write back the result */
1007 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
1008
1009 break;
1010 }
1011
1012 /* DIV */
1013 case 6:
1014 {
1015 UCHAR Quotient, Remainder;
1016
1017 if (Value == 0)
1018 {
1019 /* Divide error */
1020 Fast486Exception(State, FAST486_EXCEPTION_DE);
1021 return FALSE;
1022 }
1023
1024 Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
1025 Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
1026
1027 /* Write back the results */
1028 State->GeneralRegs[FAST486_REG_EAX].LowByte = Quotient;
1029 State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1030
1031 break;
1032 }
1033
1034 /* IDIV */
1035 case 7:
1036 {
1037 CHAR Quotient, Remainder;
1038
1039 if (Value == 0)
1040 {
1041 /* Divide error */
1042 Fast486Exception(State, FAST486_EXCEPTION_DE);
1043 return FALSE;
1044 }
1045
1046 Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1047 Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1048
1049 /* Write back the results */
1050 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1051 State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1052
1053 break;
1054 }
1055 }
1056
1057 return TRUE;
1058 }
1059
1060 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1061 {
1062 ULONG Value = 0, SignFlag;
1063 FAST486_MOD_REG_RM ModRegRm;
1064 BOOLEAN OperandSize, AddressSize;
1065
1066 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1067
1068 TOGGLE_OPSIZE(OperandSize);
1069 TOGGLE_ADSIZE(AddressSize);
1070
1071 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1072 {
1073 /* Exception occurred */
1074 return FALSE;
1075 }
1076
1077 /* Set the sign flag */
1078 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1079 else SignFlag = SIGN_FLAG_WORD;
1080
1081 /* Read the operand */
1082 if (OperandSize)
1083 {
1084 /* 32-bit */
1085 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1086 {
1087 /* Exception occurred */
1088 return FALSE;
1089 }
1090 }
1091 else
1092 {
1093 /* 16-bit */
1094 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1095 {
1096 /* Exception occurred */
1097 return FALSE;
1098 }
1099 }
1100
1101 switch (ModRegRm.Register)
1102 {
1103 /* TEST */
1104 case 0:
1105 case 1:
1106 {
1107 ULONG Immediate = 0, Result = 0;
1108
1109 if (OperandSize)
1110 {
1111 /* Fetch the immediate dword */
1112 if (!Fast486FetchDword(State, &Immediate))
1113 {
1114 /* Exception occurred */
1115 return FALSE;
1116 }
1117 }
1118 else
1119 {
1120 /* Fetch the immediate word */
1121 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1122 {
1123 /* Exception occurred */
1124 return FALSE;
1125 }
1126 }
1127
1128 /* Calculate the result */
1129 Result = Value & Immediate;
1130
1131 /* Update the flags */
1132 State->Flags.Cf = FALSE;
1133 State->Flags.Of = FALSE;
1134 State->Flags.Zf = (Result == 0);
1135 State->Flags.Sf = ((Result & SignFlag) != 0);
1136 State->Flags.Pf = Fast486CalculateParity(Result);
1137
1138 break;
1139 }
1140
1141 /* NOT */
1142 case 2:
1143 {
1144 /* Write back the result */
1145 if (OperandSize)
1146 {
1147 /* 32-bit */
1148 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1149 }
1150 else
1151 {
1152 /* 16-bit */
1153 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1154 }
1155 }
1156
1157 /* NEG */
1158 case 3:
1159 {
1160 /* Calculate the result */
1161 ULONG Result = -Value;
1162 if (!OperandSize) Result &= 0xFFFF;
1163
1164 /* Update the flags */
1165 State->Flags.Cf = (Value != 0);
1166 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1167 State->Flags.Af = ((Value & 0x0F) != 0);
1168 State->Flags.Zf = (Result == 0);
1169 State->Flags.Sf = ((Result & SignFlag) != 0);
1170 State->Flags.Pf = Fast486CalculateParity(Result);
1171
1172 /* Write back the result */
1173 if (OperandSize)
1174 {
1175 /* 32-bit */
1176 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1177 }
1178 else
1179 {
1180 /* 16-bit */
1181 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1182 }
1183 }
1184
1185 /* MUL */
1186 case 4:
1187 {
1188 if (OperandSize)
1189 {
1190 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1191
1192 /* Update the flags */
1193 State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
1194
1195 /* Write back the result */
1196 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1197 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1198 }
1199 else
1200 {
1201 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1202
1203 /* Update the flags */
1204 State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
1205
1206 /* Write back the result */
1207 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1208 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1209 }
1210
1211 break;
1212 }
1213
1214 /* IMUL */
1215 case 5:
1216 {
1217 if (OperandSize)
1218 {
1219 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1220
1221 /* Update the flags */
1222 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1223
1224 /* Write back the result */
1225 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1226 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1227 }
1228 else
1229 {
1230 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1231
1232 /* Update the flags */
1233 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1234
1235 /* Write back the result */
1236 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1237 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1238 }
1239
1240 break;
1241 }
1242
1243 /* DIV */
1244 case 6:
1245 {
1246 if (Value == 0)
1247 {
1248 /* Divide error */
1249 Fast486Exception(State, FAST486_EXCEPTION_DE);
1250 return FALSE;
1251 }
1252
1253 if (OperandSize)
1254 {
1255 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1256 | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1257 ULONG Quotient = Dividend / Value;
1258 ULONG Remainder = Dividend % Value;
1259
1260 /* Write back the results */
1261 State->GeneralRegs[FAST486_REG_EAX].Long = Quotient;
1262 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1263 }
1264 else
1265 {
1266 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1267 | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1268 USHORT Quotient = Dividend / Value;
1269 USHORT Remainder = Dividend % Value;
1270
1271 /* Write back the results */
1272 State->GeneralRegs[FAST486_REG_EAX].LowWord = Quotient;
1273 State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
1274 }
1275
1276 break;
1277 }
1278
1279 /* IDIV */
1280 case 7:
1281 {
1282 if (Value == 0)
1283 {
1284 /* Divide error */
1285 Fast486Exception(State, FAST486_EXCEPTION_DE);
1286 return FALSE;
1287 }
1288
1289 if (OperandSize)
1290 {
1291 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1292 | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1293 LONG Quotient = Dividend / (LONG)Value;
1294 LONG Remainder = Dividend % (LONG)Value;
1295
1296 /* Write back the results */
1297 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1298 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1299 }
1300 else
1301 {
1302 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1303 | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1304 SHORT Quotient = Dividend / (SHORT)LOWORD(Value);
1305 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1306
1307 /* Write back the results */
1308 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
1309 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1310 }
1311
1312 break;
1313 }
1314 }
1315
1316 return TRUE;
1317 }
1318
1319 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1320 {
1321 UCHAR Value;
1322 FAST486_MOD_REG_RM ModRegRm;
1323 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1324
1325 TOGGLE_ADSIZE(AddressSize);
1326
1327 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1328 {
1329 /* Exception occurred */
1330 return FALSE;
1331 }
1332
1333 if (ModRegRm.Register > 1)
1334 {
1335 /* Invalid */
1336 Fast486Exception(State, FAST486_EXCEPTION_UD);
1337 return FALSE;
1338 }
1339
1340 /* Read the operands */
1341 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1342 {
1343 /* Exception occurred */
1344 return FALSE;
1345 }
1346
1347 if (ModRegRm.Register == 0)
1348 {
1349 /* Increment and update OF and AF */
1350 Value++;
1351 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1352 State->Flags.Af = ((Value & 0x0F) == 0);
1353 }
1354 else
1355 {
1356 /* Decrement and update OF and AF */
1357 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1358 Value--;
1359 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1360 }
1361
1362 /* Update flags */
1363 State->Flags.Zf = (Value == 0);
1364 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
1365 State->Flags.Pf = Fast486CalculateParity(Value);
1366
1367 /* Write back the result */
1368 return Fast486WriteModrmByteOperands(State,
1369 &ModRegRm,
1370 FALSE,
1371 Value);
1372 }
1373
1374 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1375 {
1376 FAST486_MOD_REG_RM ModRegRm;
1377 BOOLEAN OperandSize, AddressSize;
1378
1379 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1380
1381 TOGGLE_OPSIZE(OperandSize);
1382 TOGGLE_ADSIZE(AddressSize);
1383
1384 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1385 {
1386 /* Exception occurred */
1387 return FALSE;
1388 }
1389
1390 if (ModRegRm.Register == 7)
1391 {
1392 /* Invalid */
1393 Fast486Exception(State, FAST486_EXCEPTION_UD);
1394 return FALSE;
1395 }
1396
1397 /* Read the operands */
1398 if (OperandSize)
1399 {
1400 ULONG Value;
1401
1402 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1403 {
1404 /* Exception occurred */
1405 return FALSE;
1406 }
1407
1408 if (ModRegRm.Register == 0)
1409 {
1410 /* Increment and update OF and AF */
1411 Value++;
1412 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1413 State->Flags.Af = ((Value & 0x0F) == 0);
1414 }
1415 else if (ModRegRm.Register == 1)
1416 {
1417 /* Decrement and update OF and AF */
1418 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1419 Value--;
1420 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1421 }
1422 else if (ModRegRm.Register == 2)
1423 {
1424 /* Push the current value of EIP */
1425 if (!Fast486StackPush(State, State->InstPtr.Long))
1426 {
1427 /* Exception occurred */
1428 return FALSE;
1429 }
1430
1431 /* Set the EIP to the address */
1432 State->InstPtr.Long = Value;
1433 }
1434 else if (ModRegRm.Register == 3)
1435 {
1436 USHORT Selector;
1437 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1438
1439 /* Check for the segment override */
1440 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1441 {
1442 /* Use the override segment instead */
1443 Segment = State->SegmentOverride;
1444 }
1445
1446 /* Read the selector */
1447 if (!Fast486ReadMemory(State,
1448 Segment,
1449 ModRegRm.MemoryAddress + sizeof(ULONG),
1450 FALSE,
1451 &Selector,
1452 sizeof(USHORT)))
1453 {
1454 /* Exception occurred */
1455 return FALSE;
1456 }
1457
1458 /* Push the current value of CS */
1459 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1460 {
1461 /* Exception occurred */
1462 return FALSE;
1463 }
1464
1465 /* Push the current value of EIP */
1466 if (!Fast486StackPush(State, State->InstPtr.Long))
1467 {
1468 /* Exception occurred */
1469 return FALSE;
1470 }
1471
1472 /* Load the new code segment */
1473 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1474 {
1475 /* Exception occurred */
1476 return FALSE;
1477 }
1478
1479 /* Set the EIP to the address */
1480 State->InstPtr.Long = Value;
1481 }
1482 else if (ModRegRm.Register == 4)
1483 {
1484 /* Set the EIP to the address */
1485 State->InstPtr.Long = Value;
1486 }
1487 else if (ModRegRm.Register == 5)
1488 {
1489 USHORT Selector;
1490 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1491
1492 /* Check for the segment override */
1493 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1494 {
1495 /* Use the override segment instead */
1496 Segment = State->SegmentOverride;
1497 }
1498
1499 /* Read the selector */
1500 if (!Fast486ReadMemory(State,
1501 Segment,
1502 ModRegRm.MemoryAddress + sizeof(ULONG),
1503 FALSE,
1504 &Selector,
1505 sizeof(USHORT)))
1506 {
1507 /* Exception occurred */
1508 return FALSE;
1509 }
1510
1511 /* Load the new code segment */
1512 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1513 {
1514 /* Exception occurred */
1515 return FALSE;
1516 }
1517
1518 /* Set the EIP to the address */
1519 State->InstPtr.Long = Value;
1520 }
1521 else if (ModRegRm.Register == 6)
1522 {
1523 /* Push the value on to the stack */
1524 return Fast486StackPush(State, Value);
1525 }
1526
1527 if (ModRegRm.Register <= 1)
1528 {
1529 /* Update flags */
1530 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1531 State->Flags.Zf = (Value == 0);
1532 State->Flags.Pf = Fast486CalculateParity(Value);
1533
1534 /* Write back the result */
1535 return Fast486WriteModrmDwordOperands(State,
1536 &ModRegRm,
1537 FALSE,
1538 Value);
1539 }
1540 }
1541 else
1542 {
1543 USHORT Value;
1544
1545 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1546 {
1547 /* Exception occurred */
1548 return FALSE;
1549 }
1550
1551 if (ModRegRm.Register == 0)
1552 {
1553 /* Increment and update OF */
1554 Value++;
1555 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1556 State->Flags.Af = ((Value & 0x0F) == 0);
1557 }
1558 else if (ModRegRm.Register == 1)
1559 {
1560 /* Decrement and update OF */
1561 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1562 Value--;
1563 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1564 }
1565 else if (ModRegRm.Register == 2)
1566 {
1567 /* Push the current value of IP */
1568 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1569 {
1570 /* Exception occurred */
1571 return FALSE;
1572 }
1573
1574 /* Set the IP to the address */
1575 State->InstPtr.LowWord = Value;
1576
1577 /* Clear the top half of EIP */
1578 State->InstPtr.Long &= 0xFFFF;
1579 }
1580 else if (ModRegRm.Register == 3)
1581 {
1582 USHORT Selector;
1583 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1584
1585 /* Check for the segment override */
1586 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1587 {
1588 /* Use the override segment instead */
1589 Segment = State->SegmentOverride;
1590 }
1591
1592 /* Read the selector */
1593 if (!Fast486ReadMemory(State,
1594 Segment,
1595 ModRegRm.MemoryAddress + sizeof(USHORT),
1596 FALSE,
1597 &Selector,
1598 sizeof(USHORT)))
1599 {
1600 /* Exception occurred */
1601 return FALSE;
1602 }
1603
1604 /* Push the current value of CS */
1605 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1606 {
1607 /* Exception occurred */
1608 return FALSE;
1609 }
1610
1611 /* Push the current value of IP */
1612 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1613 {
1614 /* Exception occurred */
1615 return FALSE;
1616 }
1617
1618 /* Load the new code segment */
1619 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1620 {
1621 /* Exception occurred */
1622 return FALSE;
1623 }
1624
1625 /* Set the IP to the address */
1626 State->InstPtr.LowWord = Value;
1627
1628 /* Clear the top half of EIP */
1629 State->InstPtr.Long &= 0xFFFF;
1630 }
1631 else if (ModRegRm.Register == 4)
1632 {
1633 /* Set the IP to the address */
1634 State->InstPtr.LowWord = Value;
1635 }
1636 else if (ModRegRm.Register == 5)
1637 {
1638 USHORT Selector;
1639 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1640
1641 /* Check for the segment override */
1642 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1643 {
1644 /* Use the override segment instead */
1645 Segment = State->SegmentOverride;
1646 }
1647
1648 /* Read the selector */
1649 if (!Fast486ReadMemory(State,
1650 Segment,
1651 ModRegRm.MemoryAddress + sizeof(USHORT),
1652 FALSE,
1653 &Selector,
1654 sizeof(USHORT)))
1655 {
1656 /* Exception occurred */
1657 return FALSE;
1658 }
1659
1660 /* Load the new code segment */
1661 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1662 {
1663 /* Exception occurred */
1664 return FALSE;
1665 }
1666
1667 /* Set the IP to the address */
1668 State->InstPtr.LowWord = Value;
1669
1670 /* Clear the top half of EIP */
1671 State->InstPtr.Long &= 0xFFFF;
1672 }
1673 else if (ModRegRm.Register == 6)
1674 {
1675 /* Push the value on to the stack */
1676 return Fast486StackPush(State, Value);
1677 }
1678 else
1679 {
1680 /* Invalid */
1681 Fast486Exception(State, FAST486_EXCEPTION_UD);
1682 return FALSE;
1683 }
1684
1685 if (ModRegRm.Register <= 1)
1686 {
1687 /* Update flags */
1688 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1689 State->Flags.Zf = (Value == 0);
1690 State->Flags.Pf = Fast486CalculateParity(Value);
1691
1692 /* Write back the result */
1693 return Fast486WriteModrmWordOperands(State,
1694 &ModRegRm,
1695 FALSE,
1696 Value);
1697 }
1698 }
1699
1700 return TRUE;
1701 }
1702
1703 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
1704 {
1705 UCHAR TableReg[6];
1706 FAST486_MOD_REG_RM ModRegRm;
1707 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1708 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1709
1710 NO_LOCK_PREFIX();
1711 TOGGLE_ADSIZE(AddressSize);
1712
1713 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1714 {
1715 /* Exception occurred */
1716 return FALSE;
1717 }
1718
1719 /* Check for the segment override */
1720 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1721 {
1722 /* Use the override segment instead */
1723 Segment = State->SegmentOverride;
1724 }
1725
1726 /* Check which operation this is */
1727 switch (ModRegRm.Register)
1728 {
1729 /* SLDT */
1730 case 0:
1731 {
1732 if (!ModRegRm.Memory)
1733 {
1734 /* The second operand must be a memory location */
1735 Fast486Exception(State, FAST486_EXCEPTION_UD);
1736 return FALSE;
1737 }
1738
1739 /* Fill the 6-byte table register */
1740 RtlCopyMemory(TableReg, &State->Ldtr.Size, sizeof(USHORT));
1741 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Ldtr.Address, sizeof(ULONG));
1742
1743 /* Store the LDTR */
1744 return Fast486WriteMemory(State,
1745 Segment,
1746 ModRegRm.MemoryAddress,
1747 TableReg,
1748 sizeof(TableReg));
1749 }
1750
1751 /* STR */
1752 case 1:
1753 {
1754 /* Not recognized in real mode or virtual 8086 mode */
1755 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1756 || State->Flags.Vm)
1757 {
1758 Fast486Exception(State, FAST486_EXCEPTION_UD);
1759 }
1760
1761 return Fast486WriteModrmWordOperands(State,
1762 &ModRegRm,
1763 FALSE,
1764 State->TaskReg.Selector);
1765 }
1766
1767 /* LLDT */
1768 case 2:
1769 {
1770 /* This is a privileged instruction */
1771 if (Fast486GetCurrentPrivLevel(State) != 0)
1772 {
1773 Fast486Exception(State, FAST486_EXCEPTION_GP);
1774 return FALSE;
1775 }
1776
1777 if (!ModRegRm.Memory)
1778 {
1779 /* The second operand must be a memory location */
1780 Fast486Exception(State, FAST486_EXCEPTION_UD);
1781 return FALSE;
1782 }
1783
1784 /* Read the new LDTR */
1785 if (!Fast486ReadMemory(State,
1786 Segment,
1787 ModRegRm.MemoryAddress,
1788 FALSE,
1789 TableReg,
1790 sizeof(TableReg)))
1791 {
1792 /* Exception occurred */
1793 return FALSE;
1794 }
1795
1796 /* Load the new LDT */
1797 State->Ldtr.Size = *((PUSHORT)TableReg);
1798 State->Ldtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
1799
1800 return TRUE;
1801 }
1802
1803 /* LTR */
1804 case 3:
1805 {
1806 USHORT Selector;
1807 FAST486_TSS_DESCRIPTOR GdtEntry;
1808
1809 /* Not recognized in real mode or virtual 8086 mode */
1810 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1811 || State->Flags.Vm)
1812 {
1813 Fast486Exception(State, FAST486_EXCEPTION_UD);
1814 }
1815
1816 /* This is a privileged instruction */
1817 if (Fast486GetCurrentPrivLevel(State) != 0)
1818 {
1819 Fast486Exception(State, FAST486_EXCEPTION_GP);
1820 return FALSE;
1821 }
1822
1823 if (!Fast486ReadModrmWordOperands(State,
1824 &ModRegRm,
1825 NULL,
1826 &Selector))
1827 {
1828 /* Exception occurred */
1829 return FALSE;
1830 }
1831
1832 /* Make sure the GDT contains the entry */
1833 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1834 {
1835 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1836 return FALSE;
1837 }
1838
1839 /* Read the GDT */
1840 if (!Fast486ReadLinearMemory(State,
1841 State->Gdtr.Address
1842 + GET_SEGMENT_INDEX(Selector),
1843 &GdtEntry,
1844 sizeof(GdtEntry)))
1845 {
1846 /* Exception occurred */
1847 return FALSE;
1848 }
1849
1850 if (GET_SEGMENT_INDEX(Selector) == 0)
1851 {
1852 Fast486Exception(State, FAST486_EXCEPTION_GP);
1853 return FALSE;
1854 }
1855
1856 if (!GdtEntry.Present)
1857 {
1858 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1859 return FALSE;
1860 }
1861
1862 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
1863 {
1864 /* This is not a TSS descriptor */
1865 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1866 return FALSE;
1867 }
1868
1869 /* Update the TR */
1870 State->TaskReg.Selector = Selector;
1871 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1872 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1873 if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
1874 State->TaskReg.Busy = TRUE;
1875
1876 return TRUE;
1877 }
1878
1879 /* VERR/VERW */
1880 case 4:
1881 case 5:
1882 {
1883 USHORT Selector;
1884 FAST486_GDT_ENTRY GdtEntry;
1885
1886 /* Not recognized in real mode or virtual 8086 mode */
1887 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1888 || State->Flags.Vm)
1889 {
1890 Fast486Exception(State, FAST486_EXCEPTION_UD);
1891 }
1892
1893 /* This is a privileged instruction */
1894 if (Fast486GetCurrentPrivLevel(State) != 0)
1895 {
1896 Fast486Exception(State, FAST486_EXCEPTION_GP);
1897 return FALSE;
1898 }
1899
1900 if (!Fast486ReadModrmWordOperands(State,
1901 &ModRegRm,
1902 NULL,
1903 &Selector))
1904 {
1905 /* Exception occurred */
1906 return FALSE;
1907 }
1908
1909 if (!(Selector & SEGMENT_TABLE_INDICATOR))
1910 {
1911 /* Make sure the GDT contains the entry */
1912 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1913 {
1914 /* Clear ZF */
1915 State->Flags.Zf = FALSE;
1916 return TRUE;
1917 }
1918
1919 /* Read the GDT */
1920 if (!Fast486ReadLinearMemory(State,
1921 State->Gdtr.Address
1922 + GET_SEGMENT_INDEX(Selector),
1923 &GdtEntry,
1924 sizeof(GdtEntry)))
1925 {
1926 /* Exception occurred */
1927 return FALSE;
1928 }
1929 }
1930 else
1931 {
1932 /* Make sure the LDT contains the entry */
1933 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Size + 1))
1934 {
1935 /* Clear ZF */
1936 State->Flags.Zf = FALSE;
1937 return TRUE;
1938 }
1939
1940 /* Read the LDT */
1941 if (!Fast486ReadLinearMemory(State,
1942 State->Ldtr.Address
1943 + GET_SEGMENT_INDEX(Selector),
1944 &GdtEntry,
1945 sizeof(GdtEntry)))
1946 {
1947 /* Exception occurred */
1948 return FALSE;
1949 }
1950 }
1951
1952 /* Set ZF if it is valid and accessible */
1953 State->Flags.Zf = GdtEntry.Present // must be present
1954 && GdtEntry.SystemType // must be a segment
1955 && (((ModRegRm.Register == 4)
1956 /* code segments are only readable if the RW bit is set */
1957 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
1958 || ((ModRegRm.Register == 5)
1959 /* code segments are never writable, data segments are writable when RW is set */
1960 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
1961 /*
1962 * for segments other than conforming code segments,
1963 * both RPL and CPL must be less than or equal to DPL
1964 */
1965 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
1966 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
1967 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
1968 /* for conforming code segments, DPL must be less than or equal to CPL */
1969 && ((GdtEntry.Executable && GdtEntry.DirConf)
1970 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
1971
1972
1973 return TRUE;
1974 }
1975
1976 /* Invalid */
1977 default:
1978 {
1979 Fast486Exception(State, FAST486_EXCEPTION_UD);
1980 return FALSE;
1981 }
1982 }
1983 }
1984
1985 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
1986 {
1987 UCHAR TableReg[6];
1988 FAST486_MOD_REG_RM ModRegRm;
1989 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1990 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1991
1992 NO_LOCK_PREFIX();
1993 TOGGLE_ADSIZE(AddressSize);
1994
1995 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1996 {
1997 /* Exception occurred */
1998 return FALSE;
1999 }
2000
2001 /* Check for the segment override */
2002 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2003 {
2004 /* Use the override segment instead */
2005 Segment = State->SegmentOverride;
2006 }
2007
2008 /* Check which operation this is */
2009 switch (ModRegRm.Register)
2010 {
2011 /* SGDT */
2012 case 0:
2013 {
2014 if (!ModRegRm.Memory)
2015 {
2016 /* The second operand must be a memory location */
2017 Fast486Exception(State, FAST486_EXCEPTION_UD);
2018 return FALSE;
2019 }
2020
2021 /* Fill the 6-byte table register */
2022 RtlCopyMemory(TableReg, &State->Gdtr.Size, sizeof(USHORT));
2023 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Gdtr.Address, sizeof(ULONG));
2024
2025 /* Store the GDTR */
2026 return Fast486WriteMemory(State,
2027 Segment,
2028 ModRegRm.MemoryAddress,
2029 TableReg,
2030 sizeof(TableReg));
2031 }
2032
2033 /* SIDT */
2034 case 1:
2035 {
2036 if (!ModRegRm.Memory)
2037 {
2038 /* The second operand must be a memory location */
2039 Fast486Exception(State, FAST486_EXCEPTION_UD);
2040 return FALSE;
2041 }
2042
2043 /* Fill the 6-byte table register */
2044 RtlCopyMemory(TableReg, &State->Idtr.Size, sizeof(USHORT));
2045 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Idtr.Address, sizeof(ULONG));
2046
2047 /* Store the IDTR */
2048 return Fast486WriteMemory(State,
2049 Segment,
2050 ModRegRm.MemoryAddress,
2051 TableReg,
2052 sizeof(TableReg));
2053 }
2054
2055 /* LGDT */
2056 case 2:
2057 {
2058 /* This is a privileged instruction */
2059 if (Fast486GetCurrentPrivLevel(State) != 0)
2060 {
2061 Fast486Exception(State, FAST486_EXCEPTION_GP);
2062 return FALSE;
2063 }
2064
2065 if (!ModRegRm.Memory)
2066 {
2067 /* The second operand must be a memory location */
2068 Fast486Exception(State, FAST486_EXCEPTION_UD);
2069 return FALSE;
2070 }
2071
2072 /* Read the new GDTR */
2073 if (!Fast486ReadMemory(State,
2074 Segment,
2075 ModRegRm.MemoryAddress,
2076 FALSE,
2077 TableReg,
2078 sizeof(TableReg)))
2079 {
2080 /* Exception occurred */
2081 return FALSE;
2082 }
2083
2084 /* Load the new GDT */
2085 State->Gdtr.Size = *((PUSHORT)TableReg);
2086 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2087
2088 return TRUE;
2089 }
2090
2091 /* LIDT */
2092 case 3:
2093 {
2094 /* This is a privileged instruction */
2095 if (Fast486GetCurrentPrivLevel(State) != 0)
2096 {
2097 Fast486Exception(State, FAST486_EXCEPTION_GP);
2098 return FALSE;
2099 }
2100
2101 if (!ModRegRm.Memory)
2102 {
2103 /* The second operand must be a memory location */
2104 Fast486Exception(State, FAST486_EXCEPTION_UD);
2105 return FALSE;
2106 }
2107
2108 /* Read the new IDTR */
2109 if (!Fast486ReadMemory(State,
2110 Segment,
2111 ModRegRm.MemoryAddress,
2112 FALSE,
2113 TableReg,
2114 sizeof(TableReg)))
2115 {
2116 /* Exception occurred */
2117 return FALSE;
2118 }
2119
2120 /* Load the new IDT */
2121 State->Idtr.Size = *((PUSHORT)TableReg);
2122 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2123
2124 return TRUE;
2125 }
2126
2127 /* SMSW */
2128 case 4:
2129 {
2130 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2131 return Fast486WriteModrmWordOperands(State,
2132 &ModRegRm,
2133 FALSE,
2134 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2135 }
2136
2137 /* LMSW */
2138 case 6:
2139 {
2140 USHORT MachineStatusWord;
2141
2142 /* This is a privileged instruction */
2143 if (Fast486GetCurrentPrivLevel(State) != 0)
2144 {
2145 Fast486Exception(State, FAST486_EXCEPTION_GP);
2146 return FALSE;
2147 }
2148
2149 /* Read the new Machine Status Word */
2150 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2151 {
2152 /* Exception occurred */
2153 return FALSE;
2154 }
2155
2156 /* This instruction cannot be used to return to real mode */
2157 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2158 && !(MachineStatusWord & FAST486_CR0_PE))
2159 {
2160 Fast486Exception(State, FAST486_EXCEPTION_GP);
2161 return FALSE;
2162 }
2163
2164 /* Set the lowest 4 bits */
2165 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2166 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2167
2168 return TRUE;
2169 }
2170
2171 /* INVLPG */
2172 case 7:
2173 {
2174 UNIMPLEMENTED;
2175 return FALSE;
2176 }
2177
2178 /* Invalid */
2179 default:
2180 {
2181 Fast486Exception(State, FAST486_EXCEPTION_UD);
2182 return FALSE;
2183 }
2184 }
2185 }
2186
2187 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
2188 {
2189 FAST486_MOD_REG_RM ModRegRm;
2190 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2191
2192 TOGGLE_ADSIZE(AddressSize);
2193
2194 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2195 {
2196 /* Exception occurred */
2197 return FALSE;
2198 }
2199
2200 /* All of them are reserved (UD2) */
2201 Fast486Exception(State, FAST486_EXCEPTION_UD);
2202 return FALSE;
2203 }
2204
2205 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
2206 {
2207 FAST486_MOD_REG_RM ModRegRm;
2208 BOOLEAN OperandSize, AddressSize;
2209 UINT DataSize;
2210 UCHAR BitNumber;
2211
2212 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2213
2214 TOGGLE_OPSIZE(OperandSize);
2215 TOGGLE_ADSIZE(AddressSize);
2216
2217 /* Get the number of bits */
2218 if (OperandSize) DataSize = 32;
2219 else DataSize = 16;
2220
2221 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2222 {
2223 /* Exception occurred */
2224 return FALSE;
2225 }
2226
2227 if (ModRegRm.Register < 4)
2228 {
2229 /* Invalid */
2230 Fast486Exception(State, FAST486_EXCEPTION_UD);
2231 return FALSE;
2232 }
2233
2234 /* Get the bit number */
2235 if (!Fast486FetchByte(State, &BitNumber))
2236 {
2237 /* Exception occurred */
2238 return FALSE;
2239 }
2240
2241 if (ModRegRm.Memory)
2242 {
2243 /*
2244 * For memory operands, add the bit offset divided by
2245 * the data size to the address
2246 */
2247 ModRegRm.MemoryAddress += BitNumber / DataSize;
2248 }
2249
2250 /* Normalize the bit number */
2251 BitNumber %= DataSize;
2252
2253 if (OperandSize)
2254 {
2255 ULONG Value;
2256
2257 /* Read the value */
2258 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2259 {
2260 /* Exception occurred */
2261 return FALSE;
2262 }
2263
2264 /* Set CF to the bit value */
2265 State->Flags.Cf = (Value >> BitNumber) & 1;
2266
2267 if (ModRegRm.Register == 5)
2268 {
2269 /* BTS */
2270 Value |= 1 << BitNumber;
2271 }
2272 else if (ModRegRm.Register == 6)
2273 {
2274 /* BTR */
2275 Value &= ~(1 << BitNumber);
2276 }
2277 else if (ModRegRm.Register == 7)
2278 {
2279 /* BTC */
2280 Value ^= 1 << BitNumber;
2281 }
2282
2283 if (ModRegRm.Register >= 5)
2284 {
2285 /* Write back the result */
2286 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2287 {
2288 /* Exception occurred */
2289 return FALSE;
2290 }
2291 }
2292 }
2293 else
2294 {
2295 USHORT Value;
2296
2297 /* Read the value */
2298 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2299 {
2300 /* Exception occurred */
2301 return FALSE;
2302 }
2303
2304 /* Set CF to the bit value */
2305 State->Flags.Cf = (Value >> BitNumber) & 1;
2306
2307 if (ModRegRm.Register == 5)
2308 {
2309 /* BTS */
2310 Value |= 1 << BitNumber;
2311 }
2312 else if (ModRegRm.Register == 6)
2313 {
2314 /* BTR */
2315 Value &= ~(1 << BitNumber);
2316 }
2317 else if (ModRegRm.Register == 7)
2318 {
2319 /* BTC */
2320 Value ^= 1 << BitNumber;
2321 }
2322
2323 if (ModRegRm.Register >= 5)
2324 {
2325 /* Write back the result */
2326 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2327 {
2328 /* Exception occurred */
2329 return FALSE;
2330 }
2331 }
2332 }
2333
2334 /* Return success */
2335 return TRUE;
2336 }
2337
2338 /* EOF */