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 /* Pop a value from the stack - this must be done first */
490 if (!Fast486StackPop(State
, &Value
))
492 /* Exception occurred */
496 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
498 /* Exception occurred - restore SP */
499 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= sizeof(ULONG
);
500 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= sizeof(USHORT
);
505 if (ModRegRm
.Register
!= 0)
508 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
514 return Fast486WriteModrmDwordOperands(State
,
521 return Fast486WriteModrmWordOperands(State
,
528 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
530 UCHAR Dummy
, Value
, Count
;
531 FAST486_MOD_REG_RM ModRegRm
;
532 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
534 TOGGLE_ADSIZE(AddressSize
);
536 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
538 /* Exception occurred */
542 /* Fetch the count */
543 if (!Fast486FetchByte(State
, &Count
))
545 /* Exception occurred */
549 /* Read the operands */
550 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
552 /* Exception occurred */
556 /* Calculate the result */
557 Value
= LOBYTE(Fast486RotateOperation(State
,
563 /* Write back the result */
564 return Fast486WriteModrmByteOperands(State
,
570 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
573 FAST486_MOD_REG_RM ModRegRm
;
574 BOOLEAN OperandSize
, AddressSize
;
576 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
578 TOGGLE_OPSIZE(OperandSize
);
579 TOGGLE_ADSIZE(AddressSize
);
581 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
583 /* Exception occurred */
587 /* Fetch the count */
588 if (!Fast486FetchByte(State
, &Count
))
590 /* Exception occurred */
598 /* Read the operands */
599 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
601 /* Exception occurred */
605 /* Calculate the result */
606 Value
= Fast486RotateOperation(State
,
612 /* Write back the result */
613 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
619 /* Read the operands */
620 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
622 /* Exception occurred */
626 /* Calculate the result */
627 Value
= LOWORD(Fast486RotateOperation(State
,
633 /* Write back the result */
634 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
638 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
641 FAST486_MOD_REG_RM ModRegRm
;
642 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
644 TOGGLE_ADSIZE(AddressSize
);
646 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
648 /* Exception occurred */
652 if (ModRegRm
.Register
!= 0)
655 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
659 /* Get the immediate operand */
660 if (!Fast486FetchByte(State
, &Immediate
))
662 /* Exception occurred */
666 return Fast486WriteModrmByteOperands(State
,
672 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
674 FAST486_MOD_REG_RM ModRegRm
;
675 BOOLEAN OperandSize
, AddressSize
;
677 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
679 TOGGLE_OPSIZE(OperandSize
);
680 TOGGLE_ADSIZE(AddressSize
);
682 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
684 /* Exception occurred */
688 if (ModRegRm
.Register
!= 0)
691 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
699 /* Get the immediate operand */
700 if (!Fast486FetchDword(State
, &Immediate
))
702 /* Exception occurred */
706 return Fast486WriteModrmDwordOperands(State
,
715 /* Get the immediate operand */
716 if (!Fast486FetchWord(State
, &Immediate
))
718 /* Exception occurred */
722 return Fast486WriteModrmWordOperands(State
,
729 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
732 FAST486_MOD_REG_RM ModRegRm
;
733 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
735 TOGGLE_ADSIZE(AddressSize
);
737 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
739 /* Exception occurred */
743 /* Read the operands */
744 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
746 /* Exception occurred */
750 /* Calculate the result */
751 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
753 /* Write back the result */
754 return Fast486WriteModrmByteOperands(State
,
761 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
763 FAST486_MOD_REG_RM ModRegRm
;
764 BOOLEAN OperandSize
, AddressSize
;
766 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
768 TOGGLE_OPSIZE(OperandSize
);
769 TOGGLE_ADSIZE(AddressSize
);
771 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
773 /* Exception occurred */
781 /* Read the operands */
782 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
784 /* Exception occurred */
788 /* Calculate the result */
789 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
791 /* Write back the result */
792 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
798 /* Read the operands */
799 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
801 /* Exception occurred */
805 /* Calculate the result */
806 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
808 /* Write back the result */
809 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
813 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
816 FAST486_MOD_REG_RM ModRegRm
;
817 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
819 TOGGLE_ADSIZE(AddressSize
);
821 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
823 /* Exception occurred */
827 /* Read the operands */
828 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
830 /* Exception occurred */
834 /* Calculate the result */
835 Value
= LOBYTE(Fast486RotateOperation(State
,
839 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
841 /* Write back the result */
842 return Fast486WriteModrmByteOperands(State
,
848 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
850 FAST486_MOD_REG_RM ModRegRm
;
851 BOOLEAN OperandSize
, AddressSize
;
853 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
855 TOGGLE_OPSIZE(OperandSize
);
856 TOGGLE_ADSIZE(AddressSize
);
858 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
860 /* Exception occurred */
868 /* Read the operands */
869 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
871 /* Exception occurred */
875 /* Calculate the result */
876 Value
= Fast486RotateOperation(State
,
880 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
882 /* Write back the result */
883 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
889 /* Read the operands */
890 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
892 /* Exception occurred */
896 /* Calculate the result */
897 Value
= LOWORD(Fast486RotateOperation(State
,
901 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
903 /* Write back the result */
904 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
908 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
910 UCHAR Dummy
, Value
= 0;
911 FAST486_MOD_REG_RM ModRegRm
;
912 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
914 TOGGLE_ADSIZE(AddressSize
);
916 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
918 /* Exception occurred */
922 /* Read the operands */
923 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
925 /* Exception occurred */
929 switch (ModRegRm
.Register
)
935 UCHAR Immediate
, Result
;
937 /* Fetch the immediate byte */
938 if (!Fast486FetchByte(State
, &Immediate
))
940 /* Exception occurred */
944 /* Calculate the result */
945 Result
= Value
& Immediate
;
947 /* Update the flags */
948 State
->Flags
.Cf
= FALSE
;
949 State
->Flags
.Of
= FALSE
;
950 State
->Flags
.Zf
= (Result
== 0);
951 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
952 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
960 /* Write back the result */
961 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
967 /* Calculate the result */
968 UCHAR Result
= -Value
;
970 /* Update the flags */
971 State
->Flags
.Cf
= (Value
!= 0);
972 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
973 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
974 State
->Flags
.Zf
= (Result
== 0);
975 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
976 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
978 /* Write back the result */
979 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
985 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
987 /* Update the flags */
988 State
->Flags
.Cf
= State
->Flags
.Of
= (HIBYTE(Result
) != 0);
990 /* Write back the result */
991 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
999 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
1001 /* Update the flags */
1002 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -128) || (Result
> 127));
1004 /* Write back the result */
1005 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1013 UCHAR Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1014 UCHAR Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1016 /* Write back the results */
1017 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1018 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1026 CHAR Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1027 CHAR Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1029 /* Write back the results */
1030 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1031 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1040 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1042 ULONG Dummy
, Value
= 0, SignFlag
;
1043 FAST486_MOD_REG_RM ModRegRm
;
1044 BOOLEAN OperandSize
, AddressSize
;
1046 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1048 TOGGLE_OPSIZE(OperandSize
);
1049 TOGGLE_ADSIZE(AddressSize
);
1051 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1053 /* Exception occurred */
1057 /* Set the sign flag */
1058 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1059 else SignFlag
= SIGN_FLAG_WORD
;
1061 /* Read the operand */
1065 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1067 /* Exception occurred */
1074 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, (PUSHORT
)&Dummy
, (PUSHORT
)&Value
))
1076 /* Exception occurred */
1081 switch (ModRegRm
.Register
)
1087 ULONG Immediate
= 0, Result
= 0;
1091 /* Fetch the immediate dword */
1092 if (!Fast486FetchDword(State
, &Immediate
))
1094 /* Exception occurred */
1100 /* Fetch the immediate word */
1101 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1103 /* Exception occurred */
1108 /* Calculate the result */
1109 Result
= Value
& Immediate
;
1111 /* Update the flags */
1112 State
->Flags
.Cf
= FALSE
;
1113 State
->Flags
.Of
= FALSE
;
1114 State
->Flags
.Zf
= (Result
== 0);
1115 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1116 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1124 /* Write back the result */
1128 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1133 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1140 /* Calculate the result */
1141 ULONG Result
= -Value
;
1142 if (!OperandSize
) Result
&= 0xFFFF;
1144 /* Update the flags */
1145 State
->Flags
.Cf
= (Value
!= 0);
1146 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1147 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1148 State
->Flags
.Zf
= (Result
== 0);
1149 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1150 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1152 /* Write back the result */
1156 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1161 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1170 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1172 /* Update the flags */
1173 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1175 /* Write back the result */
1176 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1177 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1181 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1183 /* Update the flags */
1184 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1186 /* Write back the result */
1187 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1188 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1199 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1201 /* Update the flags */
1202 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1204 /* Write back the result */
1205 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1206 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1210 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1212 /* Update the flags */
1213 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1215 /* Write back the result */
1216 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1217 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1228 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1229 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1230 ULONG Quotient
= Dividend
/ Value
;
1231 ULONG Remainder
= Dividend
% Value
;
1233 /* Write back the results */
1234 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1235 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1239 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1240 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1241 USHORT Quotient
= Dividend
/ Value
;
1242 USHORT Remainder
= Dividend
% Value
;
1244 /* Write back the results */
1245 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1246 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1257 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1258 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1259 LONG Quotient
= Dividend
/ (LONG
)Value
;
1260 LONG Remainder
= Dividend
% (LONG
)Value
;
1262 /* Write back the results */
1263 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1264 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1268 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1269 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1270 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1271 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1273 /* Write back the results */
1274 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1275 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1285 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1288 FAST486_MOD_REG_RM ModRegRm
;
1289 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1291 TOGGLE_ADSIZE(AddressSize
);
1293 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1295 /* Exception occurred */
1299 if (ModRegRm
.Register
> 1)
1302 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1306 /* Read the operands */
1307 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1309 /* Exception occurred */
1313 if (ModRegRm
.Register
== 0)
1315 /* Increment and update OF and AF */
1317 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1318 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1322 /* Decrement and update OF and AF */
1323 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1325 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1329 State
->Flags
.Zf
= (Value
== 0);
1330 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1331 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1333 /* Write back the result */
1334 return Fast486WriteModrmByteOperands(State
,
1340 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1342 FAST486_MOD_REG_RM ModRegRm
;
1343 BOOLEAN OperandSize
, AddressSize
;
1345 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1347 TOGGLE_OPSIZE(OperandSize
);
1348 TOGGLE_ADSIZE(AddressSize
);
1350 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1352 /* Exception occurred */
1356 if (ModRegRm
.Register
== 7)
1359 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1363 /* Read the operands */
1368 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1370 /* Exception occurred */
1374 if (ModRegRm
.Register
== 0)
1376 /* Increment and update OF and AF */
1378 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1379 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1381 else if (ModRegRm
.Register
== 1)
1383 /* Decrement and update OF and AF */
1384 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1386 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1388 else if (ModRegRm
.Register
== 2)
1390 /* Push the current value of EIP */
1391 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1393 /* Exception occurred */
1397 /* Set the EIP to the address */
1398 State
->InstPtr
.Long
= Value
;
1400 else if (ModRegRm
.Register
== 3)
1403 INT Segment
= FAST486_REG_DS
;
1405 /* Check for the segment override */
1406 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1408 /* Use the override segment instead */
1409 Segment
= State
->SegmentOverride
;
1412 /* Read the selector */
1413 if (!Fast486ReadMemory(State
,
1415 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1420 /* Exception occurred */
1424 /* Push the current value of CS */
1425 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1427 /* Exception occurred */
1431 /* Push the current value of EIP */
1432 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1434 /* Exception occurred */
1438 /* Load the new code segment */
1439 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1441 /* Exception occurred */
1445 /* Set the EIP to the address */
1446 State
->InstPtr
.Long
= Value
;
1448 else if (ModRegRm
.Register
== 4)
1450 /* Set the EIP to the address */
1451 State
->InstPtr
.Long
= Value
;
1453 else if (ModRegRm
.Register
== 5)
1456 INT Segment
= FAST486_REG_DS
;
1458 /* Check for the segment override */
1459 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1461 /* Use the override segment instead */
1462 Segment
= State
->SegmentOverride
;
1465 /* Read the selector */
1466 if (!Fast486ReadMemory(State
,
1468 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1473 /* Exception occurred */
1477 /* Load the new code segment */
1478 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1480 /* Exception occurred */
1484 /* Set the EIP to the address */
1485 State
->InstPtr
.Long
= Value
;
1487 else if (ModRegRm
.Register
== 6)
1489 /* Push the value on to the stack */
1490 return Fast486StackPush(State
, Value
);
1493 if (ModRegRm
.Register
<= 1)
1496 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
1497 State
->Flags
.Zf
= (Value
== 0);
1498 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1500 /* Write back the result */
1501 return Fast486WriteModrmDwordOperands(State
,
1509 USHORT Dummy
, Value
;
1511 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1513 /* Exception occurred */
1517 if (ModRegRm
.Register
== 0)
1519 /* Increment and update OF */
1521 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1522 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1524 else if (ModRegRm
.Register
== 1)
1526 /* Decrement and update OF */
1527 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1529 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1531 else if (ModRegRm
.Register
== 2)
1533 /* Push the current value of IP */
1534 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1536 /* Exception occurred */
1540 /* Set the IP to the address */
1541 State
->InstPtr
.LowWord
= Value
;
1543 else if (ModRegRm
.Register
== 3)
1546 INT Segment
= FAST486_REG_DS
;
1548 /* Check for the segment override */
1549 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1551 /* Use the override segment instead */
1552 Segment
= State
->SegmentOverride
;
1555 /* Read the selector */
1556 if (!Fast486ReadMemory(State
,
1558 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1563 /* Exception occurred */
1567 /* Push the current value of CS */
1568 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1570 /* Exception occurred */
1574 /* Push the current value of IP */
1575 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1577 /* Exception occurred */
1581 /* Load the new code segment */
1582 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1584 /* Exception occurred */
1588 /* Set the IP to the address */
1589 State
->InstPtr
.LowWord
= Value
;
1592 else if (ModRegRm
.Register
== 4)
1594 /* Set the IP to the address */
1595 State
->InstPtr
.LowWord
= Value
;
1597 else if (ModRegRm
.Register
== 5)
1600 INT Segment
= FAST486_REG_DS
;
1602 /* Check for the segment override */
1603 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1605 /* Use the override segment instead */
1606 Segment
= State
->SegmentOverride
;
1609 /* Read the selector */
1610 if (!Fast486ReadMemory(State
,
1612 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1617 /* Exception occurred */
1621 /* Load the new code segment */
1622 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1624 /* Exception occurred */
1628 /* Set the IP to the address */
1629 State
->InstPtr
.LowWord
= Value
;
1631 else if (ModRegRm
.Register
== 6)
1633 /* Push the value on to the stack */
1634 return Fast486StackPush(State
, Value
);
1639 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1643 if (ModRegRm
.Register
<= 1)
1646 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1647 State
->Flags
.Zf
= (Value
== 0);
1648 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1650 /* Write back the result */
1651 return Fast486WriteModrmWordOperands(State
,
1661 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
1664 FAST486_MOD_REG_RM ModRegRm
;
1665 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1666 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1669 TOGGLE_ADSIZE(AddressSize
);
1671 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1673 /* Exception occurred */
1677 /* Check for the segment override */
1678 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1680 /* Use the override segment instead */
1681 Segment
= State
->SegmentOverride
;
1684 /* Check which operation this is */
1685 switch (ModRegRm
.Register
)
1690 if (!ModRegRm
.Memory
)
1692 /* The second operand must be a memory location */
1693 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1697 /* Fill the 6-byte table register */
1698 RtlCopyMemory(TableReg
, &State
->Gdtr
.Size
, sizeof(USHORT
));
1699 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Gdtr
.Address
, sizeof(ULONG
));
1701 /* Store the GDTR */
1702 return Fast486WriteMemory(State
,
1704 ModRegRm
.MemoryAddress
,
1712 if (!ModRegRm
.Memory
)
1714 /* The second operand must be a memory location */
1715 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1719 /* Fill the 6-byte table register */
1720 RtlCopyMemory(TableReg
, &State
->Idtr
.Size
, sizeof(USHORT
));
1721 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Idtr
.Address
, sizeof(ULONG
));
1723 /* Store the IDTR */
1724 return Fast486WriteMemory(State
,
1726 ModRegRm
.MemoryAddress
,
1734 /* This is a privileged instruction */
1735 if (Fast486GetCurrentPrivLevel(State
) != 0)
1737 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1741 if (!ModRegRm
.Memory
)
1743 /* The second operand must be a memory location */
1744 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1748 /* Read the new GDTR */
1749 if (!Fast486ReadMemory(State
,
1751 ModRegRm
.MemoryAddress
,
1756 /* Exception occurred */
1760 /* Load the new GDT */
1761 State
->Gdtr
.Size
= *((PUSHORT
)TableReg
);
1762 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1770 /* This is a privileged instruction */
1771 if (Fast486GetCurrentPrivLevel(State
) != 0)
1773 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1777 if (!ModRegRm
.Memory
)
1779 /* The second operand must be a memory location */
1780 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1784 /* Read the new IDTR */
1785 if (!Fast486ReadMemory(State
,
1787 ModRegRm
.MemoryAddress
,
1792 /* Exception occurred */
1796 /* Load the new IDT */
1797 State
->Idtr
.Size
= *((PUSHORT
)TableReg
);
1798 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1806 /* Store the lower 16 bits (Machine Status Word) of CR0 */
1807 return Fast486WriteModrmWordOperands(State
,
1810 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
1816 USHORT MachineStatusWord
, Dummy
;
1818 /* This is a privileged instruction */
1819 if (Fast486GetCurrentPrivLevel(State
) != 0)
1821 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1825 /* Read the new Machine Status Word */
1826 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &MachineStatusWord
))
1828 /* Exception occurred */
1832 /* This instruction cannot be used to return to real mode */
1833 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1834 && !(MachineStatusWord
& FAST486_CR0_PE
))
1836 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1840 /* Set the lowest 4 bits */
1841 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
1842 State
->ControlRegisters
[FAST486_REG_CR0
] |= MachineStatusWord
& 0x0F;
1857 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1863 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
1865 FAST486_MOD_REG_RM ModRegRm
;
1866 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1868 TOGGLE_ADSIZE(AddressSize
);
1870 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1872 /* Exception occurred */
1876 /* All of them are reserved (UD2) */
1877 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1881 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
1883 FAST486_MOD_REG_RM ModRegRm
;
1884 BOOLEAN OperandSize
, AddressSize
;
1888 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1890 TOGGLE_OPSIZE(OperandSize
);
1891 TOGGLE_ADSIZE(AddressSize
);
1893 /* Get the number of bits */
1894 if (OperandSize
) DataSize
= 32;
1897 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1899 /* Exception occurred */
1903 if (ModRegRm
.Register
< 4)
1906 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1910 /* Get the bit number */
1911 if (!Fast486FetchByte(State
, &BitNumber
))
1913 /* Exception occurred */
1917 if (ModRegRm
.Memory
)
1920 * For memory operands, add the bit offset divided by
1921 * the data size to the address
1923 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1926 /* Normalize the bit number */
1927 BitNumber
%= DataSize
;
1933 /* Read the value */
1934 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1936 /* Exception occurred */
1940 /* Set CF to the bit value */
1941 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1943 if (ModRegRm
.Register
== 5)
1946 Value
|= 1 << BitNumber
;
1948 else if (ModRegRm
.Register
== 6)
1951 Value
&= ~(1 << BitNumber
);
1953 else if (ModRegRm
.Register
== 7)
1956 Value
^= 1 << BitNumber
;
1959 if (ModRegRm
.Register
>= 5)
1961 /* Write back the result */
1962 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1964 /* Exception occurred */
1971 USHORT Dummy
, Value
;
1973 /* Read the value */
1974 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1976 /* Exception occurred */
1980 /* Set CF to the bit value */
1981 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1983 if (ModRegRm
.Register
== 5)
1986 Value
|= 1 << BitNumber
;
1988 else if (ModRegRm
.Register
== 6)
1991 Value
&= ~(1 << BitNumber
);
1993 else if (ModRegRm
.Register
== 7)
1996 Value
^= 1 << BitNumber
;
1999 if (ModRegRm
.Register
>= 5)
2001 /* Write back the result */
2002 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2004 /* Exception occurred */
2010 /* Return success */