0e560d5e15143f1a90d7b29dfecdcc73093c728b
[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 /* Clear the top half of EIP */
1637 State->InstPtr.Long &= 0xFFFF;
1638 }
1639 else if (ModRegRm.Register == 5)
1640 {
1641 USHORT Selector;
1642 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1643
1644 /* Check for the segment override */
1645 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1646 {
1647 /* Use the override segment instead */
1648 Segment = State->SegmentOverride;
1649 }
1650
1651 /* Read the selector */
1652 if (!Fast486ReadMemory(State,
1653 Segment,
1654 ModRegRm.MemoryAddress + sizeof(USHORT),
1655 FALSE,
1656 &Selector,
1657 sizeof(USHORT)))
1658 {
1659 /* Exception occurred */
1660 return FALSE;
1661 }
1662
1663 /* Load the new code segment */
1664 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1665 {
1666 /* Exception occurred */
1667 return FALSE;
1668 }
1669
1670 /* Set the IP to the address */
1671 State->InstPtr.LowWord = Value;
1672
1673 /* Clear the top half of EIP */
1674 State->InstPtr.Long &= 0xFFFF;
1675 }
1676 else if (ModRegRm.Register == 6)
1677 {
1678 /* Push the value on to the stack */
1679 return Fast486StackPush(State, Value);
1680 }
1681 else
1682 {
1683 /* Invalid */
1684 Fast486Exception(State, FAST486_EXCEPTION_UD);
1685 return FALSE;
1686 }
1687
1688 if (ModRegRm.Register <= 1)
1689 {
1690 /* Update flags */
1691 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1692 State->Flags.Zf = (Value == 0);
1693 State->Flags.Pf = Fast486CalculateParity(Value);
1694
1695 /* Write back the result */
1696 return Fast486WriteModrmWordOperands(State,
1697 &ModRegRm,
1698 FALSE,
1699 Value);
1700 }
1701 }
1702
1703 return TRUE;
1704 }
1705
1706 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
1707 {
1708 FAST486_MOD_REG_RM ModRegRm;
1709 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1710
1711 NO_LOCK_PREFIX();
1712 TOGGLE_ADSIZE(AddressSize);
1713
1714 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1715 {
1716 /* Exception occurred */
1717 return FALSE;
1718 }
1719
1720 /* Check which operation this is */
1721 switch (ModRegRm.Register)
1722 {
1723 /* SLDT */
1724 case 0:
1725 {
1726 /* Not recognized in real mode or virtual 8086 mode */
1727 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1728 || State->Flags.Vm)
1729 {
1730 Fast486Exception(State, FAST486_EXCEPTION_UD);
1731 }
1732
1733 return Fast486WriteModrmWordOperands(State,
1734 &ModRegRm,
1735 FALSE,
1736 State->Ldtr.Selector);
1737 }
1738
1739 /* STR */
1740 case 1:
1741 {
1742 /* Not recognized in real mode or virtual 8086 mode */
1743 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1744 || State->Flags.Vm)
1745 {
1746 Fast486Exception(State, FAST486_EXCEPTION_UD);
1747 }
1748
1749 return Fast486WriteModrmWordOperands(State,
1750 &ModRegRm,
1751 FALSE,
1752 State->TaskReg.Selector);
1753 }
1754
1755 /* LLDT */
1756 case 2:
1757 {
1758 USHORT Selector;
1759 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1760
1761 /* Not recognized in real mode or virtual 8086 mode */
1762 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1763 || State->Flags.Vm)
1764 {
1765 Fast486Exception(State, FAST486_EXCEPTION_UD);
1766 }
1767
1768 /* This is a privileged instruction */
1769 if (Fast486GetCurrentPrivLevel(State) != 0)
1770 {
1771 Fast486Exception(State, FAST486_EXCEPTION_GP);
1772 return FALSE;
1773 }
1774
1775 if (!Fast486ReadModrmWordOperands(State,
1776 &ModRegRm,
1777 NULL,
1778 &Selector))
1779 {
1780 /* Exception occurred */
1781 return FALSE;
1782 }
1783
1784 /* Make sure the GDT contains the entry */
1785 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1786 {
1787 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1788 return FALSE;
1789 }
1790
1791 /* Read the GDT */
1792 if (!Fast486ReadLinearMemory(State,
1793 State->Gdtr.Address
1794 + GET_SEGMENT_INDEX(Selector),
1795 &GdtEntry,
1796 sizeof(GdtEntry)))
1797 {
1798 /* Exception occurred */
1799 return FALSE;
1800 }
1801
1802 if (GET_SEGMENT_INDEX(Selector) == 0)
1803 {
1804 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1805 return TRUE;
1806 }
1807
1808 if (!GdtEntry.Present)
1809 {
1810 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1811 return FALSE;
1812 }
1813
1814 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1815 {
1816 /* This is not a LDT descriptor */
1817 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1818 return FALSE;
1819 }
1820
1821 /* Update the LDTR */
1822 State->Ldtr.Selector = Selector;
1823 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1824 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1825 if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12;
1826
1827 return TRUE;
1828 }
1829
1830 /* LTR */
1831 case 3:
1832 {
1833 USHORT Selector;
1834 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1835
1836 /* Not recognized in real mode or virtual 8086 mode */
1837 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1838 || State->Flags.Vm)
1839 {
1840 Fast486Exception(State, FAST486_EXCEPTION_UD);
1841 }
1842
1843 /* This is a privileged instruction */
1844 if (Fast486GetCurrentPrivLevel(State) != 0)
1845 {
1846 Fast486Exception(State, FAST486_EXCEPTION_GP);
1847 return FALSE;
1848 }
1849
1850 if (!Fast486ReadModrmWordOperands(State,
1851 &ModRegRm,
1852 NULL,
1853 &Selector))
1854 {
1855 /* Exception occurred */
1856 return FALSE;
1857 }
1858
1859 /* Make sure the GDT contains the entry */
1860 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1861 {
1862 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1863 return FALSE;
1864 }
1865
1866 /* Read the GDT */
1867 if (!Fast486ReadLinearMemory(State,
1868 State->Gdtr.Address
1869 + GET_SEGMENT_INDEX(Selector),
1870 &GdtEntry,
1871 sizeof(GdtEntry)))
1872 {
1873 /* Exception occurred */
1874 return FALSE;
1875 }
1876
1877 if (GET_SEGMENT_INDEX(Selector) == 0)
1878 {
1879 Fast486Exception(State, FAST486_EXCEPTION_GP);
1880 return FALSE;
1881 }
1882
1883 if (!GdtEntry.Present)
1884 {
1885 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1886 return FALSE;
1887 }
1888
1889 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
1890 {
1891 /* This is not a TSS descriptor */
1892 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1893 return FALSE;
1894 }
1895
1896 /* Update the TR */
1897 State->TaskReg.Selector = Selector;
1898 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1899 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1900 if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
1901 State->TaskReg.Busy = TRUE;
1902
1903 return TRUE;
1904 }
1905
1906 /* VERR/VERW */
1907 case 4:
1908 case 5:
1909 {
1910 USHORT Selector;
1911 FAST486_GDT_ENTRY GdtEntry;
1912
1913 /* Not recognized in real mode or virtual 8086 mode */
1914 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1915 || State->Flags.Vm)
1916 {
1917 Fast486Exception(State, FAST486_EXCEPTION_UD);
1918 }
1919
1920 /* This is a privileged instruction */
1921 if (Fast486GetCurrentPrivLevel(State) != 0)
1922 {
1923 Fast486Exception(State, FAST486_EXCEPTION_GP);
1924 return FALSE;
1925 }
1926
1927 if (!Fast486ReadModrmWordOperands(State,
1928 &ModRegRm,
1929 NULL,
1930 &Selector))
1931 {
1932 /* Exception occurred */
1933 return FALSE;
1934 }
1935
1936 if (!(Selector & SEGMENT_TABLE_INDICATOR))
1937 {
1938 /* Make sure the GDT contains the entry */
1939 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1940 {
1941 /* Clear ZF */
1942 State->Flags.Zf = FALSE;
1943 return TRUE;
1944 }
1945
1946 /* Read the GDT */
1947 if (!Fast486ReadLinearMemory(State,
1948 State->Gdtr.Address
1949 + GET_SEGMENT_INDEX(Selector),
1950 &GdtEntry,
1951 sizeof(GdtEntry)))
1952 {
1953 /* Exception occurred */
1954 return FALSE;
1955 }
1956 }
1957 else
1958 {
1959 /* Make sure the LDT contains the entry */
1960 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
1961 {
1962 /* Clear ZF */
1963 State->Flags.Zf = FALSE;
1964 return TRUE;
1965 }
1966
1967 /* Read the LDT */
1968 if (!Fast486ReadLinearMemory(State,
1969 State->Ldtr.Base
1970 + GET_SEGMENT_INDEX(Selector),
1971 &GdtEntry,
1972 sizeof(GdtEntry)))
1973 {
1974 /* Exception occurred */
1975 return FALSE;
1976 }
1977 }
1978
1979 /* Set ZF if it is valid and accessible */
1980 State->Flags.Zf = GdtEntry.Present // must be present
1981 && GdtEntry.SystemType // must be a segment
1982 && (((ModRegRm.Register == 4)
1983 /* code segments are only readable if the RW bit is set */
1984 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
1985 || ((ModRegRm.Register == 5)
1986 /* code segments are never writable, data segments are writable when RW is set */
1987 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
1988 /*
1989 * for segments other than conforming code segments,
1990 * both RPL and CPL must be less than or equal to DPL
1991 */
1992 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
1993 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
1994 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
1995 /* for conforming code segments, DPL must be less than or equal to CPL */
1996 && ((GdtEntry.Executable && GdtEntry.DirConf)
1997 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
1998
1999
2000 return TRUE;
2001 }
2002
2003 /* Invalid */
2004 default:
2005 {
2006 Fast486Exception(State, FAST486_EXCEPTION_UD);
2007 return FALSE;
2008 }
2009 }
2010 }
2011
2012 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
2013 {
2014 UCHAR TableReg[6];
2015 FAST486_MOD_REG_RM ModRegRm;
2016 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2017 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2018
2019 NO_LOCK_PREFIX();
2020 TOGGLE_ADSIZE(AddressSize);
2021
2022 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2023 {
2024 /* Exception occurred */
2025 return FALSE;
2026 }
2027
2028 /* Check for the segment override */
2029 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2030 {
2031 /* Use the override segment instead */
2032 Segment = State->SegmentOverride;
2033 }
2034
2035 /* Check which operation this is */
2036 switch (ModRegRm.Register)
2037 {
2038 /* SGDT */
2039 case 0:
2040 {
2041 if (!ModRegRm.Memory)
2042 {
2043 /* The second operand must be a memory location */
2044 Fast486Exception(State, FAST486_EXCEPTION_UD);
2045 return FALSE;
2046 }
2047
2048 /* Fill the 6-byte table register */
2049 RtlCopyMemory(TableReg, &State->Gdtr.Size, sizeof(USHORT));
2050 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Gdtr.Address, sizeof(ULONG));
2051
2052 /* Store the GDTR */
2053 return Fast486WriteMemory(State,
2054 Segment,
2055 ModRegRm.MemoryAddress,
2056 TableReg,
2057 sizeof(TableReg));
2058 }
2059
2060 /* SIDT */
2061 case 1:
2062 {
2063 if (!ModRegRm.Memory)
2064 {
2065 /* The second operand must be a memory location */
2066 Fast486Exception(State, FAST486_EXCEPTION_UD);
2067 return FALSE;
2068 }
2069
2070 /* Fill the 6-byte table register */
2071 RtlCopyMemory(TableReg, &State->Idtr.Size, sizeof(USHORT));
2072 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Idtr.Address, sizeof(ULONG));
2073
2074 /* Store the IDTR */
2075 return Fast486WriteMemory(State,
2076 Segment,
2077 ModRegRm.MemoryAddress,
2078 TableReg,
2079 sizeof(TableReg));
2080 }
2081
2082 /* LGDT */
2083 case 2:
2084 {
2085 /* This is a privileged instruction */
2086 if (Fast486GetCurrentPrivLevel(State) != 0)
2087 {
2088 Fast486Exception(State, FAST486_EXCEPTION_GP);
2089 return FALSE;
2090 }
2091
2092 if (!ModRegRm.Memory)
2093 {
2094 /* The second operand must be a memory location */
2095 Fast486Exception(State, FAST486_EXCEPTION_UD);
2096 return FALSE;
2097 }
2098
2099 /* Read the new GDTR */
2100 if (!Fast486ReadMemory(State,
2101 Segment,
2102 ModRegRm.MemoryAddress,
2103 FALSE,
2104 TableReg,
2105 sizeof(TableReg)))
2106 {
2107 /* Exception occurred */
2108 return FALSE;
2109 }
2110
2111 /* Load the new GDT */
2112 State->Gdtr.Size = *((PUSHORT)TableReg);
2113 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2114
2115 return TRUE;
2116 }
2117
2118 /* LIDT */
2119 case 3:
2120 {
2121 /* This is a privileged instruction */
2122 if (Fast486GetCurrentPrivLevel(State) != 0)
2123 {
2124 Fast486Exception(State, FAST486_EXCEPTION_GP);
2125 return FALSE;
2126 }
2127
2128 if (!ModRegRm.Memory)
2129 {
2130 /* The second operand must be a memory location */
2131 Fast486Exception(State, FAST486_EXCEPTION_UD);
2132 return FALSE;
2133 }
2134
2135 /* Read the new IDTR */
2136 if (!Fast486ReadMemory(State,
2137 Segment,
2138 ModRegRm.MemoryAddress,
2139 FALSE,
2140 TableReg,
2141 sizeof(TableReg)))
2142 {
2143 /* Exception occurred */
2144 return FALSE;
2145 }
2146
2147 /* Load the new IDT */
2148 State->Idtr.Size = *((PUSHORT)TableReg);
2149 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2150
2151 return TRUE;
2152 }
2153
2154 /* SMSW */
2155 case 4:
2156 {
2157 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2158 return Fast486WriteModrmWordOperands(State,
2159 &ModRegRm,
2160 FALSE,
2161 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2162 }
2163
2164 /* LMSW */
2165 case 6:
2166 {
2167 USHORT MachineStatusWord;
2168
2169 /* This is a privileged instruction */
2170 if (Fast486GetCurrentPrivLevel(State) != 0)
2171 {
2172 Fast486Exception(State, FAST486_EXCEPTION_GP);
2173 return FALSE;
2174 }
2175
2176 /* Read the new Machine Status Word */
2177 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2178 {
2179 /* Exception occurred */
2180 return FALSE;
2181 }
2182
2183 /* This instruction cannot be used to return to real mode */
2184 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2185 && !(MachineStatusWord & FAST486_CR0_PE))
2186 {
2187 Fast486Exception(State, FAST486_EXCEPTION_GP);
2188 return FALSE;
2189 }
2190
2191 /* Set the lowest 4 bits */
2192 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2193 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2194
2195 return TRUE;
2196 }
2197
2198 /* INVLPG */
2199 case 7:
2200 {
2201 UNIMPLEMENTED;
2202 return FALSE;
2203 }
2204
2205 /* Invalid */
2206 default:
2207 {
2208 Fast486Exception(State, FAST486_EXCEPTION_UD);
2209 return FALSE;
2210 }
2211 }
2212 }
2213
2214 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
2215 {
2216 FAST486_MOD_REG_RM ModRegRm;
2217 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2218
2219 TOGGLE_ADSIZE(AddressSize);
2220
2221 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2222 {
2223 /* Exception occurred */
2224 return FALSE;
2225 }
2226
2227 /* All of them are reserved (UD2) */
2228 Fast486Exception(State, FAST486_EXCEPTION_UD);
2229 return FALSE;
2230 }
2231
2232 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
2233 {
2234 FAST486_MOD_REG_RM ModRegRm;
2235 BOOLEAN OperandSize, AddressSize;
2236 UINT DataSize;
2237 UCHAR BitNumber;
2238
2239 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2240
2241 TOGGLE_OPSIZE(OperandSize);
2242 TOGGLE_ADSIZE(AddressSize);
2243
2244 /* Get the number of bits */
2245 if (OperandSize) DataSize = 32;
2246 else DataSize = 16;
2247
2248 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2249 {
2250 /* Exception occurred */
2251 return FALSE;
2252 }
2253
2254 if (ModRegRm.Register < 4)
2255 {
2256 /* Invalid */
2257 Fast486Exception(State, FAST486_EXCEPTION_UD);
2258 return FALSE;
2259 }
2260
2261 /* Get the bit number */
2262 if (!Fast486FetchByte(State, &BitNumber))
2263 {
2264 /* Exception occurred */
2265 return FALSE;
2266 }
2267
2268 if (ModRegRm.Memory)
2269 {
2270 /*
2271 * For memory operands, add the bit offset divided by
2272 * the data size to the address
2273 */
2274 ModRegRm.MemoryAddress += BitNumber / DataSize;
2275 }
2276
2277 /* Normalize the bit number */
2278 BitNumber %= DataSize;
2279
2280 if (OperandSize)
2281 {
2282 ULONG Value;
2283
2284 /* Read the value */
2285 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2286 {
2287 /* Exception occurred */
2288 return FALSE;
2289 }
2290
2291 /* Set CF to the bit value */
2292 State->Flags.Cf = (Value >> BitNumber) & 1;
2293
2294 if (ModRegRm.Register == 5)
2295 {
2296 /* BTS */
2297 Value |= 1 << BitNumber;
2298 }
2299 else if (ModRegRm.Register == 6)
2300 {
2301 /* BTR */
2302 Value &= ~(1 << BitNumber);
2303 }
2304 else if (ModRegRm.Register == 7)
2305 {
2306 /* BTC */
2307 Value ^= 1 << BitNumber;
2308 }
2309
2310 if (ModRegRm.Register >= 5)
2311 {
2312 /* Write back the result */
2313 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2314 {
2315 /* Exception occurred */
2316 return FALSE;
2317 }
2318 }
2319 }
2320 else
2321 {
2322 USHORT Value;
2323
2324 /* Read the value */
2325 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2326 {
2327 /* Exception occurred */
2328 return FALSE;
2329 }
2330
2331 /* Set CF to the bit value */
2332 State->Flags.Cf = (Value >> BitNumber) & 1;
2333
2334 if (ModRegRm.Register == 5)
2335 {
2336 /* BTS */
2337 Value |= 1 << BitNumber;
2338 }
2339 else if (ModRegRm.Register == 6)
2340 {
2341 /* BTR */
2342 Value &= ~(1 << BitNumber);
2343 }
2344 else if (ModRegRm.Register == 7)
2345 {
2346 /* BTC */
2347 Value ^= 1 << BitNumber;
2348 }
2349
2350 if (ModRegRm.Register >= 5)
2351 {
2352 /* Write back the result */
2353 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2354 {
2355 /* Exception occurred */
2356 return FALSE;
2357 }
2358 }
2359 }
2360
2361 /* Return success */
2362 return TRUE;
2363 }
2364
2365 /* EOF */