[FAST486]
[reactos.git] / reactos / 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 USHORT Quotient;
984 UCHAR Remainder;
985
986 if (Value == 0)
987 {
988 /* Divide error */
989 Fast486Exception(State, FAST486_EXCEPTION_DE);
990 return;
991 }
992
993 Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
994 Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
995
996 if (Quotient > 0xFF)
997 {
998 /* Divide error */
999 Fast486Exception(State, FAST486_EXCEPTION_DE);
1000 return;
1001 }
1002
1003 /* Write back the results */
1004 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1005 State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1006
1007 break;
1008 }
1009
1010 /* IDIV */
1011 case 7:
1012 {
1013 SHORT Quotient;
1014 CHAR Remainder;
1015
1016 if (Value == 0)
1017 {
1018 /* Divide error */
1019 Fast486Exception(State, FAST486_EXCEPTION_DE);
1020 return;
1021 }
1022
1023 Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1024 Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1025
1026 if (Quotient > 127 || Quotient < -128)
1027 {
1028 /* Divide error */
1029 Fast486Exception(State, FAST486_EXCEPTION_DE);
1030 return;
1031 }
1032
1033 /* Write back the results */
1034 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)((CHAR)Quotient);
1035 State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1036
1037 break;
1038 }
1039 }
1040 }
1041
1042 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1043 {
1044 ULONG Value = 0, SignFlag;
1045 FAST486_MOD_REG_RM ModRegRm;
1046 BOOLEAN OperandSize, AddressSize;
1047
1048 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1049
1050 TOGGLE_OPSIZE(OperandSize);
1051 TOGGLE_ADSIZE(AddressSize);
1052
1053 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1054 {
1055 /* Exception occurred */
1056 return;
1057 }
1058
1059 /* Set the sign flag */
1060 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1061 else SignFlag = SIGN_FLAG_WORD;
1062
1063 /* Read the operand */
1064 if (OperandSize)
1065 {
1066 /* 32-bit */
1067 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1068 {
1069 /* Exception occurred */
1070 return;
1071 }
1072 }
1073 else
1074 {
1075 /* 16-bit */
1076 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1077 {
1078 /* Exception occurred */
1079 return;
1080 }
1081 }
1082
1083 switch (ModRegRm.Register)
1084 {
1085 /* TEST */
1086 case 0:
1087 case 1:
1088 {
1089 ULONG Immediate = 0, Result = 0;
1090
1091 if (OperandSize)
1092 {
1093 /* Fetch the immediate dword */
1094 if (!Fast486FetchDword(State, &Immediate))
1095 {
1096 /* Exception occurred */
1097 return;
1098 }
1099 }
1100 else
1101 {
1102 /* Fetch the immediate word */
1103 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1104 {
1105 /* Exception occurred */
1106 return;
1107 }
1108 }
1109
1110 /* Calculate the result */
1111 Result = Value & Immediate;
1112
1113 /* Update the flags */
1114 State->Flags.Cf = FALSE;
1115 State->Flags.Of = FALSE;
1116 State->Flags.Zf = (Result == 0);
1117 State->Flags.Sf = ((Result & SignFlag) != 0);
1118 State->Flags.Pf = Fast486CalculateParity(Result);
1119
1120 break;
1121 }
1122
1123 /* NOT */
1124 case 2:
1125 {
1126 /* Write back the result */
1127 if (OperandSize)
1128 {
1129 /* 32-bit */
1130 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1131 }
1132 else
1133 {
1134 /* 16-bit */
1135 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1136 }
1137
1138 break;
1139 }
1140
1141 /* NEG */
1142 case 3:
1143 {
1144 /* Calculate the result */
1145 ULONG Result = -Value;
1146 if (!OperandSize) Result &= 0xFFFF;
1147
1148 /* Update the flags */
1149 State->Flags.Cf = (Value != 0);
1150 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1151 State->Flags.Af = ((Value & 0x0F) != 0);
1152 State->Flags.Zf = (Result == 0);
1153 State->Flags.Sf = ((Result & SignFlag) != 0);
1154 State->Flags.Pf = Fast486CalculateParity(Result);
1155
1156 /* Write back the result */
1157 if (OperandSize)
1158 {
1159 /* 32-bit */
1160 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1161 }
1162 else
1163 {
1164 /* 16-bit */
1165 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1166 }
1167
1168 break;
1169 }
1170
1171 /* MUL */
1172 case 4:
1173 {
1174 if (OperandSize)
1175 {
1176 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1177
1178 /* Update the flags */
1179 State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
1180
1181 /* Write back the result */
1182 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1183 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1184 }
1185 else
1186 {
1187 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1188
1189 /* Update the flags */
1190 State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
1191
1192 /* Write back the result */
1193 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1194 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1195 }
1196
1197 break;
1198 }
1199
1200 /* IMUL */
1201 case 5:
1202 {
1203 if (OperandSize)
1204 {
1205 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1206
1207 /* Update the flags */
1208 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1209
1210 /* Write back the result */
1211 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1212 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1213 }
1214 else
1215 {
1216 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1217
1218 /* Update the flags */
1219 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1220
1221 /* Write back the result */
1222 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1223 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1224 }
1225
1226 break;
1227 }
1228
1229 /* DIV */
1230 case 6:
1231 {
1232 if (Value == 0)
1233 {
1234 /* Divide error */
1235 Fast486Exception(State, FAST486_EXCEPTION_DE);
1236 return;
1237 }
1238
1239 if (OperandSize)
1240 {
1241 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1242 | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1243 ULONGLONG Quotient = Dividend / Value;
1244 ULONG Remainder = Dividend % Value;
1245
1246 if (Quotient > 0xFFFFFFFFULL)
1247 {
1248 /* Divide error */
1249 Fast486Exception(State, FAST486_EXCEPTION_DE);
1250 return;
1251 }
1252
1253 /* Write back the results */
1254 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1255 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1256 }
1257 else
1258 {
1259 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1260 | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1261 ULONG Quotient = Dividend / Value;
1262 USHORT Remainder = Dividend % Value;
1263
1264 if (Quotient > 0xFFFF)
1265 {
1266 /* Divide error */
1267 Fast486Exception(State, FAST486_EXCEPTION_DE);
1268 return;
1269 }
1270
1271 /* Write back the results */
1272 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)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;
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 LONGLONG Quotient = Dividend / (LONG)Value;
1294 LONG Remainder = Dividend % (LONG)Value;
1295
1296 if (Quotient > 2147483647LL || Quotient < -2147483648LL)
1297 {
1298 /* Divide error */
1299 Fast486Exception(State, FAST486_EXCEPTION_DE);
1300 return;
1301 }
1302
1303 /* Write back the results */
1304 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)((LONG)Quotient);
1305 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1306 }
1307 else
1308 {
1309 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1310 | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1311 LONG Quotient = Dividend / (SHORT)LOWORD(Value);
1312 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1313
1314 if (Quotient > 32767 || Quotient < -32768)
1315 {
1316 /* Divide error */
1317 Fast486Exception(State, FAST486_EXCEPTION_DE);
1318 return;
1319 }
1320
1321 /* Write back the results */
1322 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)((SHORT)Quotient);
1323 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1324 }
1325
1326 break;
1327 }
1328 }
1329 }
1330
1331 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1332 {
1333 UCHAR Value;
1334 FAST486_MOD_REG_RM ModRegRm;
1335 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1336
1337 TOGGLE_ADSIZE(AddressSize);
1338
1339 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1340 {
1341 /* Exception occurred */
1342 return;
1343 }
1344
1345 if (ModRegRm.Register > 1)
1346 {
1347 /* Invalid */
1348 Fast486Exception(State, FAST486_EXCEPTION_UD);
1349 return;
1350 }
1351
1352 /* Read the operands */
1353 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1354 {
1355 /* Exception occurred */
1356 return;
1357 }
1358
1359 if (ModRegRm.Register == 0)
1360 {
1361 /* Increment and update OF and AF */
1362 Value++;
1363 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1364 State->Flags.Af = ((Value & 0x0F) == 0);
1365 }
1366 else
1367 {
1368 /* Decrement and update OF and AF */
1369 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1370 Value--;
1371 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1372 }
1373
1374 /* Update flags */
1375 State->Flags.Zf = (Value == 0);
1376 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
1377 State->Flags.Pf = Fast486CalculateParity(Value);
1378
1379 /* Write back the result */
1380 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1381 }
1382
1383 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1384 {
1385 FAST486_MOD_REG_RM ModRegRm;
1386 BOOLEAN OperandSize, AddressSize;
1387
1388 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1389
1390 TOGGLE_OPSIZE(OperandSize);
1391 TOGGLE_ADSIZE(AddressSize);
1392
1393 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1394 {
1395 /* Exception occurred */
1396 return;
1397 }
1398
1399 if (ModRegRm.Register == 7)
1400 {
1401 /* Invalid */
1402 Fast486Exception(State, FAST486_EXCEPTION_UD);
1403 return;
1404 }
1405
1406 /* Read the operands */
1407 if (OperandSize)
1408 {
1409 ULONG Value;
1410
1411 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1412 {
1413 /* Exception occurred */
1414 return;
1415 }
1416
1417 if (ModRegRm.Register == 0)
1418 {
1419 /* Increment and update OF and AF */
1420 Value++;
1421 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1422 State->Flags.Af = ((Value & 0x0F) == 0);
1423 }
1424 else if (ModRegRm.Register == 1)
1425 {
1426 /* Decrement and update OF and AF */
1427 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1428 Value--;
1429 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1430 }
1431 else if (ModRegRm.Register == 2)
1432 {
1433 /* Push the current value of EIP */
1434 if (!Fast486StackPush(State, State->InstPtr.Long))
1435 {
1436 /* Exception occurred */
1437 return;
1438 }
1439
1440 /* Set the EIP to the address */
1441 State->InstPtr.Long = Value;
1442 }
1443 else if (ModRegRm.Register == 3)
1444 {
1445 USHORT Selector;
1446 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1447
1448 /* Check for the segment override */
1449 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1450 {
1451 /* Use the override segment instead */
1452 Segment = State->SegmentOverride;
1453 }
1454
1455 /* Read the selector */
1456 if (!Fast486ReadMemory(State,
1457 Segment,
1458 ModRegRm.MemoryAddress + sizeof(ULONG),
1459 FALSE,
1460 &Selector,
1461 sizeof(USHORT)))
1462 {
1463 /* Exception occurred */
1464 return;
1465 }
1466
1467 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1468 {
1469 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1470 {
1471 /* Gate processed or exception occurred */
1472 return;
1473 }
1474 }
1475
1476 /* Push the current value of CS */
1477 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1478 {
1479 /* Exception occurred */
1480 return;
1481 }
1482
1483 /* Push the current value of EIP */
1484 if (!Fast486StackPush(State, State->InstPtr.Long))
1485 {
1486 /* Exception occurred */
1487 return;
1488 }
1489
1490 /* Load the new code segment */
1491 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1492 {
1493 /* Exception occurred */
1494 return;
1495 }
1496
1497 /* Set the EIP to the address */
1498 State->InstPtr.Long = Value;
1499 }
1500 else if (ModRegRm.Register == 4)
1501 {
1502 /* Set the EIP to the address */
1503 State->InstPtr.Long = Value;
1504 }
1505 else if (ModRegRm.Register == 5)
1506 {
1507 USHORT Selector;
1508 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1509
1510 /* Check for the segment override */
1511 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1512 {
1513 /* Use the override segment instead */
1514 Segment = State->SegmentOverride;
1515 }
1516
1517 /* Read the selector */
1518 if (!Fast486ReadMemory(State,
1519 Segment,
1520 ModRegRm.MemoryAddress + sizeof(ULONG),
1521 FALSE,
1522 &Selector,
1523 sizeof(USHORT)))
1524 {
1525 /* Exception occurred */
1526 return;
1527 }
1528
1529 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1530 {
1531 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1532 {
1533 /* Gate processed or exception occurred */
1534 return;
1535 }
1536 }
1537
1538 /* Load the new code segment */
1539 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1540 {
1541 /* Exception occurred */
1542 return;
1543 }
1544
1545 /* Set the EIP to the address */
1546 State->InstPtr.Long = Value;
1547 }
1548 else if (ModRegRm.Register == 6)
1549 {
1550 /* Push the value on to the stack */
1551 Fast486StackPush(State, Value);
1552 return;
1553 }
1554
1555 if (ModRegRm.Register <= 1)
1556 {
1557 /* Update flags */
1558 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1559 State->Flags.Zf = (Value == 0);
1560 State->Flags.Pf = Fast486CalculateParity(Value);
1561
1562 /* Write back the result */
1563 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1564 }
1565 }
1566 else
1567 {
1568 USHORT Value;
1569
1570 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1571 {
1572 /* Exception occurred */
1573 return;
1574 }
1575
1576 if (ModRegRm.Register == 0)
1577 {
1578 /* Increment and update OF */
1579 Value++;
1580 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1581 State->Flags.Af = ((Value & 0x0F) == 0);
1582 }
1583 else if (ModRegRm.Register == 1)
1584 {
1585 /* Decrement and update OF */
1586 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1587 Value--;
1588 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1589 }
1590 else if (ModRegRm.Register == 2)
1591 {
1592 /* Push the current value of IP */
1593 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1594 {
1595 /* Exception occurred */
1596 return;
1597 }
1598
1599 /* Set the IP to the address */
1600 State->InstPtr.LowWord = Value;
1601
1602 /* Clear the top half of EIP */
1603 State->InstPtr.Long &= 0xFFFF;
1604 }
1605 else if (ModRegRm.Register == 3)
1606 {
1607 USHORT Selector;
1608 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1609
1610 /* Check for the segment override */
1611 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1612 {
1613 /* Use the override segment instead */
1614 Segment = State->SegmentOverride;
1615 }
1616
1617 /* Read the selector */
1618 if (!Fast486ReadMemory(State,
1619 Segment,
1620 ModRegRm.MemoryAddress + sizeof(USHORT),
1621 FALSE,
1622 &Selector,
1623 sizeof(USHORT)))
1624 {
1625 /* Exception occurred */
1626 return;
1627 }
1628
1629 /* Push the current value of CS */
1630 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1631 {
1632 /* Exception occurred */
1633 return;
1634 }
1635
1636 /* Push the current value of IP */
1637 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1638 {
1639 /* Exception occurred */
1640 return;
1641 }
1642
1643 /* Load the new code segment */
1644 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1645 {
1646 /* Exception occurred */
1647 return;
1648 }
1649
1650 /* Set the IP to the address */
1651 State->InstPtr.LowWord = Value;
1652
1653 /* Clear the top half of EIP */
1654 State->InstPtr.Long &= 0xFFFF;
1655 }
1656 else if (ModRegRm.Register == 4)
1657 {
1658 /* Set the IP to the address */
1659 State->InstPtr.LowWord = Value;
1660
1661 /* Clear the top half of EIP */
1662 State->InstPtr.Long &= 0xFFFF;
1663 }
1664 else if (ModRegRm.Register == 5)
1665 {
1666 USHORT Selector;
1667 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1668
1669 /* Check for the segment override */
1670 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1671 {
1672 /* Use the override segment instead */
1673 Segment = State->SegmentOverride;
1674 }
1675
1676 /* Read the selector */
1677 if (!Fast486ReadMemory(State,
1678 Segment,
1679 ModRegRm.MemoryAddress + sizeof(USHORT),
1680 FALSE,
1681 &Selector,
1682 sizeof(USHORT)))
1683 {
1684 /* Exception occurred */
1685 return;
1686 }
1687
1688 /* Load the new code segment */
1689 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1690 {
1691 /* Exception occurred */
1692 return;
1693 }
1694
1695 /* Set the IP to the address */
1696 State->InstPtr.LowWord = Value;
1697
1698 /* Clear the top half of EIP */
1699 State->InstPtr.Long &= 0xFFFF;
1700 }
1701 else if (ModRegRm.Register == 6)
1702 {
1703 /* Push the value on to the stack */
1704 Fast486StackPush(State, Value);
1705 return;
1706 }
1707 else
1708 {
1709 /* Invalid */
1710 Fast486Exception(State, FAST486_EXCEPTION_UD);
1711 return;
1712 }
1713
1714 if (ModRegRm.Register <= 1)
1715 {
1716 /* Update flags */
1717 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1718 State->Flags.Zf = (Value == 0);
1719 State->Flags.Pf = Fast486CalculateParity(Value);
1720
1721 /* Write back the result */
1722 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1723 }
1724 }
1725 }
1726
1727 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
1728 {
1729 FAST486_MOD_REG_RM ModRegRm;
1730 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1731
1732 NO_LOCK_PREFIX();
1733 TOGGLE_ADSIZE(AddressSize);
1734
1735 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1736 {
1737 /* Exception occurred */
1738 return;
1739 }
1740
1741 /* Check which operation this is */
1742 switch (ModRegRm.Register)
1743 {
1744 /* SLDT */
1745 case 0:
1746 {
1747 /* Not recognized in real mode or virtual 8086 mode */
1748 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1749 || State->Flags.Vm)
1750 {
1751 Fast486Exception(State, FAST486_EXCEPTION_UD);
1752 return;
1753 }
1754
1755 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
1756 break;
1757 }
1758
1759 /* STR */
1760 case 1:
1761 {
1762 /* Not recognized in real mode or virtual 8086 mode */
1763 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1764 || State->Flags.Vm)
1765 {
1766 Fast486Exception(State, FAST486_EXCEPTION_UD);
1767 return;
1768 }
1769
1770 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
1771 break;
1772 }
1773
1774 /* LLDT */
1775 case 2:
1776 {
1777 BOOLEAN Valid;
1778 USHORT Selector;
1779 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1780
1781 /* Not recognized in real mode or virtual 8086 mode */
1782 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1783 || State->Flags.Vm)
1784 {
1785 Fast486Exception(State, FAST486_EXCEPTION_UD);
1786 return;
1787 }
1788
1789 /* This is a privileged instruction */
1790 if (Fast486GetCurrentPrivLevel(State) != 0)
1791 {
1792 Fast486Exception(State, FAST486_EXCEPTION_GP);
1793 return;
1794 }
1795
1796 if (!Fast486ReadModrmWordOperands(State,
1797 &ModRegRm,
1798 NULL,
1799 &Selector))
1800 {
1801 /* Exception occurred */
1802 return;
1803 }
1804
1805 if (Selector & SEGMENT_TABLE_INDICATOR)
1806 {
1807 /* This selector doesn't point to the GDT */
1808 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1809 return;
1810 }
1811
1812 if (!Fast486ReadDescriptorEntry(State,
1813 Selector,
1814 &Valid,
1815 (PFAST486_GDT_ENTRY)&GdtEntry))
1816 {
1817 /* Exception occurred */
1818 return;
1819 }
1820
1821 if (!Valid)
1822 {
1823 /* Invalid selector */
1824 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1825 return;
1826 }
1827
1828 if (GET_SEGMENT_INDEX(Selector) == 0)
1829 {
1830 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1831 return;
1832 }
1833
1834 if (!GdtEntry.Present)
1835 {
1836 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1837 return;
1838 }
1839
1840 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1841 {
1842 /* This is not a LDT descriptor */
1843 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1844 return;
1845 }
1846
1847 /* Update the LDTR */
1848 State->Ldtr.Selector = Selector;
1849 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1850 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1851
1852 if (GdtEntry.Granularity)
1853 {
1854 State->Ldtr.Limit <<= 12;
1855 State->Ldtr.Limit |= 0x00000FFF;
1856 }
1857
1858 break;
1859 }
1860
1861 /* LTR */
1862 case 3:
1863 {
1864 BOOLEAN Valid;
1865 USHORT Selector;
1866 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1867
1868 /* Not recognized in real mode or virtual 8086 mode */
1869 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1870 || State->Flags.Vm)
1871 {
1872 Fast486Exception(State, FAST486_EXCEPTION_UD);
1873 return;
1874 }
1875
1876 /* This is a privileged instruction */
1877 if (Fast486GetCurrentPrivLevel(State) != 0)
1878 {
1879 Fast486Exception(State, FAST486_EXCEPTION_GP);
1880 return;
1881 }
1882
1883 if (!Fast486ReadModrmWordOperands(State,
1884 &ModRegRm,
1885 NULL,
1886 &Selector))
1887 {
1888 /* Exception occurred */
1889 return;
1890 }
1891
1892 if (Selector & SEGMENT_TABLE_INDICATOR)
1893 {
1894 /* This selector doesn't point to the GDT */
1895 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1896 return;
1897 }
1898
1899 if (!Fast486ReadDescriptorEntry(State,
1900 Selector,
1901 &Valid,
1902 (PFAST486_GDT_ENTRY)&GdtEntry))
1903 {
1904 /* Exception occurred */
1905 return;
1906 }
1907
1908 if (!Valid)
1909 {
1910 /* Invalid selector */
1911 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1912 return;
1913 }
1914
1915 if (GET_SEGMENT_INDEX(Selector) == 0)
1916 {
1917 Fast486Exception(State, FAST486_EXCEPTION_GP);
1918 return;
1919 }
1920
1921 if (!GdtEntry.Present)
1922 {
1923 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1924 return;
1925 }
1926
1927 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
1928 {
1929 /* This is not a TSS descriptor */
1930 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1931 return;
1932 }
1933
1934 /* Update the TR */
1935 State->TaskReg.Selector = Selector;
1936 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1937 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1938
1939 if (GdtEntry.Granularity)
1940 {
1941 State->TaskReg.Limit <<= 12;
1942 State->TaskReg.Limit |= 0x00000FFF;
1943 }
1944
1945 break;
1946 }
1947
1948 /* VERR/VERW */
1949 case 4:
1950 case 5:
1951 {
1952 USHORT Selector;
1953 BOOLEAN Valid;
1954 FAST486_GDT_ENTRY GdtEntry;
1955
1956 /* Not recognized in real mode or virtual 8086 mode */
1957 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1958 || State->Flags.Vm)
1959 {
1960 Fast486Exception(State, FAST486_EXCEPTION_UD);
1961 return;
1962 }
1963
1964 /* This is a privileged instruction */
1965 if (Fast486GetCurrentPrivLevel(State) != 0)
1966 {
1967 Fast486Exception(State, FAST486_EXCEPTION_GP);
1968 return;
1969 }
1970
1971 if (!Fast486ReadModrmWordOperands(State,
1972 &ModRegRm,
1973 NULL,
1974 &Selector))
1975 {
1976 /* Exception occurred */
1977 return;
1978 }
1979
1980 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
1981 {
1982 /* Exception occurred */
1983 return;
1984 }
1985
1986 if (!Valid)
1987 {
1988 /* Clear ZF */
1989 State->Flags.Zf = FALSE;
1990 return;
1991 }
1992
1993 /* Set ZF if it is valid and accessible */
1994 State->Flags.Zf = GdtEntry.Present // must be present
1995 && GdtEntry.SystemType // must be a segment
1996 && (((ModRegRm.Register == 4)
1997 /* code segments are only readable if the RW bit is set */
1998 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
1999 || ((ModRegRm.Register == 5)
2000 /* code segments are never writable, data segments are writable when RW is set */
2001 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2002 /*
2003 * for segments other than conforming code segments,
2004 * both RPL and CPL must be less than or equal to DPL
2005 */
2006 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
2007 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2008 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
2009 /* for conforming code segments, DPL must be less than or equal to CPL */
2010 && ((GdtEntry.Executable && GdtEntry.DirConf)
2011 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
2012
2013
2014 break;
2015 }
2016
2017 /* Invalid */
2018 default:
2019 {
2020 Fast486Exception(State, FAST486_EXCEPTION_UD);
2021 }
2022 }
2023 }
2024
2025 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2026 {
2027 // FAST486_TABLE_REG TableReg;
2028 UCHAR TableReg[6];
2029 FAST486_MOD_REG_RM ModRegRm;
2030 BOOLEAN OperandSize, AddressSize;
2031 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2032
2033 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2034
2035 NO_LOCK_PREFIX();
2036 TOGGLE_OPSIZE(OperandSize);
2037 TOGGLE_ADSIZE(AddressSize);
2038
2039 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2040 {
2041 /* Exception occurred */
2042 return;
2043 }
2044
2045 /* Check for the segment override */
2046 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2047 {
2048 /* Use the override segment instead */
2049 Segment = State->SegmentOverride;
2050 }
2051
2052 /* Check which operation this is */
2053 switch (ModRegRm.Register)
2054 {
2055 /* SGDT */
2056 case 0:
2057 {
2058 if (!ModRegRm.Memory)
2059 {
2060 /* The second operand must be a memory location */
2061 Fast486Exception(State, FAST486_EXCEPTION_UD);
2062 return;
2063 }
2064
2065 /* Fill the 6-byte table register */
2066 // TableReg = State->Gdtr;
2067 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2068 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2069
2070 /* Store the GDTR */
2071 Fast486WriteMemory(State,
2072 Segment,
2073 ModRegRm.MemoryAddress,
2074 TableReg,
2075 sizeof(TableReg));
2076
2077 break;
2078 }
2079
2080 /* SIDT */
2081 case 1:
2082 {
2083 if (!ModRegRm.Memory)
2084 {
2085 /* The second operand must be a memory location */
2086 Fast486Exception(State, FAST486_EXCEPTION_UD);
2087 return;
2088 }
2089
2090 /* Fill the 6-byte table register */
2091 // TableReg = State->Idtr;
2092 *((PUSHORT)&TableReg) = State->Idtr.Size;
2093 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2094
2095 /* Store the IDTR */
2096 Fast486WriteMemory(State,
2097 Segment,
2098 ModRegRm.MemoryAddress,
2099 TableReg,
2100 sizeof(TableReg));
2101
2102 break;
2103 }
2104
2105 /* LGDT */
2106 case 2:
2107 {
2108 /* This is a privileged instruction */
2109 if (Fast486GetCurrentPrivLevel(State) != 0)
2110 {
2111 Fast486Exception(State, FAST486_EXCEPTION_GP);
2112 return;
2113 }
2114
2115 if (!ModRegRm.Memory)
2116 {
2117 /* The second operand must be a memory location */
2118 Fast486Exception(State, FAST486_EXCEPTION_UD);
2119 return;
2120 }
2121
2122 /* Read the new GDTR */
2123 if (!Fast486ReadMemory(State,
2124 Segment,
2125 ModRegRm.MemoryAddress,
2126 FALSE,
2127 TableReg,
2128 sizeof(TableReg)))
2129 {
2130 /* Exception occurred */
2131 return;
2132 }
2133
2134 /* Load the new GDT */
2135 // State->Gdtr = TableReg;
2136 State->Gdtr.Size = *((PUSHORT)&TableReg);
2137 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2138
2139 /* In 16-bit mode the highest byte is masked out */
2140 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2141
2142 break;
2143 }
2144
2145 /* LIDT */
2146 case 3:
2147 {
2148 /* This is a privileged instruction */
2149 if (Fast486GetCurrentPrivLevel(State) != 0)
2150 {
2151 Fast486Exception(State, FAST486_EXCEPTION_GP);
2152 return;
2153 }
2154
2155 if (!ModRegRm.Memory)
2156 {
2157 /* The second operand must be a memory location */
2158 Fast486Exception(State, FAST486_EXCEPTION_UD);
2159 return;
2160 }
2161
2162 /* Read the new IDTR */
2163 if (!Fast486ReadMemory(State,
2164 Segment,
2165 ModRegRm.MemoryAddress,
2166 FALSE,
2167 TableReg,
2168 sizeof(TableReg)))
2169 {
2170 /* Exception occurred */
2171 return;
2172 }
2173
2174 /* Load the new IDT */
2175 // State->Idtr = TableReg;
2176 State->Idtr.Size = *((PUSHORT)&TableReg);
2177 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2178
2179 /* In 16-bit mode the highest byte is masked out */
2180 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2181
2182 break;
2183 }
2184
2185 /* SMSW */
2186 case 4:
2187 {
2188 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2189 Fast486WriteModrmWordOperands(State,
2190 &ModRegRm,
2191 FALSE,
2192 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2193
2194 break;
2195 }
2196
2197 /* LMSW */
2198 case 6:
2199 {
2200 USHORT MachineStatusWord;
2201
2202 /* This is a privileged instruction */
2203 if (Fast486GetCurrentPrivLevel(State) != 0)
2204 {
2205 Fast486Exception(State, FAST486_EXCEPTION_GP);
2206 return;
2207 }
2208
2209 /* Read the new Machine Status Word */
2210 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2211 {
2212 /* Exception occurred */
2213 return;
2214 }
2215
2216 /* This instruction cannot be used to return to real mode */
2217 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2218 && !(MachineStatusWord & FAST486_CR0_PE))
2219 {
2220 Fast486Exception(State, FAST486_EXCEPTION_GP);
2221 return;
2222 }
2223
2224 /* Set the lowest 4 bits */
2225 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2226 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2227
2228 break;
2229 }
2230
2231 /* INVLPG */
2232 case 7:
2233 {
2234 #ifndef FAST486_NO_PREFETCH
2235 /* Invalidate the prefetch */
2236 State->PrefetchValid = FALSE;
2237 #endif
2238
2239 /* This is a privileged instruction */
2240 if (Fast486GetCurrentPrivLevel(State) != 0)
2241 {
2242 Fast486Exception(State, FAST486_EXCEPTION_GP);
2243 return;
2244 }
2245
2246 if (!ModRegRm.Memory)
2247 {
2248 /* The second operand must be a memory location */
2249 Fast486Exception(State, FAST486_EXCEPTION_UD);
2250 return;
2251 }
2252
2253 if (State->Tlb != NULL)
2254 {
2255 /* Clear the TLB entry */
2256 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2257 }
2258
2259 break;
2260 }
2261
2262 /* Invalid */
2263 default:
2264 {
2265 Fast486Exception(State, FAST486_EXCEPTION_UD);
2266 }
2267 }
2268 }
2269
2270 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2271 {
2272 FAST486_MOD_REG_RM ModRegRm;
2273 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2274
2275 TOGGLE_ADSIZE(AddressSize);
2276
2277 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2278 {
2279 /* Exception occurred */
2280 return;
2281 }
2282
2283 /* All of them are reserved (UD2) */
2284 Fast486Exception(State, FAST486_EXCEPTION_UD);
2285 return;
2286 }
2287
2288 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2289 {
2290 FAST486_MOD_REG_RM ModRegRm;
2291 BOOLEAN OperandSize, AddressSize;
2292 UINT DataSize;
2293 UCHAR BitNumber;
2294
2295 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2296
2297 TOGGLE_OPSIZE(OperandSize);
2298 TOGGLE_ADSIZE(AddressSize);
2299
2300 /* Get the number of bits */
2301 if (OperandSize) DataSize = 32;
2302 else DataSize = 16;
2303
2304 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2305 {
2306 /* Exception occurred */
2307 return;
2308 }
2309
2310 if (ModRegRm.Register < 4)
2311 {
2312 /* Invalid */
2313 Fast486Exception(State, FAST486_EXCEPTION_UD);
2314 return;
2315 }
2316
2317 /* Get the bit number */
2318 if (!Fast486FetchByte(State, &BitNumber))
2319 {
2320 /* Exception occurred */
2321 return;
2322 }
2323
2324 if (ModRegRm.Memory)
2325 {
2326 /*
2327 * For memory operands, add the bit offset divided by
2328 * the data size to the address
2329 */
2330 ModRegRm.MemoryAddress += BitNumber / DataSize;
2331 }
2332
2333 /* Normalize the bit number */
2334 BitNumber %= DataSize;
2335
2336 if (OperandSize)
2337 {
2338 ULONG Value;
2339
2340 /* Read the value */
2341 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2342 {
2343 /* Exception occurred */
2344 return;
2345 }
2346
2347 /* Set CF to the bit value */
2348 State->Flags.Cf = (Value >> BitNumber) & 1;
2349
2350 if (ModRegRm.Register == 5)
2351 {
2352 /* BTS */
2353 Value |= 1 << BitNumber;
2354 }
2355 else if (ModRegRm.Register == 6)
2356 {
2357 /* BTR */
2358 Value &= ~(1 << BitNumber);
2359 }
2360 else if (ModRegRm.Register == 7)
2361 {
2362 /* BTC */
2363 Value ^= 1 << BitNumber;
2364 }
2365
2366 if (ModRegRm.Register >= 5)
2367 {
2368 /* Write back the result */
2369 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2370 {
2371 /* Exception occurred */
2372 return;
2373 }
2374 }
2375 }
2376 else
2377 {
2378 USHORT Value;
2379
2380 /* Read the value */
2381 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2382 {
2383 /* Exception occurred */
2384 return;
2385 }
2386
2387 /* Set CF to the bit value */
2388 State->Flags.Cf = (Value >> BitNumber) & 1;
2389
2390 if (ModRegRm.Register == 5)
2391 {
2392 /* BTS */
2393 Value |= 1 << BitNumber;
2394 }
2395 else if (ModRegRm.Register == 6)
2396 {
2397 /* BTR */
2398 Value &= ~(1 << BitNumber);
2399 }
2400 else if (ModRegRm.Register == 7)
2401 {
2402 /* BTC */
2403 Value ^= 1 << BitNumber;
2404 }
2405
2406 if (ModRegRm.Register >= 5)
2407 {
2408 /* Write back the result */
2409 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2410 {
2411 /* Exception occurred */
2412 return;
2413 }
2414 }
2415 }
2416 }
2417
2418 /* EOF */