[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 - 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 {
1472 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1473 {
1474 /* Gate processed or exception occurred */
1475 return;
1476 }
1477 }
1478
1479 /* Push the current value of CS */
1480 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1481 {
1482 /* Exception occurred */
1483 return;
1484 }
1485
1486 /* Push the current value of EIP */
1487 if (!Fast486StackPush(State, State->InstPtr.Long))
1488 {
1489 /* Exception occurred */
1490 return;
1491 }
1492
1493 /* Load the new code segment */
1494 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1495 {
1496 /* Exception occurred */
1497 return;
1498 }
1499
1500 /* Set the EIP to the address */
1501 State->InstPtr.Long = Value;
1502 }
1503 else if (ModRegRm.Register == 4)
1504 {
1505 /* Set the EIP to the address */
1506 State->InstPtr.Long = Value;
1507 }
1508 else if (ModRegRm.Register == 5)
1509 {
1510 USHORT Selector;
1511 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1512
1513 /* Check for the segment override */
1514 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1515 {
1516 /* Use the override segment instead */
1517 Segment = State->SegmentOverride;
1518 }
1519
1520 /* Read the selector */
1521 if (!Fast486ReadMemory(State,
1522 Segment,
1523 ModRegRm.MemoryAddress + sizeof(ULONG),
1524 FALSE,
1525 &Selector,
1526 sizeof(USHORT)))
1527 {
1528 /* Exception occurred */
1529 return;
1530 }
1531
1532 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1533 {
1534 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1535 {
1536 /* Gate processed or exception occurred */
1537 return;
1538 }
1539 }
1540
1541 /* Load the new code segment */
1542 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1543 {
1544 /* Exception occurred */
1545 return;
1546 }
1547
1548 /* Set the EIP to the address */
1549 State->InstPtr.Long = Value;
1550 }
1551 else if (ModRegRm.Register == 6)
1552 {
1553 /* Push the value on to the stack */
1554 Fast486StackPush(State, Value);
1555 return;
1556 }
1557
1558 if (ModRegRm.Register <= 1)
1559 {
1560 /* Update flags */
1561 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1562 State->Flags.Zf = (Value == 0);
1563 State->Flags.Pf = Fast486CalculateParity(Value);
1564
1565 /* Write back the result */
1566 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1567 }
1568 }
1569 else
1570 {
1571 USHORT Value;
1572
1573 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1574 {
1575 /* Exception occurred */
1576 return;
1577 }
1578
1579 if (ModRegRm.Register == 0)
1580 {
1581 /* Increment and update OF */
1582 Value++;
1583 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1584 State->Flags.Af = ((Value & 0x0F) == 0);
1585 }
1586 else if (ModRegRm.Register == 1)
1587 {
1588 /* Decrement and update OF */
1589 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1590 Value--;
1591 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1592 }
1593 else if (ModRegRm.Register == 2)
1594 {
1595 /* Push the current value of IP */
1596 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1597 {
1598 /* Exception occurred */
1599 return;
1600 }
1601
1602 /* Set the IP to the address */
1603 State->InstPtr.LowWord = Value;
1604
1605 /* Clear the top half of EIP */
1606 State->InstPtr.Long &= 0xFFFF;
1607 }
1608 else if (ModRegRm.Register == 3)
1609 {
1610 USHORT Selector;
1611 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1612
1613 /* Check for the segment override */
1614 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1615 {
1616 /* Use the override segment instead */
1617 Segment = State->SegmentOverride;
1618 }
1619
1620 /* Read the selector */
1621 if (!Fast486ReadMemory(State,
1622 Segment,
1623 ModRegRm.MemoryAddress + sizeof(USHORT),
1624 FALSE,
1625 &Selector,
1626 sizeof(USHORT)))
1627 {
1628 /* Exception occurred */
1629 return;
1630 }
1631
1632 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
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 {
1702 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1703 {
1704 /* Gate processed or exception occurred */
1705 return;
1706 }
1707 }
1708
1709 /* Load the new code segment */
1710 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1711 {
1712 /* Exception occurred */
1713 return;
1714 }
1715
1716 /* Set the IP to the address */
1717 State->InstPtr.LowWord = Value;
1718
1719 /* Clear the top half of EIP */
1720 State->InstPtr.Long &= 0xFFFF;
1721 }
1722 else if (ModRegRm.Register == 6)
1723 {
1724 /* Push the value on to the stack */
1725 Fast486StackPush(State, Value);
1726 return;
1727 }
1728 else
1729 {
1730 /* Invalid */
1731 Fast486Exception(State, FAST486_EXCEPTION_UD);
1732 return;
1733 }
1734
1735 if (ModRegRm.Register <= 1)
1736 {
1737 /* Update flags */
1738 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1739 State->Flags.Zf = (Value == 0);
1740 State->Flags.Pf = Fast486CalculateParity(Value);
1741
1742 /* Write back the result */
1743 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1744 }
1745 }
1746 }
1747
1748 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
1749 {
1750 FAST486_MOD_REG_RM ModRegRm;
1751 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1752
1753 NO_LOCK_PREFIX();
1754 TOGGLE_ADSIZE(AddressSize);
1755
1756 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1757 {
1758 /* Exception occurred */
1759 return;
1760 }
1761
1762 /* Check which operation this is */
1763 switch (ModRegRm.Register)
1764 {
1765 /* SLDT */
1766 case 0:
1767 {
1768 /* Not recognized in real mode or virtual 8086 mode */
1769 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1770 || State->Flags.Vm)
1771 {
1772 Fast486Exception(State, FAST486_EXCEPTION_UD);
1773 return;
1774 }
1775
1776 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
1777 break;
1778 }
1779
1780 /* STR */
1781 case 1:
1782 {
1783 /* Not recognized in real mode or virtual 8086 mode */
1784 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1785 || State->Flags.Vm)
1786 {
1787 Fast486Exception(State, FAST486_EXCEPTION_UD);
1788 return;
1789 }
1790
1791 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
1792 break;
1793 }
1794
1795 /* LLDT */
1796 case 2:
1797 {
1798 BOOLEAN Valid;
1799 USHORT Selector;
1800 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1801
1802 /* Not recognized in real mode or virtual 8086 mode */
1803 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1804 || State->Flags.Vm)
1805 {
1806 Fast486Exception(State, FAST486_EXCEPTION_UD);
1807 return;
1808 }
1809
1810 /* This is a privileged instruction */
1811 if (Fast486GetCurrentPrivLevel(State) != 0)
1812 {
1813 Fast486Exception(State, FAST486_EXCEPTION_GP);
1814 return;
1815 }
1816
1817 if (!Fast486ReadModrmWordOperands(State,
1818 &ModRegRm,
1819 NULL,
1820 &Selector))
1821 {
1822 /* Exception occurred */
1823 return;
1824 }
1825
1826 if (Selector & SEGMENT_TABLE_INDICATOR)
1827 {
1828 /* This selector doesn't point to the GDT */
1829 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1830 return;
1831 }
1832
1833 if (!Fast486ReadDescriptorEntry(State,
1834 Selector,
1835 &Valid,
1836 (PFAST486_GDT_ENTRY)&GdtEntry))
1837 {
1838 /* Exception occurred */
1839 return;
1840 }
1841
1842 if (!Valid)
1843 {
1844 /* Invalid selector */
1845 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1846 return;
1847 }
1848
1849 if (GET_SEGMENT_INDEX(Selector) == 0)
1850 {
1851 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1852 return;
1853 }
1854
1855 if (!GdtEntry.Present)
1856 {
1857 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1858 return;
1859 }
1860
1861 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1862 {
1863 /* This is not a LDT descriptor */
1864 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1865 return;
1866 }
1867
1868 /* Update the LDTR */
1869 State->Ldtr.Selector = Selector;
1870 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1871 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1872
1873 if (GdtEntry.Granularity)
1874 {
1875 State->Ldtr.Limit <<= 12;
1876 State->Ldtr.Limit |= 0x00000FFF;
1877 }
1878
1879 break;
1880 }
1881
1882 /* LTR */
1883 case 3:
1884 {
1885 BOOLEAN Valid;
1886 USHORT Selector;
1887 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1888
1889 /* Not recognized in real mode or virtual 8086 mode */
1890 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1891 || State->Flags.Vm)
1892 {
1893 Fast486Exception(State, FAST486_EXCEPTION_UD);
1894 return;
1895 }
1896
1897 /* This is a privileged instruction */
1898 if (Fast486GetCurrentPrivLevel(State) != 0)
1899 {
1900 Fast486Exception(State, FAST486_EXCEPTION_GP);
1901 return;
1902 }
1903
1904 if (!Fast486ReadModrmWordOperands(State,
1905 &ModRegRm,
1906 NULL,
1907 &Selector))
1908 {
1909 /* Exception occurred */
1910 return;
1911 }
1912
1913 if (Selector & SEGMENT_TABLE_INDICATOR)
1914 {
1915 /* This selector doesn't point to the GDT */
1916 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1917 return;
1918 }
1919
1920 if (!Fast486ReadDescriptorEntry(State,
1921 Selector,
1922 &Valid,
1923 (PFAST486_GDT_ENTRY)&GdtEntry))
1924 {
1925 /* Exception occurred */
1926 return;
1927 }
1928
1929 if (!Valid)
1930 {
1931 /* Invalid selector */
1932 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1933 return;
1934 }
1935
1936 if (GET_SEGMENT_INDEX(Selector) == 0)
1937 {
1938 Fast486Exception(State, FAST486_EXCEPTION_GP);
1939 return;
1940 }
1941
1942 if (!GdtEntry.Present)
1943 {
1944 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1945 return;
1946 }
1947
1948 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE
1949 && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1950 && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE
1951 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1952 {
1953 /* This is not a TSS descriptor */
1954 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1955 return;
1956 }
1957
1958 /* Update the TR */
1959 State->TaskReg.Selector = Selector;
1960 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1961 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1962
1963 if (GdtEntry.Granularity)
1964 {
1965 State->TaskReg.Limit <<= 12;
1966 State->TaskReg.Limit |= 0x00000FFF;
1967 }
1968
1969 if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1970 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1971 {
1972 /* Set the busy bit of this TSS descriptor and write it back */
1973 GdtEntry.Signature |= 2;
1974
1975 Fast486WriteLinearMemory(State,
1976 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
1977 &GdtEntry,
1978 sizeof(GdtEntry));
1979 }
1980
1981 break;
1982 }
1983
1984 /* VERR/VERW */
1985 case 4:
1986 case 5:
1987 {
1988 USHORT Selector;
1989 BOOLEAN Valid;
1990 FAST486_GDT_ENTRY GdtEntry;
1991
1992 /* Not recognized in real mode or virtual 8086 mode */
1993 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1994 || State->Flags.Vm)
1995 {
1996 Fast486Exception(State, FAST486_EXCEPTION_UD);
1997 return;
1998 }
1999
2000 /* This is a privileged instruction */
2001 if (Fast486GetCurrentPrivLevel(State) != 0)
2002 {
2003 Fast486Exception(State, FAST486_EXCEPTION_GP);
2004 return;
2005 }
2006
2007 if (!Fast486ReadModrmWordOperands(State,
2008 &ModRegRm,
2009 NULL,
2010 &Selector))
2011 {
2012 /* Exception occurred */
2013 return;
2014 }
2015
2016 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
2017 {
2018 /* Exception occurred */
2019 return;
2020 }
2021
2022 if (!Valid)
2023 {
2024 /* Clear ZF */
2025 State->Flags.Zf = FALSE;
2026 return;
2027 }
2028
2029 /* Set ZF if it is valid and accessible */
2030 State->Flags.Zf = GdtEntry.Present // must be present
2031 && GdtEntry.SystemType // must be a segment
2032 && (((ModRegRm.Register == 4)
2033 /* code segments are only readable if the RW bit is set */
2034 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
2035 || ((ModRegRm.Register == 5)
2036 /* code segments are never writable, data segments are writable when RW is set */
2037 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2038 /*
2039 * for segments other than conforming code segments,
2040 * both RPL and CPL must be less than or equal to DPL
2041 */
2042 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
2043 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2044 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
2045 /* for conforming code segments, DPL must be less than or equal to CPL */
2046 && ((GdtEntry.Executable && GdtEntry.DirConf)
2047 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
2048
2049
2050 break;
2051 }
2052
2053 /* Invalid */
2054 default:
2055 {
2056 Fast486Exception(State, FAST486_EXCEPTION_UD);
2057 }
2058 }
2059 }
2060
2061 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2062 {
2063 // FAST486_TABLE_REG TableReg;
2064 UCHAR TableReg[6];
2065 FAST486_MOD_REG_RM ModRegRm;
2066 BOOLEAN OperandSize, AddressSize;
2067 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2068
2069 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2070
2071 NO_LOCK_PREFIX();
2072 TOGGLE_OPSIZE(OperandSize);
2073 TOGGLE_ADSIZE(AddressSize);
2074
2075 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2076 {
2077 /* Exception occurred */
2078 return;
2079 }
2080
2081 /* Check for the segment override */
2082 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2083 {
2084 /* Use the override segment instead */
2085 Segment = State->SegmentOverride;
2086 }
2087
2088 /* Check which operation this is */
2089 switch (ModRegRm.Register)
2090 {
2091 /* SGDT */
2092 case 0:
2093 {
2094 if (!ModRegRm.Memory)
2095 {
2096 /* The second operand must be a memory location */
2097 Fast486Exception(State, FAST486_EXCEPTION_UD);
2098 return;
2099 }
2100
2101 /* Fill the 6-byte table register */
2102 // TableReg = State->Gdtr;
2103 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2104 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2105
2106 /* Store the GDTR */
2107 Fast486WriteMemory(State,
2108 Segment,
2109 ModRegRm.MemoryAddress,
2110 TableReg,
2111 sizeof(TableReg));
2112
2113 break;
2114 }
2115
2116 /* SIDT */
2117 case 1:
2118 {
2119 if (!ModRegRm.Memory)
2120 {
2121 /* The second operand must be a memory location */
2122 Fast486Exception(State, FAST486_EXCEPTION_UD);
2123 return;
2124 }
2125
2126 /* Fill the 6-byte table register */
2127 // TableReg = State->Idtr;
2128 *((PUSHORT)&TableReg) = State->Idtr.Size;
2129 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2130
2131 /* Store the IDTR */
2132 Fast486WriteMemory(State,
2133 Segment,
2134 ModRegRm.MemoryAddress,
2135 TableReg,
2136 sizeof(TableReg));
2137
2138 break;
2139 }
2140
2141 /* LGDT */
2142 case 2:
2143 {
2144 /* This is a privileged instruction */
2145 if (Fast486GetCurrentPrivLevel(State) != 0)
2146 {
2147 Fast486Exception(State, FAST486_EXCEPTION_GP);
2148 return;
2149 }
2150
2151 if (!ModRegRm.Memory)
2152 {
2153 /* The second operand must be a memory location */
2154 Fast486Exception(State, FAST486_EXCEPTION_UD);
2155 return;
2156 }
2157
2158 /* Read the new GDTR */
2159 if (!Fast486ReadMemory(State,
2160 Segment,
2161 ModRegRm.MemoryAddress,
2162 FALSE,
2163 TableReg,
2164 sizeof(TableReg)))
2165 {
2166 /* Exception occurred */
2167 return;
2168 }
2169
2170 /* Load the new GDT */
2171 // State->Gdtr = TableReg;
2172 State->Gdtr.Size = *((PUSHORT)&TableReg);
2173 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2174
2175 /* In 16-bit mode the highest byte is masked out */
2176 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2177
2178 break;
2179 }
2180
2181 /* LIDT */
2182 case 3:
2183 {
2184 /* This is a privileged instruction */
2185 if (Fast486GetCurrentPrivLevel(State) != 0)
2186 {
2187 Fast486Exception(State, FAST486_EXCEPTION_GP);
2188 return;
2189 }
2190
2191 if (!ModRegRm.Memory)
2192 {
2193 /* The second operand must be a memory location */
2194 Fast486Exception(State, FAST486_EXCEPTION_UD);
2195 return;
2196 }
2197
2198 /* Read the new IDTR */
2199 if (!Fast486ReadMemory(State,
2200 Segment,
2201 ModRegRm.MemoryAddress,
2202 FALSE,
2203 TableReg,
2204 sizeof(TableReg)))
2205 {
2206 /* Exception occurred */
2207 return;
2208 }
2209
2210 /* Load the new IDT */
2211 // State->Idtr = TableReg;
2212 State->Idtr.Size = *((PUSHORT)&TableReg);
2213 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2214
2215 /* In 16-bit mode the highest byte is masked out */
2216 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2217
2218 break;
2219 }
2220
2221 /* SMSW */
2222 case 4:
2223 {
2224 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2225 Fast486WriteModrmWordOperands(State,
2226 &ModRegRm,
2227 FALSE,
2228 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2229
2230 break;
2231 }
2232
2233 /* LMSW */
2234 case 6:
2235 {
2236 USHORT MachineStatusWord;
2237
2238 /* This is a privileged instruction */
2239 if (Fast486GetCurrentPrivLevel(State) != 0)
2240 {
2241 Fast486Exception(State, FAST486_EXCEPTION_GP);
2242 return;
2243 }
2244
2245 /* Read the new Machine Status Word */
2246 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2247 {
2248 /* Exception occurred */
2249 return;
2250 }
2251
2252 /* This instruction cannot be used to return to real mode */
2253 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2254 && !(MachineStatusWord & FAST486_CR0_PE))
2255 {
2256 Fast486Exception(State, FAST486_EXCEPTION_GP);
2257 return;
2258 }
2259
2260 /* Set the lowest 4 bits */
2261 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2262 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2263
2264 break;
2265 }
2266
2267 /* INVLPG */
2268 case 7:
2269 {
2270 #ifndef FAST486_NO_PREFETCH
2271 /* Invalidate the prefetch */
2272 State->PrefetchValid = FALSE;
2273 #endif
2274
2275 /* This is a privileged instruction */
2276 if (Fast486GetCurrentPrivLevel(State) != 0)
2277 {
2278 Fast486Exception(State, FAST486_EXCEPTION_GP);
2279 return;
2280 }
2281
2282 if (!ModRegRm.Memory)
2283 {
2284 /* The second operand must be a memory location */
2285 Fast486Exception(State, FAST486_EXCEPTION_UD);
2286 return;
2287 }
2288
2289 if (State->Tlb != NULL)
2290 {
2291 /* Clear the TLB entry */
2292 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2293 }
2294
2295 break;
2296 }
2297
2298 /* Invalid */
2299 default:
2300 {
2301 Fast486Exception(State, FAST486_EXCEPTION_UD);
2302 }
2303 }
2304 }
2305
2306 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2307 {
2308 FAST486_MOD_REG_RM ModRegRm;
2309 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2310
2311 TOGGLE_ADSIZE(AddressSize);
2312
2313 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2314 {
2315 /* Exception occurred */
2316 return;
2317 }
2318
2319 /* All of them are reserved (UD2) */
2320 Fast486Exception(State, FAST486_EXCEPTION_UD);
2321 return;
2322 }
2323
2324 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2325 {
2326 FAST486_MOD_REG_RM ModRegRm;
2327 BOOLEAN OperandSize, AddressSize;
2328 UINT DataSize;
2329 UCHAR BitNumber;
2330
2331 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2332
2333 TOGGLE_OPSIZE(OperandSize);
2334 TOGGLE_ADSIZE(AddressSize);
2335
2336 /* Get the number of bits */
2337 if (OperandSize) DataSize = 32;
2338 else DataSize = 16;
2339
2340 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2341 {
2342 /* Exception occurred */
2343 return;
2344 }
2345
2346 if (ModRegRm.Register < 4)
2347 {
2348 /* Invalid */
2349 Fast486Exception(State, FAST486_EXCEPTION_UD);
2350 return;
2351 }
2352
2353 /* Get the bit number */
2354 if (!Fast486FetchByte(State, &BitNumber))
2355 {
2356 /* Exception occurred */
2357 return;
2358 }
2359
2360 if (ModRegRm.Memory)
2361 {
2362 /*
2363 * For memory operands, add the bit offset divided by
2364 * the data size to the address
2365 */
2366 ModRegRm.MemoryAddress += BitNumber / DataSize;
2367 }
2368
2369 /* Normalize the bit number */
2370 BitNumber %= DataSize;
2371
2372 if (OperandSize)
2373 {
2374 ULONG Value;
2375
2376 /* Read the value */
2377 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2378 {
2379 /* Exception occurred */
2380 return;
2381 }
2382
2383 /* Set CF to the bit value */
2384 State->Flags.Cf = (Value >> BitNumber) & 1;
2385
2386 if (ModRegRm.Register == 5)
2387 {
2388 /* BTS */
2389 Value |= 1 << BitNumber;
2390 }
2391 else if (ModRegRm.Register == 6)
2392 {
2393 /* BTR */
2394 Value &= ~(1 << BitNumber);
2395 }
2396 else if (ModRegRm.Register == 7)
2397 {
2398 /* BTC */
2399 Value ^= 1 << BitNumber;
2400 }
2401
2402 if (ModRegRm.Register >= 5)
2403 {
2404 /* Write back the result */
2405 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2406 {
2407 /* Exception occurred */
2408 return;
2409 }
2410 }
2411 }
2412 else
2413 {
2414 USHORT Value;
2415
2416 /* Read the value */
2417 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2418 {
2419 /* Exception occurred */
2420 return;
2421 }
2422
2423 /* Set CF to the bit value */
2424 State->Flags.Cf = (Value >> BitNumber) & 1;
2425
2426 if (ModRegRm.Register == 5)
2427 {
2428 /* BTS */
2429 Value |= 1 << BitNumber;
2430 }
2431 else if (ModRegRm.Register == 6)
2432 {
2433 /* BTR */
2434 Value &= ~(1 << BitNumber);
2435 }
2436 else if (ModRegRm.Register == 7)
2437 {
2438 /* BTC */
2439 Value ^= 1 << BitNumber;
2440 }
2441
2442 if (ModRegRm.Register >= 5)
2443 {
2444 /* Write back the result */
2445 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2446 {
2447 /* Exception occurred */
2448 return;
2449 }
2450 }
2451 }
2452 }
2453
2454 /* EOF */