[FAST486]
[reactos.git] / reactos / lib / fast486 / opgroups.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * opgroups.c
4 *
5 * Copyright (C) 2013 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 inline
36 static
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 break;
74 }
75
76 /* ADC */
77 case 2:
78 {
79 INT Carry = State->Flags.Cf ? 1 : 0;
80
81 Result = (FirstValue + SecondValue + Carry) & MaxValue;
82
83 /* Update CF, OF and AF */
84 State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1))
85 || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
86 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
87 && ((FirstValue & SignFlag) != (Result & SignFlag));
88 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
89
90 break;
91 }
92
93 /* SBB */
94 case 3:
95 {
96 INT Carry = State->Flags.Cf ? 1 : 0;
97
98 Result = (FirstValue - SecondValue - Carry) & MaxValue;
99
100 /* Update CF, OF and AF */
101 State->Flags.Cf = Carry
102 ? (FirstValue <= SecondValue)
103 : (FirstValue < SecondValue);
104 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
105 && ((FirstValue & SignFlag) != (Result & SignFlag));
106 State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
107
108 break;
109 }
110
111 /* AND */
112 case 4:
113 {
114 Result = FirstValue & SecondValue;
115 break;
116 }
117
118 /* SUB or CMP */
119 case 5:
120 case 7:
121 {
122 Result = (FirstValue - SecondValue) & MaxValue;
123
124 /* Update CF, OF and AF */
125 State->Flags.Cf = (FirstValue < SecondValue);
126 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
127 && ((FirstValue & SignFlag) != (Result & SignFlag));
128 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
129
130 break;
131 }
132
133 /* XOR */
134 case 6:
135 {
136 Result = FirstValue ^ SecondValue;
137 break;
138 }
139
140 default:
141 {
142 /* Shouldn't happen */
143 ASSERT(FALSE);
144 }
145 }
146
147 /* Update ZF, SF and PF */
148 State->Flags.Zf = (Result == 0);
149 State->Flags.Sf = ((Result & SignFlag) != 0);
150 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
151
152 /* Return the result */
153 return Result;
154 }
155
156 static
157 inline
158 ULONG
159 Fast486RotateOperation(PFAST486_STATE State,
160 INT Operation,
161 ULONG Value,
162 UCHAR Bits,
163 UCHAR Count)
164 {
165 ULONG HighestBit = 1 << (Bits - 1);
166 ULONG MaxValue = HighestBit | (HighestBit - 1);
167 ULONG Result;
168
169 /* Normalize the count */
170 Count &= 0x1F;
171
172 if ((Operation == 2) || (Operation == 3)) Count %= Bits + 1;
173
174 /* If the count is zero, do nothing */
175 if (Count == 0) return Value;
176
177 /* Check which operation is this */
178 switch (Operation)
179 {
180 /* ROL */
181 case 0:
182 {
183 Count %= Bits;
184 Result = (Value << Count) | (Value >> (Bits - Count));
185
186 /* Update CF and OF */
187 State->Flags.Cf = Result & 1;
188 if (Count == 1) State->Flags.Of = State->Flags.Cf
189 ^ ((Result & HighestBit) != 0);
190
191 break;
192 }
193
194 /* ROR */
195 case 1:
196 {
197 Count %= Bits;
198 Result = (Value >> Count) | (Value << (Bits - Count));
199
200 /* Update CF and OF */
201 State->Flags.Cf = ((Result & HighestBit) != 0);
202 if (Count == 1) State->Flags.Of = State->Flags.Cf
203 ^ ((Result & (HighestBit >> 1)) != 0);
204
205 break;
206 }
207
208 /* RCL */
209 case 2:
210 {
211 Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
212
213 /* Complete the calculation, but make sure we don't shift by too much */
214 if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
215
216 /* Update CF and OF */
217 State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
218 if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
219
220 break;
221 }
222
223 /* RCR */
224 case 3:
225 {
226 /* Update OF */
227 if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Value & HighestBit) != 0);
228
229 Result = (Value >> Count) | (State->Flags.Cf << (Bits - Count));
230
231 /* Complete the calculation, but make sure we don't shift by too much */
232 if ((Bits - Count) < 31) Result |= Value << (Bits - Count + 1);
233
234 /* Update CF */
235 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
236
237 break;
238 }
239
240 /* SHL/SAL */
241 case 4:
242 case 6:
243 {
244 Result = Value << Count;
245
246 /* Update CF and OF */
247 State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
248 if (Count == 1) State->Flags.Of = State->Flags.Cf
249 ^ ((Result & HighestBit) != 0);
250
251 break;
252 }
253
254 /* SHR */
255 case 5:
256 {
257 Result = Value >> Count;
258
259 /* Update CF and OF */
260 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
261 if (Count == 1) State->Flags.Of = ((Value & HighestBit) != 0);
262
263 break;
264 }
265
266 /* SAR */
267 case 7:
268 {
269 Result = Value >> Count;
270
271 /* Fill the top Count bits with the sign bit */
272 if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
273
274 /* Update CF and OF */
275 State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
276 if (Count == 1) State->Flags.Of = FALSE;
277
278 break;
279 }
280 }
281
282 if (Operation >= 4)
283 {
284 /* Update ZF, SF and PF */
285 State->Flags.Zf = ((Result & MaxValue) == 0);
286 State->Flags.Sf = ((Result & HighestBit) != 0);
287 State->Flags.Pf = Fast486CalculateParity(Result);
288 }
289
290 /* Return the result */
291 return Result;
292 }
293
294 /* PUBLIC FUNCTIONS ***********************************************************/
295
296 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)
297 {
298 UCHAR Immediate, Value;
299 FAST486_MOD_REG_RM ModRegRm;
300 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
301
302 TOGGLE_ADSIZE(AddressSize);
303
304 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
305 {
306 /* Exception occurred */
307 return FALSE;
308 }
309
310 /* Fetch the immediate operand */
311 if (!Fast486FetchByte(State, &Immediate))
312 {
313 /* Exception occurred */
314 return FALSE;
315 }
316
317 /* Read the operands */
318 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
319 {
320 /* Exception occurred */
321 return FALSE;
322 }
323
324 /* Calculate the result */
325 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
326
327 /* Unless this is CMP, write back the result */
328 if (ModRegRm.Register != 7)
329 {
330 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
331 }
332
333 return TRUE;
334 }
335
336 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
337 {
338 FAST486_MOD_REG_RM ModRegRm;
339 BOOLEAN OperandSize, AddressSize;
340
341 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
342
343 TOGGLE_OPSIZE(OperandSize);
344 TOGGLE_ADSIZE(AddressSize);
345
346 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
347 {
348 /* Exception occurred */
349 return FALSE;
350 }
351
352 if (OperandSize)
353 {
354 ULONG Immediate, Value;
355
356 /* Fetch the immediate operand */
357 if (!Fast486FetchDword(State, &Immediate))
358 {
359 /* Exception occurred */
360 return FALSE;
361 }
362
363 /* Read the operands */
364 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
365 {
366 /* Exception occurred */
367 return FALSE;
368 }
369
370 /* Calculate the result */
371 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
372
373 /* Unless this is CMP, write back the result */
374 if (ModRegRm.Register != 7)
375 {
376 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
377 }
378 }
379 else
380 {
381 USHORT Immediate, Value;
382
383 /* Fetch the immediate operand */
384 if (!Fast486FetchWord(State, &Immediate))
385 {
386 /* Exception occurred */
387 return FALSE;
388 }
389
390 /* Read the operands */
391 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
392 {
393 /* Exception occurred */
394 return FALSE;
395 }
396
397 /* Calculate the result */
398 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
399
400 /* Unless this is CMP, write back the result */
401 if (ModRegRm.Register != 7)
402 {
403 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
404 }
405 }
406
407 return TRUE;
408 }
409
410 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
411 {
412 CHAR ImmByte;
413 FAST486_MOD_REG_RM ModRegRm;
414 BOOLEAN OperandSize, AddressSize;
415
416 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
417
418 TOGGLE_OPSIZE(OperandSize);
419 TOGGLE_ADSIZE(AddressSize);
420
421 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
422 {
423 /* Exception occurred */
424 return FALSE;
425 }
426
427 /* Fetch the immediate operand */
428 if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
429 {
430 /* Exception occurred */
431 return FALSE;
432 }
433
434 if (OperandSize)
435 {
436 ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
437 ULONG Value;
438
439 /* Read the operands */
440 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
441 {
442 /* Exception occurred */
443 return FALSE;
444 }
445
446 /* Calculate the result */
447 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
448
449 /* Unless this is CMP, write back the result */
450 if (ModRegRm.Register != 7)
451 {
452 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
453 }
454 }
455 else
456 {
457 USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
458 USHORT Value;
459
460 /* Read the operands */
461 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
462 {
463 /* Exception occurred */
464 return FALSE;
465 }
466
467 /* Calculate the result */
468 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
469
470 /* Unless this is CMP, write back the result */
471 if (ModRegRm.Register != 7)
472 {
473 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
474 }
475 }
476
477 return TRUE;
478 }
479
480 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
481 {
482 ULONG Value;
483 FAST486_MOD_REG_RM ModRegRm;
484 BOOLEAN OperandSize, AddressSize;
485
486 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
487
488 TOGGLE_OPSIZE(OperandSize);
489 TOGGLE_ADSIZE(AddressSize);
490
491 /* Pop a value from the stack - this must be done first */
492 if (!Fast486StackPop(State, &Value))
493 {
494 /* Exception occurred */
495 return FALSE;
496 }
497
498 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
499 {
500 /* Exception occurred - restore SP */
501 if (OperandSize) State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
502 else State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
503
504 return FALSE;
505 }
506
507 if (ModRegRm.Register != 0)
508 {
509 /* Invalid */
510 Fast486Exception(State, FAST486_EXCEPTION_UD);
511 return FALSE;
512 }
513
514 if (OperandSize)
515 {
516 return Fast486WriteModrmDwordOperands(State,
517 &ModRegRm,
518 FALSE,
519 Value);
520 }
521 else
522 {
523 return Fast486WriteModrmWordOperands(State,
524 &ModRegRm,
525 FALSE,
526 LOWORD(Value));
527 }
528 }
529
530 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
531 {
532 UCHAR Value, Count;
533 FAST486_MOD_REG_RM ModRegRm;
534 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
535
536 TOGGLE_ADSIZE(AddressSize);
537
538 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
539 {
540 /* Exception occurred */
541 return FALSE;
542 }
543
544 /* Fetch the count */
545 if (!Fast486FetchByte(State, &Count))
546 {
547 /* Exception occurred */
548 return FALSE;
549 }
550
551 /* Read the operands */
552 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
553 {
554 /* Exception occurred */
555 return FALSE;
556 }
557
558 /* Calculate the result */
559 Value = LOBYTE(Fast486RotateOperation(State,
560 ModRegRm.Register,
561 Value,
562 8,
563 Count));
564
565 /* Write back the result */
566 return Fast486WriteModrmByteOperands(State,
567 &ModRegRm,
568 FALSE,
569 Value);
570 }
571
572 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
573 {
574 UCHAR Count;
575 FAST486_MOD_REG_RM ModRegRm;
576 BOOLEAN OperandSize, AddressSize;
577
578 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
579
580 TOGGLE_OPSIZE(OperandSize);
581 TOGGLE_ADSIZE(AddressSize);
582
583 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
584 {
585 /* Exception occurred */
586 return FALSE;
587 }
588
589 /* Fetch the count */
590 if (!Fast486FetchByte(State, &Count))
591 {
592 /* Exception occurred */
593 return FALSE;
594 }
595
596 if (OperandSize)
597 {
598 ULONG Value;
599
600 /* Read the operands */
601 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
602 {
603 /* Exception occurred */
604 return FALSE;
605 }
606
607 /* Calculate the result */
608 Value = Fast486RotateOperation(State,
609 ModRegRm.Register,
610 Value,
611 32,
612 Count);
613
614 /* Write back the result */
615 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
616 }
617 else
618 {
619 USHORT Value;
620
621 /* Read the operands */
622 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
623 {
624 /* Exception occurred */
625 return FALSE;
626 }
627
628 /* Calculate the result */
629 Value = LOWORD(Fast486RotateOperation(State,
630 ModRegRm.Register,
631 Value,
632 16,
633 Count));
634
635 /* Write back the result */
636 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
637 }
638 }
639
640 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)
641 {
642 UCHAR Immediate;
643 FAST486_MOD_REG_RM ModRegRm;
644 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
645
646 TOGGLE_ADSIZE(AddressSize);
647
648 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
649 {
650 /* Exception occurred */
651 return FALSE;
652 }
653
654 if (ModRegRm.Register != 0)
655 {
656 /* Invalid */
657 Fast486Exception(State, FAST486_EXCEPTION_UD);
658 return FALSE;
659 }
660
661 /* Get the immediate operand */
662 if (!Fast486FetchByte(State, &Immediate))
663 {
664 /* Exception occurred */
665 return FALSE;
666 }
667
668 return Fast486WriteModrmByteOperands(State,
669 &ModRegRm,
670 FALSE,
671 Immediate);
672 }
673
674 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
675 {
676 FAST486_MOD_REG_RM ModRegRm;
677 BOOLEAN OperandSize, AddressSize;
678
679 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
680
681 TOGGLE_OPSIZE(OperandSize);
682 TOGGLE_ADSIZE(AddressSize);
683
684 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
685 {
686 /* Exception occurred */
687 return FALSE;
688 }
689
690 if (ModRegRm.Register != 0)
691 {
692 /* Invalid */
693 Fast486Exception(State, FAST486_EXCEPTION_UD);
694 return FALSE;
695 }
696
697 if (OperandSize)
698 {
699 ULONG Immediate;
700
701 /* Get the immediate operand */
702 if (!Fast486FetchDword(State, &Immediate))
703 {
704 /* Exception occurred */
705 return FALSE;
706 }
707
708 return Fast486WriteModrmDwordOperands(State,
709 &ModRegRm,
710 FALSE,
711 Immediate);
712 }
713 else
714 {
715 USHORT Immediate;
716
717 /* Get the immediate operand */
718 if (!Fast486FetchWord(State, &Immediate))
719 {
720 /* Exception occurred */
721 return FALSE;
722 }
723
724 return Fast486WriteModrmWordOperands(State,
725 &ModRegRm,
726 FALSE,
727 Immediate);
728 }
729 }
730
731 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)
732 {
733 UCHAR Value;
734 FAST486_MOD_REG_RM ModRegRm;
735 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
736
737 TOGGLE_ADSIZE(AddressSize);
738
739 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
740 {
741 /* Exception occurred */
742 return FALSE;
743 }
744
745 /* Read the operands */
746 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
747 {
748 /* Exception occurred */
749 return FALSE;
750 }
751
752 /* Calculate the result */
753 Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
754
755 /* Write back the result */
756 return Fast486WriteModrmByteOperands(State,
757 &ModRegRm,
758 FALSE,
759 Value);
760
761 }
762
763 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)
764 {
765 FAST486_MOD_REG_RM ModRegRm;
766 BOOLEAN OperandSize, AddressSize;
767
768 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
769
770 TOGGLE_OPSIZE(OperandSize);
771 TOGGLE_ADSIZE(AddressSize);
772
773 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
774 {
775 /* Exception occurred */
776 return FALSE;
777 }
778
779 if (OperandSize)
780 {
781 ULONG Value;
782
783 /* Read the operands */
784 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
785 {
786 /* Exception occurred */
787 return FALSE;
788 }
789
790 /* Calculate the result */
791 Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
792
793 /* Write back the result */
794 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
795 }
796 else
797 {
798 USHORT Value;
799
800 /* Read the operands */
801 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
802 {
803 /* Exception occurred */
804 return FALSE;
805 }
806
807 /* Calculate the result */
808 Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
809
810 /* Write back the result */
811 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
812 }
813 }
814
815 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)
816 {
817 UCHAR Value;
818 FAST486_MOD_REG_RM ModRegRm;
819 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
820
821 TOGGLE_ADSIZE(AddressSize);
822
823 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
824 {
825 /* Exception occurred */
826 return FALSE;
827 }
828
829 /* Read the operands */
830 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
831 {
832 /* Exception occurred */
833 return FALSE;
834 }
835
836 /* Calculate the result */
837 Value = LOBYTE(Fast486RotateOperation(State,
838 ModRegRm.Register,
839 Value,
840 8,
841 State->GeneralRegs[FAST486_REG_ECX].LowByte));
842
843 /* Write back the result */
844 return Fast486WriteModrmByteOperands(State,
845 &ModRegRm,
846 FALSE,
847 Value);
848 }
849
850 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
851 {
852 FAST486_MOD_REG_RM ModRegRm;
853 BOOLEAN OperandSize, AddressSize;
854
855 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
856
857 TOGGLE_OPSIZE(OperandSize);
858 TOGGLE_ADSIZE(AddressSize);
859
860 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
861 {
862 /* Exception occurred */
863 return FALSE;
864 }
865
866 if (OperandSize)
867 {
868 ULONG Value;
869
870 /* Read the operands */
871 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
872 {
873 /* Exception occurred */
874 return FALSE;
875 }
876
877 /* Calculate the result */
878 Value = Fast486RotateOperation(State,
879 ModRegRm.Register,
880 Value,
881 32,
882 State->GeneralRegs[FAST486_REG_ECX].LowByte);
883
884 /* Write back the result */
885 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
886 }
887 else
888 {
889 USHORT Value;
890
891 /* Read the operands */
892 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
893 {
894 /* Exception occurred */
895 return FALSE;
896 }
897
898 /* Calculate the result */
899 Value = LOWORD(Fast486RotateOperation(State,
900 ModRegRm.Register,
901 Value,
902 16,
903 State->GeneralRegs[FAST486_REG_ECX].LowByte));
904
905 /* Write back the result */
906 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
907 }
908 }
909
910 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
911 {
912 UCHAR Value = 0;
913 FAST486_MOD_REG_RM ModRegRm;
914 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
915
916 TOGGLE_ADSIZE(AddressSize);
917
918 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
919 {
920 /* Exception occurred */
921 return FALSE;
922 }
923
924 /* Read the operands */
925 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
926 {
927 /* Exception occurred */
928 return FALSE;
929 }
930
931 switch (ModRegRm.Register)
932 {
933 /* TEST */
934 case 0:
935 case 1:
936 {
937 UCHAR Immediate, Result;
938
939 /* Fetch the immediate byte */
940 if (!Fast486FetchByte(State, &Immediate))
941 {
942 /* Exception occurred */
943 return FALSE;
944 }
945
946 /* Calculate the result */
947 Result = Value & Immediate;
948
949 /* Update the flags */
950 State->Flags.Cf = FALSE;
951 State->Flags.Of = FALSE;
952 State->Flags.Zf = (Result == 0);
953 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
954 State->Flags.Pf = Fast486CalculateParity(Result);
955
956 break;
957 }
958
959 /* NOT */
960 case 2:
961 {
962 /* Write back the result */
963 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
964 }
965
966 /* NEG */
967 case 3:
968 {
969 /* Calculate the result */
970 UCHAR Result = -Value;
971
972 /* Update the flags */
973 State->Flags.Cf = (Value != 0);
974 State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
975 State->Flags.Af = ((Value & 0x0F) != 0);
976 State->Flags.Zf = (Result == 0);
977 State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
978 State->Flags.Pf = Fast486CalculateParity(Result);
979
980 /* Write back the result */
981 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
982 }
983
984 /* MUL */
985 case 4:
986 {
987 USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
988
989 /* Update the flags */
990 State->Flags.Cf = State->Flags.Of = (HIBYTE(Result) != 0);
991
992 /* Write back the result */
993 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
994
995 break;
996 }
997
998 /* IMUL */
999 case 5:
1000 {
1001 SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
1002
1003 /* Update the flags */
1004 State->Flags.Cf = State->Flags.Of = ((Result < -128) || (Result > 127));
1005
1006 /* Write back the result */
1007 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
1008
1009 break;
1010 }
1011
1012 /* DIV */
1013 case 6:
1014 {
1015 UCHAR Quotient, Remainder;
1016
1017 if (Value == 0)
1018 {
1019 /* Divide error */
1020 Fast486Exception(State, FAST486_EXCEPTION_DE);
1021 return FALSE;
1022 }
1023
1024 Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
1025 Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
1026
1027 /* Write back the results */
1028 State->GeneralRegs[FAST486_REG_EAX].LowByte = Quotient;
1029 State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1030
1031 break;
1032 }
1033
1034 /* IDIV */
1035 case 7:
1036 {
1037 CHAR Quotient, Remainder;
1038
1039 if (Value == 0)
1040 {
1041 /* Divide error */
1042 Fast486Exception(State, FAST486_EXCEPTION_DE);
1043 return FALSE;
1044 }
1045
1046 Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1047 Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1048
1049 /* Write back the results */
1050 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1051 State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1052
1053 break;
1054 }
1055 }
1056
1057 return TRUE;
1058 }
1059
1060 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1061 {
1062 ULONG Value = 0, SignFlag;
1063 FAST486_MOD_REG_RM ModRegRm;
1064 BOOLEAN OperandSize, AddressSize;
1065
1066 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1067
1068 TOGGLE_OPSIZE(OperandSize);
1069 TOGGLE_ADSIZE(AddressSize);
1070
1071 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1072 {
1073 /* Exception occurred */
1074 return FALSE;
1075 }
1076
1077 /* Set the sign flag */
1078 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1079 else SignFlag = SIGN_FLAG_WORD;
1080
1081 /* Read the operand */
1082 if (OperandSize)
1083 {
1084 /* 32-bit */
1085 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1086 {
1087 /* Exception occurred */
1088 return FALSE;
1089 }
1090 }
1091 else
1092 {
1093 /* 16-bit */
1094 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1095 {
1096 /* Exception occurred */
1097 return FALSE;
1098 }
1099 }
1100
1101 switch (ModRegRm.Register)
1102 {
1103 /* TEST */
1104 case 0:
1105 case 1:
1106 {
1107 ULONG Immediate = 0, Result = 0;
1108
1109 if (OperandSize)
1110 {
1111 /* Fetch the immediate dword */
1112 if (!Fast486FetchDword(State, &Immediate))
1113 {
1114 /* Exception occurred */
1115 return FALSE;
1116 }
1117 }
1118 else
1119 {
1120 /* Fetch the immediate word */
1121 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1122 {
1123 /* Exception occurred */
1124 return FALSE;
1125 }
1126 }
1127
1128 /* Calculate the result */
1129 Result = Value & Immediate;
1130
1131 /* Update the flags */
1132 State->Flags.Cf = FALSE;
1133 State->Flags.Of = FALSE;
1134 State->Flags.Zf = (Result == 0);
1135 State->Flags.Sf = ((Result & SignFlag) != 0);
1136 State->Flags.Pf = Fast486CalculateParity(Result);
1137
1138 break;
1139 }
1140
1141 /* NOT */
1142 case 2:
1143 {
1144 /* Write back the result */
1145 if (OperandSize)
1146 {
1147 /* 32-bit */
1148 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1149 }
1150 else
1151 {
1152 /* 16-bit */
1153 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1154 }
1155 }
1156
1157 /* NEG */
1158 case 3:
1159 {
1160 /* Calculate the result */
1161 ULONG Result = -Value;
1162 if (!OperandSize) Result &= 0xFFFF;
1163
1164 /* Update the flags */
1165 State->Flags.Cf = (Value != 0);
1166 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1167 State->Flags.Af = ((Value & 0x0F) != 0);
1168 State->Flags.Zf = (Result == 0);
1169 State->Flags.Sf = ((Result & SignFlag) != 0);
1170 State->Flags.Pf = Fast486CalculateParity(Result);
1171
1172 /* Write back the result */
1173 if (OperandSize)
1174 {
1175 /* 32-bit */
1176 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1177 }
1178 else
1179 {
1180 /* 16-bit */
1181 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1182 }
1183 }
1184
1185 /* MUL */
1186 case 4:
1187 {
1188 if (OperandSize)
1189 {
1190 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1191
1192 /* Update the flags */
1193 State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
1194
1195 /* Write back the result */
1196 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1197 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1198 }
1199 else
1200 {
1201 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1202
1203 /* Update the flags */
1204 State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
1205
1206 /* Write back the result */
1207 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1208 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1209 }
1210
1211 break;
1212 }
1213
1214 /* IMUL */
1215 case 5:
1216 {
1217 if (OperandSize)
1218 {
1219 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1220
1221 /* Update the flags */
1222 State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
1223
1224 /* Write back the result */
1225 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1226 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1227 }
1228 else
1229 {
1230 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1231
1232 /* Update the flags */
1233 State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
1234
1235 /* Write back the result */
1236 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1237 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1238 }
1239
1240 break;
1241 }
1242
1243 /* DIV */
1244 case 6:
1245 {
1246 if (Value == 0)
1247 {
1248 /* Divide error */
1249 Fast486Exception(State, FAST486_EXCEPTION_DE);
1250 return FALSE;
1251 }
1252
1253 if (OperandSize)
1254 {
1255 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1256 | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1257 ULONG Quotient = Dividend / Value;
1258 ULONG Remainder = Dividend % Value;
1259
1260 /* Write back the results */
1261 State->GeneralRegs[FAST486_REG_EAX].Long = Quotient;
1262 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1263 }
1264 else
1265 {
1266 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1267 | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1268 USHORT Quotient = Dividend / Value;
1269 USHORT Remainder = Dividend % Value;
1270
1271 /* Write back the results */
1272 State->GeneralRegs[FAST486_REG_EAX].LowWord = Quotient;
1273 State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
1274 }
1275
1276 break;
1277 }
1278
1279 /* IDIV */
1280 case 7:
1281 {
1282 if (Value == 0)
1283 {
1284 /* Divide error */
1285 Fast486Exception(State, FAST486_EXCEPTION_DE);
1286 return FALSE;
1287 }
1288
1289 if (OperandSize)
1290 {
1291 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1292 | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1293 LONG Quotient = Dividend / (LONG)Value;
1294 LONG Remainder = Dividend % (LONG)Value;
1295
1296 /* Write back the results */
1297 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1298 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1299 }
1300 else
1301 {
1302 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1303 | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1304 SHORT Quotient = Dividend / (SHORT)LOWORD(Value);
1305 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1306
1307 /* Write back the results */
1308 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
1309 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1310 }
1311
1312 break;
1313 }
1314 }
1315
1316 return TRUE;
1317 }
1318
1319 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1320 {
1321 UCHAR Value;
1322 FAST486_MOD_REG_RM ModRegRm;
1323 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1324
1325 TOGGLE_ADSIZE(AddressSize);
1326
1327 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1328 {
1329 /* Exception occurred */
1330 return FALSE;
1331 }
1332
1333 if (ModRegRm.Register > 1)
1334 {
1335 /* Invalid */
1336 Fast486Exception(State, FAST486_EXCEPTION_UD);
1337 return FALSE;
1338 }
1339
1340 /* Read the operands */
1341 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1342 {
1343 /* Exception occurred */
1344 return FALSE;
1345 }
1346
1347 if (ModRegRm.Register == 0)
1348 {
1349 /* Increment and update OF and AF */
1350 Value++;
1351 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1352 State->Flags.Af = ((Value & 0x0F) == 0);
1353 }
1354 else
1355 {
1356 /* Decrement and update OF and AF */
1357 State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1358 Value--;
1359 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1360 }
1361
1362 /* Update flags */
1363 State->Flags.Zf = (Value == 0);
1364 State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
1365 State->Flags.Pf = Fast486CalculateParity(Value);
1366
1367 /* Write back the result */
1368 return Fast486WriteModrmByteOperands(State,
1369 &ModRegRm,
1370 FALSE,
1371 Value);
1372 }
1373
1374 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1375 {
1376 FAST486_MOD_REG_RM ModRegRm;
1377 BOOLEAN OperandSize, AddressSize;
1378
1379 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1380
1381 TOGGLE_OPSIZE(OperandSize);
1382 TOGGLE_ADSIZE(AddressSize);
1383
1384 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1385 {
1386 /* Exception occurred */
1387 return FALSE;
1388 }
1389
1390 if (ModRegRm.Register == 7)
1391 {
1392 /* Invalid */
1393 Fast486Exception(State, FAST486_EXCEPTION_UD);
1394 return FALSE;
1395 }
1396
1397 /* Read the operands */
1398 if (OperandSize)
1399 {
1400 ULONG Value;
1401
1402 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1403 {
1404 /* Exception occurred */
1405 return FALSE;
1406 }
1407
1408 if (ModRegRm.Register == 0)
1409 {
1410 /* Increment and update OF and AF */
1411 Value++;
1412 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1413 State->Flags.Af = ((Value & 0x0F) == 0);
1414 }
1415 else if (ModRegRm.Register == 1)
1416 {
1417 /* Decrement and update OF and AF */
1418 State->Flags.Of = (Value == SIGN_FLAG_LONG);
1419 Value--;
1420 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1421 }
1422 else if (ModRegRm.Register == 2)
1423 {
1424 /* Push the current value of EIP */
1425 if (!Fast486StackPush(State, State->InstPtr.Long))
1426 {
1427 /* Exception occurred */
1428 return FALSE;
1429 }
1430
1431 /* Set the EIP to the address */
1432 State->InstPtr.Long = Value;
1433 }
1434 else if (ModRegRm.Register == 3)
1435 {
1436 USHORT Selector;
1437 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1438
1439 /* Check for the segment override */
1440 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1441 {
1442 /* Use the override segment instead */
1443 Segment = State->SegmentOverride;
1444 }
1445
1446 /* Read the selector */
1447 if (!Fast486ReadMemory(State,
1448 Segment,
1449 ModRegRm.MemoryAddress + sizeof(ULONG),
1450 FALSE,
1451 &Selector,
1452 sizeof(USHORT)))
1453 {
1454 /* Exception occurred */
1455 return FALSE;
1456 }
1457
1458 /* Push the current value of CS */
1459 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1460 {
1461 /* Exception occurred */
1462 return FALSE;
1463 }
1464
1465 /* Push the current value of EIP */
1466 if (!Fast486StackPush(State, State->InstPtr.Long))
1467 {
1468 /* Exception occurred */
1469 return FALSE;
1470 }
1471
1472 /* Load the new code segment */
1473 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1474 {
1475 /* Exception occurred */
1476 return FALSE;
1477 }
1478
1479 /* Set the EIP to the address */
1480 State->InstPtr.Long = Value;
1481 }
1482 else if (ModRegRm.Register == 4)
1483 {
1484 /* Set the EIP to the address */
1485 State->InstPtr.Long = Value;
1486 }
1487 else if (ModRegRm.Register == 5)
1488 {
1489 USHORT Selector;
1490 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1491
1492 /* Check for the segment override */
1493 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1494 {
1495 /* Use the override segment instead */
1496 Segment = State->SegmentOverride;
1497 }
1498
1499 /* Read the selector */
1500 if (!Fast486ReadMemory(State,
1501 Segment,
1502 ModRegRm.MemoryAddress + sizeof(ULONG),
1503 FALSE,
1504 &Selector,
1505 sizeof(USHORT)))
1506 {
1507 /* Exception occurred */
1508 return FALSE;
1509 }
1510
1511 /* Load the new code segment */
1512 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1513 {
1514 /* Exception occurred */
1515 return FALSE;
1516 }
1517
1518 /* Set the EIP to the address */
1519 State->InstPtr.Long = Value;
1520 }
1521 else if (ModRegRm.Register == 6)
1522 {
1523 /* Push the value on to the stack */
1524 return Fast486StackPush(State, Value);
1525 }
1526
1527 if (ModRegRm.Register <= 1)
1528 {
1529 /* Update flags */
1530 State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1531 State->Flags.Zf = (Value == 0);
1532 State->Flags.Pf = Fast486CalculateParity(Value);
1533
1534 /* Write back the result */
1535 return Fast486WriteModrmDwordOperands(State,
1536 &ModRegRm,
1537 FALSE,
1538 Value);
1539 }
1540 }
1541 else
1542 {
1543 USHORT Value;
1544
1545 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1546 {
1547 /* Exception occurred */
1548 return FALSE;
1549 }
1550
1551 if (ModRegRm.Register == 0)
1552 {
1553 /* Increment and update OF */
1554 Value++;
1555 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1556 State->Flags.Af = ((Value & 0x0F) == 0);
1557 }
1558 else if (ModRegRm.Register == 1)
1559 {
1560 /* Decrement and update OF */
1561 State->Flags.Of = (Value == SIGN_FLAG_WORD);
1562 Value--;
1563 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1564 }
1565 else if (ModRegRm.Register == 2)
1566 {
1567 /* Push the current value of IP */
1568 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1569 {
1570 /* Exception occurred */
1571 return FALSE;
1572 }
1573
1574 /* Set the IP to the address */
1575 State->InstPtr.LowWord = Value;
1576
1577 /* Clear the top half of EIP */
1578 State->InstPtr.Long &= 0xFFFF;
1579 }
1580 else if (ModRegRm.Register == 3)
1581 {
1582 USHORT Selector;
1583 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1584
1585 /* Check for the segment override */
1586 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1587 {
1588 /* Use the override segment instead */
1589 Segment = State->SegmentOverride;
1590 }
1591
1592 /* Read the selector */
1593 if (!Fast486ReadMemory(State,
1594 Segment,
1595 ModRegRm.MemoryAddress + sizeof(USHORT),
1596 FALSE,
1597 &Selector,
1598 sizeof(USHORT)))
1599 {
1600 /* Exception occurred */
1601 return FALSE;
1602 }
1603
1604 /* Push the current value of CS */
1605 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1606 {
1607 /* Exception occurred */
1608 return FALSE;
1609 }
1610
1611 /* Push the current value of IP */
1612 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1613 {
1614 /* Exception occurred */
1615 return FALSE;
1616 }
1617
1618 /* Load the new code segment */
1619 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1620 {
1621 /* Exception occurred */
1622 return FALSE;
1623 }
1624
1625 /* Set the IP to the address */
1626 State->InstPtr.LowWord = Value;
1627
1628 /* Clear the top half of EIP */
1629 State->InstPtr.Long &= 0xFFFF;
1630 }
1631 else if (ModRegRm.Register == 4)
1632 {
1633 /* Set the IP to the address */
1634 State->InstPtr.LowWord = Value;
1635
1636 /* Clear the top half of EIP */
1637 State->InstPtr.Long &= 0xFFFF;
1638 }
1639 else if (ModRegRm.Register == 5)
1640 {
1641 USHORT Selector;
1642 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1643
1644 /* Check for the segment override */
1645 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1646 {
1647 /* Use the override segment instead */
1648 Segment = State->SegmentOverride;
1649 }
1650
1651 /* Read the selector */
1652 if (!Fast486ReadMemory(State,
1653 Segment,
1654 ModRegRm.MemoryAddress + sizeof(USHORT),
1655 FALSE,
1656 &Selector,
1657 sizeof(USHORT)))
1658 {
1659 /* Exception occurred */
1660 return FALSE;
1661 }
1662
1663 /* Load the new code segment */
1664 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1665 {
1666 /* Exception occurred */
1667 return FALSE;
1668 }
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 == 6)
1677 {
1678 /* Push the value on to the stack */
1679 return Fast486StackPush(State, Value);
1680 }
1681 else
1682 {
1683 /* Invalid */
1684 Fast486Exception(State, FAST486_EXCEPTION_UD);
1685 return FALSE;
1686 }
1687
1688 if (ModRegRm.Register <= 1)
1689 {
1690 /* Update flags */
1691 State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1692 State->Flags.Zf = (Value == 0);
1693 State->Flags.Pf = Fast486CalculateParity(Value);
1694
1695 /* Write back the result */
1696 return Fast486WriteModrmWordOperands(State,
1697 &ModRegRm,
1698 FALSE,
1699 Value);
1700 }
1701 }
1702
1703 return TRUE;
1704 }
1705
1706 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00)
1707 {
1708 FAST486_MOD_REG_RM ModRegRm;
1709 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1710
1711 NO_LOCK_PREFIX();
1712 TOGGLE_ADSIZE(AddressSize);
1713
1714 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1715 {
1716 /* Exception occurred */
1717 return FALSE;
1718 }
1719
1720 /* Check which operation this is */
1721 switch (ModRegRm.Register)
1722 {
1723 /* SLDT */
1724 case 0:
1725 {
1726 /* Not recognized in real mode or virtual 8086 mode */
1727 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1728 || State->Flags.Vm)
1729 {
1730 Fast486Exception(State, FAST486_EXCEPTION_UD);
1731 return FALSE;
1732 }
1733
1734 return Fast486WriteModrmWordOperands(State,
1735 &ModRegRm,
1736 FALSE,
1737 State->Ldtr.Selector);
1738 }
1739
1740 /* STR */
1741 case 1:
1742 {
1743 /* Not recognized in real mode or virtual 8086 mode */
1744 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1745 || State->Flags.Vm)
1746 {
1747 Fast486Exception(State, FAST486_EXCEPTION_UD);
1748 return FALSE;
1749 }
1750
1751 return Fast486WriteModrmWordOperands(State,
1752 &ModRegRm,
1753 FALSE,
1754 State->TaskReg.Selector);
1755 }
1756
1757 /* LLDT */
1758 case 2:
1759 {
1760 USHORT Selector;
1761 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1762
1763 /* Not recognized in real mode or virtual 8086 mode */
1764 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1765 || State->Flags.Vm)
1766 {
1767 Fast486Exception(State, FAST486_EXCEPTION_UD);
1768 return FALSE;
1769 }
1770
1771 /* This is a privileged instruction */
1772 if (Fast486GetCurrentPrivLevel(State) != 0)
1773 {
1774 Fast486Exception(State, FAST486_EXCEPTION_GP);
1775 return FALSE;
1776 }
1777
1778 if (!Fast486ReadModrmWordOperands(State,
1779 &ModRegRm,
1780 NULL,
1781 &Selector))
1782 {
1783 /* Exception occurred */
1784 return FALSE;
1785 }
1786
1787 /* Make sure the GDT contains the entry */
1788 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1789 {
1790 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1791 return FALSE;
1792 }
1793
1794 /* Read the GDT */
1795 if (!Fast486ReadLinearMemory(State,
1796 State->Gdtr.Address
1797 + GET_SEGMENT_INDEX(Selector),
1798 &GdtEntry,
1799 sizeof(GdtEntry)))
1800 {
1801 /* Exception occurred */
1802 return FALSE;
1803 }
1804
1805 if (GET_SEGMENT_INDEX(Selector) == 0)
1806 {
1807 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1808 return TRUE;
1809 }
1810
1811 if (!GdtEntry.Present)
1812 {
1813 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1814 return FALSE;
1815 }
1816
1817 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1818 {
1819 /* This is not a LDT descriptor */
1820 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1821 return FALSE;
1822 }
1823
1824 /* Update the LDTR */
1825 State->Ldtr.Selector = Selector;
1826 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1827 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1828 if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12;
1829
1830 return TRUE;
1831 }
1832
1833 /* LTR */
1834 case 3:
1835 {
1836 USHORT Selector;
1837 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1838
1839 /* Not recognized in real mode or virtual 8086 mode */
1840 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1841 || State->Flags.Vm)
1842 {
1843 Fast486Exception(State, FAST486_EXCEPTION_UD);
1844 return FALSE;
1845 }
1846
1847 /* This is a privileged instruction */
1848 if (Fast486GetCurrentPrivLevel(State) != 0)
1849 {
1850 Fast486Exception(State, FAST486_EXCEPTION_GP);
1851 return FALSE;
1852 }
1853
1854 if (!Fast486ReadModrmWordOperands(State,
1855 &ModRegRm,
1856 NULL,
1857 &Selector))
1858 {
1859 /* Exception occurred */
1860 return FALSE;
1861 }
1862
1863 /* Make sure the GDT contains the entry */
1864 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1865 {
1866 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1867 return FALSE;
1868 }
1869
1870 /* Read the GDT */
1871 if (!Fast486ReadLinearMemory(State,
1872 State->Gdtr.Address
1873 + GET_SEGMENT_INDEX(Selector),
1874 &GdtEntry,
1875 sizeof(GdtEntry)))
1876 {
1877 /* Exception occurred */
1878 return FALSE;
1879 }
1880
1881 if (GET_SEGMENT_INDEX(Selector) == 0)
1882 {
1883 Fast486Exception(State, FAST486_EXCEPTION_GP);
1884 return FALSE;
1885 }
1886
1887 if (!GdtEntry.Present)
1888 {
1889 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1890 return FALSE;
1891 }
1892
1893 if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
1894 {
1895 /* This is not a TSS descriptor */
1896 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1897 return FALSE;
1898 }
1899
1900 /* Update the TR */
1901 State->TaskReg.Selector = Selector;
1902 State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1903 State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1904 if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
1905 State->TaskReg.Busy = TRUE;
1906
1907 return TRUE;
1908 }
1909
1910 /* VERR/VERW */
1911 case 4:
1912 case 5:
1913 {
1914 USHORT Selector;
1915 FAST486_GDT_ENTRY GdtEntry;
1916
1917 /* Not recognized in real mode or virtual 8086 mode */
1918 if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1919 || State->Flags.Vm)
1920 {
1921 Fast486Exception(State, FAST486_EXCEPTION_UD);
1922 return FALSE;
1923 }
1924
1925 /* This is a privileged instruction */
1926 if (Fast486GetCurrentPrivLevel(State) != 0)
1927 {
1928 Fast486Exception(State, FAST486_EXCEPTION_GP);
1929 return FALSE;
1930 }
1931
1932 if (!Fast486ReadModrmWordOperands(State,
1933 &ModRegRm,
1934 NULL,
1935 &Selector))
1936 {
1937 /* Exception occurred */
1938 return FALSE;
1939 }
1940
1941 if (!(Selector & SEGMENT_TABLE_INDICATOR))
1942 {
1943 /* Make sure the GDT contains the entry */
1944 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
1945 {
1946 /* Clear ZF */
1947 State->Flags.Zf = FALSE;
1948 return TRUE;
1949 }
1950
1951 /* Read the GDT */
1952 if (!Fast486ReadLinearMemory(State,
1953 State->Gdtr.Address
1954 + GET_SEGMENT_INDEX(Selector),
1955 &GdtEntry,
1956 sizeof(GdtEntry)))
1957 {
1958 /* Exception occurred */
1959 return FALSE;
1960 }
1961 }
1962 else
1963 {
1964 /* Make sure the LDT contains the entry */
1965 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
1966 {
1967 /* Clear ZF */
1968 State->Flags.Zf = FALSE;
1969 return TRUE;
1970 }
1971
1972 /* Read the LDT */
1973 if (!Fast486ReadLinearMemory(State,
1974 State->Ldtr.Base
1975 + GET_SEGMENT_INDEX(Selector),
1976 &GdtEntry,
1977 sizeof(GdtEntry)))
1978 {
1979 /* Exception occurred */
1980 return FALSE;
1981 }
1982 }
1983
1984 /* Set ZF if it is valid and accessible */
1985 State->Flags.Zf = GdtEntry.Present // must be present
1986 && GdtEntry.SystemType // must be a segment
1987 && (((ModRegRm.Register == 4)
1988 /* code segments are only readable if the RW bit is set */
1989 && (!GdtEntry.Executable || GdtEntry.ReadWrite))
1990 || ((ModRegRm.Register == 5)
1991 /* code segments are never writable, data segments are writable when RW is set */
1992 && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
1993 /*
1994 * for segments other than conforming code segments,
1995 * both RPL and CPL must be less than or equal to DPL
1996 */
1997 && ((!GdtEntry.Executable || !GdtEntry.DirConf)
1998 && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
1999 && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
2000 /* for conforming code segments, DPL must be less than or equal to CPL */
2001 && ((GdtEntry.Executable && GdtEntry.DirConf)
2002 && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
2003
2004
2005 return TRUE;
2006 }
2007
2008 /* Invalid */
2009 default:
2010 {
2011 Fast486Exception(State, FAST486_EXCEPTION_UD);
2012 return FALSE;
2013 }
2014 }
2015 }
2016
2017 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
2018 {
2019 UCHAR TableReg[6];
2020 FAST486_MOD_REG_RM ModRegRm;
2021 BOOLEAN OperandSize, AddressSize;
2022 FAST486_SEG_REGS Segment = FAST486_REG_DS;
2023
2024 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2025
2026 NO_LOCK_PREFIX();
2027 TOGGLE_OPSIZE(OperandSize);
2028 TOGGLE_ADSIZE(AddressSize);
2029
2030 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2031 {
2032 /* Exception occurred */
2033 return FALSE;
2034 }
2035
2036 /* Check for the segment override */
2037 if (State->PrefixFlags & FAST486_PREFIX_SEG)
2038 {
2039 /* Use the override segment instead */
2040 Segment = State->SegmentOverride;
2041 }
2042
2043 /* Check which operation this is */
2044 switch (ModRegRm.Register)
2045 {
2046 /* SGDT */
2047 case 0:
2048 {
2049 if (!ModRegRm.Memory)
2050 {
2051 /* The second operand must be a memory location */
2052 Fast486Exception(State, FAST486_EXCEPTION_UD);
2053 return FALSE;
2054 }
2055
2056 /* Fill the 6-byte table register */
2057 RtlCopyMemory(TableReg, &State->Gdtr.Size, sizeof(USHORT));
2058 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Gdtr.Address, sizeof(ULONG));
2059
2060 /* Store the GDTR */
2061 return Fast486WriteMemory(State,
2062 Segment,
2063 ModRegRm.MemoryAddress,
2064 TableReg,
2065 sizeof(TableReg));
2066 }
2067
2068 /* SIDT */
2069 case 1:
2070 {
2071 if (!ModRegRm.Memory)
2072 {
2073 /* The second operand must be a memory location */
2074 Fast486Exception(State, FAST486_EXCEPTION_UD);
2075 return FALSE;
2076 }
2077
2078 /* Fill the 6-byte table register */
2079 RtlCopyMemory(TableReg, &State->Idtr.Size, sizeof(USHORT));
2080 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Idtr.Address, sizeof(ULONG));
2081
2082 /* Store the IDTR */
2083 return Fast486WriteMemory(State,
2084 Segment,
2085 ModRegRm.MemoryAddress,
2086 TableReg,
2087 sizeof(TableReg));
2088 }
2089
2090 /* LGDT */
2091 case 2:
2092 {
2093 /* This is a privileged instruction */
2094 if (Fast486GetCurrentPrivLevel(State) != 0)
2095 {
2096 Fast486Exception(State, FAST486_EXCEPTION_GP);
2097 return FALSE;
2098 }
2099
2100 if (!ModRegRm.Memory)
2101 {
2102 /* The second operand must be a memory location */
2103 Fast486Exception(State, FAST486_EXCEPTION_UD);
2104 return FALSE;
2105 }
2106
2107 /* Read the new GDTR */
2108 if (!Fast486ReadMemory(State,
2109 Segment,
2110 ModRegRm.MemoryAddress,
2111 FALSE,
2112 TableReg,
2113 sizeof(TableReg)))
2114 {
2115 /* Exception occurred */
2116 return FALSE;
2117 }
2118
2119 /* Load the new GDT */
2120 State->Gdtr.Size = *((PUSHORT)TableReg);
2121 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2122
2123 /* In 16-bit mode the highest byte is masked out */
2124 if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2125
2126 return TRUE;
2127 }
2128
2129 /* LIDT */
2130 case 3:
2131 {
2132 /* This is a privileged instruction */
2133 if (Fast486GetCurrentPrivLevel(State) != 0)
2134 {
2135 Fast486Exception(State, FAST486_EXCEPTION_GP);
2136 return FALSE;
2137 }
2138
2139 if (!ModRegRm.Memory)
2140 {
2141 /* The second operand must be a memory location */
2142 Fast486Exception(State, FAST486_EXCEPTION_UD);
2143 return FALSE;
2144 }
2145
2146 /* Read the new IDTR */
2147 if (!Fast486ReadMemory(State,
2148 Segment,
2149 ModRegRm.MemoryAddress,
2150 FALSE,
2151 TableReg,
2152 sizeof(TableReg)))
2153 {
2154 /* Exception occurred */
2155 return FALSE;
2156 }
2157
2158 /* Load the new IDT */
2159 State->Idtr.Size = *((PUSHORT)TableReg);
2160 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2161
2162 /* In 16-bit mode the highest byte is masked out */
2163 if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2164
2165 return TRUE;
2166 }
2167
2168 /* SMSW */
2169 case 4:
2170 {
2171 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2172 return Fast486WriteModrmWordOperands(State,
2173 &ModRegRm,
2174 FALSE,
2175 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2176 }
2177
2178 /* LMSW */
2179 case 6:
2180 {
2181 USHORT MachineStatusWord;
2182
2183 /* This is a privileged instruction */
2184 if (Fast486GetCurrentPrivLevel(State) != 0)
2185 {
2186 Fast486Exception(State, FAST486_EXCEPTION_GP);
2187 return FALSE;
2188 }
2189
2190 /* Read the new Machine Status Word */
2191 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2192 {
2193 /* Exception occurred */
2194 return FALSE;
2195 }
2196
2197 /* This instruction cannot be used to return to real mode */
2198 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2199 && !(MachineStatusWord & FAST486_CR0_PE))
2200 {
2201 Fast486Exception(State, FAST486_EXCEPTION_GP);
2202 return FALSE;
2203 }
2204
2205 /* Set the lowest 4 bits */
2206 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
2207 State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2208
2209 return TRUE;
2210 }
2211
2212 /* INVLPG */
2213 case 7:
2214 {
2215 UNIMPLEMENTED;
2216 return FALSE;
2217 }
2218
2219 /* Invalid */
2220 default:
2221 {
2222 Fast486Exception(State, FAST486_EXCEPTION_UD);
2223 return FALSE;
2224 }
2225 }
2226 }
2227
2228 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
2229 {
2230 FAST486_MOD_REG_RM ModRegRm;
2231 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2232
2233 TOGGLE_ADSIZE(AddressSize);
2234
2235 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2236 {
2237 /* Exception occurred */
2238 return FALSE;
2239 }
2240
2241 /* All of them are reserved (UD2) */
2242 Fast486Exception(State, FAST486_EXCEPTION_UD);
2243 return FALSE;
2244 }
2245
2246 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
2247 {
2248 FAST486_MOD_REG_RM ModRegRm;
2249 BOOLEAN OperandSize, AddressSize;
2250 UINT DataSize;
2251 UCHAR BitNumber;
2252
2253 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2254
2255 TOGGLE_OPSIZE(OperandSize);
2256 TOGGLE_ADSIZE(AddressSize);
2257
2258 /* Get the number of bits */
2259 if (OperandSize) DataSize = 32;
2260 else DataSize = 16;
2261
2262 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2263 {
2264 /* Exception occurred */
2265 return FALSE;
2266 }
2267
2268 if (ModRegRm.Register < 4)
2269 {
2270 /* Invalid */
2271 Fast486Exception(State, FAST486_EXCEPTION_UD);
2272 return FALSE;
2273 }
2274
2275 /* Get the bit number */
2276 if (!Fast486FetchByte(State, &BitNumber))
2277 {
2278 /* Exception occurred */
2279 return FALSE;
2280 }
2281
2282 if (ModRegRm.Memory)
2283 {
2284 /*
2285 * For memory operands, add the bit offset divided by
2286 * the data size to the address
2287 */
2288 ModRegRm.MemoryAddress += BitNumber / DataSize;
2289 }
2290
2291 /* Normalize the bit number */
2292 BitNumber %= DataSize;
2293
2294 if (OperandSize)
2295 {
2296 ULONG Value;
2297
2298 /* Read the value */
2299 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2300 {
2301 /* Exception occurred */
2302 return FALSE;
2303 }
2304
2305 /* Set CF to the bit value */
2306 State->Flags.Cf = (Value >> BitNumber) & 1;
2307
2308 if (ModRegRm.Register == 5)
2309 {
2310 /* BTS */
2311 Value |= 1 << BitNumber;
2312 }
2313 else if (ModRegRm.Register == 6)
2314 {
2315 /* BTR */
2316 Value &= ~(1 << BitNumber);
2317 }
2318 else if (ModRegRm.Register == 7)
2319 {
2320 /* BTC */
2321 Value ^= 1 << BitNumber;
2322 }
2323
2324 if (ModRegRm.Register >= 5)
2325 {
2326 /* Write back the result */
2327 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2328 {
2329 /* Exception occurred */
2330 return FALSE;
2331 }
2332 }
2333 }
2334 else
2335 {
2336 USHORT Value;
2337
2338 /* Read the value */
2339 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2340 {
2341 /* Exception occurred */
2342 return FALSE;
2343 }
2344
2345 /* Set CF to the bit value */
2346 State->Flags.Cf = (Value >> BitNumber) & 1;
2347
2348 if (ModRegRm.Register == 5)
2349 {
2350 /* BTS */
2351 Value |= 1 << BitNumber;
2352 }
2353 else if (ModRegRm.Register == 6)
2354 {
2355 /* BTR */
2356 Value &= ~(1 << BitNumber);
2357 }
2358 else if (ModRegRm.Register == 7)
2359 {
2360 /* BTC */
2361 Value ^= 1 << BitNumber;
2362 }
2363
2364 if (ModRegRm.Register >= 5)
2365 {
2366 /* Write back the result */
2367 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2368 {
2369 /* Exception occurred */
2370 return FALSE;
2371 }
2372 }
2373 }
2374
2375 /* Return success */
2376 return TRUE;
2377 }
2378
2379 /* EOF */