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