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