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);
166 /* Normalize the count */
169 /* If the count is zero, do nothing */
170 if (Count
== 0) goto SetFlags
;
172 /* Check which operation is this */
178 Result
= (Value
<< Count
) | (Value
>> (Bits
- Count
));
180 /* Update CF and OF */
181 State
->Flags
.Cf
= Result
& 1;
182 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
183 ^ ((Result
& HighestBit
) != 0);
191 Result
= (Value
>> Count
) | (Value
<< (Bits
- Count
));
193 /* Update CF and OF */
194 State
->Flags
.Cf
= ((Result
& HighestBit
) != 0);
195 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
196 ^ ((Result
& (HighestBit
>> 1)) != 0);
204 Result
= (Value
<< Count
)
205 | (State
->Flags
.Cf
<< (Count
- 1))
206 | (Value
>> (Bits
- Count
+ 1));
208 /* Update CF and OF */
209 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
210 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
211 ^ ((Result
& HighestBit
) != 0);
219 Result
= (Value
>> Count
)
220 | (State
->Flags
.Cf
<< (Bits
- Count
))
221 | (Value
<< (Bits
- Count
+ 1));
223 /* Update CF and OF */
224 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
225 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
226 ^ ((Result
& (HighestBit
>> 1)) != 0);
235 Result
= Value
<< Count
;
237 /* Update CF and OF */
238 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
239 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
240 ^ ((Result
& HighestBit
) != 0);
248 Result
= Value
>> Count
;
250 /* Update CF and OF */
251 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
252 if (Count
== 1) State
->Flags
.Of
= ((Value
& HighestBit
) != 0);
260 Result
= Value
>> Count
;
262 /* Fill the top Count bits with the sign bit */
263 if (Value
& HighestBit
) Result
|= ((1 << Count
) - 1) << (Bits
- Count
);
265 /* Update CF and OF */
266 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
267 if (Count
== 1) State
->Flags
.Of
= FALSE
;
276 /* Update ZF, SF and PF */
277 State
->Flags
.Zf
= (Result
== 0);
278 State
->Flags
.Sf
= ((Result
& HighestBit
) != 0);
279 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
282 /* Return the result */
286 /* PUBLIC FUNCTIONS ***********************************************************/
288 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082
)
290 UCHAR Immediate
, Dummy
, Value
;
291 FAST486_MOD_REG_RM ModRegRm
;
292 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
294 TOGGLE_ADSIZE(AddressSize
);
296 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
298 /* Exception occurred */
302 /* Fetch the immediate operand */
303 if (!Fast486FetchByte(State
, &Immediate
))
305 /* Exception occurred */
309 /* Read the operands */
310 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
312 /* Exception occurred */
316 /* Calculate the result */
317 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 8);
319 /* Unless this is CMP, write back the result */
320 if (ModRegRm
.Register
!= 7)
322 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
328 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81
)
330 FAST486_MOD_REG_RM ModRegRm
;
331 BOOLEAN OperandSize
, AddressSize
;
333 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
335 TOGGLE_OPSIZE(OperandSize
);
336 TOGGLE_ADSIZE(AddressSize
);
338 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
340 /* Exception occurred */
346 ULONG Immediate
, Value
, Dummy
;
348 /* Fetch the immediate operand */
349 if (!Fast486FetchDword(State
, &Immediate
))
351 /* Exception occurred */
355 /* Read the operands */
356 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
358 /* Exception occurred */
362 /* Calculate the result */
363 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
365 /* Unless this is CMP, write back the result */
366 if (ModRegRm
.Register
!= 7)
368 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
373 USHORT Immediate
, Value
, Dummy
;
375 /* Fetch the immediate operand */
376 if (!Fast486FetchWord(State
, &Immediate
))
378 /* Exception occurred */
382 /* Read the operands */
383 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
385 /* Exception occurred */
389 /* Calculate the result */
390 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
392 /* Unless this is CMP, write back the result */
393 if (ModRegRm
.Register
!= 7)
395 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
402 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83
)
405 FAST486_MOD_REG_RM ModRegRm
;
406 BOOLEAN OperandSize
, AddressSize
;
408 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
410 TOGGLE_OPSIZE(OperandSize
);
411 TOGGLE_ADSIZE(AddressSize
);
413 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
415 /* Exception occurred */
419 /* Fetch the immediate operand */
420 if (!Fast486FetchByte(State
, (PUCHAR
)&ImmByte
))
422 /* Exception occurred */
428 ULONG Immediate
= (ULONG
)((LONG
)ImmByte
); // Sign extend
431 /* Read the operands */
432 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
434 /* Exception occurred */
438 /* Calculate the result */
439 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
441 /* Unless this is CMP, write back the result */
442 if (ModRegRm
.Register
!= 7)
444 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
449 USHORT Immediate
= (USHORT
)((SHORT
)ImmByte
); // Sign extend
452 /* Read the operands */
453 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
455 /* Exception occurred */
459 /* Calculate the result */
460 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
462 /* Unless this is CMP, write back the result */
463 if (ModRegRm
.Register
!= 7)
465 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
472 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F
)
475 FAST486_MOD_REG_RM ModRegRm
;
476 BOOLEAN OperandSize
, AddressSize
;
478 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
480 TOGGLE_OPSIZE(OperandSize
);
481 TOGGLE_ADSIZE(AddressSize
);
483 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
485 /* Exception occurred */
489 if (ModRegRm
.Register
!= 0)
492 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
496 /* Pop a value from the stack */
497 if (!Fast486StackPop(State
, &Value
))
499 /* Exception occurred */
505 return Fast486WriteModrmDwordOperands(State
,
512 return Fast486WriteModrmWordOperands(State
,
519 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
521 UCHAR Dummy
, Value
, Count
;
522 FAST486_MOD_REG_RM ModRegRm
;
523 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
525 TOGGLE_ADSIZE(AddressSize
);
527 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
529 /* Exception occurred */
533 /* Fetch the count */
534 if (!Fast486FetchByte(State
, &Count
))
536 /* Exception occurred */
540 /* Read the operands */
541 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
543 /* Exception occurred */
547 /* Calculate the result */
548 Value
= LOBYTE(Fast486RotateOperation(State
,
554 /* Write back the result */
555 return Fast486WriteModrmByteOperands(State
,
561 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
564 FAST486_MOD_REG_RM ModRegRm
;
565 BOOLEAN OperandSize
, AddressSize
;
567 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
569 TOGGLE_OPSIZE(OperandSize
);
570 TOGGLE_ADSIZE(AddressSize
);
572 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
574 /* Exception occurred */
578 /* Fetch the count */
579 if (!Fast486FetchByte(State
, &Count
))
581 /* Exception occurred */
589 /* Read the operands */
590 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
592 /* Exception occurred */
596 /* Calculate the result */
597 Value
= Fast486RotateOperation(State
,
603 /* Write back the result */
604 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
610 /* Read the operands */
611 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
613 /* Exception occurred */
617 /* Calculate the result */
618 Value
= LOWORD(Fast486RotateOperation(State
,
624 /* Write back the result */
625 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
629 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
632 FAST486_MOD_REG_RM ModRegRm
;
633 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
635 TOGGLE_ADSIZE(AddressSize
);
637 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
639 /* Exception occurred */
643 if (ModRegRm
.Register
!= 0)
646 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
650 /* Get the immediate operand */
651 if (!Fast486FetchByte(State
, &Immediate
))
653 /* Exception occurred */
657 return Fast486WriteModrmByteOperands(State
,
663 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
665 FAST486_MOD_REG_RM ModRegRm
;
666 BOOLEAN OperandSize
, AddressSize
;
668 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
670 TOGGLE_OPSIZE(OperandSize
);
671 TOGGLE_ADSIZE(AddressSize
);
673 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
675 /* Exception occurred */
679 if (ModRegRm
.Register
!= 0)
682 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
690 /* Get the immediate operand */
691 if (!Fast486FetchDword(State
, &Immediate
))
693 /* Exception occurred */
697 return Fast486WriteModrmDwordOperands(State
,
706 /* Get the immediate operand */
707 if (!Fast486FetchWord(State
, &Immediate
))
709 /* Exception occurred */
713 return Fast486WriteModrmWordOperands(State
,
720 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
723 FAST486_MOD_REG_RM ModRegRm
;
724 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
726 TOGGLE_ADSIZE(AddressSize
);
728 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
730 /* Exception occurred */
734 /* Read the operands */
735 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
737 /* Exception occurred */
741 /* Calculate the result */
742 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
744 /* Write back the result */
745 return Fast486WriteModrmByteOperands(State
,
752 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
754 FAST486_MOD_REG_RM ModRegRm
;
755 BOOLEAN OperandSize
, AddressSize
;
757 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
759 TOGGLE_OPSIZE(OperandSize
);
760 TOGGLE_ADSIZE(AddressSize
);
762 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
764 /* Exception occurred */
772 /* Read the operands */
773 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
775 /* Exception occurred */
779 /* Calculate the result */
780 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
782 /* Write back the result */
783 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
789 /* Read the operands */
790 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
792 /* Exception occurred */
796 /* Calculate the result */
797 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
799 /* Write back the result */
800 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
804 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
807 FAST486_MOD_REG_RM ModRegRm
;
808 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
810 TOGGLE_ADSIZE(AddressSize
);
812 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
814 /* Exception occurred */
818 /* Read the operands */
819 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
821 /* Exception occurred */
825 /* Calculate the result */
826 Value
= LOBYTE(Fast486RotateOperation(State
,
830 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
832 /* Write back the result */
833 return Fast486WriteModrmByteOperands(State
,
839 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
841 FAST486_MOD_REG_RM ModRegRm
;
842 BOOLEAN OperandSize
, AddressSize
;
844 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
846 TOGGLE_OPSIZE(OperandSize
);
847 TOGGLE_ADSIZE(AddressSize
);
849 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
851 /* Exception occurred */
859 /* Read the operands */
860 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
862 /* Exception occurred */
866 /* Calculate the result */
867 Value
= Fast486RotateOperation(State
,
871 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
873 /* Write back the result */
874 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
880 /* Read the operands */
881 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
883 /* Exception occurred */
887 /* Calculate the result */
888 Value
= LOWORD(Fast486RotateOperation(State
,
892 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
894 /* Write back the result */
895 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
899 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
901 UCHAR Dummy
, Value
= 0;
902 FAST486_MOD_REG_RM ModRegRm
;
903 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
905 TOGGLE_ADSIZE(AddressSize
);
907 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
909 /* Exception occurred */
913 /* Read the operands */
914 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
916 /* Exception occurred */
920 switch (ModRegRm
.Register
)
926 UCHAR Immediate
, Result
;
928 /* Fetch the immediate byte */
929 if (!Fast486FetchByte(State
, &Immediate
))
931 /* Exception occurred */
935 /* Calculate the result */
936 Result
= Value
& Immediate
;
938 /* Update the flags */
939 State
->Flags
.Cf
= FALSE
;
940 State
->Flags
.Of
= FALSE
;
941 State
->Flags
.Zf
= (Result
== 0);
942 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
943 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
951 /* Write back the result */
952 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
958 /* Calculate the result */
959 UCHAR Result
= -Value
;
961 /* Update the flags */
962 State
->Flags
.Cf
= (Value
!= 0);
963 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
964 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
965 State
->Flags
.Zf
= (Result
== 0);
966 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
967 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
969 /* Write back the result */
970 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
976 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
978 /* Update the flags */
979 State
->Flags
.Cf
= State
->Flags
.Of
= (HIBYTE(Result
) != 0);
981 /* Write back the result */
982 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
990 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
992 /* Update the flags */
993 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -128) || (Result
> 127));
995 /* Write back the result */
996 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1004 UCHAR Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1005 UCHAR Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1007 /* Write back the results */
1008 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1009 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1017 CHAR Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1018 CHAR Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1020 /* Write back the results */
1021 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1022 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1031 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1033 ULONG Dummy
, Value
= 0, SignFlag
;
1034 FAST486_MOD_REG_RM ModRegRm
;
1035 BOOLEAN OperandSize
, AddressSize
;
1037 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1039 TOGGLE_OPSIZE(OperandSize
);
1040 TOGGLE_ADSIZE(AddressSize
);
1042 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1044 /* Exception occurred */
1048 /* Set the sign flag */
1049 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1050 else SignFlag
= SIGN_FLAG_WORD
;
1052 /* Read the operand */
1056 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1058 /* Exception occurred */
1065 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, (PUSHORT
)&Dummy
, (PUSHORT
)&Value
))
1067 /* Exception occurred */
1072 switch (ModRegRm
.Register
)
1078 ULONG Immediate
= 0, Result
= 0;
1082 /* Fetch the immediate dword */
1083 if (!Fast486FetchDword(State
, &Immediate
))
1085 /* Exception occurred */
1091 /* Fetch the immediate word */
1092 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1094 /* Exception occurred */
1099 /* Calculate the result */
1100 Result
= Value
& Immediate
;
1102 /* Update the flags */
1103 State
->Flags
.Cf
= FALSE
;
1104 State
->Flags
.Of
= FALSE
;
1105 State
->Flags
.Zf
= (Result
== 0);
1106 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1107 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1115 /* Write back the result */
1119 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1124 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1131 /* Calculate the result */
1132 ULONG Result
= -Value
;
1133 if (!OperandSize
) Result
&= 0xFFFF;
1135 /* Update the flags */
1136 State
->Flags
.Cf
= (Value
!= 0);
1137 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1138 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1139 State
->Flags
.Zf
= (Result
== 0);
1140 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1141 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1143 /* Write back the result */
1147 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1152 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1161 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1163 /* Update the flags */
1164 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1166 /* Write back the result */
1167 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1168 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1172 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1174 /* Update the flags */
1175 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1177 /* Write back the result */
1178 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1179 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1190 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1192 /* Update the flags */
1193 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1195 /* Write back the result */
1196 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1197 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1201 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1203 /* Update the flags */
1204 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1206 /* Write back the result */
1207 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1208 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1219 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1220 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1221 ULONG Quotient
= Dividend
/ Value
;
1222 ULONG Remainder
= Dividend
% Value
;
1224 /* Write back the results */
1225 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1226 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1230 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1231 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1232 USHORT Quotient
= Dividend
/ Value
;
1233 USHORT Remainder
= Dividend
% Value
;
1235 /* Write back the results */
1236 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1237 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1248 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1249 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1250 LONG Quotient
= Dividend
/ (LONG
)Value
;
1251 LONG Remainder
= Dividend
% (LONG
)Value
;
1253 /* Write back the results */
1254 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1255 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1259 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1260 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1261 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1262 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1264 /* Write back the results */
1265 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1266 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1276 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1279 FAST486_MOD_REG_RM ModRegRm
;
1280 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1282 TOGGLE_ADSIZE(AddressSize
);
1284 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1286 /* Exception occurred */
1290 if (ModRegRm
.Register
> 1)
1293 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1297 /* Read the operands */
1298 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1300 /* Exception occurred */
1304 if (ModRegRm
.Register
== 0)
1306 /* Increment and update OF and AF */
1308 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1309 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1313 /* Decrement and update OF and AF */
1314 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1316 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1320 State
->Flags
.Zf
= (Value
== 0);
1321 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1322 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1324 /* Write back the result */
1325 return Fast486WriteModrmByteOperands(State
,
1331 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1333 FAST486_MOD_REG_RM ModRegRm
;
1334 BOOLEAN OperandSize
, AddressSize
;
1336 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1338 TOGGLE_OPSIZE(OperandSize
);
1339 TOGGLE_ADSIZE(AddressSize
);
1341 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1343 /* Exception occurred */
1347 if (ModRegRm
.Register
== 7)
1350 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1354 /* Read the operands */
1359 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1361 /* Exception occurred */
1365 if (ModRegRm
.Register
== 0)
1367 /* Increment and update OF and AF */
1369 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1370 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1372 else if (ModRegRm
.Register
== 1)
1374 /* Decrement and update OF and AF */
1375 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1377 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1379 else if (ModRegRm
.Register
== 2)
1381 /* Push the current value of EIP */
1382 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1384 /* Exception occurred */
1388 /* Set the EIP to the address */
1389 State
->InstPtr
.Long
= Value
;
1391 else if (ModRegRm
.Register
== 3)
1394 INT Segment
= FAST486_REG_DS
;
1396 /* Check for the segment override */
1397 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1399 /* Use the override segment instead */
1400 Segment
= State
->SegmentOverride
;
1403 /* Read the selector */
1404 if (!Fast486ReadMemory(State
,
1406 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1411 /* Exception occurred */
1415 /* Push the current value of CS */
1416 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1418 /* Exception occurred */
1422 /* Push the current value of EIP */
1423 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1425 /* Exception occurred */
1429 /* Load the new code segment */
1430 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1432 /* Exception occurred */
1436 /* Set the EIP to the address */
1437 State
->InstPtr
.Long
= Value
;
1439 else if (ModRegRm
.Register
== 4)
1441 /* Set the EIP to the address */
1442 State
->InstPtr
.Long
= Value
;
1444 else if (ModRegRm
.Register
== 5)
1447 INT Segment
= FAST486_REG_DS
;
1449 /* Check for the segment override */
1450 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1452 /* Use the override segment instead */
1453 Segment
= State
->SegmentOverride
;
1456 /* Read the selector */
1457 if (!Fast486ReadMemory(State
,
1459 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1464 /* Exception occurred */
1468 /* Load the new code segment */
1469 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1471 /* Exception occurred */
1475 /* Set the EIP to the address */
1476 State
->InstPtr
.Long
= Value
;
1478 else if (ModRegRm
.Register
== 6)
1480 /* Push the value on to the stack */
1481 return Fast486StackPush(State
, Value
);
1484 if (ModRegRm
.Register
<= 1)
1487 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
1488 State
->Flags
.Zf
= (Value
== 0);
1489 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1491 /* Write back the result */
1492 return Fast486WriteModrmDwordOperands(State
,
1500 USHORT Dummy
, Value
;
1502 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1504 /* Exception occurred */
1508 if (ModRegRm
.Register
== 0)
1510 /* Increment and update OF */
1512 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1513 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1515 else if (ModRegRm
.Register
== 1)
1517 /* Decrement and update OF */
1518 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1520 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1522 else if (ModRegRm
.Register
== 2)
1524 /* Push the current value of IP */
1525 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1527 /* Exception occurred */
1531 /* Set the IP to the address */
1532 State
->InstPtr
.LowWord
= Value
;
1534 else if (ModRegRm
.Register
== 3)
1537 INT Segment
= FAST486_REG_DS
;
1539 /* Check for the segment override */
1540 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1542 /* Use the override segment instead */
1543 Segment
= State
->SegmentOverride
;
1546 /* Read the selector */
1547 if (!Fast486ReadMemory(State
,
1549 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1554 /* Exception occurred */
1558 /* Push the current value of CS */
1559 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1561 /* Exception occurred */
1565 /* Push the current value of IP */
1566 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1568 /* Exception occurred */
1572 /* Load the new code segment */
1573 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1575 /* Exception occurred */
1579 /* Set the IP to the address */
1580 State
->InstPtr
.LowWord
= Value
;
1583 else if (ModRegRm
.Register
== 4)
1585 /* Set the IP to the address */
1586 State
->InstPtr
.LowWord
= Value
;
1588 else if (ModRegRm
.Register
== 5)
1591 INT Segment
= FAST486_REG_DS
;
1593 /* Check for the segment override */
1594 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1596 /* Use the override segment instead */
1597 Segment
= State
->SegmentOverride
;
1600 /* Read the selector */
1601 if (!Fast486ReadMemory(State
,
1603 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1608 /* Exception occurred */
1612 /* Load the new code segment */
1613 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1615 /* Exception occurred */
1619 /* Set the IP to the address */
1620 State
->InstPtr
.LowWord
= Value
;
1622 else if (ModRegRm
.Register
== 6)
1624 /* Push the value on to the stack */
1625 return Fast486StackPush(State
, Value
);
1630 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1634 if (ModRegRm
.Register
<= 1)
1637 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1638 State
->Flags
.Zf
= (Value
== 0);
1639 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1641 /* Write back the result */
1642 return Fast486WriteModrmWordOperands(State
,
1652 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
1655 FAST486_MOD_REG_RM ModRegRm
;
1656 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1657 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1660 TOGGLE_ADSIZE(AddressSize
);
1662 /* Check for the segment override */
1663 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1665 /* Use the override segment instead */
1666 Segment
= State
->SegmentOverride
;
1669 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1671 /* Exception occurred */
1675 /* Check which operation this is */
1676 switch (ModRegRm
.Register
)
1681 if (!ModRegRm
.Memory
)
1683 /* The second operand must be a memory location */
1684 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1688 /* Fill the 6-byte table register */
1689 RtlCopyMemory(TableReg
, &State
->Gdtr
.Size
, sizeof(USHORT
));
1690 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Gdtr
.Address
, sizeof(ULONG
));
1692 /* Store the GDTR */
1693 return Fast486WriteMemory(State
,
1695 ModRegRm
.MemoryAddress
,
1703 if (!ModRegRm
.Memory
)
1705 /* The second operand must be a memory location */
1706 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1710 /* Fill the 6-byte table register */
1711 RtlCopyMemory(TableReg
, &State
->Idtr
.Size
, sizeof(USHORT
));
1712 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Idtr
.Address
, sizeof(ULONG
));
1714 /* Store the IDTR */
1715 return Fast486WriteMemory(State
,
1717 ModRegRm
.MemoryAddress
,
1725 /* This is a privileged instruction */
1726 if (Fast486GetCurrentPrivLevel(State
) != 0)
1728 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1732 if (!ModRegRm
.Memory
)
1734 /* The second operand must be a memory location */
1735 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1739 /* Read the new GDTR */
1740 if (!Fast486ReadMemory(State
,
1742 ModRegRm
.MemoryAddress
,
1747 /* Exception occurred */
1751 /* Load the new GDT */
1752 State
->Gdtr
.Size
= *((PUSHORT
)TableReg
);
1753 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1761 /* This is a privileged instruction */
1762 if (Fast486GetCurrentPrivLevel(State
) != 0)
1764 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1768 if (!ModRegRm
.Memory
)
1770 /* The second operand must be a memory location */
1771 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1775 /* Read the new IDTR */
1776 if (!Fast486ReadMemory(State
,
1778 ModRegRm
.MemoryAddress
,
1783 /* Exception occurred */
1787 /* Load the new IDT */
1788 State
->Idtr
.Size
= *((PUSHORT
)TableReg
);
1789 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1797 /* Store the lower 16 bits of CR0 */
1798 return Fast486WriteModrmWordOperands(State
,
1801 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
1807 USHORT MasterStatusWord
, Dummy
;
1809 /* This is a privileged instruction */
1810 if (Fast486GetCurrentPrivLevel(State
) != 0)
1812 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1816 /* Read the new master status word */
1817 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &MasterStatusWord
))
1819 /* Exception occurred */
1823 /* This instruction cannot be used to return to real mode */
1824 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1825 && !(MasterStatusWord
& FAST486_CR0_PE
))
1827 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1831 /* Set the lowest 4 bits */
1832 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
1833 State
->ControlRegisters
[FAST486_REG_CR0
] |= MasterStatusWord
& 0x0F;
1848 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1854 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
1856 FAST486_MOD_REG_RM ModRegRm
;
1857 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1859 TOGGLE_ADSIZE(AddressSize
);
1861 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1863 /* Exception occurred */
1867 /* All of them are reserved (UD2) */
1868 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1872 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
1874 FAST486_MOD_REG_RM ModRegRm
;
1875 BOOLEAN OperandSize
, AddressSize
;
1879 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1881 TOGGLE_OPSIZE(OperandSize
);
1882 TOGGLE_ADSIZE(AddressSize
);
1884 /* Get the number of bits */
1885 if (OperandSize
) DataSize
= 32;
1888 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1890 /* Exception occurred */
1894 if (ModRegRm
.Register
< 4)
1897 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1901 /* Get the bit number */
1902 if (!Fast486FetchByte(State
, &BitNumber
))
1904 /* Exception occurred */
1908 if (ModRegRm
.Memory
)
1911 * For memory operands, add the bit offset divided by
1912 * the data size to the address
1914 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1917 /* Normalize the bit number */
1918 BitNumber
&= (1 << DataSize
) - 1;
1924 /* Read the value */
1925 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1927 /* Exception occurred */
1931 /* Set CF to the bit value */
1932 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1934 if (ModRegRm
.Register
== 5)
1937 Value
|= 1 << BitNumber
;
1939 else if (ModRegRm
.Register
== 6)
1942 Value
&= ~(1 << BitNumber
);
1944 else if (ModRegRm
.Register
== 7)
1947 Value
^= 1 << BitNumber
;
1950 if (ModRegRm
.Register
>= 5)
1952 /* Write back the result */
1953 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1955 /* Exception occurred */
1962 USHORT Dummy
, Value
;
1964 /* Read the value */
1965 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1967 /* Exception occurred */
1971 /* Set CF to the bit value */
1972 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1974 if (ModRegRm
.Register
== 5)
1977 Value
|= 1 << BitNumber
;
1979 else if (ModRegRm
.Register
== 6)
1982 Value
&= ~(1 << BitNumber
);
1984 else if (ModRegRm
.Register
== 7)
1987 Value
^= 1 << BitNumber
;
1990 if (ModRegRm
.Register
>= 5)
1992 /* Write back the result */
1993 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1995 /* Exception occurred */
2001 /* Return success */