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
;
281 /* Update ZF, SF and PF */
282 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
283 State
->Flags
.Sf
= (Result
& HighestBit
) ? TRUE
: FALSE
;
284 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) ? TRUE
: FALSE
;
946 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
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) ? TRUE
: FALSE
;
967 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
968 State
->Flags
.Af
= ((Value
& 0x0F) != 0) ? TRUE
: FALSE
;
969 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
970 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
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
) ? TRUE
: FALSE
;
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
=
998 ((Result
< -128) || (Result
> 127)) ? TRUE
: FALSE
;
1000 /* Write back the result */
1001 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1009 UCHAR Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1010 UCHAR Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1012 /* Write back the results */
1013 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1014 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1022 CHAR Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1023 CHAR Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1025 /* Write back the results */
1026 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1027 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1036 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1038 ULONG Dummy
, Value
= 0, SignFlag
;
1039 FAST486_MOD_REG_RM ModRegRm
;
1040 BOOLEAN OperandSize
, AddressSize
;
1042 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1044 TOGGLE_OPSIZE(OperandSize
);
1045 TOGGLE_ADSIZE(AddressSize
);
1047 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1049 /* Exception occurred */
1053 /* Set the sign flag */
1054 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1055 else SignFlag
= SIGN_FLAG_WORD
;
1057 /* Read the operand */
1061 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1063 /* Exception occurred */
1070 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, (PUSHORT
)&Dummy
, (PUSHORT
)&Value
))
1072 /* Exception occurred */
1077 switch (ModRegRm
.Register
)
1083 ULONG Immediate
= 0, Result
= 0;
1087 /* Fetch the immediate dword */
1088 if (!Fast486FetchDword(State
, &Immediate
))
1090 /* Exception occurred */
1096 /* Fetch the immediate word */
1097 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1099 /* Exception occurred */
1104 /* Calculate the result */
1105 Result
= Value
& Immediate
;
1107 /* Update the flags */
1108 State
->Flags
.Cf
= FALSE
;
1109 State
->Flags
.Of
= FALSE
;
1110 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1111 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
1112 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1120 /* Write back the result */
1124 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1129 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1136 /* Calculate the result */
1137 ULONG Result
= -Value
;
1138 if (!OperandSize
) Result
&= 0xFFFF;
1140 /* Update the flags */
1141 State
->Flags
.Cf
= (Value
!= 0) ? TRUE
: FALSE
;
1142 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1143 State
->Flags
.Af
= ((Value
& 0x0F) != 0) ? TRUE
: FALSE
;
1144 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1145 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
1146 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1148 /* Write back the result */
1152 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1157 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1166 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1168 /* Update the flags */
1169 State
->Flags
.Cf
= State
->Flags
.Of
=
1170 (Result
& 0xFFFFFFFF00000000ULL
) ? TRUE
: FALSE
;
1172 /* Write back the result */
1173 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1174 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1178 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1180 /* Update the flags */
1181 State
->Flags
.Cf
= State
->Flags
.Of
= HIWORD(Result
) ? TRUE
: FALSE
;
1183 /* Write back the result */
1184 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1185 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1196 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1198 /* Update the flags */
1199 State
->Flags
.Cf
= State
->Flags
.Of
=
1200 ((Result
< -2147483648LL) || (Result
> 2147483647LL)) ? TRUE
: FALSE
;
1202 /* Write back the result */
1203 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1204 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1208 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1210 /* Update the flags */
1211 State
->Flags
.Cf
= State
->Flags
.Of
=
1212 ((Result
< -32768) || (Result
> 32767)) ? TRUE
: FALSE
;
1214 /* Write back the result */
1215 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1216 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1227 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1228 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1229 ULONG Quotient
= Dividend
/ Value
;
1230 ULONG Remainder
= Dividend
% Value
;
1232 /* Write back the results */
1233 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1234 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1238 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1239 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1240 USHORT Quotient
= Dividend
/ Value
;
1241 USHORT Remainder
= Dividend
% Value
;
1243 /* Write back the results */
1244 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1245 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1256 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1257 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1258 LONG Quotient
= Dividend
/ (LONG
)Value
;
1259 LONG Remainder
= Dividend
% (LONG
)Value
;
1261 /* Write back the results */
1262 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1263 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1267 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1268 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1269 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1270 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1272 /* Write back the results */
1273 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1274 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1284 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1287 FAST486_MOD_REG_RM ModRegRm
;
1288 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1290 TOGGLE_ADSIZE(AddressSize
);
1292 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1294 /* Exception occurred */
1298 if (ModRegRm
.Register
> 1)
1301 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1305 /* Read the operands */
1306 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1308 /* Exception occurred */
1312 if (ModRegRm
.Register
== 0)
1314 /* Increment and update OF and AF */
1316 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1317 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1321 /* Decrement and update OF and AF */
1322 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1324 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1328 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1329 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
1330 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1332 /* Write back the result */
1333 return Fast486WriteModrmByteOperands(State
,
1339 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1341 FAST486_MOD_REG_RM ModRegRm
;
1342 BOOLEAN OperandSize
, AddressSize
;
1344 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1346 TOGGLE_OPSIZE(OperandSize
);
1347 TOGGLE_ADSIZE(AddressSize
);
1349 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1351 /* Exception occurred */
1355 if (ModRegRm
.Register
== 7)
1358 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1362 /* Read the operands */
1367 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1369 /* Exception occurred */
1373 if (ModRegRm
.Register
== 0)
1375 /* Increment and update OF and AF */
1377 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1378 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1380 else if (ModRegRm
.Register
== 1)
1382 /* Decrement and update OF and AF */
1383 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1385 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1387 else if (ModRegRm
.Register
== 2)
1389 /* Push the current value of EIP */
1390 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1392 /* Exception occurred */
1396 /* Set the EIP to the address */
1397 State
->InstPtr
.Long
= Value
;
1399 else if (ModRegRm
.Register
== 3)
1402 INT Segment
= FAST486_REG_DS
;
1404 /* Check for the segment override */
1405 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1407 /* Use the override segment instead */
1408 Segment
= State
->SegmentOverride
;
1411 /* Read the selector */
1412 if (!Fast486ReadMemory(State
,
1414 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1419 /* Exception occurred */
1423 /* Push the current value of CS */
1424 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1426 /* Exception occurred */
1430 /* Push the current value of EIP */
1431 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1433 /* Exception occurred */
1437 /* Load the new code segment */
1438 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1440 /* Exception occurred */
1444 /* Set the EIP to the address */
1445 State
->InstPtr
.Long
= Value
;
1447 else if (ModRegRm
.Register
== 4)
1449 /* Set the EIP to the address */
1450 State
->InstPtr
.Long
= Value
;
1452 else if (ModRegRm
.Register
== 5)
1455 INT Segment
= FAST486_REG_DS
;
1457 /* Check for the segment override */
1458 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1460 /* Use the override segment instead */
1461 Segment
= State
->SegmentOverride
;
1464 /* Read the selector */
1465 if (!Fast486ReadMemory(State
,
1467 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1472 /* Exception occurred */
1476 /* Load the new code segment */
1477 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1479 /* Exception occurred */
1483 /* Set the EIP to the address */
1484 State
->InstPtr
.Long
= Value
;
1486 else if (ModRegRm
.Register
== 6)
1488 /* Push the value on to the stack */
1489 return Fast486StackPush(State
, Value
);
1492 if (ModRegRm
.Register
<= 1)
1495 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1496 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
1497 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1499 /* Write back the result */
1500 return Fast486WriteModrmDwordOperands(State
,
1508 USHORT Dummy
, Value
;
1510 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1512 /* Exception occurred */
1516 if (ModRegRm
.Register
== 0)
1518 /* Increment and update OF */
1520 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1521 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1523 else if (ModRegRm
.Register
== 1)
1525 /* Decrement and update OF */
1526 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1528 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1530 else if (ModRegRm
.Register
== 2)
1532 /* Push the current value of IP */
1533 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1535 /* Exception occurred */
1539 /* Set the IP to the address */
1540 State
->InstPtr
.LowWord
= Value
;
1542 else if (ModRegRm
.Register
== 3)
1545 INT Segment
= FAST486_REG_DS
;
1547 /* Check for the segment override */
1548 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1550 /* Use the override segment instead */
1551 Segment
= State
->SegmentOverride
;
1554 /* Read the selector */
1555 if (!Fast486ReadMemory(State
,
1557 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1562 /* Exception occurred */
1566 /* Push the current value of CS */
1567 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1569 /* Exception occurred */
1573 /* Push the current value of IP */
1574 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1576 /* Exception occurred */
1580 /* Load the new code segment */
1581 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1583 /* Exception occurred */
1587 /* Set the IP to the address */
1588 State
->InstPtr
.LowWord
= Value
;
1591 else if (ModRegRm
.Register
== 4)
1593 /* Set the IP to the address */
1594 State
->InstPtr
.LowWord
= Value
;
1596 else if (ModRegRm
.Register
== 5)
1599 INT Segment
= FAST486_REG_DS
;
1601 /* Check for the segment override */
1602 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1604 /* Use the override segment instead */
1605 Segment
= State
->SegmentOverride
;
1608 /* Read the selector */
1609 if (!Fast486ReadMemory(State
,
1611 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1616 /* Exception occurred */
1620 /* Load the new code segment */
1621 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1623 /* Exception occurred */
1627 /* Set the IP to the address */
1628 State
->InstPtr
.LowWord
= Value
;
1630 else if (ModRegRm
.Register
== 6)
1632 /* Push the value on to the stack */
1633 return Fast486StackPush(State
, Value
);
1638 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1642 if (ModRegRm
.Register
<= 1)
1645 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1646 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
1647 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1649 /* Write back the result */
1650 return Fast486WriteModrmWordOperands(State
,
1660 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
1663 FAST486_MOD_REG_RM ModRegRm
;
1664 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1665 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1668 TOGGLE_ADSIZE(AddressSize
);
1670 /* Check for the segment override */
1671 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1673 /* Use the override segment instead */
1674 Segment
= State
->SegmentOverride
;
1677 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1679 /* Exception occurred */
1683 /* Check which operation this is */
1684 switch (ModRegRm
.Register
)
1689 if (!ModRegRm
.Memory
)
1691 /* The second operand must be a memory location */
1692 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1696 /* Fill the 6-byte table register */
1697 RtlCopyMemory(TableReg
, &State
->Gdtr
.Size
, sizeof(USHORT
));
1698 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Gdtr
.Address
, sizeof(ULONG
));
1700 /* Store the GDTR */
1701 return Fast486WriteMemory(State
,
1703 ModRegRm
.MemoryAddress
,
1711 if (!ModRegRm
.Memory
)
1713 /* The second operand must be a memory location */
1714 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1718 /* Fill the 6-byte table register */
1719 RtlCopyMemory(TableReg
, &State
->Idtr
.Size
, sizeof(USHORT
));
1720 RtlCopyMemory(&TableReg
[sizeof(USHORT
)], &State
->Idtr
.Address
, sizeof(ULONG
));
1722 /* Store the IDTR */
1723 return Fast486WriteMemory(State
,
1725 ModRegRm
.MemoryAddress
,
1733 /* This is a privileged instruction */
1734 if (Fast486GetCurrentPrivLevel(State
) != 0)
1736 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1740 if (!ModRegRm
.Memory
)
1742 /* The second operand must be a memory location */
1743 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1747 /* Read the new GDTR */
1748 if (!Fast486ReadMemory(State
,
1750 ModRegRm
.MemoryAddress
,
1755 /* Exception occurred */
1759 /* Load the new GDT */
1760 State
->Gdtr
.Size
= *((PUSHORT
)TableReg
);
1761 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1769 /* This is a privileged instruction */
1770 if (Fast486GetCurrentPrivLevel(State
) != 0)
1772 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1776 if (!ModRegRm
.Memory
)
1778 /* The second operand must be a memory location */
1779 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1783 /* Read the new IDTR */
1784 if (!Fast486ReadMemory(State
,
1786 ModRegRm
.MemoryAddress
,
1791 /* Exception occurred */
1795 /* Load the new IDT */
1796 State
->Idtr
.Size
= *((PUSHORT
)TableReg
);
1797 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
1805 /* Store the lower 16 bits of CR0 */
1806 return Fast486WriteModrmWordOperands(State
,
1809 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
1815 USHORT MasterStatusWord
, Dummy
;
1817 /* This is a privileged instruction */
1818 if (Fast486GetCurrentPrivLevel(State
) != 0)
1820 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1824 /* Read the new master status word */
1825 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &MasterStatusWord
))
1827 /* Exception occurred */
1831 /* This instruction cannot be used to return to real mode */
1832 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1833 && !(MasterStatusWord
& FAST486_CR0_PE
))
1835 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1839 /* Set the lowest 4 bits */
1840 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
1841 State
->ControlRegisters
[FAST486_REG_CR0
] |= MasterStatusWord
& 0x0F;
1856 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1862 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
1864 FAST486_MOD_REG_RM ModRegRm
;
1865 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1867 TOGGLE_ADSIZE(AddressSize
);
1869 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1871 /* Exception occurred */
1875 /* All of them are reserved (UD2) */
1876 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1880 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
1882 FAST486_MOD_REG_RM ModRegRm
;
1883 BOOLEAN OperandSize
, AddressSize
;
1887 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1889 TOGGLE_OPSIZE(OperandSize
);
1890 TOGGLE_ADSIZE(AddressSize
);
1892 /* Get the number of bits */
1893 if (OperandSize
) DataSize
= 32;
1896 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1898 /* Exception occurred */
1902 if (ModRegRm
.Register
< 4)
1905 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1909 /* Get the bit number */
1910 if (!Fast486FetchByte(State
, &BitNumber
))
1912 /* Exception occurred */
1916 if (ModRegRm
.Memory
)
1919 * For memory operands, add the bit offset divided by
1920 * the data size to the address
1922 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
1925 /* Normalize the bit number */
1926 BitNumber
&= (1 << DataSize
) - 1;
1932 /* Read the value */
1933 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1935 /* Exception occurred */
1939 /* Set CF to the bit value */
1940 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1942 if (ModRegRm
.Register
== 5)
1945 Value
|= 1 << BitNumber
;
1947 else if (ModRegRm
.Register
== 6)
1950 Value
&= ~(1 << BitNumber
);
1952 else if (ModRegRm
.Register
== 7)
1955 Value
^= 1 << BitNumber
;
1958 if (ModRegRm
.Register
>= 5)
1960 /* Write back the result */
1961 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
1963 /* Exception occurred */
1970 USHORT Dummy
, Value
;
1972 /* Read the value */
1973 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Value
))
1975 /* Exception occurred */
1979 /* Set CF to the bit value */
1980 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
1982 if (ModRegRm
.Register
== 5)
1985 Value
|= 1 << BitNumber
;
1987 else if (ModRegRm
.Register
== 6)
1990 Value
&= ~(1 << BitNumber
);
1992 else if (ModRegRm
.Register
== 7)
1995 Value
^= 1 << BitNumber
;
1998 if (ModRegRm
.Register
>= 5)
2000 /* Write back the result */
2001 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2003 /* Exception occurred */
2009 /* Return success */