[FAST486]
[reactos.git] / reactos / 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 < -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 = -(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 < -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 && !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
1964 if (GdtEntry.Granularity)
1965 {
1966 State->TaskReg.Limit <<= 12;
1967 State->TaskReg.Limit |= 0x00000FFF;
1968 }
1969
1970 if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1971 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1972 {
1973 /* Set the busy bit of this TSS descriptor and write it back */
1974 GdtEntry.Signature |= 2;
1975
1976 Fast486WriteLinearMemory(State,
1977 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
1978 &GdtEntry,
1979 sizeof(GdtEntry),
1980 FALSE /* We already made sure CPL is 0 */);
1981 }
1982
1983 break;
1984 }
1985
1986 /* VERR/VERW */
1987 case 4:
1988 case 5:
1989 {
1990 USHORT Selector;
1991 BOOLEAN Valid;
1992 FAST486_GDT_ENTRY GdtEntry;
1993
1994 /* Not recognized in real mode or virtual 8086 mode */
1995 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1996 || State->Flags.Vm)
1997 {
1998 Fast486Exception(State, FAST486_EXCEPTION_UD);
1999 return;
2000 }
2001
2002 if (!Fast486ReadModrmWordOperands(State,
2003 &ModRegRm,
2004 NULL,
2005 &Selector))
2006 {
2007 /* Exception occurred */
2008 return;
2009 }
2010
2011 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
2012 {
2013 /* Exception occurred */
2014 return;
2015 }
2016
2017 if (!Valid)
2018 {
2019 /* Clear ZF */
2020 State->Flags.Zf = FALSE;
2021 return;
2022 }
2023
2024 /* Set ZF if it is valid and accessible */
2025 State->Flags.Zf = GdtEntry.Present // must be present
2026 && GdtEntry.SystemType // must be a segment
2027 && (((ModRegRm.Register == 4)
2028 /* code segments are only readable if the RW bit is set */
2029 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
2030 || ((ModRegRm.Register == 5)
2031 /* code segments are never writable, data segments are writable when RW is set */
2032 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2033 /*
2034 * for segments other than conforming code segments,
2035 * both RPL and CPL must be less than or equal to DPL
2036 */
2037 && (((!GdtEntry.Executable || !GdtEntry.DirConf)
2038 && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2039 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl))
2040 /* for conforming code segments, DPL must be less than or equal to CPL */
2041 || ((GdtEntry.Executable && GdtEntry.DirConf)
2042 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
2043
2044
2045 break;
2046 }
2047
2048 /* Invalid */
2049 default:
2050 {
2051 Fast486Exception(State, FAST486_EXCEPTION_UD);
2052 }
2053 }
2054 }
2055
2056 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2057 {
2058 // FAST486_TABLE_REG TableReg;
2059 UCHAR TableReg[6];
2060 FAST486_MOD_REG_RM ModRegRm;
2061 BOOLEAN OperandSize, AddressSize;
2062 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2063
2064 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2065
2066 NO_LOCK_PREFIX();
2067 TOGGLE_OPSIZE(OperandSize);
2068 TOGGLE_ADSIZE(AddressSize);
2069
2070 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2071 {
2072 /* Exception occurred */
2073 return;
2074 }
2075
2076 /* Check for the segment override */
2077 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2078 {
2079 /* Use the override segment instead */
2080 Segment = State->SegmentOverride;
2081 }
2082
2083 /* Check which operation this is */
2084 switch (ModRegRm.Register)
2085 {
2086 /* SGDT */
2087 case 0:
2088 {
2089 if (!ModRegRm.Memory)
2090 {
2091 /* The second operand must be a memory location */
2092 Fast486Exception(State, FAST486_EXCEPTION_UD);
2093 return;
2094 }
2095
2096 /* Fill the 6-byte table register */
2097 // TableReg = State->Gdtr;
2098 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2099 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2100
2101 /* Store the GDTR */
2102 Fast486WriteMemory(State,
2103 Segment,
2104 ModRegRm.MemoryAddress,
2105 TableReg,
2106 sizeof(TableReg));
2107
2108 break;
2109 }
2110
2111 /* SIDT */
2112 case 1:
2113 {
2114 if (!ModRegRm.Memory)
2115 {
2116 /* The second operand must be a memory location */
2117 Fast486Exception(State, FAST486_EXCEPTION_UD);
2118 return;
2119 }
2120
2121 /* Fill the 6-byte table register */
2122 // TableReg = State->Idtr;
2123 *((PUSHORT)&TableReg) = State->Idtr.Size;
2124 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2125
2126 /* Store the IDTR */
2127 Fast486WriteMemory(State,
2128 Segment,
2129 ModRegRm.MemoryAddress,
2130 TableReg,
2131 sizeof(TableReg));
2132
2133 break;
2134 }
2135
2136 /* LGDT */
2137 case 2:
2138 {
2139 /* This is a privileged instruction */
2140 if (Fast486GetCurrentPrivLevel(State) != 0)
2141 {
2142 Fast486Exception(State, FAST486_EXCEPTION_GP);
2143 return;
2144 }
2145
2146 if (!ModRegRm.Memory)
2147 {
2148 /* The second operand must be a memory location */
2149 Fast486Exception(State, FAST486_EXCEPTION_UD);
2150 return;
2151 }
2152
2153 /* Read the new GDTR */
2154 if (!Fast486ReadMemory(State,
2155 Segment,
2156 ModRegRm.MemoryAddress,
2157 FALSE,
2158 TableReg,
2159 sizeof(TableReg)))
2160 {
2161 /* Exception occurred */
2162 return;
2163 }
2164
2165 /* Load the new GDT */
2166 // State->Gdtr = TableReg;
2167 State->Gdtr.Size = *((PUSHORT)&TableReg);
2168 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2169
2170 /* In 16-bit mode the highest byte is masked out */
2171 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2172
2173 break;
2174 }
2175
2176 /* LIDT */
2177 case 3:
2178 {
2179 /* This is a privileged instruction */
2180 if (Fast486GetCurrentPrivLevel(State) != 0)
2181 {
2182 Fast486Exception(State, FAST486_EXCEPTION_GP);
2183 return;
2184 }
2185
2186 if (!ModRegRm.Memory)
2187 {
2188 /* The second operand must be a memory location */
2189 Fast486Exception(State, FAST486_EXCEPTION_UD);
2190 return;
2191 }
2192
2193 /* Read the new IDTR */
2194 if (!Fast486ReadMemory(State,
2195 Segment,
2196 ModRegRm.MemoryAddress,
2197 FALSE,
2198 TableReg,
2199 sizeof(TableReg)))
2200 {
2201 /* Exception occurred */
2202 return;
2203 }
2204
2205 /* Load the new IDT */
2206 // State->Idtr = TableReg;
2207 State->Idtr.Size = *((PUSHORT)&TableReg);
2208 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2209
2210 /* In 16-bit mode the highest byte is masked out */
2211 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2212
2213 break;
2214 }
2215
2216 /* SMSW */
2217 case 4:
2218 {
2219 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2220 Fast486WriteModrmWordOperands(State,
2221 &ModRegRm,
2222 FALSE,
2223 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2224
2225 break;
2226 }
2227
2228 /* LMSW */
2229 case 6:
2230 {
2231 USHORT MachineStatusWord;
2232
2233 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2234 {
2235 /* This is a privileged instruction */
2236 if (Fast486GetCurrentPrivLevel(State) != 0)
2237 {
2238 Fast486Exception(State, FAST486_EXCEPTION_GP);
2239 return;
2240 }
2241 }
2242
2243 /* Read the new Machine Status Word */
2244 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2245 {
2246 /* Exception occurred */
2247 return;
2248 }
2249
2250 /* Set the lowest 4 bits, but never clear bit 0 */
2251 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1;
2252 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2253
2254 break;
2255 }
2256
2257 /* INVLPG */
2258 case 7:
2259 {
2260 #ifndef FAST486_NO_PREFETCH
2261 /* Invalidate the prefetch */
2262 State->PrefetchValid = FALSE;
2263 #endif
2264
2265 /* This is a privileged instruction */
2266 if (Fast486GetCurrentPrivLevel(State) != 0)
2267 {
2268 Fast486Exception(State, FAST486_EXCEPTION_GP);
2269 return;
2270 }
2271
2272 if (!ModRegRm.Memory)
2273 {
2274 /* The second operand must be a memory location */
2275 Fast486Exception(State, FAST486_EXCEPTION_UD);
2276 return;
2277 }
2278
2279 if (State->Tlb != NULL)
2280 {
2281 /* Clear the TLB entry */
2282 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2283 }
2284
2285 break;
2286 }
2287
2288 /* Invalid */
2289 default:
2290 {
2291 Fast486Exception(State, FAST486_EXCEPTION_UD);
2292 }
2293 }
2294 }
2295
2296 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2297 {
2298 FAST486_MOD_REG_RM ModRegRm;
2299 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2300
2301 TOGGLE_ADSIZE(AddressSize);
2302
2303 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2304 {
2305 /* Exception occurred */
2306 return;
2307 }
2308
2309 /* All of them are reserved (UD2) */
2310 Fast486Exception(State, FAST486_EXCEPTION_UD);
2311 return;
2312 }
2313
2314 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2315 {
2316 FAST486_MOD_REG_RM ModRegRm;
2317 BOOLEAN OperandSize, AddressSize;
2318 UINT DataSize;
2319 UCHAR BitNumber;
2320
2321 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2322
2323 TOGGLE_OPSIZE(OperandSize);
2324 TOGGLE_ADSIZE(AddressSize);
2325
2326 /* Get the number of bits */
2327 if (OperandSize) DataSize = 32;
2328 else DataSize = 16;
2329
2330 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2331 {
2332 /* Exception occurred */
2333 return;
2334 }
2335
2336 if (ModRegRm.Register < 4)
2337 {
2338 /* Invalid */
2339 Fast486Exception(State, FAST486_EXCEPTION_UD);
2340 return;
2341 }
2342
2343 /* Get the bit number */
2344 if (!Fast486FetchByte(State, &BitNumber))
2345 {
2346 /* Exception occurred */
2347 return;
2348 }
2349
2350 if (ModRegRm.Memory)
2351 {
2352 /*
2353 * For memory operands, add the bit offset divided by
2354 * the data size to the address
2355 */
2356 ModRegRm.MemoryAddress += BitNumber / DataSize;
2357 }
2358
2359 /* Normalize the bit number */
2360 BitNumber %= DataSize;
2361
2362 if (OperandSize)
2363 {
2364 ULONG Value;
2365
2366 /* Read the value */
2367 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2368 {
2369 /* Exception occurred */
2370 return;
2371 }
2372
2373 /* Set CF to the bit value */
2374 State->Flags.Cf = (Value >> BitNumber) & 1;
2375
2376 if (ModRegRm.Register == 5)
2377 {
2378 /* BTS */
2379 Value |= 1 << BitNumber;
2380 }
2381 else if (ModRegRm.Register == 6)
2382 {
2383 /* BTR */
2384 Value &= ~(1 << BitNumber);
2385 }
2386 else if (ModRegRm.Register == 7)
2387 {
2388 /* BTC */
2389 Value ^= 1 << BitNumber;
2390 }
2391
2392 if (ModRegRm.Register >= 5)
2393 {
2394 /* Write back the result */
2395 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2396 {
2397 /* Exception occurred */
2398 return;
2399 }
2400 }
2401 }
2402 else
2403 {
2404 USHORT Value;
2405
2406 /* Read the value */
2407 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2408 {
2409 /* Exception occurred */
2410 return;
2411 }
2412
2413 /* Set CF to the bit value */
2414 State->Flags.Cf = (Value >> BitNumber) & 1;
2415
2416 if (ModRegRm.Register == 5)
2417 {
2418 /* BTS */
2419 Value |= 1 << BitNumber;
2420 }
2421 else if (ModRegRm.Register == 6)
2422 {
2423 /* BTR */
2424 Value &= ~(1 << BitNumber);
2425 }
2426 else if (ModRegRm.Register == 7)
2427 {
2428 /* BTC */
2429 Value ^= 1 << BitNumber;
2430 }
2431
2432 if (ModRegRm.Register >= 5)
2433 {
2434 /* Write back the result */
2435 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2436 {
2437 /* Exception occurred */
2438 return;
2439 }
2440 }
2441 }
2442 }
2443
2444 /* EOF */