Create the AHCI branch for Aman's work
[reactos.git] / sdk / lib / fast486 / opgroups.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opgroups.c
4 *
5 * Copyright (C) 2015 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 State->Flags.Cf = State->Flags.Of = FALSE;
74 break;
75 }
76
77 /* ADC */
78 case 2:
79 {
80 INT Carry = State->Flags.Cf ? 1 : 0;
81
82 Result = (FirstValue + SecondValue + Carry) & MaxValue;
83
84 /* Update CF, OF and AF */
85 State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1))
86 || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
87 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
88 && ((FirstValue & SignFlag) != (Result & SignFlag));
89 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
90
91 break;
92 }
93
94 /* SBB */
95 case 3:
96 {
97 INT Carry = State->Flags.Cf ? 1 : 0;
98
99 Result = (FirstValue - SecondValue - Carry) & MaxValue;
100
101 /* Update CF, OF and AF */
102 State->Flags.Cf = Carry
103 ? (FirstValue <= SecondValue)
104 : (FirstValue < SecondValue);
105 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
106 && ((FirstValue & SignFlag) != (Result & SignFlag));
107 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
108
109 break;
110 }
111
112 /* AND */
113 case 4:
114 {
115 Result = FirstValue & SecondValue;
116 State->Flags.Cf = State->Flags.Of = FALSE;
117 break;
118 }
119
120 /* SUB or CMP */
121 case 5:
122 case 7:
123 {
124 Result = (FirstValue - SecondValue) & MaxValue;
125
126 /* Update CF, OF and AF */
127 State->Flags.Cf = (FirstValue < SecondValue);
128 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
129 && ((FirstValue & SignFlag) != (Result & SignFlag));
130 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
131
132 break;
133 }
134
135 /* XOR */
136 case 6:
137 {
138 Result = FirstValue ^ SecondValue;
139 State->Flags.Cf = State->Flags.Of = FALSE;
140 break;
141 }
142
143 default:
144 {
145 /* Shouldn't happen */
146 ASSERT(FALSE);
147 }
148 }
149
150 /* Update ZF, SF and PF */
151 State->Flags.Zf = (Result == 0);
152 State->Flags.Sf = ((Result & SignFlag) != 0);
153 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
154
155 /* Return the result */
156 return Result;
157 }
158
159 static
160 inline
161 ULONG
162 Fast486RotateOperation(PFAST486_STATE State,
163 INT Operation,
164 ULONG Value,
165 UCHAR Bits,
166 UCHAR Count)
167 {
168 ULONG HighestBit = 1 << (Bits - 1);
169 ULONG MaxValue = HighestBit | (HighestBit - 1);
170 ULONG Result;
171
172 /* Normalize the count */
173 Count &= 0x1F;
174
175 if ((Operation == 2) || (Operation == 3)) Count %= Bits + 1;
176
177 /* If the count is zero, do nothing */
178 if (Count == 0) return Value;
179
180 /* Check which operation is this */
181 switch (Operation)
182 {
183 /* ROL */
184 case 0:
185 {
186 Count %= Bits;
187 Result = (Value << Count) | (Value >> (Bits - Count));
188
189 /* Update CF and OF */
190 State->Flags.Cf = Result & 1;
191 if (Count == 1) State->Flags.Of = State->Flags.Cf
192 ^ ((Result & HighestBit) != 0);
193
194 break;
195 }
196
197 /* ROR */
198 case 1:
199 {
200 Count %= Bits;
201 Result = (Value >> Count) | (Value << (Bits - Count));
202
203 /* Update CF and OF */
204 State->Flags.Cf = ((Result & HighestBit) != 0);
205 if (Count == 1) State->Flags.Of = State->Flags.Cf
206 ^ ((Result & (HighestBit >> 1)) != 0);
207
208 break;
209 }
210
211 /* RCL */
212 case 2:
213 {
214 Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
215
216 /* Complete the calculation, but make sure we don't shift by too much */
217 if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
218
219 /* Update CF and OF */
220 State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
221 if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
222
223 break;
224 }
225
226 /* RCR */
227 case 3:
228 {
229 /* Update OF */
230 if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Value & HighestBit) != 0);
231
232 Result = (Value >> Count) | (State->Flags.Cf << (Bits - Count));
233
234 /* Complete the calculation, but make sure we don't shift by too much */
235 if ((Bits - Count) < 31) Result |= Value << (Bits - Count + 1);
236
237 /* Update CF */
238 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
239
240 break;
241 }
242
243 /* SHL/SAL */
244 case 4:
245 case 6:
246 {
247 Result = Value << Count;
248
249 /* Update CF and OF */
250 State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
251 if (Count == 1) State->Flags.Of = State->Flags.Cf
252 ^ ((Result & HighestBit) != 0);
253
254 break;
255 }
256
257 /* SHR */
258 case 5:
259 {
260 Result = Value >> Count;
261
262 /* Update CF and OF */
263 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
264 if (Count == 1) State->Flags.Of = ((Value & HighestBit) != 0);
265
266 break;
267 }
268
269 /* SAR */
270 case 7:
271 {
272 Result = Value >> Count;
273
274 /* Fill the top Count bits with the sign bit */
275 if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
276
277 /* Update CF and OF */
278 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
279 if (Count == 1) State->Flags.Of = FALSE;
280
281 break;
282 }
283 }
284
285 if (Operation >= 4)
286 {
287 /* Update ZF, SF and PF */
288 State->Flags.Zf = ((Result & MaxValue) == 0);
289 State->Flags.Sf = ((Result & HighestBit) != 0);
290 State->Flags.Pf = Fast486CalculateParity(Result);
291 }
292
293 /* Return the result */
294 return Result;
295 }
296
297 /* PUBLIC FUNCTIONS ***********************************************************/
298
299 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)
300 {
301 UCHAR Immediate, Value;
302 FAST486_MOD_REG_RM ModRegRm;
303 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
304
305 TOGGLE_ADSIZE(AddressSize);
306
307 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
308 {
309 /* Exception occurred */
310 return;
311 }
312
313 /* Fetch the immediate operand */
314 if (!Fast486FetchByte(State, &Immediate))
315 {
316 /* Exception occurred */
317 return;
318 }
319
320 /* Read the operands */
321 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
322 {
323 /* Exception occurred */
324 return;
325 }
326
327 /* Calculate the result */
328 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
329
330 /* Unless this is CMP, write back the result */
331 if (ModRegRm.Register != 7)
332 {
333 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
334 }
335 }
336
337 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
338 {
339 FAST486_MOD_REG_RM ModRegRm;
340 BOOLEAN OperandSize, AddressSize;
341
342 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
343
344 TOGGLE_OPSIZE(OperandSize);
345 TOGGLE_ADSIZE(AddressSize);
346
347 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
348 {
349 /* Exception occurred */
350 return;
351 }
352
353 if (OperandSize)
354 {
355 ULONG Immediate, Value;
356
357 /* Fetch the immediate operand */
358 if (!Fast486FetchDword(State, &Immediate))
359 {
360 /* Exception occurred */
361 return;
362 }
363
364 /* Read the operands */
365 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
366 {
367 /* Exception occurred */
368 return;
369 }
370
371 /* Calculate the result */
372 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
373
374 /* Unless this is CMP, write back the result */
375 if (ModRegRm.Register != 7)
376 {
377 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
378 }
379 }
380 else
381 {
382 USHORT Immediate, Value;
383
384 /* Fetch the immediate operand */
385 if (!Fast486FetchWord(State, &Immediate))
386 {
387 /* Exception occurred */
388 return;
389 }
390
391 /* Read the operands */
392 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
393 {
394 /* Exception occurred */
395 return;
396 }
397
398 /* Calculate the result */
399 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
400
401 /* Unless this is CMP, write back the result */
402 if (ModRegRm.Register != 7)
403 {
404 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
405 }
406 }
407 }
408
409 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
410 {
411 CHAR ImmByte;
412 FAST486_MOD_REG_RM ModRegRm;
413 BOOLEAN OperandSize, AddressSize;
414
415 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
416
417 TOGGLE_OPSIZE(OperandSize);
418 TOGGLE_ADSIZE(AddressSize);
419
420 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
421 {
422 /* Exception occurred */
423 return;
424 }
425
426 /* Fetch the immediate operand */
427 if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
428 {
429 /* Exception occurred */
430 return;
431 }
432
433 if (OperandSize)
434 {
435 ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
436 ULONG Value;
437
438 /* Read the operands */
439 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
440 {
441 /* Exception occurred */
442 return;
443 }
444
445 /* Calculate the result */
446 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
447
448 /* Unless this is CMP, write back the result */
449 if (ModRegRm.Register != 7)
450 {
451 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
452 }
453 }
454 else
455 {
456 USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
457 USHORT Value;
458
459 /* Read the operands */
460 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
461 {
462 /* Exception occurred */
463 return;
464 }
465
466 /* Calculate the result */
467 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
468
469 /* Unless this is CMP, write back the result */
470 if (ModRegRm.Register != 7)
471 {
472 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
473 }
474 }
475 }
476
477 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
478 {
479 ULONG Value;
480 FAST486_MOD_REG_RM ModRegRm;
481 BOOLEAN OperandSize, AddressSize;
482
483 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
484
485 TOGGLE_OPSIZE(OperandSize);
486 TOGGLE_ADSIZE(AddressSize);
487
488 /* Pop a value from the stack - this must be done first */
489 if (!Fast486StackPop(State, &Value))
490 {
491 /* Exception occurred */
492 return;
493 }
494
495 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
496 {
497 /* Exception occurred */
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 < FAST486_CHAR_MIN) || (Result > FAST486_CHAR_MAX));
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 > FAST486_CHAR_MAX || Quotient < FAST486_CHAR_MIN)
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 = -(LONG)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 < FAST486_LONG_MIN) || (Result > FAST486_LONG_MAX));
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 < FAST486_SHORT_MIN) || (Result > FAST486_SHORT_MAX));
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 > FAST486_LONG_MAX || Quotient < FAST486_LONG_MIN)
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 > FAST486_SHORT_MAX || Quotient < FAST486_SHORT_MIN)
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 && !State->Flags.Vm)
1469 {
1470 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1471 {
1472 /* Gate processed or exception occurred */
1473 return;
1474 }
1475 }
1476
1477 /* Push the current value of CS */
1478 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1479 {
1480 /* Exception occurred */
1481 return;
1482 }
1483
1484 /* Push the current value of EIP */
1485 if (!Fast486StackPush(State, State->InstPtr.Long))
1486 {
1487 /* Exception occurred */
1488 return;
1489 }
1490
1491 /* Load the new code segment */
1492 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1493 {
1494 /* Exception occurred */
1495 return;
1496 }
1497
1498 /* Set the EIP to the address */
1499 State->InstPtr.Long = Value;
1500 }
1501 else if (ModRegRm.Register == 4)
1502 {
1503 /* Set the EIP to the address */
1504 State->InstPtr.Long = Value;
1505 }
1506 else if (ModRegRm.Register == 5)
1507 {
1508 USHORT Selector;
1509 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1510
1511 /* Check for the segment override */
1512 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1513 {
1514 /* Use the override segment instead */
1515 Segment = State->SegmentOverride;
1516 }
1517
1518 /* Read the selector */
1519 if (!Fast486ReadMemory(State,
1520 Segment,
1521 ModRegRm.MemoryAddress + sizeof(ULONG),
1522 FALSE,
1523 &Selector,
1524 sizeof(USHORT)))
1525 {
1526 /* Exception occurred */
1527 return;
1528 }
1529
1530 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1531 && !State->Flags.Vm)
1532 {
1533 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1534 {
1535 /* Gate processed or exception occurred */
1536 return;
1537 }
1538 }
1539
1540 /* Load the new code segment */
1541 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1542 {
1543 /* Exception occurred */
1544 return;
1545 }
1546
1547 /* Set the EIP to the address */
1548 State->InstPtr.Long = Value;
1549 }
1550 else if (ModRegRm.Register == 6)
1551 {
1552 /* Push the value on to the stack */
1553 Fast486StackPush(State, Value);
1554 return;
1555 }
1556
1557 if (ModRegRm.Register <= 1)
1558 {
1559 /* Update flags */
1560 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1561 State->Flags.Zf = (Value == 0);
1562 State->Flags.Pf = Fast486CalculateParity(Value);
1563
1564 /* Write back the result */
1565 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1566 }
1567 }
1568 else
1569 {
1570 USHORT Value;
1571
1572 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1573 {
1574 /* Exception occurred */
1575 return;
1576 }
1577
1578 if (ModRegRm.Register == 0)
1579 {
1580 /* Increment and update OF */
1581 Value++;
1582 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1583 State->Flags.Af = ((Value & 0x0F) == 0);
1584 }
1585 else if (ModRegRm.Register == 1)
1586 {
1587 /* Decrement and update OF */
1588 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1589 Value--;
1590 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1591 }
1592 else if (ModRegRm.Register == 2)
1593 {
1594 /* Push the current value of IP */
1595 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1596 {
1597 /* Exception occurred */
1598 return;
1599 }
1600
1601 /* Set the IP to the address */
1602 State->InstPtr.LowWord = Value;
1603
1604 /* Clear the top half of EIP */
1605 State->InstPtr.Long &= 0xFFFF;
1606 }
1607 else if (ModRegRm.Register == 3)
1608 {
1609 USHORT Selector;
1610 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1611
1612 /* Check for the segment override */
1613 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1614 {
1615 /* Use the override segment instead */
1616 Segment = State->SegmentOverride;
1617 }
1618
1619 /* Read the selector */
1620 if (!Fast486ReadMemory(State,
1621 Segment,
1622 ModRegRm.MemoryAddress + sizeof(USHORT),
1623 FALSE,
1624 &Selector,
1625 sizeof(USHORT)))
1626 {
1627 /* Exception occurred */
1628 return;
1629 }
1630
1631 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1632 && !State->Flags.Vm)
1633 {
1634 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1635 {
1636 /* Gate processed or exception occurred */
1637 return;
1638 }
1639 }
1640
1641 /* Push the current value of CS */
1642 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1643 {
1644 /* Exception occurred */
1645 return;
1646 }
1647
1648 /* Push the current value of IP */
1649 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1650 {
1651 /* Exception occurred */
1652 return;
1653 }
1654
1655 /* Load the new code segment */
1656 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1657 {
1658 /* Exception occurred */
1659 return;
1660 }
1661
1662 /* Set the IP to the address */
1663 State->InstPtr.LowWord = Value;
1664
1665 /* Clear the top half of EIP */
1666 State->InstPtr.Long &= 0xFFFF;
1667 }
1668 else if (ModRegRm.Register == 4)
1669 {
1670 /* Set the IP to the address */
1671 State->InstPtr.LowWord = Value;
1672
1673 /* Clear the top half of EIP */
1674 State->InstPtr.Long &= 0xFFFF;
1675 }
1676 else if (ModRegRm.Register == 5)
1677 {
1678 USHORT Selector;
1679 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1680
1681 /* Check for the segment override */
1682 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1683 {
1684 /* Use the override segment instead */
1685 Segment = State->SegmentOverride;
1686 }
1687
1688 /* Read the selector */
1689 if (!Fast486ReadMemory(State,
1690 Segment,
1691 ModRegRm.MemoryAddress + sizeof(USHORT),
1692 FALSE,
1693 &Selector,
1694 sizeof(USHORT)))
1695 {
1696 /* Exception occurred */
1697 return;
1698 }
1699
1700 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1701 && !State->Flags.Vm)
1702 {
1703 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1704 {
1705 /* Gate processed or exception occurred */
1706 return;
1707 }
1708 }
1709
1710 /* Load the new code segment */
1711 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1712 {
1713 /* Exception occurred */
1714 return;
1715 }
1716
1717 /* Set the IP to the address */
1718 State->InstPtr.LowWord = Value;
1719
1720 /* Clear the top half of EIP */
1721 State->InstPtr.Long &= 0xFFFF;
1722 }
1723 else if (ModRegRm.Register == 6)
1724 {
1725 /* Push the value on to the stack */
1726 Fast486StackPush(State, Value);
1727 return;
1728 }
1729 else
1730 {
1731 /* Invalid */
1732 Fast486Exception(State, FAST486_EXCEPTION_UD);
1733 return;
1734 }
1735
1736 if (ModRegRm.Register <= 1)
1737 {
1738 /* Update flags */
1739 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1740 State->Flags.Zf = (Value == 0);
1741 State->Flags.Pf = Fast486CalculateParity(Value);
1742
1743 /* Write back the result */
1744 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1745 }
1746 }
1747 }
1748
1749 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
1750 {
1751 FAST486_MOD_REG_RM ModRegRm;
1752 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1753
1754 NO_LOCK_PREFIX();
1755 TOGGLE_ADSIZE(AddressSize);
1756
1757 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1758 {
1759 /* Exception occurred */
1760 return;
1761 }
1762
1763 /* Check which operation this is */
1764 switch (ModRegRm.Register)
1765 {
1766 /* SLDT */
1767 case 0:
1768 {
1769 /* Not recognized in real mode or virtual 8086 mode */
1770 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1771 || State->Flags.Vm)
1772 {
1773 Fast486Exception(State, FAST486_EXCEPTION_UD);
1774 return;
1775 }
1776
1777 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
1778 break;
1779 }
1780
1781 /* STR */
1782 case 1:
1783 {
1784 /* Not recognized in real mode or virtual 8086 mode */
1785 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1786 || State->Flags.Vm)
1787 {
1788 Fast486Exception(State, FAST486_EXCEPTION_UD);
1789 return;
1790 }
1791
1792 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
1793 break;
1794 }
1795
1796 /* LLDT */
1797 case 2:
1798 {
1799 BOOLEAN Valid;
1800 USHORT Selector;
1801 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1802
1803 /* Not recognized in real mode or virtual 8086 mode */
1804 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1805 || State->Flags.Vm)
1806 {
1807 Fast486Exception(State, FAST486_EXCEPTION_UD);
1808 return;
1809 }
1810
1811 /* This is a privileged instruction */
1812 if (Fast486GetCurrentPrivLevel(State) != 0)
1813 {
1814 Fast486Exception(State, FAST486_EXCEPTION_GP);
1815 return;
1816 }
1817
1818 if (!Fast486ReadModrmWordOperands(State,
1819 &ModRegRm,
1820 NULL,
1821 &Selector))
1822 {
1823 /* Exception occurred */
1824 return;
1825 }
1826
1827 if (Selector & SEGMENT_TABLE_INDICATOR)
1828 {
1829 /* This selector doesn't point to the GDT */
1830 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1831 return;
1832 }
1833
1834 if (!Fast486ReadDescriptorEntry(State,
1835 Selector,
1836 &Valid,
1837 (PFAST486_GDT_ENTRY)&GdtEntry))
1838 {
1839 /* Exception occurred */
1840 return;
1841 }
1842
1843 if (!Valid)
1844 {
1845 /* Invalid selector */
1846 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1847 return;
1848 }
1849
1850 if (GET_SEGMENT_INDEX(Selector) == 0)
1851 {
1852 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1853 return;
1854 }
1855
1856 if (!GdtEntry.Present)
1857 {
1858 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1859 return;
1860 }
1861
1862 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1863 {
1864 /* This is not a LDT descriptor */
1865 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1866 return;
1867 }
1868
1869 /* Update the LDTR */
1870 State->Ldtr.Selector = Selector;
1871 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1872 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1873
1874 if (GdtEntry.Granularity)
1875 {
1876 State->Ldtr.Limit <<= 12;
1877 State->Ldtr.Limit |= 0x00000FFF;
1878 }
1879
1880 break;
1881 }
1882
1883 /* LTR */
1884 case 3:
1885 {
1886 BOOLEAN Valid;
1887 USHORT Selector;
1888 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1889
1890 /* Not recognized in real mode or virtual 8086 mode */
1891 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1892 || State->Flags.Vm)
1893 {
1894 Fast486Exception(State, FAST486_EXCEPTION_UD);
1895 return;
1896 }
1897
1898 /* This is a privileged instruction */
1899 if (Fast486GetCurrentPrivLevel(State) != 0)
1900 {
1901 Fast486Exception(State, FAST486_EXCEPTION_GP);
1902 return;
1903 }
1904
1905 if (!Fast486ReadModrmWordOperands(State,
1906 &ModRegRm,
1907 NULL,
1908 &Selector))
1909 {
1910 /* Exception occurred */
1911 return;
1912 }
1913
1914 if (Selector & SEGMENT_TABLE_INDICATOR)
1915 {
1916 /* This selector doesn't point to the GDT */
1917 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1918 return;
1919 }
1920
1921 if (!Fast486ReadDescriptorEntry(State,
1922 Selector,
1923 &Valid,
1924 (PFAST486_GDT_ENTRY)&GdtEntry))
1925 {
1926 /* Exception occurred */
1927 return;
1928 }
1929
1930 if (!Valid)
1931 {
1932 /* Invalid selector */
1933 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1934 return;
1935 }
1936
1937 if (GET_SEGMENT_INDEX(Selector) == 0)
1938 {
1939 Fast486Exception(State, FAST486_EXCEPTION_GP);
1940 return;
1941 }
1942
1943 if (!GdtEntry.Present)
1944 {
1945 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1946 return;
1947 }
1948
1949 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE
1950 && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1951 && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE
1952 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1953 {
1954 /* This is not a TSS descriptor */
1955 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1956 return;
1957 }
1958
1959 /* Update the TR */
1960 State->TaskReg.Selector = Selector;
1961 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1962 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1963 State->TaskReg.Modern = GdtEntry.Signature == FAST486_TSS_SIGNATURE
1964 || GdtEntry.Signature == FAST486_BUSY_TSS_SIGNATURE;
1965
1966 if (GdtEntry.Granularity)
1967 {
1968 State->TaskReg.Limit <<= 12;
1969 State->TaskReg.Limit |= 0x00000FFF;
1970 }
1971
1972 if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1973 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1974 {
1975 /* Set the busy bit of this TSS descriptor and write it back */
1976 GdtEntry.Signature |= 2;
1977
1978 Fast486WriteLinearMemory(State,
1979 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
1980 &GdtEntry,
1981 sizeof(GdtEntry),
1982 FALSE /* We already made sure CPL is 0 */);
1983 }
1984
1985 break;
1986 }
1987
1988 /* VERR/VERW */
1989 case 4:
1990 case 5:
1991 {
1992 USHORT Selector;
1993 BOOLEAN Valid;
1994 FAST486_GDT_ENTRY GdtEntry;
1995
1996 /* Not recognized in real mode or virtual 8086 mode */
1997 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1998 || State->Flags.Vm)
1999 {
2000 Fast486Exception(State, FAST486_EXCEPTION_UD);
2001 return;
2002 }
2003
2004 if (!Fast486ReadModrmWordOperands(State,
2005 &ModRegRm,
2006 NULL,
2007 &Selector))
2008 {
2009 /* Exception occurred */
2010 return;
2011 }
2012
2013 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
2014 {
2015 /* Exception occurred */
2016 return;
2017 }
2018
2019 if (!Valid)
2020 {
2021 /* Clear ZF */
2022 State->Flags.Zf = FALSE;
2023 return;
2024 }
2025
2026 /* Set ZF if it is valid and accessible */
2027 State->Flags.Zf = GdtEntry.Present // must be present
2028 && GdtEntry.SystemType // must be a segment
2029 && (((ModRegRm.Register == 4)
2030 /* code segments are only readable if the RW bit is set */
2031 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
2032 || ((ModRegRm.Register == 5)
2033 /* code segments are never writable, data segments are writable when RW is set */
2034 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2035 /*
2036 * for segments other than conforming code segments,
2037 * both RPL and CPL must be less than or equal to DPL
2038 */
2039 && (((!GdtEntry.Executable || !GdtEntry.DirConf)
2040 && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2041 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl))
2042 /* for conforming code segments, DPL must be less than or equal to CPL */
2043 || ((GdtEntry.Executable && GdtEntry.DirConf)
2044 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
2045
2046
2047 break;
2048 }
2049
2050 /* Invalid */
2051 default:
2052 {
2053 Fast486Exception(State, FAST486_EXCEPTION_UD);
2054 }
2055 }
2056 }
2057
2058 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2059 {
2060 // FAST486_TABLE_REG TableReg;
2061 UCHAR TableReg[6];
2062 FAST486_MOD_REG_RM ModRegRm;
2063 BOOLEAN OperandSize, AddressSize;
2064 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2065
2066 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2067
2068 NO_LOCK_PREFIX();
2069 TOGGLE_OPSIZE(OperandSize);
2070 TOGGLE_ADSIZE(AddressSize);
2071
2072 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2073 {
2074 /* Exception occurred */
2075 return;
2076 }
2077
2078 /* Check for the segment override */
2079 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2080 {
2081 /* Use the override segment instead */
2082 Segment = State->SegmentOverride;
2083 }
2084
2085 /* Check which operation this is */
2086 switch (ModRegRm.Register)
2087 {
2088 /* SGDT */
2089 case 0:
2090 {
2091 if (!ModRegRm.Memory)
2092 {
2093 /* The second operand must be a memory location */
2094 Fast486Exception(State, FAST486_EXCEPTION_UD);
2095 return;
2096 }
2097
2098 /* Fill the 6-byte table register */
2099 // TableReg = State->Gdtr;
2100 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2101 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2102
2103 /* Store the GDTR */
2104 Fast486WriteMemory(State,
2105 Segment,
2106 ModRegRm.MemoryAddress,
2107 TableReg,
2108 sizeof(TableReg));
2109
2110 break;
2111 }
2112
2113 /* SIDT */
2114 case 1:
2115 {
2116 if (!ModRegRm.Memory)
2117 {
2118 /* The second operand must be a memory location */
2119 Fast486Exception(State, FAST486_EXCEPTION_UD);
2120 return;
2121 }
2122
2123 /* Fill the 6-byte table register */
2124 // TableReg = State->Idtr;
2125 *((PUSHORT)&TableReg) = State->Idtr.Size;
2126 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2127
2128 /* Store the IDTR */
2129 Fast486WriteMemory(State,
2130 Segment,
2131 ModRegRm.MemoryAddress,
2132 TableReg,
2133 sizeof(TableReg));
2134
2135 break;
2136 }
2137
2138 /* LGDT */
2139 case 2:
2140 {
2141 /* This is a privileged instruction */
2142 if (Fast486GetCurrentPrivLevel(State) != 0)
2143 {
2144 Fast486Exception(State, FAST486_EXCEPTION_GP);
2145 return;
2146 }
2147
2148 if (!ModRegRm.Memory)
2149 {
2150 /* The second operand must be a memory location */
2151 Fast486Exception(State, FAST486_EXCEPTION_UD);
2152 return;
2153 }
2154
2155 /* Read the new GDTR */
2156 if (!Fast486ReadMemory(State,
2157 Segment,
2158 ModRegRm.MemoryAddress,
2159 FALSE,
2160 TableReg,
2161 sizeof(TableReg)))
2162 {
2163 /* Exception occurred */
2164 return;
2165 }
2166
2167 /* Load the new GDT */
2168 // State->Gdtr = TableReg;
2169 State->Gdtr.Size = *((PUSHORT)&TableReg);
2170 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2171
2172 /* In 16-bit mode the highest byte is masked out */
2173 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2174
2175 break;
2176 }
2177
2178 /* LIDT */
2179 case 3:
2180 {
2181 /* This is a privileged instruction */
2182 if (Fast486GetCurrentPrivLevel(State) != 0)
2183 {
2184 Fast486Exception(State, FAST486_EXCEPTION_GP);
2185 return;
2186 }
2187
2188 if (!ModRegRm.Memory)
2189 {
2190 /* The second operand must be a memory location */
2191 Fast486Exception(State, FAST486_EXCEPTION_UD);
2192 return;
2193 }
2194
2195 /* Read the new IDTR */
2196 if (!Fast486ReadMemory(State,
2197 Segment,
2198 ModRegRm.MemoryAddress,
2199 FALSE,
2200 TableReg,
2201 sizeof(TableReg)))
2202 {
2203 /* Exception occurred */
2204 return;
2205 }
2206
2207 /* Load the new IDT */
2208 // State->Idtr = TableReg;
2209 State->Idtr.Size = *((PUSHORT)&TableReg);
2210 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2211
2212 /* In 16-bit mode the highest byte is masked out */
2213 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2214
2215 break;
2216 }
2217
2218 /* SMSW */
2219 case 4:
2220 {
2221 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2222 Fast486WriteModrmWordOperands(State,
2223 &ModRegRm,
2224 FALSE,
2225 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2226
2227 break;
2228 }
2229
2230 /* LMSW */
2231 case 6:
2232 {
2233 USHORT MachineStatusWord;
2234
2235 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2236 {
2237 /* This is a privileged instruction */
2238 if (Fast486GetCurrentPrivLevel(State) != 0)
2239 {
2240 Fast486Exception(State, FAST486_EXCEPTION_GP);
2241 return;
2242 }
2243 }
2244
2245 /* Read the new Machine Status Word */
2246 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2247 {
2248 /* Exception occurred */
2249 return;
2250 }
2251
2252 /* Set the lowest 4 bits, but never clear bit 0 */
2253 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1;
2254 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2255
2256 break;
2257 }
2258
2259 /* INVLPG */
2260 case 7:
2261 {
2262 #ifndef FAST486_NO_PREFETCH
2263 /* Invalidate the prefetch */
2264 State->PrefetchValid = FALSE;
2265 #endif
2266
2267 /* This is a privileged instruction */
2268 if (Fast486GetCurrentPrivLevel(State) != 0)
2269 {
2270 Fast486Exception(State, FAST486_EXCEPTION_GP);
2271 return;
2272 }
2273
2274 if (!ModRegRm.Memory)
2275 {
2276 /* The second operand must be a memory location */
2277 Fast486Exception(State, FAST486_EXCEPTION_UD);
2278 return;
2279 }
2280
2281 if (State->Tlb != NULL)
2282 {
2283 /* Clear the TLB entry */
2284 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2285 }
2286
2287 break;
2288 }
2289
2290 /* Invalid */
2291 default:
2292 {
2293 Fast486Exception(State, FAST486_EXCEPTION_UD);
2294 }
2295 }
2296 }
2297
2298 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2299 {
2300 FAST486_MOD_REG_RM ModRegRm;
2301 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2302
2303 TOGGLE_ADSIZE(AddressSize);
2304
2305 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2306 {
2307 /* Exception occurred */
2308 return;
2309 }
2310
2311 /* All of them are reserved (UD2) */
2312 Fast486Exception(State, FAST486_EXCEPTION_UD);
2313 return;
2314 }
2315
2316 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2317 {
2318 FAST486_MOD_REG_RM ModRegRm;
2319 BOOLEAN OperandSize, AddressSize;
2320 UINT DataSize;
2321 UCHAR BitNumber;
2322
2323 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2324
2325 TOGGLE_OPSIZE(OperandSize);
2326 TOGGLE_ADSIZE(AddressSize);
2327
2328 /* Get the number of bits */
2329 if (OperandSize) DataSize = 32;
2330 else DataSize = 16;
2331
2332 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2333 {
2334 /* Exception occurred */
2335 return;
2336 }
2337
2338 if (ModRegRm.Register < 4)
2339 {
2340 /* Invalid */
2341 Fast486Exception(State, FAST486_EXCEPTION_UD);
2342 return;
2343 }
2344
2345 /* Get the bit number */
2346 if (!Fast486FetchByte(State, &BitNumber))
2347 {
2348 /* Exception occurred */
2349 return;
2350 }
2351
2352 if (ModRegRm.Memory)
2353 {
2354 /*
2355 * For memory operands, add the bit offset divided by
2356 * the data size to the address
2357 */
2358 ModRegRm.MemoryAddress += BitNumber / DataSize;
2359 }
2360
2361 /* Normalize the bit number */
2362 BitNumber %= DataSize;
2363
2364 if (OperandSize)
2365 {
2366 ULONG Value;
2367
2368 /* Read the value */
2369 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2370 {
2371 /* Exception occurred */
2372 return;
2373 }
2374
2375 /* Set CF to the bit value */
2376 State->Flags.Cf = (Value >> BitNumber) & 1;
2377
2378 if (ModRegRm.Register == 5)
2379 {
2380 /* BTS */
2381 Value |= 1 << BitNumber;
2382 }
2383 else if (ModRegRm.Register == 6)
2384 {
2385 /* BTR */
2386 Value &= ~(1 << BitNumber);
2387 }
2388 else if (ModRegRm.Register == 7)
2389 {
2390 /* BTC */
2391 Value ^= 1 << BitNumber;
2392 }
2393
2394 if (ModRegRm.Register >= 5)
2395 {
2396 /* Write back the result */
2397 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2398 {
2399 /* Exception occurred */
2400 return;
2401 }
2402 }
2403 }
2404 else
2405 {
2406 USHORT Value;
2407
2408 /* Read the value */
2409 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2410 {
2411 /* Exception occurred */
2412 return;
2413 }
2414
2415 /* Set CF to the bit value */
2416 State->Flags.Cf = (Value >> BitNumber) & 1;
2417
2418 if (ModRegRm.Register == 5)
2419 {
2420 /* BTS */
2421 Value |= 1 << BitNumber;
2422 }
2423 else if (ModRegRm.Register == 6)
2424 {
2425 /* BTR */
2426 Value &= ~(1 << BitNumber);
2427 }
2428 else if (ModRegRm.Register == 7)
2429 {
2430 /* BTC */
2431 Value ^= 1 << BitNumber;
2432 }
2433
2434 if (ModRegRm.Register >= 5)
2435 {
2436 /* Write back the result */
2437 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2438 {
2439 /* Exception occurred */
2440 return;
2441 }
2442 }
2443 }
2444 }
2445
2446 /* EOF */