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 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Value
);
336 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81
)
338 FAST486_MOD_REG_RM ModRegRm
;
339 BOOLEAN OperandSize
, AddressSize
;
341 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
343 TOGGLE_OPSIZE(OperandSize
);
344 TOGGLE_ADSIZE(AddressSize
);
346 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
348 /* Exception occurred */
354 ULONG Immediate
, Value
;
356 /* Fetch the immediate operand */
357 if (!Fast486FetchDword(State
, &Immediate
))
359 /* Exception occurred */
363 /* Read the operands */
364 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
366 /* Exception occurred */
370 /* Calculate the result */
371 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
373 /* Unless this is CMP, write back the result */
374 if (ModRegRm
.Register
!= 7)
376 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
381 USHORT Immediate
, Value
;
383 /* Fetch the immediate operand */
384 if (!Fast486FetchWord(State
, &Immediate
))
386 /* Exception occurred */
390 /* Read the operands */
391 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
393 /* Exception occurred */
397 /* Calculate the result */
398 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
400 /* Unless this is CMP, write back the result */
401 if (ModRegRm
.Register
!= 7)
403 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
410 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83
)
413 FAST486_MOD_REG_RM ModRegRm
;
414 BOOLEAN OperandSize
, AddressSize
;
416 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
418 TOGGLE_OPSIZE(OperandSize
);
419 TOGGLE_ADSIZE(AddressSize
);
421 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
423 /* Exception occurred */
427 /* Fetch the immediate operand */
428 if (!Fast486FetchByte(State
, (PUCHAR
)&ImmByte
))
430 /* Exception occurred */
436 ULONG Immediate
= (ULONG
)((LONG
)ImmByte
); // Sign extend
439 /* Read the operands */
440 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
442 /* Exception occurred */
446 /* Calculate the result */
447 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 32);
449 /* Unless this is CMP, write back the result */
450 if (ModRegRm
.Register
!= 7)
452 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
457 USHORT Immediate
= (USHORT
)((SHORT
)ImmByte
); // Sign extend
460 /* Read the operands */
461 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
463 /* Exception occurred */
467 /* Calculate the result */
468 Value
= Fast486ArithmeticOperation(State
, ModRegRm
.Register
, Value
, Immediate
, 16);
470 /* Unless this is CMP, write back the result */
471 if (ModRegRm
.Register
!= 7)
473 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
480 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F
)
483 FAST486_MOD_REG_RM ModRegRm
;
484 BOOLEAN OperandSize
, AddressSize
;
486 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
488 TOGGLE_OPSIZE(OperandSize
);
489 TOGGLE_ADSIZE(AddressSize
);
491 /* Pop a value from the stack - this must be done first */
492 if (!Fast486StackPop(State
, &Value
))
494 /* Exception occurred */
498 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
500 /* Exception occurred - restore SP */
501 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= sizeof(ULONG
);
502 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= sizeof(USHORT
);
507 if (ModRegRm
.Register
!= 0)
510 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
516 return Fast486WriteModrmDwordOperands(State
,
523 return Fast486WriteModrmWordOperands(State
,
530 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0
)
533 FAST486_MOD_REG_RM ModRegRm
;
534 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
536 TOGGLE_ADSIZE(AddressSize
);
538 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
540 /* Exception occurred */
544 /* Fetch the count */
545 if (!Fast486FetchByte(State
, &Count
))
547 /* Exception occurred */
551 /* Read the operands */
552 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
554 /* Exception occurred */
558 /* Calculate the result */
559 Value
= LOBYTE(Fast486RotateOperation(State
,
565 /* Write back the result */
566 return Fast486WriteModrmByteOperands(State
,
572 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1
)
575 FAST486_MOD_REG_RM ModRegRm
;
576 BOOLEAN OperandSize
, AddressSize
;
578 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
580 TOGGLE_OPSIZE(OperandSize
);
581 TOGGLE_ADSIZE(AddressSize
);
583 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
585 /* Exception occurred */
589 /* Fetch the count */
590 if (!Fast486FetchByte(State
, &Count
))
592 /* Exception occurred */
600 /* Read the operands */
601 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
603 /* Exception occurred */
607 /* Calculate the result */
608 Value
= Fast486RotateOperation(State
,
614 /* Write back the result */
615 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
621 /* Read the operands */
622 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
624 /* Exception occurred */
628 /* Calculate the result */
629 Value
= LOWORD(Fast486RotateOperation(State
,
635 /* Write back the result */
636 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
640 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6
)
643 FAST486_MOD_REG_RM ModRegRm
;
644 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
646 TOGGLE_ADSIZE(AddressSize
);
648 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
650 /* Exception occurred */
654 if (ModRegRm
.Register
!= 0)
657 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
661 /* Get the immediate operand */
662 if (!Fast486FetchByte(State
, &Immediate
))
664 /* Exception occurred */
668 return Fast486WriteModrmByteOperands(State
,
674 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7
)
676 FAST486_MOD_REG_RM ModRegRm
;
677 BOOLEAN OperandSize
, AddressSize
;
679 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
681 TOGGLE_OPSIZE(OperandSize
);
682 TOGGLE_ADSIZE(AddressSize
);
684 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
686 /* Exception occurred */
690 if (ModRegRm
.Register
!= 0)
693 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
701 /* Get the immediate operand */
702 if (!Fast486FetchDword(State
, &Immediate
))
704 /* Exception occurred */
708 return Fast486WriteModrmDwordOperands(State
,
717 /* Get the immediate operand */
718 if (!Fast486FetchWord(State
, &Immediate
))
720 /* Exception occurred */
724 return Fast486WriteModrmWordOperands(State
,
731 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0
)
734 FAST486_MOD_REG_RM ModRegRm
;
735 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
737 TOGGLE_ADSIZE(AddressSize
);
739 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
741 /* Exception occurred */
745 /* Read the operands */
746 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
748 /* Exception occurred */
752 /* Calculate the result */
753 Value
= LOBYTE(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 8, 1));
755 /* Write back the result */
756 return Fast486WriteModrmByteOperands(State
,
763 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1
)
765 FAST486_MOD_REG_RM ModRegRm
;
766 BOOLEAN OperandSize
, AddressSize
;
768 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
770 TOGGLE_OPSIZE(OperandSize
);
771 TOGGLE_ADSIZE(AddressSize
);
773 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
775 /* Exception occurred */
783 /* Read the operands */
784 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
786 /* Exception occurred */
790 /* Calculate the result */
791 Value
= Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 32, 1);
793 /* Write back the result */
794 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
800 /* Read the operands */
801 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
803 /* Exception occurred */
807 /* Calculate the result */
808 Value
= LOWORD(Fast486RotateOperation(State
, ModRegRm
.Register
, Value
, 16, 1));
810 /* Write back the result */
811 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
815 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2
)
818 FAST486_MOD_REG_RM ModRegRm
;
819 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
821 TOGGLE_ADSIZE(AddressSize
);
823 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
825 /* Exception occurred */
829 /* Read the operands */
830 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
832 /* Exception occurred */
836 /* Calculate the result */
837 Value
= LOBYTE(Fast486RotateOperation(State
,
841 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
843 /* Write back the result */
844 return Fast486WriteModrmByteOperands(State
,
850 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3
)
852 FAST486_MOD_REG_RM ModRegRm
;
853 BOOLEAN OperandSize
, AddressSize
;
855 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
857 TOGGLE_OPSIZE(OperandSize
);
858 TOGGLE_ADSIZE(AddressSize
);
860 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
862 /* Exception occurred */
870 /* Read the operands */
871 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
873 /* Exception occurred */
877 /* Calculate the result */
878 Value
= Fast486RotateOperation(State
,
882 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
);
884 /* Write back the result */
885 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
);
891 /* Read the operands */
892 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
894 /* Exception occurred */
898 /* Calculate the result */
899 Value
= LOWORD(Fast486RotateOperation(State
,
903 State
->GeneralRegs
[FAST486_REG_ECX
].LowByte
));
905 /* Write back the result */
906 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
);
910 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6
)
913 FAST486_MOD_REG_RM ModRegRm
;
914 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
916 TOGGLE_ADSIZE(AddressSize
);
918 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
920 /* Exception occurred */
924 /* Read the operands */
925 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
927 /* Exception occurred */
931 switch (ModRegRm
.Register
)
937 UCHAR Immediate
, Result
;
939 /* Fetch the immediate byte */
940 if (!Fast486FetchByte(State
, &Immediate
))
942 /* Exception occurred */
946 /* Calculate the result */
947 Result
= Value
& Immediate
;
949 /* Update the flags */
950 State
->Flags
.Cf
= FALSE
;
951 State
->Flags
.Of
= FALSE
;
952 State
->Flags
.Zf
= (Result
== 0);
953 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
954 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
962 /* Write back the result */
963 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, ~Value
);
969 /* Calculate the result */
970 UCHAR Result
= -Value
;
972 /* Update the flags */
973 State
->Flags
.Cf
= (Value
!= 0);
974 State
->Flags
.Of
= (Value
& SIGN_FLAG_BYTE
) && (Result
& SIGN_FLAG_BYTE
);
975 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
976 State
->Flags
.Zf
= (Result
== 0);
977 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
978 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
980 /* Write back the result */
981 return Fast486WriteModrmByteOperands(State
, &ModRegRm
, FALSE
, Result
);
987 USHORT Result
= (USHORT
)Value
* (USHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
989 /* Update the flags */
990 State
->Flags
.Cf
= State
->Flags
.Of
= (HIBYTE(Result
) != 0);
992 /* Write back the result */
993 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1001 SHORT Result
= (SHORT
)((CHAR
)Value
) * (SHORT
)((CHAR
)State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
1003 /* Update the flags */
1004 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -128) || (Result
> 127));
1006 /* Write back the result */
1007 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Result
;
1015 UCHAR Quotient
, Remainder
;
1020 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1024 Quotient
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ Value
;
1025 Remainder
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% Value
;
1027 /* Write back the results */
1028 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Quotient
;
1029 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Remainder
;
1037 CHAR Quotient
, Remainder
;
1042 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1046 Quotient
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
/ (CHAR
)Value
;
1047 Remainder
= (SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
% (CHAR
)Value
;
1049 /* Write back the results */
1050 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= (UCHAR
)Quotient
;
1051 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= (UCHAR
)Remainder
;
1060 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7
)
1062 ULONG Value
= 0, SignFlag
;
1063 FAST486_MOD_REG_RM ModRegRm
;
1064 BOOLEAN OperandSize
, AddressSize
;
1066 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1068 TOGGLE_OPSIZE(OperandSize
);
1069 TOGGLE_ADSIZE(AddressSize
);
1071 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1073 /* Exception occurred */
1077 /* Set the sign flag */
1078 if (OperandSize
) SignFlag
= SIGN_FLAG_LONG
;
1079 else SignFlag
= SIGN_FLAG_WORD
;
1081 /* Read the operand */
1085 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1087 /* Exception occurred */
1094 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, (PUSHORT
)&Value
))
1096 /* Exception occurred */
1101 switch (ModRegRm
.Register
)
1107 ULONG Immediate
= 0, Result
= 0;
1111 /* Fetch the immediate dword */
1112 if (!Fast486FetchDword(State
, &Immediate
))
1114 /* Exception occurred */
1120 /* Fetch the immediate word */
1121 if (!Fast486FetchWord(State
, (PUSHORT
)&Immediate
))
1123 /* Exception occurred */
1128 /* Calculate the result */
1129 Result
= Value
& Immediate
;
1131 /* Update the flags */
1132 State
->Flags
.Cf
= FALSE
;
1133 State
->Flags
.Of
= FALSE
;
1134 State
->Flags
.Zf
= (Result
== 0);
1135 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1136 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1144 /* Write back the result */
1148 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, ~Value
);
1153 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(~Value
));
1160 /* Calculate the result */
1161 ULONG Result
= -Value
;
1162 if (!OperandSize
) Result
&= 0xFFFF;
1164 /* Update the flags */
1165 State
->Flags
.Cf
= (Value
!= 0);
1166 State
->Flags
.Of
= (Value
& SignFlag
) && (Result
& SignFlag
);
1167 State
->Flags
.Af
= ((Value
& 0x0F) != 0);
1168 State
->Flags
.Zf
= (Result
== 0);
1169 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
1170 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1172 /* Write back the result */
1176 return Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Result
);
1181 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, LOWORD(Result
));
1190 ULONGLONG Result
= (ULONGLONG
)Value
* (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1192 /* Update the flags */
1193 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
& 0xFFFFFFFF00000000ULL
) != 0);
1195 /* Write back the result */
1196 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1197 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1201 ULONG Result
= (ULONG
)Value
* (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1203 /* Update the flags */
1204 State
->Flags
.Cf
= State
->Flags
.Of
= (HIWORD(Result
) != 0);
1206 /* Write back the result */
1207 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1208 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1219 LONGLONG Result
= (LONGLONG
)((LONG
)Value
) * (LONGLONG
)((LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
);
1221 /* Update the flags */
1222 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -2147483648LL) || (Result
> 2147483647LL));
1224 /* Write back the result */
1225 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
& 0xFFFFFFFFULL
;
1226 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Result
>> 32;
1230 LONG Result
= (LONG
)((SHORT
)Value
) * (LONG
)((SHORT
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
);
1232 /* Update the flags */
1233 State
->Flags
.Cf
= State
->Flags
.Of
= ((Result
< -32768) || (Result
> 32767));
1235 /* Write back the result */
1236 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= LOWORD(Result
);
1237 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= HIWORD(Result
);
1249 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
1255 ULONGLONG Dividend
= (ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EAX
].Long
1256 | ((ULONGLONG
)State
->GeneralRegs
[FAST486_REG_EDX
].Long
<< 32);
1257 ULONG Quotient
= Dividend
/ Value
;
1258 ULONG Remainder
= Dividend
% Value
;
1260 /* Write back the results */
1261 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Quotient
;
1262 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= Remainder
;
1266 ULONG Dividend
= (ULONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1267 | ((ULONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1268 USHORT Quotient
= Dividend
/ Value
;
1269 USHORT Remainder
= Dividend
% Value
;
1271 /* Write back the results */
1272 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= 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 LONG Quotient
= Dividend
/ (LONG
)Value
;
1294 LONG Remainder
= Dividend
% (LONG
)Value
;
1296 /* Write back the results */
1297 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= (ULONG
)Quotient
;
1298 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= (ULONG
)Remainder
;
1302 LONG Dividend
= (LONG
)State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
1303 | ((LONG
)State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
<< 16);
1304 SHORT Quotient
= Dividend
/ (SHORT
)LOWORD(Value
);
1305 SHORT Remainder
= Dividend
% (SHORT
)LOWORD(Value
);
1307 /* Write back the results */
1308 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= (USHORT
)Quotient
;
1309 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= (USHORT
)Remainder
;
1319 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE
)
1322 FAST486_MOD_REG_RM ModRegRm
;
1323 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1325 TOGGLE_ADSIZE(AddressSize
);
1327 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1329 /* Exception occurred */
1333 if (ModRegRm
.Register
> 1)
1336 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1340 /* Read the operands */
1341 if (!Fast486ReadModrmByteOperands(State
, &ModRegRm
, NULL
, &Value
))
1343 /* Exception occurred */
1347 if (ModRegRm
.Register
== 0)
1349 /* Increment and update OF and AF */
1351 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1352 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1356 /* Decrement and update OF and AF */
1357 State
->Flags
.Of
= (Value
== SIGN_FLAG_BYTE
);
1359 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1363 State
->Flags
.Zf
= (Value
== 0);
1364 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
1365 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1367 /* Write back the result */
1368 return Fast486WriteModrmByteOperands(State
,
1374 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF
)
1376 FAST486_MOD_REG_RM ModRegRm
;
1377 BOOLEAN OperandSize
, AddressSize
;
1379 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1381 TOGGLE_OPSIZE(OperandSize
);
1382 TOGGLE_ADSIZE(AddressSize
);
1384 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1386 /* Exception occurred */
1390 if (ModRegRm
.Register
== 7)
1393 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1397 /* Read the operands */
1402 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
1404 /* Exception occurred */
1408 if (ModRegRm
.Register
== 0)
1410 /* Increment and update OF and AF */
1412 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1413 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1415 else if (ModRegRm
.Register
== 1)
1417 /* Decrement and update OF and AF */
1418 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
1420 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1422 else if (ModRegRm
.Register
== 2)
1424 /* Push the current value of EIP */
1425 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1427 /* Exception occurred */
1431 /* Set the EIP to the address */
1432 State
->InstPtr
.Long
= Value
;
1434 else if (ModRegRm
.Register
== 3)
1437 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1439 /* Check for the segment override */
1440 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1442 /* Use the override segment instead */
1443 Segment
= State
->SegmentOverride
;
1446 /* Read the selector */
1447 if (!Fast486ReadMemory(State
,
1449 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1454 /* Exception occurred */
1458 /* Push the current value of CS */
1459 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1461 /* Exception occurred */
1465 /* Push the current value of EIP */
1466 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
1468 /* Exception occurred */
1472 /* Load the new code segment */
1473 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1475 /* Exception occurred */
1479 /* Set the EIP to the address */
1480 State
->InstPtr
.Long
= Value
;
1482 else if (ModRegRm
.Register
== 4)
1484 /* Set the EIP to the address */
1485 State
->InstPtr
.Long
= Value
;
1487 else if (ModRegRm
.Register
== 5)
1490 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1492 /* Check for the segment override */
1493 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1495 /* Use the override segment instead */
1496 Segment
= State
->SegmentOverride
;
1499 /* Read the selector */
1500 if (!Fast486ReadMemory(State
,
1502 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
1507 /* Exception occurred */
1511 /* Load the new code segment */
1512 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1514 /* Exception occurred */
1518 /* Set the EIP to the address */
1519 State
->InstPtr
.Long
= Value
;
1521 else if (ModRegRm
.Register
== 6)
1523 /* Push the value on to the stack */
1524 return Fast486StackPush(State
, Value
);
1527 if (ModRegRm
.Register
<= 1)
1530 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
1531 State
->Flags
.Zf
= (Value
== 0);
1532 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1534 /* Write back the result */
1535 return Fast486WriteModrmDwordOperands(State
,
1545 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
1547 /* Exception occurred */
1551 if (ModRegRm
.Register
== 0)
1553 /* Increment and update OF */
1555 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1556 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
1558 else if (ModRegRm
.Register
== 1)
1560 /* Decrement and update OF */
1561 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
1563 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
1565 else if (ModRegRm
.Register
== 2)
1567 /* Push the current value of IP */
1568 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1570 /* Exception occurred */
1574 /* Set the IP to the address */
1575 State
->InstPtr
.LowWord
= Value
;
1577 /* Clear the top half of EIP */
1578 State
->InstPtr
.Long
&= 0xFFFF;
1580 else if (ModRegRm
.Register
== 3)
1583 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1585 /* Check for the segment override */
1586 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1588 /* Use the override segment instead */
1589 Segment
= State
->SegmentOverride
;
1592 /* Read the selector */
1593 if (!Fast486ReadMemory(State
,
1595 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1600 /* Exception occurred */
1604 /* Push the current value of CS */
1605 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
1607 /* Exception occurred */
1611 /* Push the current value of IP */
1612 if (!Fast486StackPush(State
, State
->InstPtr
.LowWord
))
1614 /* Exception occurred */
1618 /* Load the new code segment */
1619 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1621 /* Exception occurred */
1625 /* Set the IP to the address */
1626 State
->InstPtr
.LowWord
= Value
;
1628 /* Clear the top half of EIP */
1629 State
->InstPtr
.Long
&= 0xFFFF;
1631 else if (ModRegRm
.Register
== 4)
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
== 5)
1642 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
1644 /* Check for the segment override */
1645 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
1647 /* Use the override segment instead */
1648 Segment
= State
->SegmentOverride
;
1651 /* Read the selector */
1652 if (!Fast486ReadMemory(State
,
1654 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
1659 /* Exception occurred */
1663 /* Load the new code segment */
1664 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Selector
))
1666 /* Exception occurred */
1670 /* Set the IP to the address */
1671 State
->InstPtr
.LowWord
= Value
;
1673 /* Clear the top half of EIP */
1674 State
->InstPtr
.Long
&= 0xFFFF;
1676 else if (ModRegRm
.Register
== 6)
1678 /* Push the value on to the stack */
1679 return Fast486StackPush(State
, Value
);
1684 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1688 if (ModRegRm
.Register
<= 1)
1691 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
1692 State
->Flags
.Zf
= (Value
== 0);
1693 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
1695 /* Write back the result */
1696 return Fast486WriteModrmWordOperands(State
,
1706 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F00
)
1708 FAST486_MOD_REG_RM ModRegRm
;
1709 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1712 TOGGLE_ADSIZE(AddressSize
);
1714 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1716 /* Exception occurred */
1720 /* Check which operation this is */
1721 switch (ModRegRm
.Register
)
1726 /* Not recognized in real mode or virtual 8086 mode */
1727 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1730 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1734 return Fast486WriteModrmWordOperands(State
,
1737 State
->Ldtr
.Selector
);
1743 /* Not recognized in real mode or virtual 8086 mode */
1744 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1747 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1751 return Fast486WriteModrmWordOperands(State
,
1754 State
->TaskReg
.Selector
);
1761 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
1763 /* Not recognized in real mode or virtual 8086 mode */
1764 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1767 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1771 /* This is a privileged instruction */
1772 if (Fast486GetCurrentPrivLevel(State
) != 0)
1774 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1778 if (!Fast486ReadModrmWordOperands(State
,
1783 /* Exception occurred */
1787 /* Make sure the GDT contains the entry */
1788 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
1790 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1795 if (!Fast486ReadLinearMemory(State
,
1797 + GET_SEGMENT_INDEX(Selector
),
1801 /* Exception occurred */
1805 if (GET_SEGMENT_INDEX(Selector
) == 0)
1807 RtlZeroMemory(&State
->Ldtr
, sizeof(State
->Ldtr
));
1811 if (!GdtEntry
.Present
)
1813 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
1817 if (GdtEntry
.Signature
!= FAST486_LDT_SIGNATURE
)
1819 /* This is not a LDT descriptor */
1820 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1824 /* Update the LDTR */
1825 State
->Ldtr
.Selector
= Selector
;
1826 State
->Ldtr
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
1827 State
->Ldtr
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
1828 if (GdtEntry
.Granularity
) State
->Ldtr
.Limit
<<= 12;
1837 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
1839 /* Not recognized in real mode or virtual 8086 mode */
1840 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1843 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1847 /* This is a privileged instruction */
1848 if (Fast486GetCurrentPrivLevel(State
) != 0)
1850 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1854 if (!Fast486ReadModrmWordOperands(State
,
1859 /* Exception occurred */
1863 /* Make sure the GDT contains the entry */
1864 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
1866 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1871 if (!Fast486ReadLinearMemory(State
,
1873 + GET_SEGMENT_INDEX(Selector
),
1877 /* Exception occurred */
1881 if (GET_SEGMENT_INDEX(Selector
) == 0)
1883 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1887 if (!GdtEntry
.Present
)
1889 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
1893 if (GdtEntry
.Signature
!= FAST486_TSS_SIGNATURE
)
1895 /* This is not a TSS descriptor */
1896 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
1901 State
->TaskReg
.Selector
= Selector
;
1902 State
->TaskReg
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
1903 State
->TaskReg
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
1904 if (GdtEntry
.Granularity
) State
->TaskReg
.Limit
<<= 12;
1905 State
->TaskReg
.Busy
= TRUE
;
1915 FAST486_GDT_ENTRY GdtEntry
;
1917 /* Not recognized in real mode or virtual 8086 mode */
1918 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
1921 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1925 /* This is a privileged instruction */
1926 if (Fast486GetCurrentPrivLevel(State
) != 0)
1928 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
1932 if (!Fast486ReadModrmWordOperands(State
,
1937 /* Exception occurred */
1941 if (!(Selector
& SEGMENT_TABLE_INDICATOR
))
1943 /* Make sure the GDT contains the entry */
1944 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1))
1947 State
->Flags
.Zf
= FALSE
;
1952 if (!Fast486ReadLinearMemory(State
,
1954 + GET_SEGMENT_INDEX(Selector
),
1958 /* Exception occurred */
1964 /* Make sure the LDT contains the entry */
1965 if (GET_SEGMENT_INDEX(Selector
) >= (State
->Ldtr
.Limit
+ 1))
1968 State
->Flags
.Zf
= FALSE
;
1973 if (!Fast486ReadLinearMemory(State
,
1975 + GET_SEGMENT_INDEX(Selector
),
1979 /* Exception occurred */
1984 /* Set ZF if it is valid and accessible */
1985 State
->Flags
.Zf
= GdtEntry
.Present
// must be present
1986 && GdtEntry
.SystemType
// must be a segment
1987 && (((ModRegRm
.Register
== 4)
1988 /* code segments are only readable if the RW bit is set */
1989 && (!GdtEntry
.Executable
|| GdtEntry
.ReadWrite
))
1990 || ((ModRegRm
.Register
== 5)
1991 /* code segments are never writable, data segments are writable when RW is set */
1992 && (!GdtEntry
.Executable
&& GdtEntry
.ReadWrite
)))
1994 * for segments other than conforming code segments,
1995 * both RPL and CPL must be less than or equal to DPL
1997 && ((!GdtEntry
.Executable
|| !GdtEntry
.DirConf
)
1998 && ((GET_SEGMENT_RPL(Selector
) <= GdtEntry
.Dpl
)
1999 && (Fast486GetCurrentPrivLevel(State
) <= GdtEntry
.Dpl
)))
2000 /* for conforming code segments, DPL must be less than or equal to CPL */
2001 && ((GdtEntry
.Executable
&& GdtEntry
.DirConf
)
2002 && (GdtEntry
.Dpl
<= Fast486GetCurrentPrivLevel(State
)));
2011 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2017 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01
)
2019 // FAST486_TABLE_REG TableReg;
2021 FAST486_MOD_REG_RM ModRegRm
;
2022 BOOLEAN OperandSize
, AddressSize
;
2023 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
2025 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2028 TOGGLE_OPSIZE(OperandSize
);
2029 TOGGLE_ADSIZE(AddressSize
);
2031 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2033 /* Exception occurred */
2037 /* Check for the segment override */
2038 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
2040 /* Use the override segment instead */
2041 Segment
= State
->SegmentOverride
;
2044 /* Check which operation this is */
2045 switch (ModRegRm
.Register
)
2050 if (!ModRegRm
.Memory
)
2052 /* The second operand must be a memory location */
2053 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2057 /* Fill the 6-byte table register */
2058 // TableReg = State->Gdtr;
2059 *((PUSHORT
)&TableReg
) = State
->Gdtr
.Size
;
2060 *((PULONG
)&TableReg
[sizeof(USHORT
)]) = State
->Gdtr
.Address
;
2062 /* Store the GDTR */
2063 return Fast486WriteMemory(State
,
2065 ModRegRm
.MemoryAddress
,
2073 if (!ModRegRm
.Memory
)
2075 /* The second operand must be a memory location */
2076 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2080 /* Fill the 6-byte table register */
2081 // TableReg = State->Idtr;
2082 *((PUSHORT
)&TableReg
) = State
->Idtr
.Size
;
2083 *((PULONG
)&TableReg
[sizeof(USHORT
)]) = State
->Idtr
.Address
;
2085 /* Store the IDTR */
2086 return Fast486WriteMemory(State
,
2088 ModRegRm
.MemoryAddress
,
2096 /* This is a privileged instruction */
2097 if (Fast486GetCurrentPrivLevel(State
) != 0)
2099 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2103 if (!ModRegRm
.Memory
)
2105 /* The second operand must be a memory location */
2106 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2110 /* Read the new GDTR */
2111 if (!Fast486ReadMemory(State
,
2113 ModRegRm
.MemoryAddress
,
2118 /* Exception occurred */
2122 /* Load the new GDT */
2123 // State->Gdtr = TableReg;
2124 State
->Gdtr
.Size
= *((PUSHORT
)&TableReg
);
2125 State
->Gdtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
2127 /* In 16-bit mode the highest byte is masked out */
2128 if (!OperandSize
) State
->Gdtr
.Address
&= 0x00FFFFFF;
2136 /* This is a privileged instruction */
2137 if (Fast486GetCurrentPrivLevel(State
) != 0)
2139 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2143 if (!ModRegRm
.Memory
)
2145 /* The second operand must be a memory location */
2146 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2150 /* Read the new IDTR */
2151 if (!Fast486ReadMemory(State
,
2153 ModRegRm
.MemoryAddress
,
2158 /* Exception occurred */
2162 /* Load the new IDT */
2163 // State->Idtr = TableReg;
2164 State
->Idtr
.Size
= *((PUSHORT
)&TableReg
);
2165 State
->Idtr
.Address
= *((PULONG
)&TableReg
[sizeof(USHORT
)]);
2167 /* In 16-bit mode the highest byte is masked out */
2168 if (!OperandSize
) State
->Idtr
.Address
&= 0x00FFFFFF;
2176 /* Store the lower 16 bits (Machine Status Word) of CR0 */
2177 return Fast486WriteModrmWordOperands(State
,
2180 LOWORD(State
->ControlRegisters
[FAST486_REG_CR0
]));
2186 USHORT MachineStatusWord
;
2188 /* This is a privileged instruction */
2189 if (Fast486GetCurrentPrivLevel(State
) != 0)
2191 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2195 /* Read the new Machine Status Word */
2196 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &MachineStatusWord
))
2198 /* Exception occurred */
2202 /* This instruction cannot be used to return to real mode */
2203 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
2204 && !(MachineStatusWord
& FAST486_CR0_PE
))
2206 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
2210 /* Set the lowest 4 bits */
2211 State
->ControlRegisters
[FAST486_REG_CR0
] &= 0xFFFFFFF0;
2212 State
->ControlRegisters
[FAST486_REG_CR0
] |= MachineStatusWord
& 0x0F;
2227 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2233 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9
)
2235 FAST486_MOD_REG_RM ModRegRm
;
2236 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2238 TOGGLE_ADSIZE(AddressSize
);
2240 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2242 /* Exception occurred */
2246 /* All of them are reserved (UD2) */
2247 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2251 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA
)
2253 FAST486_MOD_REG_RM ModRegRm
;
2254 BOOLEAN OperandSize
, AddressSize
;
2258 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2260 TOGGLE_OPSIZE(OperandSize
);
2261 TOGGLE_ADSIZE(AddressSize
);
2263 /* Get the number of bits */
2264 if (OperandSize
) DataSize
= 32;
2267 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2269 /* Exception occurred */
2273 if (ModRegRm
.Register
< 4)
2276 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2280 /* Get the bit number */
2281 if (!Fast486FetchByte(State
, &BitNumber
))
2283 /* Exception occurred */
2287 if (ModRegRm
.Memory
)
2290 * For memory operands, add the bit offset divided by
2291 * the data size to the address
2293 ModRegRm
.MemoryAddress
+= BitNumber
/ DataSize
;
2296 /* Normalize the bit number */
2297 BitNumber
%= DataSize
;
2303 /* Read the value */
2304 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Value
))
2306 /* Exception occurred */
2310 /* Set CF to the bit value */
2311 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
2313 if (ModRegRm
.Register
== 5)
2316 Value
|= 1 << BitNumber
;
2318 else if (ModRegRm
.Register
== 6)
2321 Value
&= ~(1 << BitNumber
);
2323 else if (ModRegRm
.Register
== 7)
2326 Value
^= 1 << BitNumber
;
2329 if (ModRegRm
.Register
>= 5)
2331 /* Write back the result */
2332 if (!Fast486WriteModrmDwordOperands(State
, &ModRegRm
, FALSE
, Value
))
2334 /* Exception occurred */
2343 /* Read the value */
2344 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Value
))
2346 /* Exception occurred */
2350 /* Set CF to the bit value */
2351 State
->Flags
.Cf
= (Value
>> BitNumber
) & 1;
2353 if (ModRegRm
.Register
== 5)
2356 Value
|= 1 << BitNumber
;
2358 else if (ModRegRm
.Register
== 6)
2361 Value
&= ~(1 << BitNumber
);
2363 else if (ModRegRm
.Register
== 7)
2366 Value
^= 1 << BitNumber
;
2369 if (ModRegRm
.Register
>= 5)
2371 /* Write back the result */
2372 if (!Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, Value
))
2374 /* Exception occurred */
2380 /* Return success */