e3e6ba7ed2cb315ed65ed05578de5480d6337fe9
[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 - restore SP */
498 if (OperandSize) State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
499 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
500
501 return;
502 }
503
504 if (ModRegRm.Register != 0)
505 {
506 /* Invalid */
507 Fast486Exception(State, FAST486_EXCEPTION_UD);
508 return;
509 }
510
511 if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
512 else Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Value));
513 }
514
515 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
516 {
517 UCHAR Value, Count;
518 FAST486_MOD_REG_RM ModRegRm;
519 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
520
521 TOGGLE_ADSIZE(AddressSize);
522
523 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
524 {
525 /* Exception occurred */
526 return;
527 }
528
529 /* Fetch the count */
530 if (!Fast486FetchByte(State, &Count))
531 {
532 /* Exception occurred */
533 return;
534 }
535
536 /* Read the operands */
537 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
538 {
539 /* Exception occurred */
540 return;
541 }
542
543 /* Calculate the result */
544 Value = LOBYTE(Fast486RotateOperation(State,
545 ModRegRm.Register,
546 Value,
547 8,
548 Count));
549
550 /* Write back the result */
551 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
552 }
553
554 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
555 {
556 UCHAR Count;
557 FAST486_MOD_REG_RM ModRegRm;
558 BOOLEAN OperandSize, AddressSize;
559
560 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
561
562 TOGGLE_OPSIZE(OperandSize);
563 TOGGLE_ADSIZE(AddressSize);
564
565 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
566 {
567 /* Exception occurred */
568 return;
569 }
570
571 /* Fetch the count */
572 if (!Fast486FetchByte(State, &Count))
573 {
574 /* Exception occurred */
575 return;
576 }
577
578 if (OperandSize)
579 {
580 ULONG Value;
581
582 /* Read the operands */
583 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
584 {
585 /* Exception occurred */
586 return;
587 }
588
589 /* Calculate the result */
590 Value = Fast486RotateOperation(State,
591 ModRegRm.Register,
592 Value,
593 32,
594 Count);
595
596 /* Write back the result */
597 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
598 }
599 else
600 {
601 USHORT Value;
602
603 /* Read the operands */
604 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
605 {
606 /* Exception occurred */
607 return;
608 }
609
610 /* Calculate the result */
611 Value = LOWORD(Fast486RotateOperation(State,
612 ModRegRm.Register,
613 Value,
614 16,
615 Count));
616
617 /* Write back the result */
618 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
619 }
620 }
621
622 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)
623 {
624 UCHAR Immediate;
625 FAST486_MOD_REG_RM ModRegRm;
626 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
627
628 TOGGLE_ADSIZE(AddressSize);
629
630 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
631 {
632 /* Exception occurred */
633 return;
634 }
635
636 if (ModRegRm.Register != 0)
637 {
638 /* Invalid */
639 Fast486Exception(State, FAST486_EXCEPTION_UD);
640 return;
641 }
642
643 /* Get the immediate operand */
644 if (!Fast486FetchByte(State, &Immediate))
645 {
646 /* Exception occurred */
647 return;
648 }
649
650 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Immediate);
651 }
652
653 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
654 {
655 FAST486_MOD_REG_RM ModRegRm;
656 BOOLEAN OperandSize, AddressSize;
657
658 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
659
660 TOGGLE_OPSIZE(OperandSize);
661 TOGGLE_ADSIZE(AddressSize);
662
663 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
664 {
665 /* Exception occurred */
666 return;
667 }
668
669 if (ModRegRm.Register != 0)
670 {
671 /* Invalid */
672 Fast486Exception(State, FAST486_EXCEPTION_UD);
673 return;
674 }
675
676 if (OperandSize)
677 {
678 ULONG Immediate;
679
680 /* Get the immediate operand */
681 if (!Fast486FetchDword(State, &Immediate))
682 {
683 /* Exception occurred */
684 return;
685 }
686
687 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Immediate);
688 }
689 else
690 {
691 USHORT Immediate;
692
693 /* Get the immediate operand */
694 if (!Fast486FetchWord(State, &Immediate))
695 {
696 /* Exception occurred */
697 return;
698 }
699
700 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Immediate);
701 }
702 }
703
704 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)
705 {
706 UCHAR Value;
707 FAST486_MOD_REG_RM ModRegRm;
708 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
709
710 TOGGLE_ADSIZE(AddressSize);
711
712 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
713 {
714 /* Exception occurred */
715 return;
716 }
717
718 /* Read the operands */
719 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
720 {
721 /* Exception occurred */
722 return;
723 }
724
725 /* Calculate the result */
726 Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
727
728 /* Write back the result */
729 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
730
731 }
732
733 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)
734 {
735 FAST486_MOD_REG_RM ModRegRm;
736 BOOLEAN OperandSize, AddressSize;
737
738 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
739
740 TOGGLE_OPSIZE(OperandSize);
741 TOGGLE_ADSIZE(AddressSize);
742
743 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
744 {
745 /* Exception occurred */
746 return;
747 }
748
749 if (OperandSize)
750 {
751 ULONG Value;
752
753 /* Read the operands */
754 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
755 {
756 /* Exception occurred */
757 return;
758 }
759
760 /* Calculate the result */
761 Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
762
763 /* Write back the result */
764 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
765 }
766 else
767 {
768 USHORT Value;
769
770 /* Read the operands */
771 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
772 {
773 /* Exception occurred */
774 return;
775 }
776
777 /* Calculate the result */
778 Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
779
780 /* Write back the result */
781 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
782 }
783 }
784
785 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)
786 {
787 UCHAR Value;
788 FAST486_MOD_REG_RM ModRegRm;
789 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
790
791 TOGGLE_ADSIZE(AddressSize);
792
793 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
794 {
795 /* Exception occurred */
796 return;
797 }
798
799 /* Read the operands */
800 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
801 {
802 /* Exception occurred */
803 return;
804 }
805
806 /* Calculate the result */
807 Value = LOBYTE(Fast486RotateOperation(State,
808 ModRegRm.Register,
809 Value,
810 8,
811 State->GeneralRegs[FAST486_REG_ECX].LowByte));
812
813 /* Write back the result */
814 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
815 }
816
817 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
818 {
819 FAST486_MOD_REG_RM ModRegRm;
820 BOOLEAN OperandSize, AddressSize;
821
822 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
823
824 TOGGLE_OPSIZE(OperandSize);
825 TOGGLE_ADSIZE(AddressSize);
826
827 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
828 {
829 /* Exception occurred */
830 return;
831 }
832
833 if (OperandSize)
834 {
835 ULONG Value;
836
837 /* Read the operands */
838 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
839 {
840 /* Exception occurred */
841 return;
842 }
843
844 /* Calculate the result */
845 Value = Fast486RotateOperation(State,
846 ModRegRm.Register,
847 Value,
848 32,
849 State->GeneralRegs[FAST486_REG_ECX].LowByte);
850
851 /* Write back the result */
852 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
853 }
854 else
855 {
856 USHORT Value;
857
858 /* Read the operands */
859 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
860 {
861 /* Exception occurred */
862 return;
863 }
864
865 /* Calculate the result */
866 Value = LOWORD(Fast486RotateOperation(State,
867 ModRegRm.Register,
868 Value,
869 16,
870 State->GeneralRegs[FAST486_REG_ECX].LowByte));
871
872 /* Write back the result */
873 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
874 }
875 }
876
877 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
878 {
879 UCHAR Value = 0;
880 FAST486_MOD_REG_RM ModRegRm;
881 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
882
883 TOGGLE_ADSIZE(AddressSize);
884
885 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
886 {
887 /* Exception occurred */
888 return;
889 }
890
891 /* Read the operands */
892 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
893 {
894 /* Exception occurred */
895 return;
896 }
897
898 switch (ModRegRm.Register)
899 {
900 /* TEST */
901 case 0:
902 case 1:
903 {
904 UCHAR Immediate, Result;
905
906 /* Fetch the immediate byte */
907 if (!Fast486FetchByte(State, &Immediate))
908 {
909 /* Exception occurred */
910 return;
911 }
912
913 /* Calculate the result */
914 Result = Value & Immediate;
915
916 /* Update the flags */
917 State->Flags.Cf = FALSE;
918 State->Flags.Of = FALSE;
919 State->Flags.Zf = (Result == 0);
920 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
921 State->Flags.Pf = Fast486CalculateParity(Result);
922
923 break;
924 }
925
926 /* NOT */
927 case 2:
928 {
929 /* Write back the result */
930 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
931
932 break;
933 }
934
935 /* NEG */
936 case 3:
937 {
938 /* Calculate the result */
939 UCHAR Result = -Value;
940
941 /* Update the flags */
942 State->Flags.Cf = (Value != 0);
943 State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
944 State->Flags.Af = ((Value & 0x0F) != 0);
945 State->Flags.Zf = (Result == 0);
946 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
947 State->Flags.Pf = Fast486CalculateParity(Result);
948
949 /* Write back the result */
950 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
951
952 break;
953 }
954
955 /* MUL */
956 case 4:
957 {
958 USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
959
960 /* Update the flags */
961 State->Flags.Cf = State->Flags.Of = (HIBYTE(Result) != 0);
962
963 /* Write back the result */
964 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
965
966 break;
967 }
968
969 /* IMUL */
970 case 5:
971 {
972 SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
973
974 /* Update the flags */
975 State->Flags.Cf = State->Flags.Of = ((Result < -128) || (Result > 127));
976
977 /* Write back the result */
978 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
979
980 break;
981 }
982
983 /* DIV */
984 case 6:
985 {
986 USHORT Quotient;
987 UCHAR Remainder;
988
989 if (Value == 0)
990 {
991 /* Divide error */
992 Fast486Exception(State, FAST486_EXCEPTION_DE);
993 return;
994 }
995
996 Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
997 Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
998
999 if (Quotient > 0xFF)
1000 {
1001 /* Divide error */
1002 Fast486Exception(State, FAST486_EXCEPTION_DE);
1003 return;
1004 }
1005
1006 /* Write back the results */
1007 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1008 State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1009
1010 break;
1011 }
1012
1013 /* IDIV */
1014 case 7:
1015 {
1016 SHORT Quotient;
1017 CHAR Remainder;
1018
1019 if (Value == 0)
1020 {
1021 /* Divide error */
1022 Fast486Exception(State, FAST486_EXCEPTION_DE);
1023 return;
1024 }
1025
1026 Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1027 Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1028
1029 if (Quotient > 127 || Quotient < -128)
1030 {
1031 /* Divide error */
1032 Fast486Exception(State, FAST486_EXCEPTION_DE);
1033 return;
1034 }
1035
1036 /* Write back the results */
1037 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)((CHAR)Quotient);
1038 State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1039
1040 break;
1041 }
1042 }
1043 }
1044
1045 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1046 {
1047 ULONG Value = 0, SignFlag;
1048 FAST486_MOD_REG_RM ModRegRm;
1049 BOOLEAN OperandSize, AddressSize;
1050
1051 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1052
1053 TOGGLE_OPSIZE(OperandSize);
1054 TOGGLE_ADSIZE(AddressSize);
1055
1056 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1057 {
1058 /* Exception occurred */
1059 return;
1060 }
1061
1062 /* Set the sign flag */
1063 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1064 else SignFlag = SIGN_FLAG_WORD;
1065
1066 /* Read the operand */
1067 if (OperandSize)
1068 {
1069 /* 32-bit */
1070 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1071 {
1072 /* Exception occurred */
1073 return;
1074 }
1075 }
1076 else
1077 {
1078 /* 16-bit */
1079 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1080 {
1081 /* Exception occurred */
1082 return;
1083 }
1084 }
1085
1086 switch (ModRegRm.Register)
1087 {
1088 /* TEST */
1089 case 0:
1090 case 1:
1091 {
1092 ULONG Immediate = 0, Result = 0;
1093
1094 if (OperandSize)
1095 {
1096 /* Fetch the immediate dword */
1097 if (!Fast486FetchDword(State, &Immediate))
1098 {
1099 /* Exception occurred */
1100 return;
1101 }
1102 }
1103 else
1104 {
1105 /* Fetch the immediate word */
1106 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1107 {
1108 /* Exception occurred */
1109 return;
1110 }
1111 }
1112
1113 /* Calculate the result */
1114 Result = Value & Immediate;
1115
1116 /* Update the flags */
1117 State->Flags.Cf = FALSE;
1118 State->Flags.Of = FALSE;
1119 State->Flags.Zf = (Result == 0);
1120 State->Flags.Sf = ((Result & SignFlag) != 0);
1121 State->Flags.Pf = Fast486CalculateParity(Result);
1122
1123 break;
1124 }
1125
1126 /* NOT */
1127 case 2:
1128 {
1129 /* Write back the result */
1130 if (OperandSize)
1131 {
1132 /* 32-bit */
1133 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1134 }
1135 else
1136 {
1137 /* 16-bit */
1138 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1139 }
1140
1141 break;
1142 }
1143
1144 /* NEG */
1145 case 3:
1146 {
1147 /* Calculate the result */
1148 ULONG Result = -(LONG)Value;
1149 if (!OperandSize) Result &= 0xFFFF;
1150
1151 /* Update the flags */
1152 State->Flags.Cf = (Value != 0);
1153 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1154 State->Flags.Af = ((Value & 0x0F) != 0);
1155 State->Flags.Zf = (Result == 0);
1156 State->Flags.Sf = ((Result & SignFlag) != 0);
1157 State->Flags.Pf = Fast486CalculateParity(Result);
1158
1159 /* Write back the result */
1160 if (OperandSize)
1161 {
1162 /* 32-bit */
1163 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1164 }
1165 else
1166 {
1167 /* 16-bit */
1168 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1169 }
1170
1171 break;
1172 }
1173
1174 /* MUL */
1175 case 4:
1176 {
1177 if (OperandSize)
1178 {
1179 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1180
1181 /* Update the flags */
1182 State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
1183
1184 /* Write back the result */
1185 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1186 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1187 }
1188 else
1189 {
1190 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1191
1192 /* Update the flags */
1193 State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
1194
1195 /* Write back the result */
1196 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1197 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1198 }
1199
1200 break;
1201 }
1202
1203 /* IMUL */
1204 case 5:
1205 {
1206 if (OperandSize)
1207 {
1208 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1209
1210 /* Update the flags */
1211 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1212
1213 /* Write back the result */
1214 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1215 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1216 }
1217 else
1218 {
1219 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1220
1221 /* Update the flags */
1222 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1223
1224 /* Write back the result */
1225 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1226 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1227 }
1228
1229 break;
1230 }
1231
1232 /* DIV */
1233 case 6:
1234 {
1235 if (Value == 0)
1236 {
1237 /* Divide error */
1238 Fast486Exception(State, FAST486_EXCEPTION_DE);
1239 return;
1240 }
1241
1242 if (OperandSize)
1243 {
1244 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1245 | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1246 ULONGLONG Quotient = Dividend / Value;
1247 ULONG Remainder = Dividend % Value;
1248
1249 if (Quotient > 0xFFFFFFFFULL)
1250 {
1251 /* Divide error */
1252 Fast486Exception(State, FAST486_EXCEPTION_DE);
1253 return;
1254 }
1255
1256 /* Write back the results */
1257 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1258 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1259 }
1260 else
1261 {
1262 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1263 | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1264 ULONG Quotient = Dividend / Value;
1265 USHORT Remainder = Dividend % Value;
1266
1267 if (Quotient > 0xFFFF)
1268 {
1269 /* Divide error */
1270 Fast486Exception(State, FAST486_EXCEPTION_DE);
1271 return;
1272 }
1273
1274 /* Write back the results */
1275 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
1276 State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
1277 }
1278
1279 break;
1280 }
1281
1282 /* IDIV */
1283 case 7:
1284 {
1285 if (Value == 0)
1286 {
1287 /* Divide error */
1288 Fast486Exception(State, FAST486_EXCEPTION_DE);
1289 return;
1290 }
1291
1292 if (OperandSize)
1293 {
1294 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1295 | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1296 LONGLONG Quotient = Dividend / (LONG)Value;
1297 LONG Remainder = Dividend % (LONG)Value;
1298
1299 if (Quotient > 2147483647LL || Quotient < -2147483648LL)
1300 {
1301 /* Divide error */
1302 Fast486Exception(State, FAST486_EXCEPTION_DE);
1303 return;
1304 }
1305
1306 /* Write back the results */
1307 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)((LONG)Quotient);
1308 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1309 }
1310 else
1311 {
1312 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1313 | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1314 LONG Quotient = Dividend / (SHORT)LOWORD(Value);
1315 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1316
1317 if (Quotient > 32767 || Quotient < -32768)
1318 {
1319 /* Divide error */
1320 Fast486Exception(State, FAST486_EXCEPTION_DE);
1321 return;
1322 }
1323
1324 /* Write back the results */
1325 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)((SHORT)Quotient);
1326 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1327 }
1328
1329 break;
1330 }
1331 }
1332 }
1333
1334 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1335 {
1336 UCHAR Value;
1337 FAST486_MOD_REG_RM ModRegRm;
1338 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1339
1340 TOGGLE_ADSIZE(AddressSize);
1341
1342 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1343 {
1344 /* Exception occurred */
1345 return;
1346 }
1347
1348 if (ModRegRm.Register > 1)
1349 {
1350 /* Invalid */
1351 Fast486Exception(State, FAST486_EXCEPTION_UD);
1352 return;
1353 }
1354
1355 /* Read the operands */
1356 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1357 {
1358 /* Exception occurred */
1359 return;
1360 }
1361
1362 if (ModRegRm.Register == 0)
1363 {
1364 /* Increment and update OF and AF */
1365 Value++;
1366 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1367 State->Flags.Af = ((Value & 0x0F) == 0);
1368 }
1369 else
1370 {
1371 /* Decrement and update OF and AF */
1372 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1373 Value--;
1374 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1375 }
1376
1377 /* Update flags */
1378 State->Flags.Zf = (Value == 0);
1379 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
1380 State->Flags.Pf = Fast486CalculateParity(Value);
1381
1382 /* Write back the result */
1383 Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1384 }
1385
1386 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1387 {
1388 FAST486_MOD_REG_RM ModRegRm;
1389 BOOLEAN OperandSize, AddressSize;
1390
1391 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1392
1393 TOGGLE_OPSIZE(OperandSize);
1394 TOGGLE_ADSIZE(AddressSize);
1395
1396 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1397 {
1398 /* Exception occurred */
1399 return;
1400 }
1401
1402 if (ModRegRm.Register == 7)
1403 {
1404 /* Invalid */
1405 Fast486Exception(State, FAST486_EXCEPTION_UD);
1406 return;
1407 }
1408
1409 /* Read the operands */
1410 if (OperandSize)
1411 {
1412 ULONG Value;
1413
1414 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1415 {
1416 /* Exception occurred */
1417 return;
1418 }
1419
1420 if (ModRegRm.Register == 0)
1421 {
1422 /* Increment and update OF and AF */
1423 Value++;
1424 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1425 State->Flags.Af = ((Value & 0x0F) == 0);
1426 }
1427 else if (ModRegRm.Register == 1)
1428 {
1429 /* Decrement and update OF and AF */
1430 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1431 Value--;
1432 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1433 }
1434 else if (ModRegRm.Register == 2)
1435 {
1436 /* Push the current value of EIP */
1437 if (!Fast486StackPush(State, State->InstPtr.Long))
1438 {
1439 /* Exception occurred */
1440 return;
1441 }
1442
1443 /* Set the EIP to the address */
1444 State->InstPtr.Long = Value;
1445 }
1446 else if (ModRegRm.Register == 3)
1447 {
1448 USHORT Selector;
1449 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1450
1451 /* Check for the segment override */
1452 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1453 {
1454 /* Use the override segment instead */
1455 Segment = State->SegmentOverride;
1456 }
1457
1458 /* Read the selector */
1459 if (!Fast486ReadMemory(State,
1460 Segment,
1461 ModRegRm.MemoryAddress + sizeof(ULONG),
1462 FALSE,
1463 &Selector,
1464 sizeof(USHORT)))
1465 {
1466 /* Exception occurred */
1467 return;
1468 }
1469
1470 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1471 && !State->Flags.Vm)
1472 {
1473 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1474 {
1475 /* Gate processed or exception occurred */
1476 return;
1477 }
1478 }
1479
1480 /* Push the current value of CS */
1481 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1482 {
1483 /* Exception occurred */
1484 return;
1485 }
1486
1487 /* Push the current value of EIP */
1488 if (!Fast486StackPush(State, State->InstPtr.Long))
1489 {
1490 /* Exception occurred */
1491 return;
1492 }
1493
1494 /* Load the new code segment */
1495 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1496 {
1497 /* Exception occurred */
1498 return;
1499 }
1500
1501 /* Set the EIP to the address */
1502 State->InstPtr.Long = Value;
1503 }
1504 else if (ModRegRm.Register == 4)
1505 {
1506 /* Set the EIP to the address */
1507 State->InstPtr.Long = Value;
1508 }
1509 else if (ModRegRm.Register == 5)
1510 {
1511 USHORT Selector;
1512 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1513
1514 /* Check for the segment override */
1515 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1516 {
1517 /* Use the override segment instead */
1518 Segment = State->SegmentOverride;
1519 }
1520
1521 /* Read the selector */
1522 if (!Fast486ReadMemory(State,
1523 Segment,
1524 ModRegRm.MemoryAddress + sizeof(ULONG),
1525 FALSE,
1526 &Selector,
1527 sizeof(USHORT)))
1528 {
1529 /* Exception occurred */
1530 return;
1531 }
1532
1533 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1534 && !State->Flags.Vm)
1535 {
1536 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1537 {
1538 /* Gate processed or exception occurred */
1539 return;
1540 }
1541 }
1542
1543 /* Load the new code segment */
1544 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1545 {
1546 /* Exception occurred */
1547 return;
1548 }
1549
1550 /* Set the EIP to the address */
1551 State->InstPtr.Long = Value;
1552 }
1553 else if (ModRegRm.Register == 6)
1554 {
1555 /* Push the value on to the stack */
1556 Fast486StackPush(State, Value);
1557 return;
1558 }
1559
1560 if (ModRegRm.Register <= 1)
1561 {
1562 /* Update flags */
1563 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1564 State->Flags.Zf = (Value == 0);
1565 State->Flags.Pf = Fast486CalculateParity(Value);
1566
1567 /* Write back the result */
1568 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1569 }
1570 }
1571 else
1572 {
1573 USHORT Value;
1574
1575 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1576 {
1577 /* Exception occurred */
1578 return;
1579 }
1580
1581 if (ModRegRm.Register == 0)
1582 {
1583 /* Increment and update OF */
1584 Value++;
1585 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1586 State->Flags.Af = ((Value & 0x0F) == 0);
1587 }
1588 else if (ModRegRm.Register == 1)
1589 {
1590 /* Decrement and update OF */
1591 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1592 Value--;
1593 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1594 }
1595 else if (ModRegRm.Register == 2)
1596 {
1597 /* Push the current value of IP */
1598 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1599 {
1600 /* Exception occurred */
1601 return;
1602 }
1603
1604 /* Set the IP to the address */
1605 State->InstPtr.LowWord = Value;
1606
1607 /* Clear the top half of EIP */
1608 State->InstPtr.Long &= 0xFFFF;
1609 }
1610 else if (ModRegRm.Register == 3)
1611 {
1612 USHORT Selector;
1613 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1614
1615 /* Check for the segment override */
1616 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1617 {
1618 /* Use the override segment instead */
1619 Segment = State->SegmentOverride;
1620 }
1621
1622 /* Read the selector */
1623 if (!Fast486ReadMemory(State,
1624 Segment,
1625 ModRegRm.MemoryAddress + sizeof(USHORT),
1626 FALSE,
1627 &Selector,
1628 sizeof(USHORT)))
1629 {
1630 /* Exception occurred */
1631 return;
1632 }
1633
1634 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1635 && !State->Flags.Vm)
1636 {
1637 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1638 {
1639 /* Gate processed or exception occurred */
1640 return;
1641 }
1642 }
1643
1644 /* Push the current value of CS */
1645 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1646 {
1647 /* Exception occurred */
1648 return;
1649 }
1650
1651 /* Push the current value of IP */
1652 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1653 {
1654 /* Exception occurred */
1655 return;
1656 }
1657
1658 /* Load the new code segment */
1659 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1660 {
1661 /* Exception occurred */
1662 return;
1663 }
1664
1665 /* Set the IP to the address */
1666 State->InstPtr.LowWord = Value;
1667
1668 /* Clear the top half of EIP */
1669 State->InstPtr.Long &= 0xFFFF;
1670 }
1671 else if (ModRegRm.Register == 4)
1672 {
1673 /* Set the IP to the address */
1674 State->InstPtr.LowWord = Value;
1675
1676 /* Clear the top half of EIP */
1677 State->InstPtr.Long &= 0xFFFF;
1678 }
1679 else if (ModRegRm.Register == 5)
1680 {
1681 USHORT Selector;
1682 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1683
1684 /* Check for the segment override */
1685 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1686 {
1687 /* Use the override segment instead */
1688 Segment = State->SegmentOverride;
1689 }
1690
1691 /* Read the selector */
1692 if (!Fast486ReadMemory(State,
1693 Segment,
1694 ModRegRm.MemoryAddress + sizeof(USHORT),
1695 FALSE,
1696 &Selector,
1697 sizeof(USHORT)))
1698 {
1699 /* Exception occurred */
1700 return;
1701 }
1702
1703 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1704 && !State->Flags.Vm)
1705 {
1706 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1707 {
1708 /* Gate processed or exception occurred */
1709 return;
1710 }
1711 }
1712
1713 /* Load the new code segment */
1714 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1715 {
1716 /* Exception occurred */
1717 return;
1718 }
1719
1720 /* Set the IP to the address */
1721 State->InstPtr.LowWord = Value;
1722
1723 /* Clear the top half of EIP */
1724 State->InstPtr.Long &= 0xFFFF;
1725 }
1726 else if (ModRegRm.Register == 6)
1727 {
1728 /* Push the value on to the stack */
1729 Fast486StackPush(State, Value);
1730 return;
1731 }
1732 else
1733 {
1734 /* Invalid */
1735 Fast486Exception(State, FAST486_EXCEPTION_UD);
1736 return;
1737 }
1738
1739 if (ModRegRm.Register <= 1)
1740 {
1741 /* Update flags */
1742 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1743 State->Flags.Zf = (Value == 0);
1744 State->Flags.Pf = Fast486CalculateParity(Value);
1745
1746 /* Write back the result */
1747 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1748 }
1749 }
1750 }
1751
1752 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
1753 {
1754 FAST486_MOD_REG_RM ModRegRm;
1755 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1756
1757 NO_LOCK_PREFIX();
1758 TOGGLE_ADSIZE(AddressSize);
1759
1760 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1761 {
1762 /* Exception occurred */
1763 return;
1764 }
1765
1766 /* Check which operation this is */
1767 switch (ModRegRm.Register)
1768 {
1769 /* SLDT */
1770 case 0:
1771 {
1772 /* Not recognized in real mode or virtual 8086 mode */
1773 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1774 || State->Flags.Vm)
1775 {
1776 Fast486Exception(State, FAST486_EXCEPTION_UD);
1777 return;
1778 }
1779
1780 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
1781 break;
1782 }
1783
1784 /* STR */
1785 case 1:
1786 {
1787 /* Not recognized in real mode or virtual 8086 mode */
1788 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1789 || State->Flags.Vm)
1790 {
1791 Fast486Exception(State, FAST486_EXCEPTION_UD);
1792 return;
1793 }
1794
1795 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
1796 break;
1797 }
1798
1799 /* LLDT */
1800 case 2:
1801 {
1802 BOOLEAN Valid;
1803 USHORT Selector;
1804 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1805
1806 /* Not recognized in real mode or virtual 8086 mode */
1807 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1808 || State->Flags.Vm)
1809 {
1810 Fast486Exception(State, FAST486_EXCEPTION_UD);
1811 return;
1812 }
1813
1814 /* This is a privileged instruction */
1815 if (Fast486GetCurrentPrivLevel(State) != 0)
1816 {
1817 Fast486Exception(State, FAST486_EXCEPTION_GP);
1818 return;
1819 }
1820
1821 if (!Fast486ReadModrmWordOperands(State,
1822 &ModRegRm,
1823 NULL,
1824 &Selector))
1825 {
1826 /* Exception occurred */
1827 return;
1828 }
1829
1830 if (Selector & SEGMENT_TABLE_INDICATOR)
1831 {
1832 /* This selector doesn't point to the GDT */
1833 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1834 return;
1835 }
1836
1837 if (!Fast486ReadDescriptorEntry(State,
1838 Selector,
1839 &Valid,
1840 (PFAST486_GDT_ENTRY)&GdtEntry))
1841 {
1842 /* Exception occurred */
1843 return;
1844 }
1845
1846 if (!Valid)
1847 {
1848 /* Invalid selector */
1849 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1850 return;
1851 }
1852
1853 if (GET_SEGMENT_INDEX(Selector) == 0)
1854 {
1855 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1856 return;
1857 }
1858
1859 if (!GdtEntry.Present)
1860 {
1861 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1862 return;
1863 }
1864
1865 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1866 {
1867 /* This is not a LDT descriptor */
1868 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1869 return;
1870 }
1871
1872 /* Update the LDTR */
1873 State->Ldtr.Selector = Selector;
1874 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1875 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1876
1877 if (GdtEntry.Granularity)
1878 {
1879 State->Ldtr.Limit <<= 12;
1880 State->Ldtr.Limit |= 0x00000FFF;
1881 }
1882
1883 break;
1884 }
1885
1886 /* LTR */
1887 case 3:
1888 {
1889 BOOLEAN Valid;
1890 USHORT Selector;
1891 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1892
1893 /* Not recognized in real mode or virtual 8086 mode */
1894 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1895 || State->Flags.Vm)
1896 {
1897 Fast486Exception(State, FAST486_EXCEPTION_UD);
1898 return;
1899 }
1900
1901 /* This is a privileged instruction */
1902 if (Fast486GetCurrentPrivLevel(State) != 0)
1903 {
1904 Fast486Exception(State, FAST486_EXCEPTION_GP);
1905 return;
1906 }
1907
1908 if (!Fast486ReadModrmWordOperands(State,
1909 &ModRegRm,
1910 NULL,
1911 &Selector))
1912 {
1913 /* Exception occurred */
1914 return;
1915 }
1916
1917 if (Selector & SEGMENT_TABLE_INDICATOR)
1918 {
1919 /* This selector doesn't point to the GDT */
1920 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1921 return;
1922 }
1923
1924 if (!Fast486ReadDescriptorEntry(State,
1925 Selector,
1926 &Valid,
1927 (PFAST486_GDT_ENTRY)&GdtEntry))
1928 {
1929 /* Exception occurred */
1930 return;
1931 }
1932
1933 if (!Valid)
1934 {
1935 /* Invalid selector */
1936 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1937 return;
1938 }
1939
1940 if (GET_SEGMENT_INDEX(Selector) == 0)
1941 {
1942 Fast486Exception(State, FAST486_EXCEPTION_GP);
1943 return;
1944 }
1945
1946 if (!GdtEntry.Present)
1947 {
1948 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1949 return;
1950 }
1951
1952 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE
1953 && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1954 && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE
1955 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1956 {
1957 /* This is not a TSS descriptor */
1958 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1959 return;
1960 }
1961
1962 /* Update the TR */
1963 State->TaskReg.Selector = Selector;
1964 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1965 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1966
1967 if (GdtEntry.Granularity)
1968 {
1969 State->TaskReg.Limit <<= 12;
1970 State->TaskReg.Limit |= 0x00000FFF;
1971 }
1972
1973 if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1974 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1975 {
1976 /* Set the busy bit of this TSS descriptor and write it back */
1977 GdtEntry.Signature |= 2;
1978
1979 Fast486WriteLinearMemory(State,
1980 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
1981 &GdtEntry,
1982 sizeof(GdtEntry),
1983 FALSE /* We already made sure CPL is 0 */);
1984 }
1985
1986 break;
1987 }
1988
1989 /* VERR/VERW */
1990 case 4:
1991 case 5:
1992 {
1993 USHORT Selector;
1994 BOOLEAN Valid;
1995 FAST486_GDT_ENTRY GdtEntry;
1996
1997 /* Not recognized in real mode or virtual 8086 mode */
1998 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1999 || State->Flags.Vm)
2000 {
2001 Fast486Exception(State, FAST486_EXCEPTION_UD);
2002 return;
2003 }
2004
2005 if (!Fast486ReadModrmWordOperands(State,
2006 &ModRegRm,
2007 NULL,
2008 &Selector))
2009 {
2010 /* Exception occurred */
2011 return;
2012 }
2013
2014 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
2015 {
2016 /* Exception occurred */
2017 return;
2018 }
2019
2020 if (!Valid)
2021 {
2022 /* Clear ZF */
2023 State->Flags.Zf = FALSE;
2024 return;
2025 }
2026
2027 /* Set ZF if it is valid and accessible */
2028 State->Flags.Zf = GdtEntry.Present // must be present
2029 && GdtEntry.SystemType // must be a segment
2030 && (((ModRegRm.Register == 4)
2031 /* code segments are only readable if the RW bit is set */
2032 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
2033 || ((ModRegRm.Register == 5)
2034 /* code segments are never writable, data segments are writable when RW is set */
2035 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2036 /*
2037 * for segments other than conforming code segments,
2038 * both RPL and CPL must be less than or equal to DPL
2039 */
2040 && (((!GdtEntry.Executable || !GdtEntry.DirConf)
2041 && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2042 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl))
2043 /* for conforming code segments, DPL must be less than or equal to CPL */
2044 || ((GdtEntry.Executable && GdtEntry.DirConf)
2045 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
2046
2047
2048 break;
2049 }
2050
2051 /* Invalid */
2052 default:
2053 {
2054 Fast486Exception(State, FAST486_EXCEPTION_UD);
2055 }
2056 }
2057 }
2058
2059 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2060 {
2061 // FAST486_TABLE_REG TableReg;
2062 UCHAR TableReg[6];
2063 FAST486_MOD_REG_RM ModRegRm;
2064 BOOLEAN OperandSize, AddressSize;
2065 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2066
2067 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2068
2069 NO_LOCK_PREFIX();
2070 TOGGLE_OPSIZE(OperandSize);
2071 TOGGLE_ADSIZE(AddressSize);
2072
2073 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2074 {
2075 /* Exception occurred */
2076 return;
2077 }
2078
2079 /* Check for the segment override */
2080 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2081 {
2082 /* Use the override segment instead */
2083 Segment = State->SegmentOverride;
2084 }
2085
2086 /* Check which operation this is */
2087 switch (ModRegRm.Register)
2088 {
2089 /* SGDT */
2090 case 0:
2091 {
2092 if (!ModRegRm.Memory)
2093 {
2094 /* The second operand must be a memory location */
2095 Fast486Exception(State, FAST486_EXCEPTION_UD);
2096 return;
2097 }
2098
2099 /* Fill the 6-byte table register */
2100 // TableReg = State->Gdtr;
2101 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2102 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2103
2104 /* Store the GDTR */
2105 Fast486WriteMemory(State,
2106 Segment,
2107 ModRegRm.MemoryAddress,
2108 TableReg,
2109 sizeof(TableReg));
2110
2111 break;
2112 }
2113
2114 /* SIDT */
2115 case 1:
2116 {
2117 if (!ModRegRm.Memory)
2118 {
2119 /* The second operand must be a memory location */
2120 Fast486Exception(State, FAST486_EXCEPTION_UD);
2121 return;
2122 }
2123
2124 /* Fill the 6-byte table register */
2125 // TableReg = State->Idtr;
2126 *((PUSHORT)&TableReg) = State->Idtr.Size;
2127 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2128
2129 /* Store the IDTR */
2130 Fast486WriteMemory(State,
2131 Segment,
2132 ModRegRm.MemoryAddress,
2133 TableReg,
2134 sizeof(TableReg));
2135
2136 break;
2137 }
2138
2139 /* LGDT */
2140 case 2:
2141 {
2142 /* This is a privileged instruction */
2143 if (Fast486GetCurrentPrivLevel(State) != 0)
2144 {
2145 Fast486Exception(State, FAST486_EXCEPTION_GP);
2146 return;
2147 }
2148
2149 if (!ModRegRm.Memory)
2150 {
2151 /* The second operand must be a memory location */
2152 Fast486Exception(State, FAST486_EXCEPTION_UD);
2153 return;
2154 }
2155
2156 /* Read the new GDTR */
2157 if (!Fast486ReadMemory(State,
2158 Segment,
2159 ModRegRm.MemoryAddress,
2160 FALSE,
2161 TableReg,
2162 sizeof(TableReg)))
2163 {
2164 /* Exception occurred */
2165 return;
2166 }
2167
2168 /* Load the new GDT */
2169 // State->Gdtr = TableReg;
2170 State->Gdtr.Size = *((PUSHORT)&TableReg);
2171 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2172
2173 /* In 16-bit mode the highest byte is masked out */
2174 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2175
2176 break;
2177 }
2178
2179 /* LIDT */
2180 case 3:
2181 {
2182 /* This is a privileged instruction */
2183 if (Fast486GetCurrentPrivLevel(State) != 0)
2184 {
2185 Fast486Exception(State, FAST486_EXCEPTION_GP);
2186 return;
2187 }
2188
2189 if (!ModRegRm.Memory)
2190 {
2191 /* The second operand must be a memory location */
2192 Fast486Exception(State, FAST486_EXCEPTION_UD);
2193 return;
2194 }
2195
2196 /* Read the new IDTR */
2197 if (!Fast486ReadMemory(State,
2198 Segment,
2199 ModRegRm.MemoryAddress,
2200 FALSE,
2201 TableReg,
2202 sizeof(TableReg)))
2203 {
2204 /* Exception occurred */
2205 return;
2206 }
2207
2208 /* Load the new IDT */
2209 // State->Idtr = TableReg;
2210 State->Idtr.Size = *((PUSHORT)&TableReg);
2211 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2212
2213 /* In 16-bit mode the highest byte is masked out */
2214 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2215
2216 break;
2217 }
2218
2219 /* SMSW */
2220 case 4:
2221 {
2222 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2223 Fast486WriteModrmWordOperands(State,
2224 &ModRegRm,
2225 FALSE,
2226 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2227
2228 break;
2229 }
2230
2231 /* LMSW */
2232 case 6:
2233 {
2234 USHORT MachineStatusWord;
2235
2236 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2237 {
2238 /* This is a privileged instruction */
2239 if (Fast486GetCurrentPrivLevel(State) != 0)
2240 {
2241 Fast486Exception(State, FAST486_EXCEPTION_GP);
2242 return;
2243 }
2244 }
2245
2246 /* Read the new Machine Status Word */
2247 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2248 {
2249 /* Exception occurred */
2250 return;
2251 }
2252
2253 /* Set the lowest 4 bits, but never clear bit 0 */
2254 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1;
2255 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2256
2257 break;
2258 }
2259
2260 /* INVLPG */
2261 case 7:
2262 {
2263 #ifndef FAST486_NO_PREFETCH
2264 /* Invalidate the prefetch */
2265 State->PrefetchValid = FALSE;
2266 #endif
2267
2268 /* This is a privileged instruction */
2269 if (Fast486GetCurrentPrivLevel(State) != 0)
2270 {
2271 Fast486Exception(State, FAST486_EXCEPTION_GP);
2272 return;
2273 }
2274
2275 if (!ModRegRm.Memory)
2276 {
2277 /* The second operand must be a memory location */
2278 Fast486Exception(State, FAST486_EXCEPTION_UD);
2279 return;
2280 }
2281
2282 if (State->Tlb != NULL)
2283 {
2284 /* Clear the TLB entry */
2285 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2286 }
2287
2288 break;
2289 }
2290
2291 /* Invalid */
2292 default:
2293 {
2294 Fast486Exception(State, FAST486_EXCEPTION_UD);
2295 }
2296 }
2297 }
2298
2299 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2300 {
2301 FAST486_MOD_REG_RM ModRegRm;
2302 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2303
2304 TOGGLE_ADSIZE(AddressSize);
2305
2306 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2307 {
2308 /* Exception occurred */
2309 return;
2310 }
2311
2312 /* All of them are reserved (UD2) */
2313 Fast486Exception(State, FAST486_EXCEPTION_UD);
2314 return;
2315 }
2316
2317 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2318 {
2319 FAST486_MOD_REG_RM ModRegRm;
2320 BOOLEAN OperandSize, AddressSize;
2321 UINT DataSize;
2322 UCHAR BitNumber;
2323
2324 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2325
2326 TOGGLE_OPSIZE(OperandSize);
2327 TOGGLE_ADSIZE(AddressSize);
2328
2329 /* Get the number of bits */
2330 if (OperandSize) DataSize = 32;
2331 else DataSize = 16;
2332
2333 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2334 {
2335 /* Exception occurred */
2336 return;
2337 }
2338
2339 if (ModRegRm.Register < 4)
2340 {
2341 /* Invalid */
2342 Fast486Exception(State, FAST486_EXCEPTION_UD);
2343 return;
2344 }
2345
2346 /* Get the bit number */
2347 if (!Fast486FetchByte(State, &BitNumber))
2348 {
2349 /* Exception occurred */
2350 return;
2351 }
2352
2353 if (ModRegRm.Memory)
2354 {
2355 /*
2356 * For memory operands, add the bit offset divided by
2357 * the data size to the address
2358 */
2359 ModRegRm.MemoryAddress += BitNumber / DataSize;
2360 }
2361
2362 /* Normalize the bit number */
2363 BitNumber %= DataSize;
2364
2365 if (OperandSize)
2366 {
2367 ULONG Value;
2368
2369 /* Read the value */
2370 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2371 {
2372 /* Exception occurred */
2373 return;
2374 }
2375
2376 /* Set CF to the bit value */
2377 State->Flags.Cf = (Value >> BitNumber) & 1;
2378
2379 if (ModRegRm.Register == 5)
2380 {
2381 /* BTS */
2382 Value |= 1 << BitNumber;
2383 }
2384 else if (ModRegRm.Register == 6)
2385 {
2386 /* BTR */
2387 Value &= ~(1 << BitNumber);
2388 }
2389 else if (ModRegRm.Register == 7)
2390 {
2391 /* BTC */
2392 Value ^= 1 << BitNumber;
2393 }
2394
2395 if (ModRegRm.Register >= 5)
2396 {
2397 /* Write back the result */
2398 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2399 {
2400 /* Exception occurred */
2401 return;
2402 }
2403 }
2404 }
2405 else
2406 {
2407 USHORT Value;
2408
2409 /* Read the value */
2410 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2411 {
2412 /* Exception occurred */
2413 return;
2414 }
2415
2416 /* Set CF to the bit value */
2417 State->Flags.Cf = (Value >> BitNumber) & 1;
2418
2419 if (ModRegRm.Register == 5)
2420 {
2421 /* BTS */
2422 Value |= 1 << BitNumber;
2423 }
2424 else if (ModRegRm.Register == 6)
2425 {
2426 /* BTR */
2427 Value &= ~(1 << BitNumber);
2428 }
2429 else if (ModRegRm.Register == 7)
2430 {
2431 /* BTC */
2432 Value ^= 1 << BitNumber;
2433 }
2434
2435 if (ModRegRm.Register >= 5)
2436 {
2437 /* Write back the result */
2438 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2439 {
2440 /* Exception occurred */
2441 return;
2442 }
2443 }
2444 }
2445 }
2446
2447 /* EOF */