* Sync up to trunk head (r65298).
[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
1808 if (GdtEntry.Granularity)
1809 {
1810 State->Ldtr.Limit <<= 12;
1811 State->Ldtr.Limit |= 0x00000FFF;
1812 }
1813
1814 break;
1815 }
1816
1817 /* LTR */
1818 case 3:
1819 {
1820 BOOLEAN Valid;
1821 USHORT Selector;
1822 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1823
1824 /* Not recognized in real mode or virtual 8086 mode */
1825 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1826 || State->Flags.Vm)
1827 {
1828 Fast486Exception(State, FAST486_EXCEPTION_UD);
1829 return;
1830 }
1831
1832 /* This is a privileged instruction */
1833 if (Fast486GetCurrentPrivLevel(State) != 0)
1834 {
1835 Fast486Exception(State, FAST486_EXCEPTION_GP);
1836 return;
1837 }
1838
1839 if (!Fast486ReadModrmWordOperands(State,
1840 &ModRegRm,
1841 NULL,
1842 &Selector))
1843 {
1844 /* Exception occurred */
1845 return;
1846 }
1847
1848 if (Selector & SEGMENT_TABLE_INDICATOR)
1849 {
1850 /* This selector doesn't point to the GDT */
1851 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1852 return;
1853 }
1854
1855 if (!Fast486ReadDescriptorEntry(State,
1856 Selector,
1857 &Valid,
1858 (PFAST486_GDT_ENTRY)&GdtEntry))
1859 {
1860 /* Exception occurred */
1861 return;
1862 }
1863
1864 if (!Valid)
1865 {
1866 /* Invalid selector */
1867 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1868 return;
1869 }
1870
1871 if (GET_SEGMENT_INDEX(Selector) == 0)
1872 {
1873 Fast486Exception(State, FAST486_EXCEPTION_GP);
1874 return;
1875 }
1876
1877 if (!GdtEntry.Present)
1878 {
1879 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1880 return;
1881 }
1882
1883 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
1884 {
1885 /* This is not a TSS descriptor */
1886 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1887 return;
1888 }
1889
1890 /* Update the TR */
1891 State->TaskReg.Selector = Selector;
1892 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1893 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1894
1895 if (GdtEntry.Granularity)
1896 {
1897 State->TaskReg.Limit <<= 12;
1898 State->TaskReg.Limit |= 0x00000FFF;
1899 }
1900
1901 break;
1902 }
1903
1904 /* VERR/VERW */
1905 case 4:
1906 case 5:
1907 {
1908 USHORT Selector;
1909 BOOLEAN Valid;
1910 FAST486_GDT_ENTRY GdtEntry;
1911
1912 /* Not recognized in real mode or virtual 8086 mode */
1913 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1914 || State->Flags.Vm)
1915 {
1916 Fast486Exception(State, FAST486_EXCEPTION_UD);
1917 return;
1918 }
1919
1920 /* This is a privileged instruction */
1921 if (Fast486GetCurrentPrivLevel(State) != 0)
1922 {
1923 Fast486Exception(State, FAST486_EXCEPTION_GP);
1924 return;
1925 }
1926
1927 if (!Fast486ReadModrmWordOperands(State,
1928 &ModRegRm,
1929 NULL,
1930 &Selector))
1931 {
1932 /* Exception occurred */
1933 return;
1934 }
1935
1936 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
1937 {
1938 /* Exception occurred */
1939 return;
1940 }
1941
1942 if (!Valid)
1943 {
1944 /* Clear ZF */
1945 State->Flags.Zf = FALSE;
1946 return;
1947 }
1948
1949 /* Set ZF if it is valid and accessible */
1950 State->Flags.Zf = GdtEntry.Present // must be present
1951 && GdtEntry.SystemType // must be a segment
1952 && (((ModRegRm.Register == 4)
1953 /* code segments are only readable if the RW bit is set */
1954 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
1955 || ((ModRegRm.Register == 5)
1956 /* code segments are never writable, data segments are writable when RW is set */
1957 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
1958 /*
1959 * for segments other than conforming code segments,
1960 * both RPL and CPL must be less than or equal to DPL
1961 */
1962 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
1963 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
1964 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
1965 /* for conforming code segments, DPL must be less than or equal to CPL */
1966 && ((GdtEntry.Executable && GdtEntry.DirConf)
1967 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
1968
1969
1970 break;
1971 }
1972
1973 /* Invalid */
1974 default:
1975 {
1976 Fast486Exception(State, FAST486_EXCEPTION_UD);
1977 }
1978 }
1979 }
1980
1981 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
1982 {
1983 // FAST486_TABLE_REG TableReg;
1984 UCHAR TableReg[6];
1985 FAST486_MOD_REG_RM ModRegRm;
1986 BOOLEAN OperandSize, AddressSize;
1987 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1988
1989 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1990
1991 NO_LOCK_PREFIX();
1992 TOGGLE_OPSIZE(OperandSize);
1993 TOGGLE_ADSIZE(AddressSize);
1994
1995 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1996 {
1997 /* Exception occurred */
1998 return;
1999 }
2000
2001 /* Check for the segment override */
2002 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2003 {
2004 /* Use the override segment instead */
2005 Segment = State->SegmentOverride;
2006 }
2007
2008 /* Check which operation this is */
2009 switch (ModRegRm.Register)
2010 {
2011 /* SGDT */
2012 case 0:
2013 {
2014 if (!ModRegRm.Memory)
2015 {
2016 /* The second operand must be a memory location */
2017 Fast486Exception(State, FAST486_EXCEPTION_UD);
2018 return;
2019 }
2020
2021 /* Fill the 6-byte table register */
2022 // TableReg = State->Gdtr;
2023 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2024 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2025
2026 /* Store the GDTR */
2027 Fast486WriteMemory(State,
2028 Segment,
2029 ModRegRm.MemoryAddress,
2030 TableReg,
2031 sizeof(TableReg));
2032
2033 break;
2034 }
2035
2036 /* SIDT */
2037 case 1:
2038 {
2039 if (!ModRegRm.Memory)
2040 {
2041 /* The second operand must be a memory location */
2042 Fast486Exception(State, FAST486_EXCEPTION_UD);
2043 return;
2044 }
2045
2046 /* Fill the 6-byte table register */
2047 // TableReg = State->Idtr;
2048 *((PUSHORT)&TableReg) = State->Idtr.Size;
2049 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2050
2051 /* Store the IDTR */
2052 Fast486WriteMemory(State,
2053 Segment,
2054 ModRegRm.MemoryAddress,
2055 TableReg,
2056 sizeof(TableReg));
2057
2058 break;
2059 }
2060
2061 /* LGDT */
2062 case 2:
2063 {
2064 /* This is a privileged instruction */
2065 if (Fast486GetCurrentPrivLevel(State) != 0)
2066 {
2067 Fast486Exception(State, FAST486_EXCEPTION_GP);
2068 return;
2069 }
2070
2071 if (!ModRegRm.Memory)
2072 {
2073 /* The second operand must be a memory location */
2074 Fast486Exception(State, FAST486_EXCEPTION_UD);
2075 return;
2076 }
2077
2078 /* Read the new GDTR */
2079 if (!Fast486ReadMemory(State,
2080 Segment,
2081 ModRegRm.MemoryAddress,
2082 FALSE,
2083 TableReg,
2084 sizeof(TableReg)))
2085 {
2086 /* Exception occurred */
2087 return;
2088 }
2089
2090 /* Load the new GDT */
2091 // State->Gdtr = TableReg;
2092 State->Gdtr.Size = *((PUSHORT)&TableReg);
2093 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2094
2095 /* In 16-bit mode the highest byte is masked out */
2096 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2097
2098 break;
2099 }
2100
2101 /* LIDT */
2102 case 3:
2103 {
2104 /* This is a privileged instruction */
2105 if (Fast486GetCurrentPrivLevel(State) != 0)
2106 {
2107 Fast486Exception(State, FAST486_EXCEPTION_GP);
2108 return;
2109 }
2110
2111 if (!ModRegRm.Memory)
2112 {
2113 /* The second operand must be a memory location */
2114 Fast486Exception(State, FAST486_EXCEPTION_UD);
2115 return;
2116 }
2117
2118 /* Read the new IDTR */
2119 if (!Fast486ReadMemory(State,
2120 Segment,
2121 ModRegRm.MemoryAddress,
2122 FALSE,
2123 TableReg,
2124 sizeof(TableReg)))
2125 {
2126 /* Exception occurred */
2127 return;
2128 }
2129
2130 /* Load the new IDT */
2131 // State->Idtr = TableReg;
2132 State->Idtr.Size = *((PUSHORT)&TableReg);
2133 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2134
2135 /* In 16-bit mode the highest byte is masked out */
2136 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2137
2138 break;
2139 }
2140
2141 /* SMSW */
2142 case 4:
2143 {
2144 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2145 Fast486WriteModrmWordOperands(State,
2146 &ModRegRm,
2147 FALSE,
2148 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2149
2150 break;
2151 }
2152
2153 /* LMSW */
2154 case 6:
2155 {
2156 USHORT MachineStatusWord;
2157
2158 /* This is a privileged instruction */
2159 if (Fast486GetCurrentPrivLevel(State) != 0)
2160 {
2161 Fast486Exception(State, FAST486_EXCEPTION_GP);
2162 return;
2163 }
2164
2165 /* Read the new Machine Status Word */
2166 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2167 {
2168 /* Exception occurred */
2169 return;
2170 }
2171
2172 /* This instruction cannot be used to return to real mode */
2173 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2174 && !(MachineStatusWord & FAST486_CR0_PE))
2175 {
2176 Fast486Exception(State, FAST486_EXCEPTION_GP);
2177 return;
2178 }
2179
2180 /* Set the lowest 4 bits */
2181 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2182 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2183
2184 break;
2185 }
2186
2187 /* INVLPG */
2188 case 7:
2189 {
2190 #ifndef FAST486_NO_PREFETCH
2191 /* Invalidate the prefetch */
2192 State->PrefetchValid = FALSE;
2193 #endif
2194
2195 /* This is a privileged instruction */
2196 if (Fast486GetCurrentPrivLevel(State) != 0)
2197 {
2198 Fast486Exception(State, FAST486_EXCEPTION_GP);
2199 return;
2200 }
2201
2202 if (!ModRegRm.Memory)
2203 {
2204 /* The second operand must be a memory location */
2205 Fast486Exception(State, FAST486_EXCEPTION_UD);
2206 return;
2207 }
2208
2209 if (State->Tlb != NULL)
2210 {
2211 /* Clear the TLB entry */
2212 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2213 }
2214
2215 break;
2216 }
2217
2218 /* Invalid */
2219 default:
2220 {
2221 Fast486Exception(State, FAST486_EXCEPTION_UD);
2222 }
2223 }
2224 }
2225
2226 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2227 {
2228 FAST486_MOD_REG_RM ModRegRm;
2229 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2230
2231 TOGGLE_ADSIZE(AddressSize);
2232
2233 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2234 {
2235 /* Exception occurred */
2236 return;
2237 }
2238
2239 /* All of them are reserved (UD2) */
2240 Fast486Exception(State, FAST486_EXCEPTION_UD);
2241 return;
2242 }
2243
2244 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2245 {
2246 FAST486_MOD_REG_RM ModRegRm;
2247 BOOLEAN OperandSize, AddressSize;
2248 UINT DataSize;
2249 UCHAR BitNumber;
2250
2251 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2252
2253 TOGGLE_OPSIZE(OperandSize);
2254 TOGGLE_ADSIZE(AddressSize);
2255
2256 /* Get the number of bits */
2257 if (OperandSize) DataSize = 32;
2258 else DataSize = 16;
2259
2260 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2261 {
2262 /* Exception occurred */
2263 return;
2264 }
2265
2266 if (ModRegRm.Register < 4)
2267 {
2268 /* Invalid */
2269 Fast486Exception(State, FAST486_EXCEPTION_UD);
2270 return;
2271 }
2272
2273 /* Get the bit number */
2274 if (!Fast486FetchByte(State, &BitNumber))
2275 {
2276 /* Exception occurred */
2277 return;
2278 }
2279
2280 if (ModRegRm.Memory)
2281 {
2282 /*
2283 * For memory operands, add the bit offset divided by
2284 * the data size to the address
2285 */
2286 ModRegRm.MemoryAddress += BitNumber / DataSize;
2287 }
2288
2289 /* Normalize the bit number */
2290 BitNumber %= DataSize;
2291
2292 if (OperandSize)
2293 {
2294 ULONG Value;
2295
2296 /* Read the value */
2297 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2298 {
2299 /* Exception occurred */
2300 return;
2301 }
2302
2303 /* Set CF to the bit value */
2304 State->Flags.Cf = (Value >> BitNumber) & 1;
2305
2306 if (ModRegRm.Register == 5)
2307 {
2308 /* BTS */
2309 Value |= 1 << BitNumber;
2310 }
2311 else if (ModRegRm.Register == 6)
2312 {
2313 /* BTR */
2314 Value &= ~(1 << BitNumber);
2315 }
2316 else if (ModRegRm.Register == 7)
2317 {
2318 /* BTC */
2319 Value ^= 1 << BitNumber;
2320 }
2321
2322 if (ModRegRm.Register >= 5)
2323 {
2324 /* Write back the result */
2325 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2326 {
2327 /* Exception occurred */
2328 return;
2329 }
2330 }
2331 }
2332 else
2333 {
2334 USHORT Value;
2335
2336 /* Read the value */
2337 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2338 {
2339 /* Exception occurred */
2340 return;
2341 }
2342
2343 /* Set CF to the bit value */
2344 State->Flags.Cf = (Value >> BitNumber) & 1;
2345
2346 if (ModRegRm.Register == 5)
2347 {
2348 /* BTS */
2349 Value |= 1 << BitNumber;
2350 }
2351 else if (ModRegRm.Register == 6)
2352 {
2353 /* BTR */
2354 Value &= ~(1 << BitNumber);
2355 }
2356 else if (ModRegRm.Register == 7)
2357 {
2358 /* BTC */
2359 Value ^= 1 << BitNumber;
2360 }
2361
2362 if (ModRegRm.Register >= 5)
2363 {
2364 /* Write back the result */
2365 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2366 {
2367 /* Exception occurred */
2368 return;
2369 }
2370 }
2371 }
2372 }
2373
2374 /* EOF */