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
= (1 << Bits
) - 1;
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) ? TRUE
: FALSE
;
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)
97 INT Carry
= State
->Flags
.Cf
? 1 : 0;
99 Result
= (FirstValue
- SecondValue
- Carry
) & MaxValue
;
101 /* Update CF, OF and AF */
102 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
103 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
104 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
105 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
113 Result
= FirstValue
& SecondValue
;
121 Result
= (FirstValue
- SecondValue
) & MaxValue
;
123 /* Update CF, OF and AF */
124 State
->Flags
.Cf
= FirstValue
< SecondValue
;
125 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
126 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
127 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
135 Result
= FirstValue
^ SecondValue
;
141 /* Shouldn't happen */
146 /* Update ZF, SF and PF */
147 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
148 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
149 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Result
));
151 /* Return the result */
158 Fast486RotateOperation(PFAST486_STATE State
,
164 ULONG HighestBit
= 1 << (Bits
- 1);
167 if ((Operation
!= 2) && (Operation
!= 3))
174 /* For RCL and RCR, the CF is included in the value */
178 /* Check which operation is this */
184 Result
= (Value
<< Count
) | (Value
>> (Bits
- Count
));
186 /* Update CF and OF */
187 State
->Flags
.Cf
= Result
& 1;
188 if (Count
== 1) State
->Flags
.Of
= ((Result
& HighestBit
) ? TRUE
: FALSE
)
197 Result
= (Value
>> Count
) | (Value
<< (Bits
- Count
));
199 /* Update CF and OF */
200 State
->Flags
.Cf
= (Result
& HighestBit
) ? TRUE
: FALSE
;
201 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
202 ^ ((Result
& (HighestBit
>> 1))
211 Result
= (Value
<< Count
)
212 | (State
->Flags
.Cf
<< (Count
- 1))
213 | (Value
>> (Bits
- Count
+ 1));
215 /* Update CF and OF */
216 State
->Flags
.Cf
= (Value
& (1 << (Bits
- Count
))) ? TRUE
: FALSE
;
217 if (Count
== 1) State
->Flags
.Of
= ((Result
& HighestBit
) ? TRUE
: FALSE
)
226 Result
= (Value
>> Count
)
227 | (State
->Flags
.Cf
<< (Bits
- Count
))
228 | (Value
<< (Bits
- Count
+ 1));
230 /* Update CF and OF */
231 State
->Flags
.Cf
= (Value
& (1 << (Bits
- Count
))) ? TRUE
: FALSE
;
232 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
233 ^ ((Result
& (HighestBit
>> 1))
243 Result
= Value
<< Count
;
245 /* Update CF and OF */
246 State
->Flags
.Cf
= (Value
& (1 << (Bits
- Count
))) ? TRUE
: FALSE
;
247 if (Count
== 1) State
->Flags
.Of
= ((Result
& HighestBit
) ? TRUE
: FALSE
)
248 ^ (State
->Flags
.Cf
? TRUE
: FALSE
);
256 Result
= Value
>> Count
;
258 /* Update CF and OF */
259 State
->Flags
.Cf
= (Value
& (1 << (Count
- 1))) ? TRUE
: FALSE
;
260 if (Count
== 1) State
->Flags
.Of
= (Value
& HighestBit
) ? TRUE
: FALSE
;
268 Result
= Value
>> Count
;
270 /* Fill the top Count bits with the sign bit */
271 if (Value
& HighestBit
) Result
|= ((1 << Count
) - 1) << (Bits
- Count
);
273 /* Update CF and OF */
274 State
->Flags
.Cf
= (Value
& (1 << (Count
- 1))) ? TRUE
: FALSE
;
275 if (Count
== 1) State
->Flags
.Of
= FALSE
;
283 /* Update ZF, SF and PF */
284 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
285 State
->Flags
.Sf
= (Result
& HighestBit
) ? TRUE
: FALSE
;
286 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
289 /* Return the result */
293 /* PUBLIC FUNCTIONS ***********************************************************/
295 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082
)
297 UCHAR Immediate
, Dummy
, Value
;
298 FAST486_MOD_REG_RM ModRegRm
;
299 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
301 TOGGLE_ADSIZE(AddressSize
);
303 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
305 /* Exception occurred */
309 /* Fetch the immediate operand */
310 if (!Fast486FetchByte(State
, &Immediate
))
312 /* Exception occurred */
316 /* Read the operands */
317 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
319 /* Exception occurred */
323 /* Calculate the result */
324 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 8);
326 /* Unless this is CMP, write back the result */
327 if (ModRegRm
.Register
!= 7)
329 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
335 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81
)
337 FAST486_MOD_REG_RM ModRegRm
;
338 BOOLEAN OperandSize
, AddressSize
;
340 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
342 TOGGLE_OPSIZE(OperandSize
);
343 TOGGLE_ADSIZE(AddressSize
);
345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
347 /* Exception occurred */
353 ULONG Immediate
, Value
, Dummy
;
355 /* Fetch the immediate operand */
356 if (!Fast486FetchDword(State
, &Immediate
))
358 /* Exception occurred */
362 /* Read the operands */
363 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
365 /* Exception occurred */
369 /* Calculate the result */
370 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
372 /* Unless this is CMP, write back the result */
373 if (ModRegRm
.Register
!= 7)
375 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
380 USHORT Immediate
, Value
, Dummy
;
382 /* Fetch the immediate operand */
383 if (!Fast486FetchWord(State
, &Immediate
))
385 /* Exception occurred */
389 /* Read the operands */
390 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
392 /* Exception occurred */
396 /* Calculate the result */
397 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
399 /* Unless this is CMP, write back the result */
400 if (ModRegRm
.Register
!= 7)
402 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
409 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83
)
412 FAST486_MOD_REG_RM ModRegRm
;
413 BOOLEAN OperandSize
, AddressSize
;
415 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
417 TOGGLE_OPSIZE(OperandSize
);
418 TOGGLE_ADSIZE(AddressSize
);
420 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
422 /* Exception occurred */
426 /* Fetch the immediate operand */
427 if (!Fast486FetchByte(State
, (PUCHAR
)&ImmByte
))
429 /* Exception occurred */
435 ULONG Immediate
= (ULONG
)((LONG
)ImmByte
); // Sign extend
438 /* Read the operands */
439 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
441 /* Exception occurred */
445 /* Calculate the result */
446 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
448 /* Unless this is CMP, write back the result */
449 if (ModRegRm
.Register
!= 7)
451 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
456 USHORT Immediate
= (USHORT
)((SHORT
)ImmByte
); // Sign extend
459 /* Read the operands */
460 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
462 /* Exception occurred */
466 /* Calculate the result */
467 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
469 /* Unless this is CMP, write back the result */
470 if (ModRegRm
.Register
!= 7)
472 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
479 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F
)
482 FAST486_MOD_REG_RM ModRegRm
;
483 BOOLEAN OperandSize
, AddressSize
;
485 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
487 TOGGLE_OPSIZE(OperandSize
);
488 TOGGLE_ADSIZE(AddressSize
);
490 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
492 /* Exception occurred */
496 if (ModRegRm
.Register
!= 0)
499 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
503 /* Pop a value from the stack */
504 if (!Fast486StackPop(State
, &Value
))
506 /* Exception occurred */
512 return Fast486WriteModrmDwordOperands(State
,
519 return Fast486WriteModrmWordOperands(State
,
526 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
528 UCHAR Dummy
, Value
, Count
;
529 FAST486_MOD_REG_RM ModRegRm
;
530 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
532 TOGGLE_ADSIZE(AddressSize
);
534 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
536 /* Exception occurred */
540 /* Fetch the count */
541 if (!Fast486FetchByte(State
, &Count
))
543 /* Exception occurred */
547 /* Read the operands */
548 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
550 /* Exception occurred */
554 /* Calculate the result */
555 Value
= LOBYTE(Fast486RotateOperation(State
,
561 /* Write back the result */
562 return Fast486WriteModrmByteOperands(State
,
568 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
571 FAST486_MOD_REG_RM ModRegRm
;
572 BOOLEAN OperandSize
, AddressSize
;
574 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
576 TOGGLE_OPSIZE(OperandSize
);
577 TOGGLE_ADSIZE(AddressSize
);
579 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
581 /* Exception occurred */
585 /* Fetch the count */
586 if (!Fast486FetchByte(State
, &Count
))
588 /* Exception occurred */
596 /* Read the operands */
597 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
599 /* Exception occurred */
603 /* Calculate the result */
604 Value
= Fast486RotateOperation(State
,
610 /* Write back the result */
611 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
617 /* Read the operands */
618 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
620 /* Exception occurred */
624 /* Calculate the result */
625 Value
= LOWORD(Fast486RotateOperation(State
,
631 /* Write back the result */
632 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
636 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
639 FAST486_MOD_REG_RM ModRegRm
;
640 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
642 TOGGLE_ADSIZE(AddressSize
);
644 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
646 /* Exception occurred */
650 if (ModRegRm
.Register
!= 0)
653 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
657 /* Get the immediate operand */
658 if (!Fast486FetchByte(State
, &Immediate
))
660 /* Exception occurred */
664 return Fast486WriteModrmByteOperands(State
,
670 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
672 FAST486_MOD_REG_RM ModRegRm
;
673 BOOLEAN OperandSize
, AddressSize
;
675 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
677 TOGGLE_OPSIZE(OperandSize
);
678 TOGGLE_ADSIZE(AddressSize
);
680 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
682 /* Exception occurred */
686 if (ModRegRm
.Register
!= 0)
689 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
697 /* Get the immediate operand */
698 if (!Fast486FetchDword(State
, &Immediate
))
700 /* Exception occurred */
704 return Fast486WriteModrmDwordOperands(State
,
713 /* Get the immediate operand */
714 if (!Fast486FetchWord(State
, &Immediate
))
716 /* Exception occurred */
720 return Fast486WriteModrmWordOperands(State
,
727 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
730 FAST486_MOD_REG_RM ModRegRm
;
731 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
733 TOGGLE_ADSIZE(AddressSize
);
735 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
737 /* Exception occurred */
741 /* Read the operands */
742 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
744 /* Exception occurred */
748 /* Calculate the result */
749 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
751 /* Write back the result */
752 return Fast486WriteModrmByteOperands(State
,
759 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
761 FAST486_MOD_REG_RM ModRegRm
;
762 BOOLEAN OperandSize
, AddressSize
;
764 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
766 TOGGLE_OPSIZE(OperandSize
);
767 TOGGLE_ADSIZE(AddressSize
);
769 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
771 /* Exception occurred */
779 /* Read the operands */
780 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
782 /* Exception occurred */
786 /* Calculate the result */
787 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
789 /* Write back the result */
790 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
796 /* Read the operands */
797 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
799 /* Exception occurred */
803 /* Calculate the result */
804 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
806 /* Write back the result */
807 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
811 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
814 FAST486_MOD_REG_RM ModRegRm
;
815 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
817 TOGGLE_ADSIZE(AddressSize
);
819 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
821 /* Exception occurred */
825 /* Read the operands */
826 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
828 /* Exception occurred */
832 /* Calculate the result */
833 Value
= LOBYTE(Fast486RotateOperation(State
,
837 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
839 /* Write back the result */
840 return Fast486WriteModrmByteOperands(State
,
846 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
848 FAST486_MOD_REG_RM ModRegRm
;
849 BOOLEAN OperandSize
, AddressSize
;
851 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
853 TOGGLE_OPSIZE(OperandSize
);
854 TOGGLE_ADSIZE(AddressSize
);
856 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
858 /* Exception occurred */
866 /* Read the operands */
867 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
869 /* Exception occurred */
873 /* Calculate the result */
874 Value
= Fast486RotateOperation(State
,
878 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
880 /* Write back the result */
881 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
887 /* Read the operands */
888 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
890 /* Exception occurred */
894 /* Calculate the result */
895 Value
= LOWORD(Fast486RotateOperation(State
,
899 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
901 /* Write back the result */
902 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
906 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
908 UCHAR Dummy
, Value
= 0;
909 FAST486_MOD_REG_RM ModRegRm
;
910 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
912 TOGGLE_ADSIZE(AddressSize
);
914 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
916 /* Exception occurred */
920 /* Read the operands */
921 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
923 /* Exception occurred */
927 switch (ModRegRm
.Register
)
933 UCHAR Immediate
, Result
;
935 /* Fetch the immediate byte */
936 if (!Fast486FetchByte(State
, &Immediate
))
938 /* Exception occurred */
942 /* Calculate the result */
943 Result
= Value
& Immediate
;
945 /* Update the flags */
946 State
->Flags
.Cf
= FALSE
;
947 State
->Flags
.Of
= FALSE
;
948 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
949 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
950 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
958 /* Write back the result */
959 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
965 /* Calculate the result */
966 UCHAR Result
= -Value
;
968 /* Update the flags */
969 State
->Flags
.Cf
= (Value
!= 0) ? TRUE
: FALSE
;
970 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
971 State
->Flags
.Af
= ((Value
& 0x0F) != 0) ? TRUE
: FALSE
;
972 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
973 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
974 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
976 /* Write back the result */
977 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
983 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
985 /* Update the flags */
986 State
->Flags
.Cf
= State
->Flags
.Of
= HIBYTE(Result
) ? TRUE
: FALSE
;
988 /* Write back the result */
989 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
997 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
999 /* Update the flags */
1000 State
->Flags
.Cf
= State
->Flags
.Of
=
1001 ((Result
< -128) || (Result
> 127)) ? TRUE
: FALSE
;
1003 /* Write back the result */
1004 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1012 UCHAR Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1013 UCHAR Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1015 /* Write back the results */
1016 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1017 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1025 CHAR Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1026 CHAR Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1028 /* Write back the results */
1029 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1030 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1039 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1041 ULONG Dummy
, Value
= 0, SignFlag
;
1042 FAST486_MOD_REG_RM ModRegRm
;
1043 BOOLEAN OperandSize
, AddressSize
;
1045 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1047 TOGGLE_OPSIZE(OperandSize
);
1048 TOGGLE_ADSIZE(AddressSize
);
1050 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1052 /* Exception occurred */
1056 /* Set the sign flag */
1057 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1058 else SignFlag
= SIGN_FLAG_WORD
;
1060 /* Read the operand */
1064 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1066 /* Exception occurred */
1073 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, (PUSHORT
)&Dummy
, (PUSHORT
)&Value
))
1075 /* Exception occurred */
1080 switch (ModRegRm
.Register
)
1086 ULONG Immediate
= 0, Result
= 0;
1090 /* Fetch the immediate dword */
1091 if (!Fast486FetchDword(State
, &Immediate
))
1093 /* Exception occurred */
1099 /* Fetch the immediate word */
1100 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1102 /* Exception occurred */
1107 /* Calculate the result */
1108 Result
= Value
& Immediate
;
1110 /* Update the flags */
1111 State
->Flags
.Cf
= FALSE
;
1112 State
->Flags
.Of
= FALSE
;
1113 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1114 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
1115 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1123 /* Write back the result */
1127 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1132 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1139 /* Calculate the result */
1140 ULONG Result
= -Value
;
1141 if (!OperandSize
) Result
&= 0xFFFF;
1143 /* Update the flags */
1144 State
->Flags
.Cf
= (Value
!= 0) ? TRUE
: FALSE
;
1145 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1146 State
->Flags
.Af
= ((Value
& 0x0F) != 0) ? TRUE
: FALSE
;
1147 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1148 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
1149 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1151 /* Write back the result */
1155 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1160 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1169 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1171 /* Update the flags */
1172 State
->Flags
.Cf
= State
->Flags
.Of
=
1173 (Result
& 0xFFFFFFFF00000000ULL
) ? TRUE
: FALSE
;
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
) ? TRUE
: FALSE
;
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
=
1203 ((Result
< -2147483648LL) || (Result
> 2147483647LL)) ? TRUE
: FALSE
;
1205 /* Write back the result */
1206 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1207 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1211 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1213 /* Update the flags */
1214 State
->Flags
.Cf
= State
->Flags
.Of
=
1215 ((Result
< -32768) || (Result
> 32767)) ? TRUE
: FALSE
;
1217 /* Write back the result */
1218 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1219 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1230 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1231 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1232 ULONG Quotient
= Dividend
/ Value
;
1233 ULONG Remainder
= Dividend
% Value
;
1235 /* Write back the results */
1236 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1237 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1241 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1242 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1243 USHORT Quotient
= Dividend
/ Value
;
1244 USHORT Remainder
= Dividend
% Value
;
1246 /* Write back the results */
1247 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1248 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1259 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1260 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1261 LONG Quotient
= Dividend
/ (LONG
)Value
;
1262 LONG Remainder
= Dividend
% (LONG
)Value
;
1264 /* Write back the results */
1265 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1266 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1270 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1271 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1272 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1273 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1275 /* Write back the results */
1276 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1277 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1287 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1290 FAST486_MOD_REG_RM ModRegRm
;
1291 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1293 TOGGLE_ADSIZE(AddressSize
);
1295 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1297 /* Exception occurred */
1301 if (ModRegRm
.Register
> 1)
1304 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1308 /* Read the operands */
1309 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1311 /* Exception occurred */
1315 if (ModRegRm
.Register
== 0)
1317 /* Increment and update OF and AF */
1319 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1320 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1324 /* Decrement and update OF and AF */
1325 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1327 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1331 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1332 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
1333 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1335 /* Write back the result */
1336 return Fast486WriteModrmByteOperands(State
,
1342 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1344 FAST486_MOD_REG_RM ModRegRm
;
1345 BOOLEAN OperandSize
, AddressSize
;
1347 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1349 TOGGLE_OPSIZE(OperandSize
);
1350 TOGGLE_ADSIZE(AddressSize
);
1352 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1354 /* Exception occurred */
1358 if (ModRegRm
.Register
== 7)
1361 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1365 /* Read the operands */
1370 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1372 /* Exception occurred */
1376 if (ModRegRm
.Register
== 0)
1378 /* Increment and update OF and AF */
1380 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1381 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1383 else if (ModRegRm
.Register
== 1)
1385 /* Decrement and update OF and AF */
1386 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1388 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1390 else if (ModRegRm
.Register
== 2)
1392 /* Push the current value of EIP */
1393 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1395 /* Exception occurred */
1399 /* Set the EIP to the address */
1400 State
->InstPtr
.Long
= Value
;
1402 else if (ModRegRm
.Register
== 3)
1405 INT Segment
= FAST486_REG_DS
;
1407 /* Check for the segment override */
1408 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1410 /* Use the override segment instead */
1411 Segment
= State
->SegmentOverride
;
1414 /* Read the selector */
1415 if (!Fast486ReadMemory(State
,
1417 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1422 /* Exception occurred */
1426 /* Push the current value of CS */
1427 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1429 /* Exception occurred */
1433 /* Push the current value of EIP */
1434 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1436 /* Exception occurred */
1440 /* Load the new code segment */
1441 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1443 /* Exception occurred */
1447 /* Set the EIP to the address */
1448 State
->InstPtr
.Long
= Value
;
1450 else if (ModRegRm
.Register
== 4)
1452 /* Set the EIP to the address */
1453 State
->InstPtr
.Long
= Value
;
1455 else if (ModRegRm
.Register
== 5)
1458 INT Segment
= FAST486_REG_DS
;
1460 /* Check for the segment override */
1461 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1463 /* Use the override segment instead */
1464 Segment
= State
->SegmentOverride
;
1467 /* Read the selector */
1468 if (!Fast486ReadMemory(State
,
1470 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1475 /* Exception occurred */
1479 /* Load the new code segment */
1480 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1482 /* Exception occurred */
1486 /* Set the EIP to the address */
1487 State
->InstPtr
.Long
= Value
;
1489 else if (ModRegRm
.Register
== 6)
1491 /* Push the value on to the stack */
1492 return Fast486StackPush(State
, Value
);
1495 if (ModRegRm
.Register
<= 1)
1498 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1499 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
1500 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1502 /* Write back the result */
1503 return Fast486WriteModrmDwordOperands(State
,
1511 USHORT Dummy
, Value
;
1513 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1515 /* Exception occurred */
1519 if (ModRegRm
.Register
== 0)
1521 /* Increment and update OF */
1523 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1524 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1526 else if (ModRegRm
.Register
== 1)
1528 /* Decrement and update OF */
1529 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1531 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1533 else if (ModRegRm
.Register
== 2)
1535 /* Push the current value of IP */
1536 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1538 /* Exception occurred */
1542 /* Set the IP to the address */
1543 State
->InstPtr
.LowWord
= Value
;
1545 else if (ModRegRm
.Register
== 3)
1548 INT Segment
= FAST486_REG_DS
;
1550 /* Check for the segment override */
1551 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1553 /* Use the override segment instead */
1554 Segment
= State
->SegmentOverride
;
1557 /* Read the selector */
1558 if (!Fast486ReadMemory(State
,
1560 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1565 /* Exception occurred */
1569 /* Push the current value of CS */
1570 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1572 /* Exception occurred */
1576 /* Push the current value of IP */
1577 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1579 /* Exception occurred */
1583 /* Load the new code segment */
1584 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1586 /* Exception occurred */
1590 /* Set the IP to the address */
1591 State
->InstPtr
.LowWord
= Value
;
1594 else if (ModRegRm
.Register
== 4)
1596 /* Set the IP to the address */
1597 State
->InstPtr
.LowWord
= Value
;
1599 else if (ModRegRm
.Register
== 5)
1602 INT Segment
= FAST486_REG_DS
;
1604 /* Check for the segment override */
1605 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1607 /* Use the override segment instead */
1608 Segment
= State
->SegmentOverride
;
1611 /* Read the selector */
1612 if (!Fast486ReadMemory(State
,
1614 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1619 /* Exception occurred */
1623 /* Load the new code segment */
1624 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1626 /* Exception occurred */
1630 /* Set the IP to the address */
1631 State
->InstPtr
.LowWord
= Value
;
1633 else if (ModRegRm
.Register
== 6)
1635 /* Push the value on to the stack */
1636 return Fast486StackPush(State
, Value
);
1641 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1645 if (ModRegRm
.Register
<= 1)
1648 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1649 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
1650 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1652 /* Write back the result */
1653 return Fast486WriteModrmWordOperands(State
,
1663 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
1666 FAST486_MOD_REG_RM ModRegRm
;
1667 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1668 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1671 TOGGLE_ADSIZE(AddressSize
);
1673 /* Check for the segment override */
1674 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1676 /* Use the override segment instead */
1677 Segment
= State
->SegmentOverride
;
1680 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1682 /* Exception occurred */
1686 /* Check which operation this is */
1687 switch (ModRegRm
.Register
)
1692 if (!ModRegRm
.Memory
)
1694 /* The second operand must be a memory location */
1695 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1699 /* Fill the 6-byte table register */
1700 RtlCopyMemory(TableReg
, &State
->Gdtr
.Size
, sizeof(USHORT
));
1701 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Gdtr
.Address
, sizeof(ULONG
));
1703 /* Store the GDTR */
1704 return Fast486WriteMemory(State
,
1706 ModRegRm
.MemoryAddress
,
1714 if (!ModRegRm
.Memory
)
1716 /* The second operand must be a memory location */
1717 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1721 /* Fill the 6-byte table register */
1722 RtlCopyMemory(TableReg
, &State
->Idtr
.Size
, sizeof(USHORT
));
1723 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Idtr
.Address
, sizeof(ULONG
));
1725 /* Store the IDTR */
1726 return Fast486WriteMemory(State
,
1728 ModRegRm
.MemoryAddress
,
1736 /* This is a privileged instruction */
1737 if (Fast486GetCurrentPrivLevel(State
) != 0)
1739 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1743 if (!ModRegRm
.Memory
)
1745 /* The second operand must be a memory location */
1746 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1750 /* Read the new GDTR */
1751 if (!Fast486ReadMemory(State
,
1753 ModRegRm
.MemoryAddress
,
1758 /* Exception occurred */
1762 /* Load the new GDT */
1763 State
->Gdtr
.Size
= *((PUSHORT
)TableReg
);
1764 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1772 /* This is a privileged instruction */
1773 if (Fast486GetCurrentPrivLevel(State
) != 0)
1775 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1779 if (!ModRegRm
.Memory
)
1781 /* The second operand must be a memory location */
1782 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1786 /* Read the new IDTR */
1787 if (!Fast486ReadMemory(State
,
1789 ModRegRm
.MemoryAddress
,
1794 /* Exception occurred */
1798 /* Load the new IDT */
1799 State
->Idtr
.Size
= *((PUSHORT
)TableReg
);
1800 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1808 /* Store the lower 16 bits of CR0 */
1809 return Fast486WriteModrmWordOperands(State
,
1812 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
1818 USHORT MasterStatusWord
, Dummy
;
1820 /* This is a privileged instruction */
1821 if (Fast486GetCurrentPrivLevel(State
) != 0)
1823 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1827 /* Read the new master status word */
1828 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &MasterStatusWord
))
1830 /* Exception occurred */
1834 /* This instruction cannot be used to return to real mode */
1835 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1836 && !(MasterStatusWord
& FAST486_CR0_PE
))
1838 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1842 /* Set the lowest 4 bits */
1843 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
1844 State
->ControlRegisters
[FAST486_REG_CR0
] |= MasterStatusWord
& 0x0F;
1859 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1865 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
1867 FAST486_MOD_REG_RM ModRegRm
;
1868 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1870 TOGGLE_ADSIZE(AddressSize
);
1872 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1874 /* Exception occurred */
1878 /* All of them are reserved (UD2) */
1879 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1883 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
1885 FAST486_MOD_REG_RM ModRegRm
;
1886 BOOLEAN OperandSize
, AddressSize
;
1890 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1892 TOGGLE_OPSIZE(OperandSize
);
1893 TOGGLE_ADSIZE(AddressSize
);
1895 /* Get the number of bits */
1896 if (OperandSize
) DataSize
= 32;
1899 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1901 /* Exception occurred */
1905 if (ModRegRm
.Register
< 4)
1908 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1912 /* Get the bit number */
1913 if (!Fast486FetchByte(State
, &BitNumber
))
1915 /* Exception occurred */
1919 if (ModRegRm
.Memory
)
1922 * For memory operands, add the bit offset divided by
1923 * the data size to the address
1925 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1928 /* Normalize the bit number */
1929 BitNumber
&= (1 << DataSize
) - 1;
1935 /* Read the value */
1936 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1938 /* Exception occurred */
1942 /* Set CF to the bit value */
1943 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1945 if (ModRegRm
.Register
== 5)
1948 Value
|= 1 << BitNumber
;
1950 else if (ModRegRm
.Register
== 6)
1953 Value
&= ~(1 << BitNumber
);
1955 else if (ModRegRm
.Register
== 7)
1958 Value
^= 1 << BitNumber
;
1961 if (ModRegRm
.Register
>= 5)
1963 /* Write back the result */
1964 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1966 /* Exception occurred */
1973 USHORT Dummy
, Value
;
1975 /* Read the value */
1976 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1978 /* Exception occurred */
1982 /* Set CF to the bit value */
1983 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1985 if (ModRegRm
.Register
== 5)
1988 Value
|= 1 << BitNumber
;
1990 else if (ModRegRm
.Register
== 6)
1993 Value
&= ~(1 << BitNumber
);
1995 else if (ModRegRm
.Register
== 7)
1998 Value
^= 1 << BitNumber
;
2001 if (ModRegRm
.Register
>= 5)
2003 /* Write back the result */
2004 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2006 /* Exception occurred */
2012 /* Return success */