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
;
989 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
993 Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
994 Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
999 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1003 /* Write back the results */
1004 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1005 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1019 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1023 Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1024 Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1026 if (Quotient
> 127 || Quotient
< -128)
1029 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1033 /* Write back the results */
1034 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)((CHAR
)Quotient
);
1035 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1042 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1044 ULONG Value
= 0, SignFlag
;
1045 FAST486_MOD_REG_RM ModRegRm
;
1046 BOOLEAN OperandSize
, AddressSize
;
1048 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1050 TOGGLE_OPSIZE(OperandSize
);
1051 TOGGLE_ADSIZE(AddressSize
);
1053 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1055 /* Exception occurred */
1059 /* Set the sign flag */
1060 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1061 else SignFlag
= SIGN_FLAG_WORD
;
1063 /* Read the operand */
1067 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1069 /* Exception occurred */
1076 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1078 /* Exception occurred */
1083 switch (ModRegRm
.Register
)
1089 ULONG Immediate
= 0, Result
= 0;
1093 /* Fetch the immediate dword */
1094 if (!Fast486FetchDword(State
, &Immediate
))
1096 /* Exception occurred */
1102 /* Fetch the immediate word */
1103 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1105 /* Exception occurred */
1110 /* Calculate the result */
1111 Result
= Value
& Immediate
;
1113 /* Update the flags */
1114 State
->Flags
.Cf
= FALSE
;
1115 State
->Flags
.Of
= FALSE
;
1116 State
->Flags
.Zf
= (Result
== 0);
1117 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1118 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1126 /* Write back the result */
1130 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1135 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1144 /* Calculate the result */
1145 ULONG Result
= -(LONG
)Value
;
1146 if (!OperandSize
) Result
&= 0xFFFF;
1148 /* Update the flags */
1149 State
->Flags
.Cf
= (Value
!= 0);
1150 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1151 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1152 State
->Flags
.Zf
= (Result
== 0);
1153 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1154 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1156 /* Write back the result */
1160 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1165 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1176 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1178 /* Update the flags */
1179 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1181 /* Write back the result */
1182 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1183 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1187 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1189 /* Update the flags */
1190 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1192 /* Write back the result */
1193 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1194 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1205 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1207 /* Update the flags */
1208 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1210 /* Write back the result */
1211 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1212 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1216 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1218 /* Update the flags */
1219 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1221 /* Write back the result */
1222 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1223 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1235 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1241 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1242 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1243 ULONGLONG Quotient
= Dividend
/ Value
;
1244 ULONG Remainder
= Dividend
% Value
;
1246 if (Quotient
> 0xFFFFFFFFULL
)
1249 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1253 /* Write back the results */
1254 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1255 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1259 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1260 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1261 ULONG Quotient
= Dividend
/ Value
;
1262 USHORT Remainder
= Dividend
% Value
;
1264 if (Quotient
> 0xFFFF)
1267 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1271 /* Write back the results */
1272 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1273 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= Remainder
;
1285 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1291 LONGLONG Dividend
= (LONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1292 | ((LONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1293 LONGLONG Quotient
= Dividend
/ (LONG
)Value
;
1294 LONG Remainder
= Dividend
% (LONG
)Value
;
1296 if (Quotient
> 2147483647LL || Quotient
< -2147483648LL)
1299 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1303 /* Write back the results */
1304 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)((LONG
)Quotient
);
1305 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1309 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1310 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1311 LONG Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1312 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1314 if (Quotient
> 32767 || Quotient
< -32768)
1317 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1321 /* Write back the results */
1322 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)((SHORT
)Quotient
);
1323 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1331 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1334 FAST486_MOD_REG_RM ModRegRm
;
1335 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1337 TOGGLE_ADSIZE(AddressSize
);
1339 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1341 /* Exception occurred */
1345 if (ModRegRm
.Register
> 1)
1348 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1352 /* Read the operands */
1353 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1355 /* Exception occurred */
1359 if (ModRegRm
.Register
== 0)
1361 /* Increment and update OF and AF */
1363 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1364 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1368 /* Decrement and update OF and AF */
1369 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1371 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1375 State
->Flags
.Zf
= (Value
== 0);
1376 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1377 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1379 /* Write back the result */
1380 Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
1383 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1385 FAST486_MOD_REG_RM ModRegRm
;
1386 BOOLEAN OperandSize
, AddressSize
;
1388 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1390 TOGGLE_OPSIZE(OperandSize
);
1391 TOGGLE_ADSIZE(AddressSize
);
1393 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1395 /* Exception occurred */
1399 if (ModRegRm
.Register
== 7)
1402 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1406 /* Read the operands */
1411 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1413 /* Exception occurred */
1417 if (ModRegRm
.Register
== 0)
1419 /* Increment and update OF and AF */
1421 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1422 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1424 else if (ModRegRm
.Register
== 1)
1426 /* Decrement and update OF and AF */
1427 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1429 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1431 else if (ModRegRm
.Register
== 2)
1433 /* Push the current value of EIP */
1434 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1436 /* Exception occurred */
1440 /* Set the EIP to the address */
1441 State
->InstPtr
.Long
= Value
;
1443 else if (ModRegRm
.Register
== 3)
1446 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1448 /* Check for the segment override */
1449 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1451 /* Use the override segment instead */
1452 Segment
= State
->SegmentOverride
;
1455 /* Read the selector */
1456 if (!Fast486ReadMemory(State
,
1458 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1463 /* Exception occurred */
1467 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1469 if (!Fast486ProcessGate(State
, Selector
, Value
, TRUE
))
1471 /* Gate processed or exception occurred */
1476 /* Push the current value of CS */
1477 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1479 /* Exception occurred */
1483 /* Push the current value of EIP */
1484 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1486 /* Exception occurred */
1490 /* Load the new code segment */
1491 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1493 /* Exception occurred */
1497 /* Set the EIP to the address */
1498 State
->InstPtr
.Long
= Value
;
1500 else if (ModRegRm
.Register
== 4)
1502 /* Set the EIP to the address */
1503 State
->InstPtr
.Long
= Value
;
1505 else if (ModRegRm
.Register
== 5)
1508 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1510 /* Check for the segment override */
1511 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1513 /* Use the override segment instead */
1514 Segment
= State
->SegmentOverride
;
1517 /* Read the selector */
1518 if (!Fast486ReadMemory(State
,
1520 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1525 /* Exception occurred */
1529 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1531 if (!Fast486ProcessGate(State
, Selector
, Value
, FALSE
))
1533 /* Gate processed or exception occurred */
1538 /* Load the new code segment */
1539 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1541 /* Exception occurred */
1545 /* Set the EIP to the address */
1546 State
->InstPtr
.Long
= Value
;
1548 else if (ModRegRm
.Register
== 6)
1550 /* Push the value on to the stack */
1551 Fast486StackPush(State
, Value
);
1555 if (ModRegRm
.Register
<= 1)
1558 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
1559 State
->Flags
.Zf
= (Value
== 0);
1560 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1562 /* Write back the result */
1563 Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
1570 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1572 /* Exception occurred */
1576 if (ModRegRm
.Register
== 0)
1578 /* Increment and update OF */
1580 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1581 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1583 else if (ModRegRm
.Register
== 1)
1585 /* Decrement and update OF */
1586 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1588 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1590 else if (ModRegRm
.Register
== 2)
1592 /* Push the current value of IP */
1593 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1595 /* Exception occurred */
1599 /* Set the IP to the address */
1600 State
->InstPtr
.LowWord
= Value
;
1602 /* Clear the top half of EIP */
1603 State
->InstPtr
.Long
&= 0xFFFF;
1605 else if (ModRegRm
.Register
== 3)
1608 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1610 /* Check for the segment override */
1611 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1613 /* Use the override segment instead */
1614 Segment
= State
->SegmentOverride
;
1617 /* Read the selector */
1618 if (!Fast486ReadMemory(State
,
1620 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1625 /* Exception occurred */
1629 /* Push the current value of CS */
1630 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1632 /* Exception occurred */
1636 /* Push the current value of IP */
1637 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1639 /* Exception occurred */
1643 /* Load the new code segment */
1644 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1646 /* Exception occurred */
1650 /* Set the IP to the address */
1651 State
->InstPtr
.LowWord
= Value
;
1653 /* Clear the top half of EIP */
1654 State
->InstPtr
.Long
&= 0xFFFF;
1656 else if (ModRegRm
.Register
== 4)
1658 /* Set the IP to the address */
1659 State
->InstPtr
.LowWord
= Value
;
1661 /* Clear the top half of EIP */
1662 State
->InstPtr
.Long
&= 0xFFFF;
1664 else if (ModRegRm
.Register
== 5)
1667 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1669 /* Check for the segment override */
1670 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1672 /* Use the override segment instead */
1673 Segment
= State
->SegmentOverride
;
1676 /* Read the selector */
1677 if (!Fast486ReadMemory(State
,
1679 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1684 /* Exception occurred */
1688 /* Load the new code segment */
1689 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1691 /* Exception occurred */
1695 /* Set the IP to the address */
1696 State
->InstPtr
.LowWord
= Value
;
1698 /* Clear the top half of EIP */
1699 State
->InstPtr
.Long
&= 0xFFFF;
1701 else if (ModRegRm
.Register
== 6)
1703 /* Push the value on to the stack */
1704 Fast486StackPush(State
, Value
);
1710 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1714 if (ModRegRm
.Register
<= 1)
1717 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1718 State
->Flags
.Zf
= (Value
== 0);
1719 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1721 /* Write back the result */
1722 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
1727 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00
)
1729 FAST486_MOD_REG_RM ModRegRm
;
1730 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1733 TOGGLE_ADSIZE(AddressSize
);
1735 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1737 /* Exception occurred */
1741 /* Check which operation this is */
1742 switch (ModRegRm
.Register
)
1747 /* Not recognized in real mode or virtual 8086 mode */
1748 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1751 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1755 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, State
->Ldtr
.Selector
);
1762 /* Not recognized in real mode or virtual 8086 mode */
1763 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1766 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1770 Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, State
->TaskReg
.Selector
);
1779 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
1781 /* Not recognized in real mode or virtual 8086 mode */
1782 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1785 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1789 /* This is a privileged instruction */
1790 if (Fast486GetCurrentPrivLevel(State
) != 0)
1792 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1796 if (!Fast486ReadModrmWordOperands(State
,
1801 /* Exception occurred */
1805 if (Selector
& SEGMENT_TABLE_INDICATOR
)
1807 /* This selector doesn't point to the GDT */
1808 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1812 if (!Fast486ReadDescriptorEntry(State
,
1815 (PFAST486_GDT_ENTRY
)&GdtEntry
))
1817 /* Exception occurred */
1823 /* Invalid selector */
1824 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1828 if (GET_SEGMENT_INDEX(Selector
) == 0)
1830 RtlZeroMemory(&State
->Ldtr
, sizeof(State
->Ldtr
));
1834 if (!GdtEntry
.Present
)
1836 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
1840 if (GdtEntry
.Signature
!= FAST486_LDT_SIGNATURE
)
1842 /* This is not a LDT descriptor */
1843 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1847 /* Update the LDTR */
1848 State
->Ldtr
.Selector
= Selector
;
1849 State
->Ldtr
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
1850 State
->Ldtr
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
1852 if (GdtEntry
.Granularity
)
1854 State
->Ldtr
.Limit
<<= 12;
1855 State
->Ldtr
.Limit
|= 0x00000FFF;
1866 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
1868 /* Not recognized in real mode or virtual 8086 mode */
1869 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1872 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1876 /* This is a privileged instruction */
1877 if (Fast486GetCurrentPrivLevel(State
) != 0)
1879 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1883 if (!Fast486ReadModrmWordOperands(State
,
1888 /* Exception occurred */
1892 if (Selector
& SEGMENT_TABLE_INDICATOR
)
1894 /* This selector doesn't point to the GDT */
1895 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1899 if (!Fast486ReadDescriptorEntry(State
,
1902 (PFAST486_GDT_ENTRY
)&GdtEntry
))
1904 /* Exception occurred */
1910 /* Invalid selector */
1911 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1915 if (GET_SEGMENT_INDEX(Selector
) == 0)
1917 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1921 if (!GdtEntry
.Present
)
1923 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
1927 if (GdtEntry
.Signature
!= FAST486_TSS_SIGNATURE
)
1929 /* This is not a TSS descriptor */
1930 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1935 State
->TaskReg
.Selector
= Selector
;
1936 State
->TaskReg
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
1937 State
->TaskReg
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
1939 if (GdtEntry
.Granularity
)
1941 State
->TaskReg
.Limit
<<= 12;
1942 State
->TaskReg
.Limit
|= 0x00000FFF;
1954 FAST486_GDT_ENTRY GdtEntry
;
1956 /* Not recognized in real mode or virtual 8086 mode */
1957 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1960 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1964 /* This is a privileged instruction */
1965 if (Fast486GetCurrentPrivLevel(State
) != 0)
1967 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1971 if (!Fast486ReadModrmWordOperands(State
,
1976 /* Exception occurred */
1980 if (!Fast486ReadDescriptorEntry(State
, Selector
, &Valid
, &GdtEntry
))
1982 /* Exception occurred */
1989 State
->Flags
.Zf
= FALSE
;
1993 /* Set ZF if it is valid and accessible */
1994 State
->Flags
.Zf
= GdtEntry
.Present
// must be present
1995 && GdtEntry
.SystemType
// must be a segment
1996 && (((ModRegRm
.Register
== 4)
1997 /* code segments are only readable if the RW bit is set */
1998 && (!GdtEntry
.Executable
|| GdtEntry
.ReadWrite
))
1999 || ((ModRegRm
.Register
== 5)
2000 /* code segments are never writable, data segments are writable when RW is set */
2001 && (!GdtEntry
.Executable
&& GdtEntry
.ReadWrite
)))
2003 * for segments other than conforming code segments,
2004 * both RPL and CPL must be less than or equal to DPL
2006 && ((!GdtEntry
.Executable
|| !GdtEntry
.DirConf
)
2007 && ((GET_SEGMENT_RPL(Selector
) <= GdtEntry
.Dpl
)
2008 && (Fast486GetCurrentPrivLevel(State
) <= GdtEntry
.Dpl
)))
2009 /* for conforming code segments, DPL must be less than or equal to CPL */
2010 && ((GdtEntry
.Executable
&& GdtEntry
.DirConf
)
2011 && (GdtEntry
.Dpl
<= Fast486GetCurrentPrivLevel(State
)));
2020 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2025 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01
)
2027 // FAST486_TABLE_REG TableReg;
2029 FAST486_MOD_REG_RM ModRegRm
;
2030 BOOLEAN OperandSize
, AddressSize
;
2031 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
2033 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2036 TOGGLE_OPSIZE(OperandSize
);
2037 TOGGLE_ADSIZE(AddressSize
);
2039 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2041 /* Exception occurred */
2045 /* Check for the segment override */
2046 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
2048 /* Use the override segment instead */
2049 Segment
= State
->SegmentOverride
;
2052 /* Check which operation this is */
2053 switch (ModRegRm
.Register
)
2058 if (!ModRegRm
.Memory
)
2060 /* The second operand must be a memory location */
2061 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2065 /* Fill the 6-byte table register */
2066 // TableReg = State->Gdtr;
2067 *((PUSHORT
)&TableReg
) = State
->Gdtr
.Size
;
2068 *((PULONG
)&TableReg
[sizeof(USHORT
)]) = State
->Gdtr
.Address
;
2070 /* Store the GDTR */
2071 Fast486WriteMemory(State
,
2073 ModRegRm
.MemoryAddress
,
2083 if (!ModRegRm
.Memory
)
2085 /* The second operand must be a memory location */
2086 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2090 /* Fill the 6-byte table register */
2091 // TableReg = State->Idtr;
2092 *((PUSHORT
)&TableReg
) = State
->Idtr
.Size
;
2093 *((PULONG
)&TableReg
[sizeof(USHORT
)]) = State
->Idtr
.Address
;
2095 /* Store the IDTR */
2096 Fast486WriteMemory(State
,
2098 ModRegRm
.MemoryAddress
,
2108 /* This is a privileged instruction */
2109 if (Fast486GetCurrentPrivLevel(State
) != 0)
2111 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2115 if (!ModRegRm
.Memory
)
2117 /* The second operand must be a memory location */
2118 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2122 /* Read the new GDTR */
2123 if (!Fast486ReadMemory(State
,
2125 ModRegRm
.MemoryAddress
,
2130 /* Exception occurred */
2134 /* Load the new GDT */
2135 // State->Gdtr = TableReg;
2136 State
->Gdtr
.Size
= *((PUSHORT
)&TableReg
);
2137 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
2139 /* In 16-bit mode the highest byte is masked out */
2140 if (!OperandSize
) State
->Gdtr
.Address
&= 0x00FFFFFF;
2148 /* This is a privileged instruction */
2149 if (Fast486GetCurrentPrivLevel(State
) != 0)
2151 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2155 if (!ModRegRm
.Memory
)
2157 /* The second operand must be a memory location */
2158 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2162 /* Read the new IDTR */
2163 if (!Fast486ReadMemory(State
,
2165 ModRegRm
.MemoryAddress
,
2170 /* Exception occurred */
2174 /* Load the new IDT */
2175 // State->Idtr = TableReg;
2176 State
->Idtr
.Size
= *((PUSHORT
)&TableReg
);
2177 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
2179 /* In 16-bit mode the highest byte is masked out */
2180 if (!OperandSize
) State
->Idtr
.Address
&= 0x00FFFFFF;
2188 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2189 Fast486WriteModrmWordOperands(State
,
2192 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
2200 USHORT MachineStatusWord
;
2202 /* This is a privileged instruction */
2203 if (Fast486GetCurrentPrivLevel(State
) != 0)
2205 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2209 /* Read the new Machine Status Word */
2210 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &MachineStatusWord
))
2212 /* Exception occurred */
2216 /* This instruction cannot be used to return to real mode */
2217 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
2218 && !(MachineStatusWord
& FAST486_CR0_PE
))
2220 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2224 /* Set the lowest 4 bits */
2225 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
2226 State
->ControlRegisters
[FAST486_REG_CR0
] |= MachineStatusWord
& 0x0F;
2234 #ifndef FAST486_NO_PREFETCH
2235 /* Invalidate the prefetch */
2236 State
->PrefetchValid
= FALSE
;
2239 /* This is a privileged instruction */
2240 if (Fast486GetCurrentPrivLevel(State
) != 0)
2242 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2246 if (!ModRegRm
.Memory
)
2248 /* The second operand must be a memory location */
2249 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2253 if (State
->Tlb
!= NULL
)
2255 /* Clear the TLB entry */
2256 State
->Tlb
[ModRegRm
.MemoryAddress
>> 12] = INVALID_TLB_FIELD
;
2265 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2270 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9
)
2272 FAST486_MOD_REG_RM ModRegRm
;
2273 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2275 TOGGLE_ADSIZE(AddressSize
);
2277 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2279 /* Exception occurred */
2283 /* All of them are reserved (UD2) */
2284 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2288 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA
)
2290 FAST486_MOD_REG_RM ModRegRm
;
2291 BOOLEAN OperandSize
, AddressSize
;
2295 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2297 TOGGLE_OPSIZE(OperandSize
);
2298 TOGGLE_ADSIZE(AddressSize
);
2300 /* Get the number of bits */
2301 if (OperandSize
) DataSize
= 32;
2304 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2306 /* Exception occurred */
2310 if (ModRegRm
.Register
< 4)
2313 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2317 /* Get the bit number */
2318 if (!Fast486FetchByte(State
, &BitNumber
))
2320 /* Exception occurred */
2324 if (ModRegRm
.Memory
)
2327 * For memory operands, add the bit offset divided by
2328 * the data size to the address
2330 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
2333 /* Normalize the bit number */
2334 BitNumber
%= DataSize
;
2340 /* Read the value */
2341 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
2343 /* Exception occurred */
2347 /* Set CF to the bit value */
2348 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
2350 if (ModRegRm
.Register
== 5)
2353 Value
|= 1 << BitNumber
;
2355 else if (ModRegRm
.Register
== 6)
2358 Value
&= ~(1 << BitNumber
);
2360 else if (ModRegRm
.Register
== 7)
2363 Value
^= 1 << BitNumber
;
2366 if (ModRegRm
.Register
>= 5)
2368 /* Write back the result */
2369 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
2371 /* Exception occurred */
2380 /* Read the value */
2381 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
2383 /* Exception occurred */
2387 /* Set CF to the bit value */
2388 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
2390 if (ModRegRm
.Register
== 5)
2393 Value
|= 1 << BitNumber
;
2395 else if (ModRegRm
.Register
== 6)
2398 Value
&= ~(1 << BitNumber
);
2400 else if (ModRegRm
.Register
== 7)
2403 Value
^= 1 << BitNumber
;
2406 if (ModRegRm
.Register
>= 5)
2408 /* Write back the result */
2409 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2411 /* Exception occurred */