2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
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.
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.
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.
22 /* INCLUDES *******************************************************************/
33 /* PRIVATE FUNCTIONS **********************************************************/
38 Fast486ArithmeticOperation(PFAST486_STATE State
,
45 ULONG SignFlag
= 1 << (Bits
- 1);
46 ULONG MaxValue
= (SignFlag
- 1) | SignFlag
;
48 /* Make sure the values don't exceed the maximum for their size */
49 FirstValue
&= MaxValue
;
50 SecondValue
&= MaxValue
;
52 /* Check which operation is this */
58 Result
= (FirstValue
+ SecondValue
) & MaxValue
;
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);
72 Result
= FirstValue
| SecondValue
;
79 INT Carry
= State
->Flags
.Cf
? 1 : 0;
81 Result
= (FirstValue
+ SecondValue
+ Carry
) & MaxValue
;
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
& 0x0F) + ((SecondValue
+ Carry
) & 0x0F)) & 0x10) != 0);
96 INT Carry
= State
->Flags
.Cf
? 1 : 0;
98 Result
= (FirstValue
- SecondValue
- Carry
) & MaxValue
;
100 /* Update CF, OF and AF */
101 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
102 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
103 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
104 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
112 Result
= FirstValue
& SecondValue
;
120 Result
= (FirstValue
- SecondValue
) & MaxValue
;
122 /* Update CF, OF and AF */
123 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
124 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
125 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
126 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
134 Result
= FirstValue
^ SecondValue
;
140 /* Shouldn't happen */
145 /* Update ZF, SF and PF */
146 State
->Flags
.Zf
= (Result
== 0);
147 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
148 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Result
));
150 /* Return the result */
157 Fast486RotateOperation(PFAST486_STATE State
,
163 ULONG HighestBit
= 1 << (Bits
- 1);
164 ULONG MaxValue
= HighestBit
| (HighestBit
- 1);
167 /* Normalize the count */
170 if ((Operation
== 2) || (Operation
== 3)) Count
%= Bits
+ 1;
172 /* If the count is zero, do nothing */
173 if (Count
== 0) return Value
;
175 /* Check which operation is this */
182 Result
= (Value
<< Count
) | (Value
>> (Bits
- Count
));
184 /* Update CF and OF */
185 State
->Flags
.Cf
= Result
& 1;
186 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
187 ^ ((Result
& HighestBit
) != 0);
196 Result
= (Value
>> Count
) | (Value
<< (Bits
- Count
));
198 /* Update CF and OF */
199 State
->Flags
.Cf
= ((Result
& HighestBit
) != 0);
200 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
201 ^ ((Result
& (HighestBit
>> 1)) != 0);
209 Result
= (Value
<< Count
) | (State
->Flags
.Cf
<< (Count
- 1));
211 /* Complete the calculation, but make sure we don't shift by too much */
212 if ((Bits
- Count
) < 31) Result
|= Value
>> (Bits
- Count
+ 1);
214 /* Update CF and OF */
215 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
216 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
^ ((Result
& HighestBit
) != 0);
225 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
^ ((Value
& HighestBit
) != 0);
227 Result
= (Value
>> Count
) | (State
->Flags
.Cf
<< (Bits
- Count
));
229 /* Complete the calculation, but make sure we don't shift by too much */
230 if ((Bits
- Count
) < 31) Result
|= Value
<< (Bits
- Count
+ 1);
233 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
242 Result
= Value
<< Count
;
244 /* Update CF and OF */
245 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
246 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
247 ^ ((Result
& HighestBit
) != 0);
255 Result
= Value
>> Count
;
257 /* Update CF and OF */
258 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
259 if (Count
== 1) State
->Flags
.Of
= ((Value
& HighestBit
) != 0);
267 Result
= Value
>> Count
;
269 /* Fill the top Count bits with the sign bit */
270 if (Value
& HighestBit
) Result
|= ((1 << Count
) - 1) << (Bits
- Count
);
272 /* Update CF and OF */
273 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
274 if (Count
== 1) State
->Flags
.Of
= FALSE
;
282 /* Update ZF, SF and PF */
283 State
->Flags
.Zf
= ((Result
& MaxValue
) == 0);
284 State
->Flags
.Sf
= ((Result
& HighestBit
) != 0);
285 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
288 /* Return the result */
292 /* PUBLIC FUNCTIONS ***********************************************************/
294 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082
)
296 UCHAR Immediate
, Dummy
, Value
;
297 FAST486_MOD_REG_RM ModRegRm
;
298 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
300 TOGGLE_ADSIZE(AddressSize
);
302 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
304 /* Exception occurred */
308 /* Fetch the immediate operand */
309 if (!Fast486FetchByte(State
, &Immediate
))
311 /* Exception occurred */
315 /* Read the operands */
316 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
318 /* Exception occurred */
322 /* Calculate the result */
323 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 8);
325 /* Unless this is CMP, write back the result */
326 if (ModRegRm
.Register
!= 7)
328 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
334 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81
)
336 FAST486_MOD_REG_RM ModRegRm
;
337 BOOLEAN OperandSize
, AddressSize
;
339 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
341 TOGGLE_OPSIZE(OperandSize
);
342 TOGGLE_ADSIZE(AddressSize
);
344 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
346 /* Exception occurred */
352 ULONG Immediate
, Value
, Dummy
;
354 /* Fetch the immediate operand */
355 if (!Fast486FetchDword(State
, &Immediate
))
357 /* Exception occurred */
361 /* Read the operands */
362 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
364 /* Exception occurred */
368 /* Calculate the result */
369 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
371 /* Unless this is CMP, write back the result */
372 if (ModRegRm
.Register
!= 7)
374 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
379 USHORT Immediate
, Value
, Dummy
;
381 /* Fetch the immediate operand */
382 if (!Fast486FetchWord(State
, &Immediate
))
384 /* Exception occurred */
388 /* Read the operands */
389 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
391 /* Exception occurred */
395 /* Calculate the result */
396 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
398 /* Unless this is CMP, write back the result */
399 if (ModRegRm
.Register
!= 7)
401 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
408 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83
)
411 FAST486_MOD_REG_RM ModRegRm
;
412 BOOLEAN OperandSize
, AddressSize
;
414 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
416 TOGGLE_OPSIZE(OperandSize
);
417 TOGGLE_ADSIZE(AddressSize
);
419 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
421 /* Exception occurred */
425 /* Fetch the immediate operand */
426 if (!Fast486FetchByte(State
, (PUCHAR
)&ImmByte
))
428 /* Exception occurred */
434 ULONG Immediate
= (ULONG
)((LONG
)ImmByte
); // Sign extend
437 /* Read the operands */
438 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
440 /* Exception occurred */
444 /* Calculate the result */
445 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
447 /* Unless this is CMP, write back the result */
448 if (ModRegRm
.Register
!= 7)
450 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
455 USHORT Immediate
= (USHORT
)((SHORT
)ImmByte
); // Sign extend
458 /* Read the operands */
459 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
461 /* Exception occurred */
465 /* Calculate the result */
466 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
468 /* Unless this is CMP, write back the result */
469 if (ModRegRm
.Register
!= 7)
471 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
478 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F
)
481 FAST486_MOD_REG_RM ModRegRm
;
482 BOOLEAN OperandSize
, AddressSize
;
484 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
486 TOGGLE_OPSIZE(OperandSize
);
487 TOGGLE_ADSIZE(AddressSize
);
489 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
491 /* Exception occurred */
495 if (ModRegRm
.Register
!= 0)
498 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
502 /* Pop a value from the stack */
503 if (!Fast486StackPop(State
, &Value
))
505 /* Exception occurred */
511 return Fast486WriteModrmDwordOperands(State
,
518 return Fast486WriteModrmWordOperands(State
,
525 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
527 UCHAR Dummy
, Value
, Count
;
528 FAST486_MOD_REG_RM ModRegRm
;
529 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
531 TOGGLE_ADSIZE(AddressSize
);
533 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
535 /* Exception occurred */
539 /* Fetch the count */
540 if (!Fast486FetchByte(State
, &Count
))
542 /* Exception occurred */
546 /* Read the operands */
547 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
549 /* Exception occurred */
553 /* Calculate the result */
554 Value
= LOBYTE(Fast486RotateOperation(State
,
560 /* Write back the result */
561 return Fast486WriteModrmByteOperands(State
,
567 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
570 FAST486_MOD_REG_RM ModRegRm
;
571 BOOLEAN OperandSize
, AddressSize
;
573 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
575 TOGGLE_OPSIZE(OperandSize
);
576 TOGGLE_ADSIZE(AddressSize
);
578 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
580 /* Exception occurred */
584 /* Fetch the count */
585 if (!Fast486FetchByte(State
, &Count
))
587 /* Exception occurred */
595 /* Read the operands */
596 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
598 /* Exception occurred */
602 /* Calculate the result */
603 Value
= Fast486RotateOperation(State
,
609 /* Write back the result */
610 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
616 /* Read the operands */
617 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
619 /* Exception occurred */
623 /* Calculate the result */
624 Value
= LOWORD(Fast486RotateOperation(State
,
630 /* Write back the result */
631 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
635 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
638 FAST486_MOD_REG_RM ModRegRm
;
639 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
641 TOGGLE_ADSIZE(AddressSize
);
643 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
645 /* Exception occurred */
649 if (ModRegRm
.Register
!= 0)
652 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
656 /* Get the immediate operand */
657 if (!Fast486FetchByte(State
, &Immediate
))
659 /* Exception occurred */
663 return Fast486WriteModrmByteOperands(State
,
669 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
671 FAST486_MOD_REG_RM ModRegRm
;
672 BOOLEAN OperandSize
, AddressSize
;
674 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
676 TOGGLE_OPSIZE(OperandSize
);
677 TOGGLE_ADSIZE(AddressSize
);
679 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
681 /* Exception occurred */
685 if (ModRegRm
.Register
!= 0)
688 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
696 /* Get the immediate operand */
697 if (!Fast486FetchDword(State
, &Immediate
))
699 /* Exception occurred */
703 return Fast486WriteModrmDwordOperands(State
,
712 /* Get the immediate operand */
713 if (!Fast486FetchWord(State
, &Immediate
))
715 /* Exception occurred */
719 return Fast486WriteModrmWordOperands(State
,
726 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
729 FAST486_MOD_REG_RM ModRegRm
;
730 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
732 TOGGLE_ADSIZE(AddressSize
);
734 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
736 /* Exception occurred */
740 /* Read the operands */
741 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
743 /* Exception occurred */
747 /* Calculate the result */
748 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
750 /* Write back the result */
751 return Fast486WriteModrmByteOperands(State
,
758 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
760 FAST486_MOD_REG_RM ModRegRm
;
761 BOOLEAN OperandSize
, AddressSize
;
763 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
765 TOGGLE_OPSIZE(OperandSize
);
766 TOGGLE_ADSIZE(AddressSize
);
768 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
770 /* Exception occurred */
778 /* Read the operands */
779 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
781 /* Exception occurred */
785 /* Calculate the result */
786 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
788 /* Write back the result */
789 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
795 /* Read the operands */
796 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
798 /* Exception occurred */
802 /* Calculate the result */
803 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
805 /* Write back the result */
806 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
810 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
813 FAST486_MOD_REG_RM ModRegRm
;
814 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
816 TOGGLE_ADSIZE(AddressSize
);
818 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
820 /* Exception occurred */
824 /* Read the operands */
825 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
827 /* Exception occurred */
831 /* Calculate the result */
832 Value
= LOBYTE(Fast486RotateOperation(State
,
836 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
838 /* Write back the result */
839 return Fast486WriteModrmByteOperands(State
,
845 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
847 FAST486_MOD_REG_RM ModRegRm
;
848 BOOLEAN OperandSize
, AddressSize
;
850 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
852 TOGGLE_OPSIZE(OperandSize
);
853 TOGGLE_ADSIZE(AddressSize
);
855 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
857 /* Exception occurred */
865 /* Read the operands */
866 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
868 /* Exception occurred */
872 /* Calculate the result */
873 Value
= Fast486RotateOperation(State
,
877 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
879 /* Write back the result */
880 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
886 /* Read the operands */
887 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
889 /* Exception occurred */
893 /* Calculate the result */
894 Value
= LOWORD(Fast486RotateOperation(State
,
898 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
900 /* Write back the result */
901 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
905 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
907 UCHAR Dummy
, Value
= 0;
908 FAST486_MOD_REG_RM ModRegRm
;
909 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
911 TOGGLE_ADSIZE(AddressSize
);
913 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
915 /* Exception occurred */
919 /* Read the operands */
920 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
922 /* Exception occurred */
926 switch (ModRegRm
.Register
)
932 UCHAR Immediate
, Result
;
934 /* Fetch the immediate byte */
935 if (!Fast486FetchByte(State
, &Immediate
))
937 /* Exception occurred */
941 /* Calculate the result */
942 Result
= Value
& Immediate
;
944 /* Update the flags */
945 State
->Flags
.Cf
= FALSE
;
946 State
->Flags
.Of
= FALSE
;
947 State
->Flags
.Zf
= (Result
== 0);
948 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
949 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
957 /* Write back the result */
958 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
964 /* Calculate the result */
965 UCHAR Result
= -Value
;
967 /* Update the flags */
968 State
->Flags
.Cf
= (Value
!= 0);
969 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
970 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
971 State
->Flags
.Zf
= (Result
== 0);
972 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
973 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
975 /* Write back the result */
976 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
982 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
984 /* Update the flags */
985 State
->Flags
.Cf
= State
->Flags
.Of
= (HIBYTE(Result
) != 0);
987 /* Write back the result */
988 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
996 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
998 /* Update the flags */
999 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -128) || (Result
> 127));
1001 /* Write back the result */
1002 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1010 UCHAR Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1011 UCHAR Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1013 /* Write back the results */
1014 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1015 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1023 CHAR Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1024 CHAR Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1026 /* Write back the results */
1027 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1028 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1037 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1039 ULONG Dummy
, Value
= 0, SignFlag
;
1040 FAST486_MOD_REG_RM ModRegRm
;
1041 BOOLEAN OperandSize
, AddressSize
;
1043 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1045 TOGGLE_OPSIZE(OperandSize
);
1046 TOGGLE_ADSIZE(AddressSize
);
1048 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1050 /* Exception occurred */
1054 /* Set the sign flag */
1055 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1056 else SignFlag
= SIGN_FLAG_WORD
;
1058 /* Read the operand */
1062 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1064 /* Exception occurred */
1071 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, (PUSHORT
)&Dummy
, (PUSHORT
)&Value
))
1073 /* Exception occurred */
1078 switch (ModRegRm
.Register
)
1084 ULONG Immediate
= 0, Result
= 0;
1088 /* Fetch the immediate dword */
1089 if (!Fast486FetchDword(State
, &Immediate
))
1091 /* Exception occurred */
1097 /* Fetch the immediate word */
1098 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1100 /* Exception occurred */
1105 /* Calculate the result */
1106 Result
= Value
& Immediate
;
1108 /* Update the flags */
1109 State
->Flags
.Cf
= FALSE
;
1110 State
->Flags
.Of
= FALSE
;
1111 State
->Flags
.Zf
= (Result
== 0);
1112 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1113 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1121 /* Write back the result */
1125 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1130 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1137 /* Calculate the result */
1138 ULONG Result
= -Value
;
1139 if (!OperandSize
) Result
&= 0xFFFF;
1141 /* Update the flags */
1142 State
->Flags
.Cf
= (Value
!= 0);
1143 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1144 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1145 State
->Flags
.Zf
= (Result
== 0);
1146 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1147 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1149 /* Write back the result */
1153 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1158 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1167 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1169 /* Update the flags */
1170 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1172 /* Write back the result */
1173 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1174 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1178 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1180 /* Update the flags */
1181 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1183 /* Write back the result */
1184 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1185 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1196 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1198 /* Update the flags */
1199 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1201 /* Write back the result */
1202 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1203 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1207 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1209 /* Update the flags */
1210 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1212 /* Write back the result */
1213 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1214 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1225 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1226 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1227 ULONG Quotient
= Dividend
/ Value
;
1228 ULONG Remainder
= Dividend
% Value
;
1230 /* Write back the results */
1231 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1232 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1236 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1237 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1238 USHORT Quotient
= Dividend
/ Value
;
1239 USHORT Remainder
= Dividend
% Value
;
1241 /* Write back the results */
1242 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1243 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1254 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1255 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1256 LONG Quotient
= Dividend
/ (LONG
)Value
;
1257 LONG Remainder
= Dividend
% (LONG
)Value
;
1259 /* Write back the results */
1260 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1261 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1265 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1266 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1267 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1268 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1270 /* Write back the results */
1271 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1272 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1282 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1285 FAST486_MOD_REG_RM ModRegRm
;
1286 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1288 TOGGLE_ADSIZE(AddressSize
);
1290 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1292 /* Exception occurred */
1296 if (ModRegRm
.Register
> 1)
1299 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1303 /* Read the operands */
1304 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1306 /* Exception occurred */
1310 if (ModRegRm
.Register
== 0)
1312 /* Increment and update OF and AF */
1314 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1315 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1319 /* Decrement and update OF and AF */
1320 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1322 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1326 State
->Flags
.Zf
= (Value
== 0);
1327 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1328 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1330 /* Write back the result */
1331 return Fast486WriteModrmByteOperands(State
,
1337 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1339 FAST486_MOD_REG_RM ModRegRm
;
1340 BOOLEAN OperandSize
, AddressSize
;
1342 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1344 TOGGLE_OPSIZE(OperandSize
);
1345 TOGGLE_ADSIZE(AddressSize
);
1347 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1349 /* Exception occurred */
1353 if (ModRegRm
.Register
== 7)
1356 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1360 /* Read the operands */
1365 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1367 /* Exception occurred */
1371 if (ModRegRm
.Register
== 0)
1373 /* Increment and update OF and AF */
1375 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1376 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1378 else if (ModRegRm
.Register
== 1)
1380 /* Decrement and update OF and AF */
1381 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1383 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1385 else if (ModRegRm
.Register
== 2)
1387 /* Push the current value of EIP */
1388 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1390 /* Exception occurred */
1394 /* Set the EIP to the address */
1395 State
->InstPtr
.Long
= Value
;
1397 else if (ModRegRm
.Register
== 3)
1400 INT Segment
= FAST486_REG_DS
;
1402 /* Check for the segment override */
1403 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1405 /* Use the override segment instead */
1406 Segment
= State
->SegmentOverride
;
1409 /* Read the selector */
1410 if (!Fast486ReadMemory(State
,
1412 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1417 /* Exception occurred */
1421 /* Push the current value of CS */
1422 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1424 /* Exception occurred */
1428 /* Push the current value of EIP */
1429 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1431 /* Exception occurred */
1435 /* Load the new code segment */
1436 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1438 /* Exception occurred */
1442 /* Set the EIP to the address */
1443 State
->InstPtr
.Long
= Value
;
1445 else if (ModRegRm
.Register
== 4)
1447 /* Set the EIP to the address */
1448 State
->InstPtr
.Long
= Value
;
1450 else if (ModRegRm
.Register
== 5)
1453 INT Segment
= FAST486_REG_DS
;
1455 /* Check for the segment override */
1456 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1458 /* Use the override segment instead */
1459 Segment
= State
->SegmentOverride
;
1462 /* Read the selector */
1463 if (!Fast486ReadMemory(State
,
1465 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1470 /* Exception occurred */
1474 /* Load the new code segment */
1475 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1477 /* Exception occurred */
1481 /* Set the EIP to the address */
1482 State
->InstPtr
.Long
= Value
;
1484 else if (ModRegRm
.Register
== 6)
1486 /* Push the value on to the stack */
1487 return Fast486StackPush(State
, Value
);
1490 if (ModRegRm
.Register
<= 1)
1493 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
1494 State
->Flags
.Zf
= (Value
== 0);
1495 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1497 /* Write back the result */
1498 return Fast486WriteModrmDwordOperands(State
,
1506 USHORT Dummy
, Value
;
1508 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1510 /* Exception occurred */
1514 if (ModRegRm
.Register
== 0)
1516 /* Increment and update OF */
1518 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1519 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1521 else if (ModRegRm
.Register
== 1)
1523 /* Decrement and update OF */
1524 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1526 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1528 else if (ModRegRm
.Register
== 2)
1530 /* Push the current value of IP */
1531 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1533 /* Exception occurred */
1537 /* Set the IP to the address */
1538 State
->InstPtr
.LowWord
= Value
;
1540 else if (ModRegRm
.Register
== 3)
1543 INT Segment
= FAST486_REG_DS
;
1545 /* Check for the segment override */
1546 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1548 /* Use the override segment instead */
1549 Segment
= State
->SegmentOverride
;
1552 /* Read the selector */
1553 if (!Fast486ReadMemory(State
,
1555 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1560 /* Exception occurred */
1564 /* Push the current value of CS */
1565 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1567 /* Exception occurred */
1571 /* Push the current value of IP */
1572 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1574 /* Exception occurred */
1578 /* Load the new code segment */
1579 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1581 /* Exception occurred */
1585 /* Set the IP to the address */
1586 State
->InstPtr
.LowWord
= Value
;
1589 else if (ModRegRm
.Register
== 4)
1591 /* Set the IP to the address */
1592 State
->InstPtr
.LowWord
= Value
;
1594 else if (ModRegRm
.Register
== 5)
1597 INT Segment
= FAST486_REG_DS
;
1599 /* Check for the segment override */
1600 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1602 /* Use the override segment instead */
1603 Segment
= State
->SegmentOverride
;
1606 /* Read the selector */
1607 if (!Fast486ReadMemory(State
,
1609 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1614 /* Exception occurred */
1618 /* Load the new code segment */
1619 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1621 /* Exception occurred */
1625 /* Set the IP to the address */
1626 State
->InstPtr
.LowWord
= Value
;
1628 else if (ModRegRm
.Register
== 6)
1630 /* Push the value on to the stack */
1631 return Fast486StackPush(State
, Value
);
1636 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1640 if (ModRegRm
.Register
<= 1)
1643 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1644 State
->Flags
.Zf
= (Value
== 0);
1645 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1647 /* Write back the result */
1648 return Fast486WriteModrmWordOperands(State
,
1658 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
1661 FAST486_MOD_REG_RM ModRegRm
;
1662 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1663 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1666 TOGGLE_ADSIZE(AddressSize
);
1668 /* Check for the segment override */
1669 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1671 /* Use the override segment instead */
1672 Segment
= State
->SegmentOverride
;
1675 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1677 /* Exception occurred */
1681 /* Check which operation this is */
1682 switch (ModRegRm
.Register
)
1687 if (!ModRegRm
.Memory
)
1689 /* The second operand must be a memory location */
1690 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1694 /* Fill the 6-byte table register */
1695 RtlCopyMemory(TableReg
, &State
->Gdtr
.Size
, sizeof(USHORT
));
1696 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Gdtr
.Address
, sizeof(ULONG
));
1698 /* Store the GDTR */
1699 return Fast486WriteMemory(State
,
1701 ModRegRm
.MemoryAddress
,
1709 if (!ModRegRm
.Memory
)
1711 /* The second operand must be a memory location */
1712 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1716 /* Fill the 6-byte table register */
1717 RtlCopyMemory(TableReg
, &State
->Idtr
.Size
, sizeof(USHORT
));
1718 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Idtr
.Address
, sizeof(ULONG
));
1720 /* Store the IDTR */
1721 return Fast486WriteMemory(State
,
1723 ModRegRm
.MemoryAddress
,
1731 /* This is a privileged instruction */
1732 if (Fast486GetCurrentPrivLevel(State
) != 0)
1734 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1738 if (!ModRegRm
.Memory
)
1740 /* The second operand must be a memory location */
1741 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1745 /* Read the new GDTR */
1746 if (!Fast486ReadMemory(State
,
1748 ModRegRm
.MemoryAddress
,
1753 /* Exception occurred */
1757 /* Load the new GDT */
1758 State
->Gdtr
.Size
= *((PUSHORT
)TableReg
);
1759 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1767 /* This is a privileged instruction */
1768 if (Fast486GetCurrentPrivLevel(State
) != 0)
1770 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1774 if (!ModRegRm
.Memory
)
1776 /* The second operand must be a memory location */
1777 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1781 /* Read the new IDTR */
1782 if (!Fast486ReadMemory(State
,
1784 ModRegRm
.MemoryAddress
,
1789 /* Exception occurred */
1793 /* Load the new IDT */
1794 State
->Idtr
.Size
= *((PUSHORT
)TableReg
);
1795 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1803 /* Store the lower 16 bits of CR0 */
1804 return Fast486WriteModrmWordOperands(State
,
1807 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
1813 USHORT MasterStatusWord
, Dummy
;
1815 /* This is a privileged instruction */
1816 if (Fast486GetCurrentPrivLevel(State
) != 0)
1818 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1822 /* Read the new master status word */
1823 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &MasterStatusWord
))
1825 /* Exception occurred */
1829 /* This instruction cannot be used to return to real mode */
1830 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1831 && !(MasterStatusWord
& FAST486_CR0_PE
))
1833 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1837 /* Set the lowest 4 bits */
1838 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
1839 State
->ControlRegisters
[FAST486_REG_CR0
] |= MasterStatusWord
& 0x0F;
1854 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1860 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
1862 FAST486_MOD_REG_RM ModRegRm
;
1863 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1865 TOGGLE_ADSIZE(AddressSize
);
1867 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1869 /* Exception occurred */
1873 /* All of them are reserved (UD2) */
1874 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1878 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
1880 FAST486_MOD_REG_RM ModRegRm
;
1881 BOOLEAN OperandSize
, AddressSize
;
1885 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1887 TOGGLE_OPSIZE(OperandSize
);
1888 TOGGLE_ADSIZE(AddressSize
);
1890 /* Get the number of bits */
1891 if (OperandSize
) DataSize
= 32;
1894 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1896 /* Exception occurred */
1900 if (ModRegRm
.Register
< 4)
1903 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1907 /* Get the bit number */
1908 if (!Fast486FetchByte(State
, &BitNumber
))
1910 /* Exception occurred */
1914 if (ModRegRm
.Memory
)
1917 * For memory operands, add the bit offset divided by
1918 * the data size to the address
1920 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1923 /* Normalize the bit number */
1924 BitNumber
%= DataSize
;
1930 /* Read the value */
1931 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1933 /* Exception occurred */
1937 /* Set CF to the bit value */
1938 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1940 if (ModRegRm
.Register
== 5)
1943 Value
|= 1 << BitNumber
;
1945 else if (ModRegRm
.Register
== 6)
1948 Value
&= ~(1 << BitNumber
);
1950 else if (ModRegRm
.Register
== 7)
1953 Value
^= 1 << BitNumber
;
1956 if (ModRegRm
.Register
>= 5)
1958 /* Write back the result */
1959 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1961 /* Exception occurred */
1968 USHORT Dummy
, Value
;
1970 /* Read the value */
1971 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1973 /* Exception occurred */
1977 /* Set CF to the bit value */
1978 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1980 if (ModRegRm
.Register
== 5)
1983 Value
|= 1 << BitNumber
;
1985 else if (ModRegRm
.Register
== 6)
1988 Value
&= ~(1 << BitNumber
);
1990 else if (ModRegRm
.Register
== 7)
1993 Value
^= 1 << BitNumber
;
1996 if (ModRegRm
.Register
>= 5)
1998 /* Write back the result */
1999 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2001 /* Exception occurred */
2007 /* Return success */