2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2014 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
^ SecondValue
^ Result
) & 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
= Carry
102 ? (FirstValue
<= SecondValue
)
103 : (FirstValue
< SecondValue
);
104 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
105 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
106 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
114 Result
= FirstValue
& SecondValue
;
122 Result
= (FirstValue
- SecondValue
) & MaxValue
;
124 /* Update CF, OF and AF */
125 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
126 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
127 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
128 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
136 Result
= FirstValue
^ SecondValue
;
142 /* Shouldn't happen */
147 /* Update ZF, SF and PF */
148 State
->Flags
.Zf
= (Result
== 0);
149 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
150 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Result
));
152 /* Return the result */
159 Fast486RotateOperation(PFAST486_STATE State
,
165 ULONG HighestBit
= 1 << (Bits
- 1);
166 ULONG MaxValue
= HighestBit
| (HighestBit
- 1);
169 /* Normalize the count */
172 if ((Operation
== 2) || (Operation
== 3)) Count
%= Bits
+ 1;
174 /* If the count is zero, do nothing */
175 if (Count
== 0) return Value
;
177 /* 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
= State
->Flags
.Cf
189 ^ ((Result
& HighestBit
) != 0);
198 Result
= (Value
>> Count
) | (Value
<< (Bits
- Count
));
200 /* Update CF and OF */
201 State
->Flags
.Cf
= ((Result
& HighestBit
) != 0);
202 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
203 ^ ((Result
& (HighestBit
>> 1)) != 0);
211 Result
= (Value
<< Count
) | (State
->Flags
.Cf
<< (Count
- 1));
213 /* Complete the calculation, but make sure we don't shift by too much */
214 if ((Bits
- Count
) < 31) Result
|= Value
>> (Bits
- Count
+ 1);
216 /* Update CF and OF */
217 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
218 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
^ ((Result
& HighestBit
) != 0);
227 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
^ ((Value
& HighestBit
) != 0);
229 Result
= (Value
>> Count
) | (State
->Flags
.Cf
<< (Bits
- Count
));
231 /* Complete the calculation, but make sure we don't shift by too much */
232 if ((Bits
- Count
) < 31) Result
|= Value
<< (Bits
- Count
+ 1);
235 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
244 Result
= Value
<< Count
;
246 /* Update CF and OF */
247 State
->Flags
.Cf
= ((Value
& (1 << (Bits
- Count
))) != 0);
248 if (Count
== 1) State
->Flags
.Of
= State
->Flags
.Cf
249 ^ ((Result
& HighestBit
) != 0);
257 Result
= Value
>> Count
;
259 /* Update CF and OF */
260 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
261 if (Count
== 1) State
->Flags
.Of
= ((Value
& HighestBit
) != 0);
269 Result
= Value
>> Count
;
271 /* Fill the top Count bits with the sign bit */
272 if (Value
& HighestBit
) Result
|= ((1 << Count
) - 1) << (Bits
- Count
);
274 /* Update CF and OF */
275 State
->Flags
.Cf
= ((Value
& (1 << (Count
- 1))) != 0);
276 if (Count
== 1) State
->Flags
.Of
= FALSE
;
284 /* Update ZF, SF and PF */
285 State
->Flags
.Zf
= ((Result
& MaxValue
) == 0);
286 State
->Flags
.Sf
= ((Result
& HighestBit
) != 0);
287 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
290 /* Return the result */
294 /* PUBLIC FUNCTIONS ***********************************************************/
296 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082
)
298 UCHAR Immediate
, Value
;
299 FAST486_MOD_REG_RM ModRegRm
;
300 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
302 TOGGLE_ADSIZE(AddressSize
);
304 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
306 /* Exception occurred */
310 /* Fetch the immediate operand */
311 if (!Fast486FetchByte(State
, &Immediate
))
313 /* Exception occurred */
317 /* Read the operands */
318 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
320 /* Exception occurred */
324 /* Calculate the result */
325 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 8);
327 /* Unless this is CMP, write back the result */
328 if (ModRegRm
.Register
!= 7)
330 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
;
354 /* Fetch the immediate operand */
355 if (!Fast486FetchDword(State
, &Immediate
))
357 /* Exception occurred */
361 /* Read the operands */
362 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &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 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
379 USHORT Immediate
, Value
;
381 /* Fetch the immediate operand */
382 if (!Fast486FetchWord(State
, &Immediate
))
384 /* Exception occurred */
388 /* Read the operands */
389 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &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 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
, NULL
, &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 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
453 USHORT Immediate
= (USHORT
)((SHORT
)ImmByte
); // Sign extend
456 /* Read the operands */
457 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &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 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
474 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F
)
477 FAST486_MOD_REG_RM ModRegRm
;
478 BOOLEAN OperandSize
, AddressSize
;
480 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
482 TOGGLE_OPSIZE(OperandSize
);
483 TOGGLE_ADSIZE(AddressSize
);
485 /* Pop a value from the stack - this must be done first */
486 if (!Fast486StackPop(State
, &Value
))
488 /* Exception occurred */
492 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
494 /* Exception occurred - restore SP */
495 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= sizeof(ULONG
);
496 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= sizeof(USHORT
);
501 if (ModRegRm
.Register
!= 0)
504 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
508 if (OperandSize
) Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
509 else Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Value
));
512 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
515 FAST486_MOD_REG_RM ModRegRm
;
516 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
518 TOGGLE_ADSIZE(AddressSize
);
520 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
522 /* Exception occurred */
526 /* Fetch the count */
527 if (!Fast486FetchByte(State
, &Count
))
529 /* Exception occurred */
533 /* Read the operands */
534 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
536 /* Exception occurred */
540 /* Calculate the result */
541 Value
= LOBYTE(Fast486RotateOperation(State
,
547 /* Write back the result */
548 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
551 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
554 FAST486_MOD_REG_RM ModRegRm
;
555 BOOLEAN OperandSize
, AddressSize
;
557 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
559 TOGGLE_OPSIZE(OperandSize
);
560 TOGGLE_ADSIZE(AddressSize
);
562 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
564 /* Exception occurred */
568 /* Fetch the count */
569 if (!Fast486FetchByte(State
, &Count
))
571 /* Exception occurred */
579 /* Read the operands */
580 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
582 /* Exception occurred */
586 /* Calculate the result */
587 Value
= Fast486RotateOperation(State
,
593 /* Write back the result */
594 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
600 /* Read the operands */
601 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
603 /* Exception occurred */
607 /* Calculate the result */
608 Value
= LOWORD(Fast486RotateOperation(State
,
614 /* Write back the result */
615 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
619 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
622 FAST486_MOD_REG_RM ModRegRm
;
623 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
625 TOGGLE_ADSIZE(AddressSize
);
627 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
629 /* Exception occurred */
633 if (ModRegRm
.Register
!= 0)
636 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
640 /* Get the immediate operand */
641 if (!Fast486FetchByte(State
, &Immediate
))
643 /* Exception occurred */
647 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Immediate
);
650 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
652 FAST486_MOD_REG_RM ModRegRm
;
653 BOOLEAN OperandSize
, AddressSize
;
655 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
657 TOGGLE_OPSIZE(OperandSize
);
658 TOGGLE_ADSIZE(AddressSize
);
660 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
662 /* Exception occurred */
666 if (ModRegRm
.Register
!= 0)
669 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
677 /* Get the immediate operand */
678 if (!Fast486FetchDword(State
, &Immediate
))
680 /* Exception occurred */
684 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Immediate
);
690 /* Get the immediate operand */
691 if (!Fast486FetchWord(State
, &Immediate
))
693 /* Exception occurred */
697 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Immediate
);
701 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
704 FAST486_MOD_REG_RM ModRegRm
;
705 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
707 TOGGLE_ADSIZE(AddressSize
);
709 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
711 /* Exception occurred */
715 /* Read the operands */
716 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
718 /* Exception occurred */
722 /* Calculate the result */
723 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
725 /* Write back the result */
726 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
730 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
732 FAST486_MOD_REG_RM ModRegRm
;
733 BOOLEAN OperandSize
, AddressSize
;
735 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
737 TOGGLE_OPSIZE(OperandSize
);
738 TOGGLE_ADSIZE(AddressSize
);
740 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
742 /* Exception occurred */
750 /* Read the operands */
751 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
753 /* Exception occurred */
757 /* Calculate the result */
758 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
760 /* Write back the result */
761 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
767 /* Read the operands */
768 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
770 /* Exception occurred */
774 /* Calculate the result */
775 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
777 /* Write back the result */
778 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
782 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
785 FAST486_MOD_REG_RM ModRegRm
;
786 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
788 TOGGLE_ADSIZE(AddressSize
);
790 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
792 /* Exception occurred */
796 /* Read the operands */
797 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
799 /* Exception occurred */
803 /* Calculate the result */
804 Value
= LOBYTE(Fast486RotateOperation(State
,
808 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
810 /* Write back the result */
811 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
814 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
816 FAST486_MOD_REG_RM ModRegRm
;
817 BOOLEAN OperandSize
, AddressSize
;
819 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
821 TOGGLE_OPSIZE(OperandSize
);
822 TOGGLE_ADSIZE(AddressSize
);
824 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
826 /* Exception occurred */
834 /* Read the operands */
835 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
837 /* Exception occurred */
841 /* Calculate the result */
842 Value
= Fast486RotateOperation(State
,
846 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
848 /* Write back the result */
849 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
855 /* Read the operands */
856 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
858 /* Exception occurred */
862 /* Calculate the result */
863 Value
= LOWORD(Fast486RotateOperation(State
,
867 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
869 /* Write back the result */
870 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
874 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
877 FAST486_MOD_REG_RM ModRegRm
;
878 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
880 TOGGLE_ADSIZE(AddressSize
);
882 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
884 /* Exception occurred */
888 /* Read the operands */
889 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
891 /* Exception occurred */
895 switch (ModRegRm
.Register
)
901 UCHAR Immediate
, Result
;
903 /* Fetch the immediate byte */
904 if (!Fast486FetchByte(State
, &Immediate
))
906 /* Exception occurred */
910 /* Calculate the result */
911 Result
= Value
& Immediate
;
913 /* Update the flags */
914 State
->Flags
.Cf
= FALSE
;
915 State
->Flags
.Of
= FALSE
;
916 State
->Flags
.Zf
= (Result
== 0);
917 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
918 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
926 /* Write back the result */
927 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
935 /* Calculate the result */
936 UCHAR Result
= -Value
;
938 /* Update the flags */
939 State
->Flags
.Cf
= (Value
!= 0);
940 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
941 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
942 State
->Flags
.Zf
= (Result
== 0);
943 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
944 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
946 /* Write back the result */
947 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
955 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
957 /* Update the flags */
958 State
->Flags
.Cf
= State
->Flags
.Of
= (HIBYTE(Result
) != 0);
960 /* Write back the result */
961 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
969 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
971 /* Update the flags */
972 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -128) || (Result
> 127));
974 /* Write back the result */
975 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
983 UCHAR Quotient
, Remainder
;
988 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
992 Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
993 Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
995 /* Write back the results */
996 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
997 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1005 CHAR Quotient
, Remainder
;
1010 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1014 Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1015 Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1017 /* Write back the results */
1018 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1019 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1026 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1028 ULONG Value
= 0, SignFlag
;
1029 FAST486_MOD_REG_RM ModRegRm
;
1030 BOOLEAN OperandSize
, AddressSize
;
1032 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1034 TOGGLE_OPSIZE(OperandSize
);
1035 TOGGLE_ADSIZE(AddressSize
);
1037 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1039 /* Exception occurred */
1043 /* Set the sign flag */
1044 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1045 else SignFlag
= SIGN_FLAG_WORD
;
1047 /* Read the operand */
1051 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1053 /* Exception occurred */
1060 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1062 /* Exception occurred */
1067 switch (ModRegRm
.Register
)
1073 ULONG Immediate
= 0, Result
= 0;
1077 /* Fetch the immediate dword */
1078 if (!Fast486FetchDword(State
, &Immediate
))
1080 /* Exception occurred */
1086 /* Fetch the immediate word */
1087 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1089 /* Exception occurred */
1094 /* Calculate the result */
1095 Result
= Value
& Immediate
;
1097 /* Update the flags */
1098 State
->Flags
.Cf
= FALSE
;
1099 State
->Flags
.Of
= FALSE
;
1100 State
->Flags
.Zf
= (Result
== 0);
1101 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1102 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1110 /* Write back the result */
1114 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1119 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1128 /* Calculate the result */
1129 ULONG Result
= -Value
;
1130 if (!OperandSize
) Result
&= 0xFFFF;
1132 /* Update the flags */
1133 State
->Flags
.Cf
= (Value
!= 0);
1134 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1135 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1136 State
->Flags
.Zf
= (Result
== 0);
1137 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1138 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1140 /* Write back the result */
1144 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1149 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1160 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1162 /* Update the flags */
1163 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1165 /* Write back the result */
1166 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1167 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1171 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1173 /* Update the flags */
1174 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1176 /* Write back the result */
1177 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1178 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1189 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1191 /* Update the flags */
1192 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1194 /* Write back the result */
1195 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1196 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1200 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1202 /* Update the flags */
1203 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1205 /* Write back the result */
1206 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1207 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1219 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1225 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1226 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1227 ULONG Quotient
= Dividend
/ Value
;
1228 ULONG Remainder
= Dividend
% Value
;
1230 /* Write back the results */
1231 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1232 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1236 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1237 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1238 USHORT Quotient
= Dividend
/ Value
;
1239 USHORT Remainder
= Dividend
% Value
;
1241 /* Write back the results */
1242 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Quotient
;
1243 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1255 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1261 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1262 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1263 LONG Quotient
= Dividend
/ (LONG
)Value
;
1264 LONG Remainder
= Dividend
% (LONG
)Value
;
1266 /* Write back the results */
1267 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1268 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1272 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1273 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1274 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1275 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1277 /* Write back the results */
1278 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1279 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
, NULL
, &Value
))
1311 /* Exception occurred */
1315 if (ModRegRm
.Register
== 0)
1317 /* Increment and update OF and AF */
1319 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1320 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1324 /* Decrement and update OF and AF */
1325 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1327 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1331 State
->Flags
.Zf
= (Value
== 0);
1332 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1333 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1335 /* Write back the result */
1336 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
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
, NULL
, &Value
))
1369 /* Exception occurred */
1373 if (ModRegRm
.Register
== 0)
1375 /* Increment and update OF and AF */
1377 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
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
);
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 FAST486_SEG_REGS 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 FAST486_SEG_REGS 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 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 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1508 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1510 /* Exception occurred */
1514 if (ModRegRm
.Register
== 0)
1516 /* Increment and update OF */
1518 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1519 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1521 else if (ModRegRm
.Register
== 1)
1523 /* Decrement and update OF */
1524 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1526 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1528 else if (ModRegRm
.Register
== 2)
1530 /* Push the current value of IP */
1531 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1533 /* Exception occurred */
1537 /* Set the IP to the address */
1538 State
->InstPtr
.LowWord
= Value
;
1540 /* Clear the top half of EIP */
1541 State
->InstPtr
.Long
&= 0xFFFF;
1543 else if (ModRegRm
.Register
== 3)
1546 FAST486_SEG_REGS 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
;
1591 /* Clear the top half of EIP */
1592 State
->InstPtr
.Long
&= 0xFFFF;
1594 else if (ModRegRm
.Register
== 4)
1596 /* Set the IP to the address */
1597 State
->InstPtr
.LowWord
= Value
;
1599 /* Clear the top half of EIP */
1600 State
->InstPtr
.Long
&= 0xFFFF;
1602 else if (ModRegRm
.Register
== 5)
1605 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1607 /* Check for the segment override */
1608 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1610 /* Use the override segment instead */
1611 Segment
= State
->SegmentOverride
;
1614 /* Read the selector */
1615 if (!Fast486ReadMemory(State
,
1617 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1622 /* Exception occurred */
1626 /* Load the new code segment */
1627 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1629 /* Exception occurred */
1633 /* Set the IP to the address */
1634 State
->InstPtr
.LowWord
= Value
;
1636 /* Clear the top half of EIP */
1637 State
->InstPtr
.Long
&= 0xFFFF;
1639 else if (ModRegRm
.Register
== 6)
1641 /* Push the value on to the stack */
1642 Fast486StackPush(State
, Value
);
1648 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1652 if (ModRegRm
.Register
<= 1)
1655 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1656 State
->Flags
.Zf
= (Value
== 0);
1657 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1659 /* Write back the result */
1660 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1665 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00
)
1667 FAST486_MOD_REG_RM ModRegRm
;
1668 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1671 TOGGLE_ADSIZE(AddressSize
);
1673 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1675 /* Exception occurred */
1679 /* Check which operation this is */
1680 switch (ModRegRm
.Register
)
1685 /* Not recognized in real mode or virtual 8086 mode */
1686 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1689 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1693 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, State
->Ldtr
.Selector
);
1700 /* Not recognized in real mode or virtual 8086 mode */
1701 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1704 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1708 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, State
->TaskReg
.Selector
);
1716 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
1718 /* Not recognized in real mode or virtual 8086 mode */
1719 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1722 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1726 /* This is a privileged instruction */
1727 if (Fast486GetCurrentPrivLevel(State
) != 0)
1729 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1733 if (!Fast486ReadModrmWordOperands(State
,
1738 /* Exception occurred */
1742 /* Make sure the GDT contains the entry */
1743 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
1745 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1750 if (!Fast486ReadLinearMemory(State
,
1752 + GET_SEGMENT_INDEX(Selector
),
1756 /* Exception occurred */
1760 if (GET_SEGMENT_INDEX(Selector
) == 0)
1762 RtlZeroMemory(&State
->Ldtr
, sizeof(State
->Ldtr
));
1766 if (!GdtEntry
.Present
)
1768 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
1772 if (GdtEntry
.Signature
!= FAST486_LDT_SIGNATURE
)
1774 /* This is not a LDT descriptor */
1775 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1779 /* Update the LDTR */
1780 State
->Ldtr
.Selector
= Selector
;
1781 State
->Ldtr
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
1782 State
->Ldtr
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
1783 if (GdtEntry
.Granularity
) State
->Ldtr
.Limit
<<= 12;
1792 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
1794 /* Not recognized in real mode or virtual 8086 mode */
1795 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1798 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1802 /* This is a privileged instruction */
1803 if (Fast486GetCurrentPrivLevel(State
) != 0)
1805 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1809 if (!Fast486ReadModrmWordOperands(State
,
1814 /* Exception occurred */
1818 /* Make sure the GDT contains the entry */
1819 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
1821 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1826 if (!Fast486ReadLinearMemory(State
,
1828 + GET_SEGMENT_INDEX(Selector
),
1832 /* Exception occurred */
1836 if (GET_SEGMENT_INDEX(Selector
) == 0)
1838 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1842 if (!GdtEntry
.Present
)
1844 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
1848 if (GdtEntry
.Signature
!= FAST486_TSS_SIGNATURE
)
1850 /* This is not a TSS descriptor */
1851 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1856 State
->TaskReg
.Selector
= Selector
;
1857 State
->TaskReg
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
1858 State
->TaskReg
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
1859 if (GdtEntry
.Granularity
) State
->TaskReg
.Limit
<<= 12;
1860 State
->TaskReg
.Busy
= TRUE
;
1870 FAST486_GDT_ENTRY GdtEntry
;
1872 /* Not recognized in real mode or virtual 8086 mode */
1873 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1876 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1880 /* This is a privileged instruction */
1881 if (Fast486GetCurrentPrivLevel(State
) != 0)
1883 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1887 if (!Fast486ReadModrmWordOperands(State
,
1892 /* Exception occurred */
1896 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
1898 /* Make sure the GDT contains the entry */
1899 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
1902 State
->Flags
.Zf
= FALSE
;
1907 if (!Fast486ReadLinearMemory(State
,
1909 + GET_SEGMENT_INDEX(Selector
),
1913 /* Exception occurred */
1919 /* Make sure the LDT contains the entry */
1920 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
1923 State
->Flags
.Zf
= FALSE
;
1928 if (!Fast486ReadLinearMemory(State
,
1930 + GET_SEGMENT_INDEX(Selector
),
1934 /* Exception occurred */
1939 /* Set ZF if it is valid and accessible */
1940 State
->Flags
.Zf
= GdtEntry
.Present
// must be present
1941 && GdtEntry
.SystemType
// must be a segment
1942 && (((ModRegRm
.Register
== 4)
1943 /* code segments are only readable if the RW bit is set */
1944 && (!GdtEntry
.Executable
|| GdtEntry
.ReadWrite
))
1945 || ((ModRegRm
.Register
== 5)
1946 /* code segments are never writable, data segments are writable when RW is set */
1947 && (!GdtEntry
.Executable
&& GdtEntry
.ReadWrite
)))
1949 * for segments other than conforming code segments,
1950 * both RPL and CPL must be less than or equal to DPL
1952 && ((!GdtEntry
.Executable
|| !GdtEntry
.DirConf
)
1953 && ((GET_SEGMENT_RPL(Selector
) <= GdtEntry
.Dpl
)
1954 && (Fast486GetCurrentPrivLevel(State
) <= GdtEntry
.Dpl
)))
1955 /* for conforming code segments, DPL must be less than or equal to CPL */
1956 && ((GdtEntry
.Executable
&& GdtEntry
.DirConf
)
1957 && (GdtEntry
.Dpl
<= Fast486GetCurrentPrivLevel(State
)));
1966 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1971 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01
)
1973 // FAST486_TABLE_REG TableReg;
1975 FAST486_MOD_REG_RM ModRegRm
;
1976 BOOLEAN OperandSize
, AddressSize
;
1977 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1979 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1982 TOGGLE_OPSIZE(OperandSize
);
1983 TOGGLE_ADSIZE(AddressSize
);
1985 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1987 /* Exception occurred */
1991 /* Check for the segment override */
1992 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1994 /* Use the override segment instead */
1995 Segment
= State
->SegmentOverride
;
1998 /* Check which operation this is */
1999 switch (ModRegRm
.Register
)
2004 if (!ModRegRm
.Memory
)
2006 /* The second operand must be a memory location */
2007 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2011 /* Fill the 6-byte table register */
2012 // TableReg = State->Gdtr;
2013 *((PUSHORT
)&TableReg
) = State
->Gdtr
.Size
;
2014 *((PULONG
)&TableReg
[sizeof(USHORT
)]) = State
->Gdtr
.Address
;
2016 /* Store the GDTR */
2017 Fast486WriteMemory(State
,
2019 ModRegRm
.MemoryAddress
,
2029 if (!ModRegRm
.Memory
)
2031 /* The second operand must be a memory location */
2032 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2036 /* Fill the 6-byte table register */
2037 // TableReg = State->Idtr;
2038 *((PUSHORT
)&TableReg
) = State
->Idtr
.Size
;
2039 *((PULONG
)&TableReg
[sizeof(USHORT
)]) = State
->Idtr
.Address
;
2041 /* Store the IDTR */
2042 Fast486WriteMemory(State
,
2044 ModRegRm
.MemoryAddress
,
2054 /* This is a privileged instruction */
2055 if (Fast486GetCurrentPrivLevel(State
) != 0)
2057 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2061 if (!ModRegRm
.Memory
)
2063 /* The second operand must be a memory location */
2064 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2068 /* Read the new GDTR */
2069 if (!Fast486ReadMemory(State
,
2071 ModRegRm
.MemoryAddress
,
2076 /* Exception occurred */
2080 /* Load the new GDT */
2081 // State->Gdtr = TableReg;
2082 State
->Gdtr
.Size
= *((PUSHORT
)&TableReg
);
2083 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
2085 /* In 16-bit mode the highest byte is masked out */
2086 if (!OperandSize
) State
->Gdtr
.Address
&= 0x00FFFFFF;
2094 /* This is a privileged instruction */
2095 if (Fast486GetCurrentPrivLevel(State
) != 0)
2097 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2101 if (!ModRegRm
.Memory
)
2103 /* The second operand must be a memory location */
2104 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2108 /* Read the new IDTR */
2109 if (!Fast486ReadMemory(State
,
2111 ModRegRm
.MemoryAddress
,
2116 /* Exception occurred */
2120 /* Load the new IDT */
2121 // State->Idtr = TableReg;
2122 State
->Idtr
.Size
= *((PUSHORT
)&TableReg
);
2123 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
2125 /* In 16-bit mode the highest byte is masked out */
2126 if (!OperandSize
) State
->Idtr
.Address
&= 0x00FFFFFF;
2134 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2135 Fast486WriteModrmWordOperands(State
,
2138 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
2146 USHORT MachineStatusWord
;
2148 /* This is a privileged instruction */
2149 if (Fast486GetCurrentPrivLevel(State
) != 0)
2151 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2155 /* Read the new Machine Status Word */
2156 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &MachineStatusWord
))
2158 /* Exception occurred */
2162 /* This instruction cannot be used to return to real mode */
2163 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
2164 && !(MachineStatusWord
& FAST486_CR0_PE
))
2166 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2170 /* Set the lowest 4 bits */
2171 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
2172 State
->ControlRegisters
[FAST486_REG_CR0
] |= MachineStatusWord
& 0x0F;
2180 #ifndef FAST486_NO_PREFETCH
2181 /* Invalidate the prefetch */
2182 State
->PrefetchValid
= FALSE
;
2185 /* This is a privileged instruction */
2186 if (Fast486GetCurrentPrivLevel(State
) != 0)
2188 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2192 if (!ModRegRm
.Memory
)
2194 /* The second operand must be a memory location */
2195 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2199 if (State
->Tlb
!= NULL
)
2201 /* Clear the TLB entry */
2202 State
->Tlb
[ModRegRm
.MemoryAddress
>> 12] = INVALID_TLB_FIELD
;
2211 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2216 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9
)
2218 FAST486_MOD_REG_RM ModRegRm
;
2219 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2221 TOGGLE_ADSIZE(AddressSize
);
2223 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2225 /* Exception occurred */
2229 /* All of them are reserved (UD2) */
2230 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2234 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA
)
2236 FAST486_MOD_REG_RM ModRegRm
;
2237 BOOLEAN OperandSize
, AddressSize
;
2241 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2243 TOGGLE_OPSIZE(OperandSize
);
2244 TOGGLE_ADSIZE(AddressSize
);
2246 /* Get the number of bits */
2247 if (OperandSize
) DataSize
= 32;
2250 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2252 /* Exception occurred */
2256 if (ModRegRm
.Register
< 4)
2259 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2263 /* Get the bit number */
2264 if (!Fast486FetchByte(State
, &BitNumber
))
2266 /* Exception occurred */
2270 if (ModRegRm
.Memory
)
2273 * For memory operands, add the bit offset divided by
2274 * the data size to the address
2276 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
2279 /* Normalize the bit number */
2280 BitNumber
%= DataSize
;
2286 /* Read the value */
2287 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
2289 /* Exception occurred */
2293 /* Set CF to the bit value */
2294 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
2296 if (ModRegRm
.Register
== 5)
2299 Value
|= 1 << BitNumber
;
2301 else if (ModRegRm
.Register
== 6)
2304 Value
&= ~(1 << BitNumber
);
2306 else if (ModRegRm
.Register
== 7)
2309 Value
^= 1 << BitNumber
;
2312 if (ModRegRm
.Register
>= 5)
2314 /* Write back the result */
2315 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
2317 /* Exception occurred */
2326 /* Read the value */
2327 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
2329 /* Exception occurred */
2333 /* Set CF to the bit value */
2334 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
2336 if (ModRegRm
.Register
== 5)
2339 Value
|= 1 << BitNumber
;
2341 else if (ModRegRm
.Register
== 6)
2344 Value
&= ~(1 << BitNumber
);
2346 else if (ModRegRm
.Register
== 7)
2349 Value
^= 1 << BitNumber
;
2352 if (ModRegRm
.Register
>= 5)
2354 /* Write back the result */
2355 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2357 /* Exception occurred */