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 */
176 /* 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);
195 Result
= (Value
>> Count
) | (Value
<< (Bits
- Count
));
197 /* Update CF and OF */
198 State
->Flags
.Cf
= ((Result
& HighestBit
) != 0);
199 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
200 ^ ((Result
& (HighestBit
>> 1)) != 0);
208 Result
= (Value
<< Count
)
209 | (State
->Flags
.Cf
<< (Count
- 1))
210 | (Value
>> (Bits
- Count
+ 1));
212 /* Update CF and OF */
213 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
214 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
215 ^ ((Result
& HighestBit
) != 0);
223 Result
= (Value
>> Count
)
224 | (State
->Flags
.Cf
<< (Bits
- Count
))
225 | (Value
<< (Bits
- Count
+ 1));
227 /* Update CF and OF */
228 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
229 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
230 ^ ((Result
& (HighestBit
>> 1)) != 0);
239 Result
= Value
<< Count
;
241 /* Update CF and OF */
242 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
243 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
244 ^ ((Result
& HighestBit
) != 0);
252 Result
= Value
>> Count
;
254 /* Update CF and OF */
255 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
256 if (Count
== 1) State
->Flags
.Of
= ((Value
& HighestBit
) != 0);
264 Result
= Value
>> Count
;
266 /* Fill the top Count bits with the sign bit */
267 if (Value
& HighestBit
) Result
|= ((1 << Count
) - 1) << (Bits
- Count
);
269 /* Update CF and OF */
270 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
271 if (Count
== 1) State
->Flags
.Of
= FALSE
;
280 /* Update ZF, SF and PF */
281 State
->Flags
.Zf
= (Result
== 0);
282 State
->Flags
.Sf
= ((Result
& HighestBit
) != 0);
283 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
286 /* Return the result */
290 /* PUBLIC FUNCTIONS ***********************************************************/
292 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082
)
294 UCHAR Immediate
, Dummy
, Value
;
295 FAST486_MOD_REG_RM ModRegRm
;
296 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
298 TOGGLE_ADSIZE(AddressSize
);
300 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
302 /* Exception occurred */
306 /* Fetch the immediate operand */
307 if (!Fast486FetchByte(State
, &Immediate
))
309 /* Exception occurred */
313 /* Read the operands */
314 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
316 /* Exception occurred */
320 /* Calculate the result */
321 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 8);
323 /* Unless this is CMP, write back the result */
324 if (ModRegRm
.Register
!= 7)
326 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
332 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81
)
334 FAST486_MOD_REG_RM ModRegRm
;
335 BOOLEAN OperandSize
, AddressSize
;
337 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
339 TOGGLE_OPSIZE(OperandSize
);
340 TOGGLE_ADSIZE(AddressSize
);
342 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
344 /* Exception occurred */
350 ULONG Immediate
, Value
, Dummy
;
352 /* Fetch the immediate operand */
353 if (!Fast486FetchDword(State
, &Immediate
))
355 /* Exception occurred */
359 /* Read the operands */
360 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
362 /* Exception occurred */
366 /* Calculate the result */
367 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
369 /* Unless this is CMP, write back the result */
370 if (ModRegRm
.Register
!= 7)
372 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
377 USHORT Immediate
, Value
, Dummy
;
379 /* Fetch the immediate operand */
380 if (!Fast486FetchWord(State
, &Immediate
))
382 /* Exception occurred */
386 /* Read the operands */
387 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
389 /* Exception occurred */
393 /* Calculate the result */
394 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
396 /* Unless this is CMP, write back the result */
397 if (ModRegRm
.Register
!= 7)
399 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
406 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83
)
409 FAST486_MOD_REG_RM ModRegRm
;
410 BOOLEAN OperandSize
, AddressSize
;
412 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
414 TOGGLE_OPSIZE(OperandSize
);
415 TOGGLE_ADSIZE(AddressSize
);
417 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
419 /* Exception occurred */
423 /* Fetch the immediate operand */
424 if (!Fast486FetchByte(State
, (PUCHAR
)&ImmByte
))
426 /* Exception occurred */
432 ULONG Immediate
= (ULONG
)((LONG
)ImmByte
); // Sign extend
435 /* Read the operands */
436 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
438 /* Exception occurred */
442 /* Calculate the result */
443 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
445 /* Unless this is CMP, write back the result */
446 if (ModRegRm
.Register
!= 7)
448 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
453 USHORT Immediate
= (USHORT
)((SHORT
)ImmByte
); // Sign extend
456 /* Read the operands */
457 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
459 /* Exception occurred */
463 /* Calculate the result */
464 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
466 /* Unless this is CMP, write back the result */
467 if (ModRegRm
.Register
!= 7)
469 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
476 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F
)
479 FAST486_MOD_REG_RM ModRegRm
;
480 BOOLEAN OperandSize
, AddressSize
;
482 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
484 TOGGLE_OPSIZE(OperandSize
);
485 TOGGLE_ADSIZE(AddressSize
);
487 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
489 /* Exception occurred */
493 if (ModRegRm
.Register
!= 0)
496 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
500 /* Pop a value from the stack */
501 if (!Fast486StackPop(State
, &Value
))
503 /* Exception occurred */
509 return Fast486WriteModrmDwordOperands(State
,
516 return Fast486WriteModrmWordOperands(State
,
523 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
525 UCHAR Dummy
, Value
, Count
;
526 FAST486_MOD_REG_RM ModRegRm
;
527 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
529 TOGGLE_ADSIZE(AddressSize
);
531 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
533 /* Exception occurred */
537 /* Fetch the count */
538 if (!Fast486FetchByte(State
, &Count
))
540 /* Exception occurred */
544 /* Read the operands */
545 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
547 /* Exception occurred */
551 /* Calculate the result */
552 Value
= LOBYTE(Fast486RotateOperation(State
,
558 /* Write back the result */
559 return Fast486WriteModrmByteOperands(State
,
565 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
568 FAST486_MOD_REG_RM ModRegRm
;
569 BOOLEAN OperandSize
, AddressSize
;
571 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
573 TOGGLE_OPSIZE(OperandSize
);
574 TOGGLE_ADSIZE(AddressSize
);
576 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
578 /* Exception occurred */
582 /* Fetch the count */
583 if (!Fast486FetchByte(State
, &Count
))
585 /* Exception occurred */
593 /* Read the operands */
594 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
596 /* Exception occurred */
600 /* Calculate the result */
601 Value
= Fast486RotateOperation(State
,
607 /* Write back the result */
608 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
614 /* Read the operands */
615 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
617 /* Exception occurred */
621 /* Calculate the result */
622 Value
= LOWORD(Fast486RotateOperation(State
,
628 /* Write back the result */
629 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
633 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
636 FAST486_MOD_REG_RM ModRegRm
;
637 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
639 TOGGLE_ADSIZE(AddressSize
);
641 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
643 /* Exception occurred */
647 if (ModRegRm
.Register
!= 0)
650 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
654 /* Get the immediate operand */
655 if (!Fast486FetchByte(State
, &Immediate
))
657 /* Exception occurred */
661 return Fast486WriteModrmByteOperands(State
,
667 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
669 FAST486_MOD_REG_RM ModRegRm
;
670 BOOLEAN OperandSize
, AddressSize
;
672 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
674 TOGGLE_OPSIZE(OperandSize
);
675 TOGGLE_ADSIZE(AddressSize
);
677 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
679 /* Exception occurred */
683 if (ModRegRm
.Register
!= 0)
686 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
694 /* Get the immediate operand */
695 if (!Fast486FetchDword(State
, &Immediate
))
697 /* Exception occurred */
701 return Fast486WriteModrmDwordOperands(State
,
710 /* Get the immediate operand */
711 if (!Fast486FetchWord(State
, &Immediate
))
713 /* Exception occurred */
717 return Fast486WriteModrmWordOperands(State
,
724 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
727 FAST486_MOD_REG_RM ModRegRm
;
728 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
730 TOGGLE_ADSIZE(AddressSize
);
732 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
734 /* Exception occurred */
738 /* Read the operands */
739 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
741 /* Exception occurred */
745 /* Calculate the result */
746 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
748 /* Write back the result */
749 return Fast486WriteModrmByteOperands(State
,
756 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
758 FAST486_MOD_REG_RM ModRegRm
;
759 BOOLEAN OperandSize
, AddressSize
;
761 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
763 TOGGLE_OPSIZE(OperandSize
);
764 TOGGLE_ADSIZE(AddressSize
);
766 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
768 /* Exception occurred */
776 /* Read the operands */
777 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
779 /* Exception occurred */
783 /* Calculate the result */
784 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
786 /* Write back the result */
787 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
793 /* Read the operands */
794 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
796 /* Exception occurred */
800 /* Calculate the result */
801 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
803 /* Write back the result */
804 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
808 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
811 FAST486_MOD_REG_RM ModRegRm
;
812 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
814 TOGGLE_ADSIZE(AddressSize
);
816 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
818 /* Exception occurred */
822 /* Read the operands */
823 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
825 /* Exception occurred */
829 /* Calculate the result */
830 Value
= LOBYTE(Fast486RotateOperation(State
,
834 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
836 /* Write back the result */
837 return Fast486WriteModrmByteOperands(State
,
843 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
845 FAST486_MOD_REG_RM ModRegRm
;
846 BOOLEAN OperandSize
, AddressSize
;
848 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
850 TOGGLE_OPSIZE(OperandSize
);
851 TOGGLE_ADSIZE(AddressSize
);
853 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
855 /* Exception occurred */
863 /* Read the operands */
864 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
866 /* Exception occurred */
870 /* Calculate the result */
871 Value
= Fast486RotateOperation(State
,
875 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
877 /* Write back the result */
878 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
884 /* Read the operands */
885 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
887 /* Exception occurred */
891 /* Calculate the result */
892 Value
= LOWORD(Fast486RotateOperation(State
,
896 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
898 /* Write back the result */
899 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
903 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
905 UCHAR Dummy
, Value
= 0;
906 FAST486_MOD_REG_RM ModRegRm
;
907 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
909 TOGGLE_ADSIZE(AddressSize
);
911 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
913 /* Exception occurred */
917 /* Read the operands */
918 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
920 /* Exception occurred */
924 switch (ModRegRm
.Register
)
930 UCHAR Immediate
, Result
;
932 /* Fetch the immediate byte */
933 if (!Fast486FetchByte(State
, &Immediate
))
935 /* Exception occurred */
939 /* Calculate the result */
940 Result
= Value
& Immediate
;
942 /* Update the flags */
943 State
->Flags
.Cf
= FALSE
;
944 State
->Flags
.Of
= FALSE
;
945 State
->Flags
.Zf
= (Result
== 0);
946 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
947 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
955 /* Write back the result */
956 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
962 /* Calculate the result */
963 UCHAR Result
= -Value
;
965 /* Update the flags */
966 State
->Flags
.Cf
= (Value
!= 0);
967 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
968 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
969 State
->Flags
.Zf
= (Result
== 0);
970 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
971 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
973 /* Write back the result */
974 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
980 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
982 /* Update the flags */
983 State
->Flags
.Cf
= State
->Flags
.Of
= (HIBYTE(Result
) != 0);
985 /* Write back the result */
986 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
994 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
996 /* Update the flags */
997 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -128) || (Result
> 127));
999 /* Write back the result */
1000 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1008 UCHAR Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1009 UCHAR Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1011 /* Write back the results */
1012 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1013 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1021 CHAR Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1022 CHAR Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1024 /* Write back the results */
1025 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1026 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1035 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1037 ULONG Dummy
, Value
= 0, SignFlag
;
1038 FAST486_MOD_REG_RM ModRegRm
;
1039 BOOLEAN OperandSize
, AddressSize
;
1041 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1043 TOGGLE_OPSIZE(OperandSize
);
1044 TOGGLE_ADSIZE(AddressSize
);
1046 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1048 /* Exception occurred */
1052 /* Set the sign flag */
1053 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1054 else SignFlag
= SIGN_FLAG_WORD
;
1056 /* Read the operand */
1060 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1062 /* Exception occurred */
1069 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, (PUSHORT
)&Dummy
, (PUSHORT
)&Value
))
1071 /* Exception occurred */
1076 switch (ModRegRm
.Register
)
1082 ULONG Immediate
= 0, Result
= 0;
1086 /* Fetch the immediate dword */
1087 if (!Fast486FetchDword(State
, &Immediate
))
1089 /* Exception occurred */
1095 /* Fetch the immediate word */
1096 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1098 /* Exception occurred */
1103 /* Calculate the result */
1104 Result
= Value
& Immediate
;
1106 /* Update the flags */
1107 State
->Flags
.Cf
= FALSE
;
1108 State
->Flags
.Of
= FALSE
;
1109 State
->Flags
.Zf
= (Result
== 0);
1110 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1111 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1119 /* Write back the result */
1123 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1128 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1135 /* Calculate the result */
1136 ULONG Result
= -Value
;
1137 if (!OperandSize
) Result
&= 0xFFFF;
1139 /* Update the flags */
1140 State
->Flags
.Cf
= (Value
!= 0);
1141 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1142 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1143 State
->Flags
.Zf
= (Result
== 0);
1144 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1145 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1147 /* Write back the result */
1151 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1156 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1165 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1167 /* Update the flags */
1168 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1170 /* Write back the result */
1171 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1172 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1176 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1178 /* Update the flags */
1179 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1181 /* Write back the result */
1182 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1183 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1194 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1196 /* Update the flags */
1197 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1199 /* Write back the result */
1200 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1201 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1205 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1207 /* Update the flags */
1208 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1210 /* Write back the result */
1211 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1212 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1223 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1224 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1225 ULONG Quotient
= Dividend
/ Value
;
1226 ULONG Remainder
= Dividend
% Value
;
1228 /* Write back the results */
1229 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1230 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1234 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1235 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1236 USHORT Quotient
= Dividend
/ Value
;
1237 USHORT Remainder
= Dividend
% Value
;
1239 /* Write back the results */
1240 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1241 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1252 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1253 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1254 LONG Quotient
= Dividend
/ (LONG
)Value
;
1255 LONG Remainder
= Dividend
% (LONG
)Value
;
1257 /* Write back the results */
1258 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1259 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1263 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1264 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1265 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1266 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1268 /* Write back the results */
1269 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1270 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1280 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1283 FAST486_MOD_REG_RM ModRegRm
;
1284 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1286 TOGGLE_ADSIZE(AddressSize
);
1288 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1290 /* Exception occurred */
1294 if (ModRegRm
.Register
> 1)
1297 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1301 /* Read the operands */
1302 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1304 /* Exception occurred */
1308 if (ModRegRm
.Register
== 0)
1310 /* Increment and update OF and AF */
1312 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1313 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1317 /* Decrement and update OF and AF */
1318 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1320 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1324 State
->Flags
.Zf
= (Value
== 0);
1325 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1326 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1328 /* Write back the result */
1329 return Fast486WriteModrmByteOperands(State
,
1335 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1337 FAST486_MOD_REG_RM ModRegRm
;
1338 BOOLEAN OperandSize
, AddressSize
;
1340 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1342 TOGGLE_OPSIZE(OperandSize
);
1343 TOGGLE_ADSIZE(AddressSize
);
1345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1347 /* Exception occurred */
1351 if (ModRegRm
.Register
== 7)
1354 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1358 /* Read the operands */
1363 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1365 /* Exception occurred */
1369 if (ModRegRm
.Register
== 0)
1371 /* Increment and update OF and AF */
1373 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1374 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1376 else if (ModRegRm
.Register
== 1)
1378 /* Decrement and update OF and AF */
1379 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1381 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1383 else if (ModRegRm
.Register
== 2)
1385 /* Push the current value of EIP */
1386 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1388 /* Exception occurred */
1392 /* Set the EIP to the address */
1393 State
->InstPtr
.Long
= Value
;
1395 else if (ModRegRm
.Register
== 3)
1398 INT Segment
= FAST486_REG_DS
;
1400 /* Check for the segment override */
1401 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1403 /* Use the override segment instead */
1404 Segment
= State
->SegmentOverride
;
1407 /* Read the selector */
1408 if (!Fast486ReadMemory(State
,
1410 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1415 /* Exception occurred */
1419 /* Push the current value of CS */
1420 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1422 /* Exception occurred */
1426 /* Push the current value of EIP */
1427 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1429 /* Exception occurred */
1433 /* Load the new code segment */
1434 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1436 /* Exception occurred */
1440 /* Set the EIP to the address */
1441 State
->InstPtr
.Long
= Value
;
1443 else if (ModRegRm
.Register
== 4)
1445 /* Set the EIP to the address */
1446 State
->InstPtr
.Long
= Value
;
1448 else if (ModRegRm
.Register
== 5)
1451 INT Segment
= FAST486_REG_DS
;
1453 /* Check for the segment override */
1454 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1456 /* Use the override segment instead */
1457 Segment
= State
->SegmentOverride
;
1460 /* Read the selector */
1461 if (!Fast486ReadMemory(State
,
1463 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1468 /* Exception occurred */
1472 /* Load the new code segment */
1473 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1475 /* Exception occurred */
1479 /* Set the EIP to the address */
1480 State
->InstPtr
.Long
= Value
;
1482 else if (ModRegRm
.Register
== 6)
1484 /* Push the value on to the stack */
1485 return Fast486StackPush(State
, Value
);
1488 if (ModRegRm
.Register
<= 1)
1491 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
1492 State
->Flags
.Zf
= (Value
== 0);
1493 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1495 /* Write back the result */
1496 return Fast486WriteModrmDwordOperands(State
,
1504 USHORT Dummy
, Value
;
1506 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1508 /* Exception occurred */
1512 if (ModRegRm
.Register
== 0)
1514 /* Increment and update OF */
1516 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1517 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1519 else if (ModRegRm
.Register
== 1)
1521 /* Decrement and update OF */
1522 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1524 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1526 else if (ModRegRm
.Register
== 2)
1528 /* Push the current value of IP */
1529 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1531 /* Exception occurred */
1535 /* Set the IP to the address */
1536 State
->InstPtr
.LowWord
= Value
;
1538 else if (ModRegRm
.Register
== 3)
1541 INT Segment
= FAST486_REG_DS
;
1543 /* Check for the segment override */
1544 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1546 /* Use the override segment instead */
1547 Segment
= State
->SegmentOverride
;
1550 /* Read the selector */
1551 if (!Fast486ReadMemory(State
,
1553 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1558 /* Exception occurred */
1562 /* Push the current value of CS */
1563 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1565 /* Exception occurred */
1569 /* Push the current value of IP */
1570 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1572 /* Exception occurred */
1576 /* Load the new code segment */
1577 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1579 /* Exception occurred */
1583 /* Set the IP to the address */
1584 State
->InstPtr
.LowWord
= Value
;
1587 else if (ModRegRm
.Register
== 4)
1589 /* Set the IP to the address */
1590 State
->InstPtr
.LowWord
= Value
;
1592 else if (ModRegRm
.Register
== 5)
1595 INT Segment
= FAST486_REG_DS
;
1597 /* Check for the segment override */
1598 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1600 /* Use the override segment instead */
1601 Segment
= State
->SegmentOverride
;
1604 /* Read the selector */
1605 if (!Fast486ReadMemory(State
,
1607 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1612 /* Exception occurred */
1616 /* Load the new code segment */
1617 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1619 /* Exception occurred */
1623 /* Set the IP to the address */
1624 State
->InstPtr
.LowWord
= Value
;
1626 else if (ModRegRm
.Register
== 6)
1628 /* Push the value on to the stack */
1629 return Fast486StackPush(State
, Value
);
1634 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1638 if (ModRegRm
.Register
<= 1)
1641 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1642 State
->Flags
.Zf
= (Value
== 0);
1643 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1645 /* Write back the result */
1646 return Fast486WriteModrmWordOperands(State
,
1656 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
1659 FAST486_MOD_REG_RM ModRegRm
;
1660 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1661 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1664 TOGGLE_ADSIZE(AddressSize
);
1666 /* Check for the segment override */
1667 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1669 /* Use the override segment instead */
1670 Segment
= State
->SegmentOverride
;
1673 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1675 /* Exception occurred */
1679 /* Check which operation this is */
1680 switch (ModRegRm
.Register
)
1685 if (!ModRegRm
.Memory
)
1687 /* The second operand must be a memory location */
1688 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1692 /* Fill the 6-byte table register */
1693 RtlCopyMemory(TableReg
, &State
->Gdtr
.Size
, sizeof(USHORT
));
1694 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Gdtr
.Address
, sizeof(ULONG
));
1696 /* Store the GDTR */
1697 return Fast486WriteMemory(State
,
1699 ModRegRm
.MemoryAddress
,
1707 if (!ModRegRm
.Memory
)
1709 /* The second operand must be a memory location */
1710 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1714 /* Fill the 6-byte table register */
1715 RtlCopyMemory(TableReg
, &State
->Idtr
.Size
, sizeof(USHORT
));
1716 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Idtr
.Address
, sizeof(ULONG
));
1718 /* Store the IDTR */
1719 return Fast486WriteMemory(State
,
1721 ModRegRm
.MemoryAddress
,
1729 /* This is a privileged instruction */
1730 if (Fast486GetCurrentPrivLevel(State
) != 0)
1732 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1736 if (!ModRegRm
.Memory
)
1738 /* The second operand must be a memory location */
1739 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1743 /* Read the new GDTR */
1744 if (!Fast486ReadMemory(State
,
1746 ModRegRm
.MemoryAddress
,
1751 /* Exception occurred */
1755 /* Load the new GDT */
1756 State
->Gdtr
.Size
= *((PUSHORT
)TableReg
);
1757 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1765 /* This is a privileged instruction */
1766 if (Fast486GetCurrentPrivLevel(State
) != 0)
1768 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1772 if (!ModRegRm
.Memory
)
1774 /* The second operand must be a memory location */
1775 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1779 /* Read the new IDTR */
1780 if (!Fast486ReadMemory(State
,
1782 ModRegRm
.MemoryAddress
,
1787 /* Exception occurred */
1791 /* Load the new IDT */
1792 State
->Idtr
.Size
= *((PUSHORT
)TableReg
);
1793 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1801 /* Store the lower 16 bits of CR0 */
1802 return Fast486WriteModrmWordOperands(State
,
1805 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
1811 USHORT MasterStatusWord
, Dummy
;
1813 /* This is a privileged instruction */
1814 if (Fast486GetCurrentPrivLevel(State
) != 0)
1816 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1820 /* Read the new master status word */
1821 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &MasterStatusWord
))
1823 /* Exception occurred */
1827 /* This instruction cannot be used to return to real mode */
1828 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1829 && !(MasterStatusWord
& FAST486_CR0_PE
))
1831 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1835 /* Set the lowest 4 bits */
1836 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
1837 State
->ControlRegisters
[FAST486_REG_CR0
] |= MasterStatusWord
& 0x0F;
1852 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1858 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
1860 FAST486_MOD_REG_RM ModRegRm
;
1861 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1863 TOGGLE_ADSIZE(AddressSize
);
1865 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1867 /* Exception occurred */
1871 /* All of them are reserved (UD2) */
1872 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1876 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
1878 FAST486_MOD_REG_RM ModRegRm
;
1879 BOOLEAN OperandSize
, AddressSize
;
1883 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1885 TOGGLE_OPSIZE(OperandSize
);
1886 TOGGLE_ADSIZE(AddressSize
);
1888 /* Get the number of bits */
1889 if (OperandSize
) DataSize
= 32;
1892 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1894 /* Exception occurred */
1898 if (ModRegRm
.Register
< 4)
1901 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1905 /* Get the bit number */
1906 if (!Fast486FetchByte(State
, &BitNumber
))
1908 /* Exception occurred */
1912 if (ModRegRm
.Memory
)
1915 * For memory operands, add the bit offset divided by
1916 * the data size to the address
1918 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1921 /* Normalize the bit number */
1922 BitNumber
&= (1 << DataSize
) - 1;
1928 /* Read the value */
1929 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1931 /* Exception occurred */
1935 /* Set CF to the bit value */
1936 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1938 if (ModRegRm
.Register
== 5)
1941 Value
|= 1 << BitNumber
;
1943 else if (ModRegRm
.Register
== 6)
1946 Value
&= ~(1 << BitNumber
);
1948 else if (ModRegRm
.Register
== 7)
1951 Value
^= 1 << BitNumber
;
1954 if (ModRegRm
.Register
>= 5)
1956 /* Write back the result */
1957 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1959 /* Exception occurred */
1966 USHORT Dummy
, Value
;
1968 /* Read the value */
1969 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1971 /* Exception occurred */
1975 /* Set CF to the bit value */
1976 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1978 if (ModRegRm
.Register
== 5)
1981 Value
|= 1 << BitNumber
;
1983 else if (ModRegRm
.Register
== 6)
1986 Value
&= ~(1 << BitNumber
);
1988 else if (ModRegRm
.Register
== 7)
1991 Value
^= 1 << BitNumber
;
1994 if (ModRegRm
.Register
>= 5)
1996 /* Write back the result */
1997 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
1999 /* Exception occurred */
2005 /* Return success */