[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 /* Push the current value of CS */
1633 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1634 {
1635 /* Exception occurred */
1636 return;
1637 }
1638
1639 /* Push the current value of IP */
1640 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1641 {
1642 /* Exception occurred */
1643 return;
1644 }
1645
1646 /* Load the new code segment */
1647 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1648 {
1649 /* Exception occurred */
1650 return;
1651 }
1652
1653 /* Set the IP to the address */
1654 State->InstPtr.LowWord = Value;
1655
1656 /* Clear the top half of EIP */
1657 State->InstPtr.Long &= 0xFFFF;
1658 }
1659 else if (ModRegRm.Register == 4)
1660 {
1661 /* Set the IP to the address */
1662 State->InstPtr.LowWord = Value;
1663
1664 /* Clear the top half of EIP */
1665 State->InstPtr.Long &= 0xFFFF;
1666 }
1667 else if (ModRegRm.Register == 5)
1668 {
1669 USHORT Selector;
1670 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1671
1672 /* Check for the segment override */
1673 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1674 {
1675 /* Use the override segment instead */
1676 Segment = State->SegmentOverride;
1677 }
1678
1679 /* Read the selector */
1680 if (!Fast486ReadMemory(State,
1681 Segment,
1682 ModRegRm.MemoryAddress + sizeof(USHORT),
1683 FALSE,
1684 &Selector,
1685 sizeof(USHORT)))
1686 {
1687 /* Exception occurred */
1688 return;
1689 }
1690
1691 /* Load the new code segment */
1692 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1693 {
1694 /* Exception occurred */
1695 return;
1696 }
1697
1698 /* Set the IP to the address */
1699 State->InstPtr.LowWord = Value;
1700
1701 /* Clear the top half of EIP */
1702 State->InstPtr.Long &= 0xFFFF;
1703 }
1704 else if (ModRegRm.Register == 6)
1705 {
1706 /* Push the value on to the stack */
1707 Fast486StackPush(State, Value);
1708 return;
1709 }
1710 else
1711 {
1712 /* Invalid */
1713 Fast486Exception(State, FAST486_EXCEPTION_UD);
1714 return;
1715 }
1716
1717 if (ModRegRm.Register <= 1)
1718 {
1719 /* Update flags */
1720 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1721 State->Flags.Zf = (Value == 0);
1722 State->Flags.Pf = Fast486CalculateParity(Value);
1723
1724 /* Write back the result */
1725 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1726 }
1727 }
1728 }
1729
1730 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
1731 {
1732 FAST486_MOD_REG_RM ModRegRm;
1733 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1734
1735 NO_LOCK_PREFIX();
1736 TOGGLE_ADSIZE(AddressSize);
1737
1738 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1739 {
1740 /* Exception occurred */
1741 return;
1742 }
1743
1744 /* Check which operation this is */
1745 switch (ModRegRm.Register)
1746 {
1747 /* SLDT */
1748 case 0:
1749 {
1750 /* Not recognized in real mode or virtual 8086 mode */
1751 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1752 || State->Flags.Vm)
1753 {
1754 Fast486Exception(State, FAST486_EXCEPTION_UD);
1755 return;
1756 }
1757
1758 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
1759 break;
1760 }
1761
1762 /* STR */
1763 case 1:
1764 {
1765 /* Not recognized in real mode or virtual 8086 mode */
1766 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1767 || State->Flags.Vm)
1768 {
1769 Fast486Exception(State, FAST486_EXCEPTION_UD);
1770 return;
1771 }
1772
1773 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
1774 break;
1775 }
1776
1777 /* LLDT */
1778 case 2:
1779 {
1780 BOOLEAN Valid;
1781 USHORT Selector;
1782 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1783
1784 /* Not recognized in real mode or virtual 8086 mode */
1785 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1786 || State->Flags.Vm)
1787 {
1788 Fast486Exception(State, FAST486_EXCEPTION_UD);
1789 return;
1790 }
1791
1792 /* This is a privileged instruction */
1793 if (Fast486GetCurrentPrivLevel(State) != 0)
1794 {
1795 Fast486Exception(State, FAST486_EXCEPTION_GP);
1796 return;
1797 }
1798
1799 if (!Fast486ReadModrmWordOperands(State,
1800 &ModRegRm,
1801 NULL,
1802 &Selector))
1803 {
1804 /* Exception occurred */
1805 return;
1806 }
1807
1808 if (Selector & SEGMENT_TABLE_INDICATOR)
1809 {
1810 /* This selector doesn't point to the GDT */
1811 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1812 return;
1813 }
1814
1815 if (!Fast486ReadDescriptorEntry(State,
1816 Selector,
1817 &Valid,
1818 (PFAST486_GDT_ENTRY)&GdtEntry))
1819 {
1820 /* Exception occurred */
1821 return;
1822 }
1823
1824 if (!Valid)
1825 {
1826 /* Invalid selector */
1827 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1828 return;
1829 }
1830
1831 if (GET_SEGMENT_INDEX(Selector) == 0)
1832 {
1833 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1834 return;
1835 }
1836
1837 if (!GdtEntry.Present)
1838 {
1839 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1840 return;
1841 }
1842
1843 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1844 {
1845 /* This is not a LDT descriptor */
1846 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1847 return;
1848 }
1849
1850 /* Update the LDTR */
1851 State->Ldtr.Selector = Selector;
1852 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1853 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1854
1855 if (GdtEntry.Granularity)
1856 {
1857 State->Ldtr.Limit <<= 12;
1858 State->Ldtr.Limit |= 0x00000FFF;
1859 }
1860
1861 break;
1862 }
1863
1864 /* LTR */
1865 case 3:
1866 {
1867 BOOLEAN Valid;
1868 USHORT Selector;
1869 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1870
1871 /* Not recognized in real mode or virtual 8086 mode */
1872 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1873 || State->Flags.Vm)
1874 {
1875 Fast486Exception(State, FAST486_EXCEPTION_UD);
1876 return;
1877 }
1878
1879 /* This is a privileged instruction */
1880 if (Fast486GetCurrentPrivLevel(State) != 0)
1881 {
1882 Fast486Exception(State, FAST486_EXCEPTION_GP);
1883 return;
1884 }
1885
1886 if (!Fast486ReadModrmWordOperands(State,
1887 &ModRegRm,
1888 NULL,
1889 &Selector))
1890 {
1891 /* Exception occurred */
1892 return;
1893 }
1894
1895 if (Selector & SEGMENT_TABLE_INDICATOR)
1896 {
1897 /* This selector doesn't point to the GDT */
1898 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1899 return;
1900 }
1901
1902 if (!Fast486ReadDescriptorEntry(State,
1903 Selector,
1904 &Valid,
1905 (PFAST486_GDT_ENTRY)&GdtEntry))
1906 {
1907 /* Exception occurred */
1908 return;
1909 }
1910
1911 if (!Valid)
1912 {
1913 /* Invalid selector */
1914 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1915 return;
1916 }
1917
1918 if (GET_SEGMENT_INDEX(Selector) == 0)
1919 {
1920 Fast486Exception(State, FAST486_EXCEPTION_GP);
1921 return;
1922 }
1923
1924 if (!GdtEntry.Present)
1925 {
1926 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1927 return;
1928 }
1929
1930 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
1931 {
1932 /* This is not a TSS descriptor */
1933 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1934 return;
1935 }
1936
1937 /* Update the TR */
1938 State->TaskReg.Selector = Selector;
1939 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1940 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1941
1942 if (GdtEntry.Granularity)
1943 {
1944 State->TaskReg.Limit <<= 12;
1945 State->TaskReg.Limit |= 0x00000FFF;
1946 }
1947
1948 break;
1949 }
1950
1951 /* VERR/VERW */
1952 case 4:
1953 case 5:
1954 {
1955 USHORT Selector;
1956 BOOLEAN Valid;
1957 FAST486_GDT_ENTRY GdtEntry;
1958
1959 /* Not recognized in real mode or virtual 8086 mode */
1960 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1961 || State->Flags.Vm)
1962 {
1963 Fast486Exception(State, FAST486_EXCEPTION_UD);
1964 return;
1965 }
1966
1967 /* This is a privileged instruction */
1968 if (Fast486GetCurrentPrivLevel(State) != 0)
1969 {
1970 Fast486Exception(State, FAST486_EXCEPTION_GP);
1971 return;
1972 }
1973
1974 if (!Fast486ReadModrmWordOperands(State,
1975 &ModRegRm,
1976 NULL,
1977 &Selector))
1978 {
1979 /* Exception occurred */
1980 return;
1981 }
1982
1983 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
1984 {
1985 /* Exception occurred */
1986 return;
1987 }
1988
1989 if (!Valid)
1990 {
1991 /* Clear ZF */
1992 State->Flags.Zf = FALSE;
1993 return;
1994 }
1995
1996 /* Set ZF if it is valid and accessible */
1997 State->Flags.Zf = GdtEntry.Present // must be present
1998 && GdtEntry.SystemType // must be a segment
1999 && (((ModRegRm.Register == 4)
2000 /* code segments are only readable if the RW bit is set */
2001 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
2002 || ((ModRegRm.Register == 5)
2003 /* code segments are never writable, data segments are writable when RW is set */
2004 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2005 /*
2006 * for segments other than conforming code segments,
2007 * both RPL and CPL must be less than or equal to DPL
2008 */
2009 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
2010 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2011 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
2012 /* for conforming code segments, DPL must be less than or equal to CPL */
2013 && ((GdtEntry.Executable && GdtEntry.DirConf)
2014 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
2015
2016
2017 break;
2018 }
2019
2020 /* Invalid */
2021 default:
2022 {
2023 Fast486Exception(State, FAST486_EXCEPTION_UD);
2024 }
2025 }
2026 }
2027
2028 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2029 {
2030 // FAST486_TABLE_REG TableReg;
2031 UCHAR TableReg[6];
2032 FAST486_MOD_REG_RM ModRegRm;
2033 BOOLEAN OperandSize, AddressSize;
2034 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2035
2036 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2037
2038 NO_LOCK_PREFIX();
2039 TOGGLE_OPSIZE(OperandSize);
2040 TOGGLE_ADSIZE(AddressSize);
2041
2042 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2043 {
2044 /* Exception occurred */
2045 return;
2046 }
2047
2048 /* Check for the segment override */
2049 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2050 {
2051 /* Use the override segment instead */
2052 Segment = State->SegmentOverride;
2053 }
2054
2055 /* Check which operation this is */
2056 switch (ModRegRm.Register)
2057 {
2058 /* SGDT */
2059 case 0:
2060 {
2061 if (!ModRegRm.Memory)
2062 {
2063 /* The second operand must be a memory location */
2064 Fast486Exception(State, FAST486_EXCEPTION_UD);
2065 return;
2066 }
2067
2068 /* Fill the 6-byte table register */
2069 // TableReg = State->Gdtr;
2070 *((PUSHORT)&TableReg) = State->Gdtr.Size;
2071 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2072
2073 /* Store the GDTR */
2074 Fast486WriteMemory(State,
2075 Segment,
2076 ModRegRm.MemoryAddress,
2077 TableReg,
2078 sizeof(TableReg));
2079
2080 break;
2081 }
2082
2083 /* SIDT */
2084 case 1:
2085 {
2086 if (!ModRegRm.Memory)
2087 {
2088 /* The second operand must be a memory location */
2089 Fast486Exception(State, FAST486_EXCEPTION_UD);
2090 return;
2091 }
2092
2093 /* Fill the 6-byte table register */
2094 // TableReg = State->Idtr;
2095 *((PUSHORT)&TableReg) = State->Idtr.Size;
2096 *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2097
2098 /* Store the IDTR */
2099 Fast486WriteMemory(State,
2100 Segment,
2101 ModRegRm.MemoryAddress,
2102 TableReg,
2103 sizeof(TableReg));
2104
2105 break;
2106 }
2107
2108 /* LGDT */
2109 case 2:
2110 {
2111 /* This is a privileged instruction */
2112 if (Fast486GetCurrentPrivLevel(State) != 0)
2113 {
2114 Fast486Exception(State, FAST486_EXCEPTION_GP);
2115 return;
2116 }
2117
2118 if (!ModRegRm.Memory)
2119 {
2120 /* The second operand must be a memory location */
2121 Fast486Exception(State, FAST486_EXCEPTION_UD);
2122 return;
2123 }
2124
2125 /* Read the new GDTR */
2126 if (!Fast486ReadMemory(State,
2127 Segment,
2128 ModRegRm.MemoryAddress,
2129 FALSE,
2130 TableReg,
2131 sizeof(TableReg)))
2132 {
2133 /* Exception occurred */
2134 return;
2135 }
2136
2137 /* Load the new GDT */
2138 // State->Gdtr = TableReg;
2139 State->Gdtr.Size = *((PUSHORT)&TableReg);
2140 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2141
2142 /* In 16-bit mode the highest byte is masked out */
2143 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2144
2145 break;
2146 }
2147
2148 /* LIDT */
2149 case 3:
2150 {
2151 /* This is a privileged instruction */
2152 if (Fast486GetCurrentPrivLevel(State) != 0)
2153 {
2154 Fast486Exception(State, FAST486_EXCEPTION_GP);
2155 return;
2156 }
2157
2158 if (!ModRegRm.Memory)
2159 {
2160 /* The second operand must be a memory location */
2161 Fast486Exception(State, FAST486_EXCEPTION_UD);
2162 return;
2163 }
2164
2165 /* Read the new IDTR */
2166 if (!Fast486ReadMemory(State,
2167 Segment,
2168 ModRegRm.MemoryAddress,
2169 FALSE,
2170 TableReg,
2171 sizeof(TableReg)))
2172 {
2173 /* Exception occurred */
2174 return;
2175 }
2176
2177 /* Load the new IDT */
2178 // State->Idtr = TableReg;
2179 State->Idtr.Size = *((PUSHORT)&TableReg);
2180 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2181
2182 /* In 16-bit mode the highest byte is masked out */
2183 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2184
2185 break;
2186 }
2187
2188 /* SMSW */
2189 case 4:
2190 {
2191 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2192 Fast486WriteModrmWordOperands(State,
2193 &ModRegRm,
2194 FALSE,
2195 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2196
2197 break;
2198 }
2199
2200 /* LMSW */
2201 case 6:
2202 {
2203 USHORT MachineStatusWord;
2204
2205 /* This is a privileged instruction */
2206 if (Fast486GetCurrentPrivLevel(State) != 0)
2207 {
2208 Fast486Exception(State, FAST486_EXCEPTION_GP);
2209 return;
2210 }
2211
2212 /* Read the new Machine Status Word */
2213 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2214 {
2215 /* Exception occurred */
2216 return;
2217 }
2218
2219 /* This instruction cannot be used to return to real mode */
2220 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2221 && !(MachineStatusWord & FAST486_CR0_PE))
2222 {
2223 Fast486Exception(State, FAST486_EXCEPTION_GP);
2224 return;
2225 }
2226
2227 /* Set the lowest 4 bits */
2228 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2229 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2230
2231 break;
2232 }
2233
2234 /* INVLPG */
2235 case 7:
2236 {
2237 #ifndef FAST486_NO_PREFETCH
2238 /* Invalidate the prefetch */
2239 State->PrefetchValid = FALSE;
2240 #endif
2241
2242 /* This is a privileged instruction */
2243 if (Fast486GetCurrentPrivLevel(State) != 0)
2244 {
2245 Fast486Exception(State, FAST486_EXCEPTION_GP);
2246 return;
2247 }
2248
2249 if (!ModRegRm.Memory)
2250 {
2251 /* The second operand must be a memory location */
2252 Fast486Exception(State, FAST486_EXCEPTION_UD);
2253 return;
2254 }
2255
2256 if (State->Tlb != NULL)
2257 {
2258 /* Clear the TLB entry */
2259 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2260 }
2261
2262 break;
2263 }
2264
2265 /* Invalid */
2266 default:
2267 {
2268 Fast486Exception(State, FAST486_EXCEPTION_UD);
2269 }
2270 }
2271 }
2272
2273 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2274 {
2275 FAST486_MOD_REG_RM ModRegRm;
2276 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2277
2278 TOGGLE_ADSIZE(AddressSize);
2279
2280 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2281 {
2282 /* Exception occurred */
2283 return;
2284 }
2285
2286 /* All of them are reserved (UD2) */
2287 Fast486Exception(State, FAST486_EXCEPTION_UD);
2288 return;
2289 }
2290
2291 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2292 {
2293 FAST486_MOD_REG_RM ModRegRm;
2294 BOOLEAN OperandSize, AddressSize;
2295 UINT DataSize;
2296 UCHAR BitNumber;
2297
2298 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2299
2300 TOGGLE_OPSIZE(OperandSize);
2301 TOGGLE_ADSIZE(AddressSize);
2302
2303 /* Get the number of bits */
2304 if (OperandSize) DataSize = 32;
2305 else DataSize = 16;
2306
2307 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2308 {
2309 /* Exception occurred */
2310 return;
2311 }
2312
2313 if (ModRegRm.Register < 4)
2314 {
2315 /* Invalid */
2316 Fast486Exception(State, FAST486_EXCEPTION_UD);
2317 return;
2318 }
2319
2320 /* Get the bit number */
2321 if (!Fast486FetchByte(State, &BitNumber))
2322 {
2323 /* Exception occurred */
2324 return;
2325 }
2326
2327 if (ModRegRm.Memory)
2328 {
2329 /*
2330 * For memory operands, add the bit offset divided by
2331 * the data size to the address
2332 */
2333 ModRegRm.MemoryAddress += BitNumber / DataSize;
2334 }
2335
2336 /* Normalize the bit number */
2337 BitNumber %= DataSize;
2338
2339 if (OperandSize)
2340 {
2341 ULONG Value;
2342
2343 /* Read the value */
2344 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2345 {
2346 /* Exception occurred */
2347 return;
2348 }
2349
2350 /* Set CF to the bit value */
2351 State->Flags.Cf = (Value >> BitNumber) & 1;
2352
2353 if (ModRegRm.Register == 5)
2354 {
2355 /* BTS */
2356 Value |= 1 << BitNumber;
2357 }
2358 else if (ModRegRm.Register == 6)
2359 {
2360 /* BTR */
2361 Value &= ~(1 << BitNumber);
2362 }
2363 else if (ModRegRm.Register == 7)
2364 {
2365 /* BTC */
2366 Value ^= 1 << BitNumber;
2367 }
2368
2369 if (ModRegRm.Register >= 5)
2370 {
2371 /* Write back the result */
2372 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2373 {
2374 /* Exception occurred */
2375 return;
2376 }
2377 }
2378 }
2379 else
2380 {
2381 USHORT Value;
2382
2383 /* Read the value */
2384 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2385 {
2386 /* Exception occurred */
2387 return;
2388 }
2389
2390 /* Set CF to the bit value */
2391 State->Flags.Cf = (Value >> BitNumber) & 1;
2392
2393 if (ModRegRm.Register == 5)
2394 {
2395 /* BTS */
2396 Value |= 1 << BitNumber;
2397 }
2398 else if (ModRegRm.Register == 6)
2399 {
2400 /* BTR */
2401 Value &= ~(1 << BitNumber);
2402 }
2403 else if (ModRegRm.Register == 7)
2404 {
2405 /* BTC */
2406 Value ^= 1 << BitNumber;
2407 }
2408
2409 if (ModRegRm.Register >= 5)
2410 {
2411 /* Write back the result */
2412 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2413 {
2414 /* Exception occurred */
2415 return;
2416 }
2417 }
2418 }
2419 }
2420
2421 /* EOF */