2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /* INCLUDES *******************************************************************/
36 /* PUBLIC VARIABLES ***********************************************************/
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
41 Fast486OpcodeAddByteModrm
,
42 Fast486OpcodeAddModrm
,
43 Fast486OpcodeAddByteModrm
,
44 Fast486OpcodeAddModrm
,
49 Fast486OpcodeOrByteModrm
,
51 Fast486OpcodeOrByteModrm
,
56 Fast486OpcodeExtended
,
57 Fast486OpcodeAdcByteModrm
,
58 Fast486OpcodeAdcModrm
,
59 Fast486OpcodeAdcByteModrm
,
60 Fast486OpcodeAdcModrm
,
65 Fast486OpcodeSbbByteModrm
,
66 Fast486OpcodeSbbModrm
,
67 Fast486OpcodeSbbByteModrm
,
68 Fast486OpcodeSbbModrm
,
73 Fast486OpcodeAndByteModrm
,
74 Fast486OpcodeAndModrm
,
75 Fast486OpcodeAndByteModrm
,
76 Fast486OpcodeAndModrm
,
81 Fast486OpcodeCmpSubByteModrm
,
82 Fast486OpcodeCmpSubModrm
,
83 Fast486OpcodeCmpSubByteModrm
,
84 Fast486OpcodeCmpSubModrm
,
85 Fast486OpcodeCmpSubAl
,
86 Fast486OpcodeCmpSubEax
,
89 Fast486OpcodeXorByteModrm
,
90 Fast486OpcodeXorModrm
,
91 Fast486OpcodeXorByteModrm
,
92 Fast486OpcodeXorModrm
,
97 Fast486OpcodeCmpSubByteModrm
,
98 Fast486OpcodeCmpSubModrm
,
99 Fast486OpcodeCmpSubByteModrm
,
100 Fast486OpcodeCmpSubModrm
,
101 Fast486OpcodeCmpSubAl
,
102 Fast486OpcodeCmpSubEax
,
105 Fast486OpcodeIncrement
,
106 Fast486OpcodeIncrement
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeIncrement
,
113 Fast486OpcodeDecrement
,
114 Fast486OpcodeDecrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodeDecrement
,
121 Fast486OpcodePushReg
,
122 Fast486OpcodePushReg
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
128 Fast486OpcodePushReg
,
137 Fast486OpcodePushAll
,
145 Fast486OpcodePushImm
,
146 Fast486OpcodeImulModrmImm
,
147 Fast486OpcodePushByteImm
,
148 Fast486OpcodeImulModrmImm
,
153 Fast486OpcodeShortConditionalJmp
,
154 Fast486OpcodeShortConditionalJmp
,
155 Fast486OpcodeShortConditionalJmp
,
156 Fast486OpcodeShortConditionalJmp
,
157 Fast486OpcodeShortConditionalJmp
,
158 Fast486OpcodeShortConditionalJmp
,
159 Fast486OpcodeShortConditionalJmp
,
160 Fast486OpcodeShortConditionalJmp
,
161 Fast486OpcodeShortConditionalJmp
,
162 Fast486OpcodeShortConditionalJmp
,
163 Fast486OpcodeShortConditionalJmp
,
164 Fast486OpcodeShortConditionalJmp
,
165 Fast486OpcodeShortConditionalJmp
,
166 Fast486OpcodeShortConditionalJmp
,
167 Fast486OpcodeShortConditionalJmp
,
168 Fast486OpcodeShortConditionalJmp
,
169 Fast486OpcodeGroup8082
,
170 Fast486OpcodeGroup81
,
171 Fast486OpcodeGroup8082
,
172 Fast486OpcodeGroup83
,
173 Fast486OpcodeTestByteModrm
,
174 Fast486OpcodeTestModrm
,
175 Fast486OpcodeXchgByteModrm
,
176 Fast486OpcodeXchgModrm
,
177 Fast486OpcodeMovByteModrm
,
178 Fast486OpcodeMovModrm
,
179 Fast486OpcodeMovByteModrm
,
180 Fast486OpcodeMovModrm
,
181 Fast486OpcodeMovStoreSeg
,
183 Fast486OpcodeMovLoadSeg
,
184 Fast486OpcodeGroup8F
,
186 Fast486OpcodeExchangeEax
,
187 Fast486OpcodeExchangeEax
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
192 Fast486OpcodeExchangeEax
,
195 Fast486OpcodeCallAbs
,
197 Fast486OpcodePushFlags
,
198 Fast486OpcodePopFlags
,
201 Fast486OpcodeMovAlOffset
,
202 Fast486OpcodeMovEaxOffset
,
203 Fast486OpcodeMovOffsetAl
,
204 Fast486OpcodeMovOffsetEax
,
210 Fast486OpcodeTestEax
,
217 Fast486OpcodeMovByteRegImm
,
218 Fast486OpcodeMovByteRegImm
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovByteRegImm
,
225 Fast486OpcodeMovRegImm
,
226 Fast486OpcodeMovRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeMovRegImm
,
233 Fast486OpcodeGroupC0
,
234 Fast486OpcodeGroupC1
,
239 Fast486OpcodeGroupC6
,
240 Fast486OpcodeGroupC7
,
249 Fast486OpcodeGroupD0
,
250 Fast486OpcodeGroupD1
,
251 Fast486OpcodeGroupD2
,
252 Fast486OpcodeGroupD3
,
271 Fast486OpcodeOutByte
,
276 Fast486OpcodeShortJump
,
279 Fast486OpcodeOutByte
,
286 Fast486OpcodeComplCarry
,
287 Fast486OpcodeGroupF6
,
288 Fast486OpcodeGroupF7
,
289 Fast486OpcodeClearCarry
,
290 Fast486OpcodeSetCarry
,
291 Fast486OpcodeClearInt
,
293 Fast486OpcodeClearDir
,
295 Fast486OpcodeGroupFE
,
296 Fast486OpcodeGroupFF
,
299 /* PUBLIC FUNCTIONS ***********************************************************/
301 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
303 BOOLEAN Valid
= FALSE
;
310 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
312 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
313 State
->SegmentOverride
= FAST486_REG_ES
;
323 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
325 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
326 State
->SegmentOverride
= FAST486_REG_CS
;
336 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
338 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
339 State
->SegmentOverride
= FAST486_REG_SS
;
349 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
351 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
352 State
->SegmentOverride
= FAST486_REG_DS
;
362 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
364 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
365 State
->SegmentOverride
= FAST486_REG_FS
;
375 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
377 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
378 State
->SegmentOverride
= FAST486_REG_GS
;
388 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
390 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
400 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
402 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
411 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
413 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
423 /* Mutually exclusive with REP */
424 if (!(State
->PrefixFlags
425 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
427 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
437 /* Mutually exclusive with REPNZ */
438 if (!(State
->PrefixFlags
439 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
441 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
451 /* Clear all prefixes */
452 State
->PrefixFlags
= 0;
454 /* Throw an exception */
455 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
462 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
465 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
470 /* Make sure this is the right instruction */
471 ASSERT((Opcode
& 0xF8) == 0x40);
475 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
477 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
478 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
482 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
484 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
485 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
488 State
->Flags
.Zf
= (Value
== 0);
489 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
490 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
496 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
499 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
504 /* Make sure this is the right instruction */
505 ASSERT((Opcode
& 0xF8) == 0x48);
509 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
511 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
512 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
516 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
518 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
519 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
522 State
->Flags
.Zf
= (Value
== 0);
523 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
524 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
530 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
534 /* Make sure this is the right instruction */
535 ASSERT((Opcode
& 0xF8) == 0x50);
537 /* Call the internal function */
538 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
541 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
544 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
549 /* Make sure this is the right instruction */
550 ASSERT((Opcode
& 0xF8) == 0x58);
552 /* Call the internal function */
553 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
555 /* Store the value */
556 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
557 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
563 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
565 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
568 State
->IdleCallback(State
);
574 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
576 INT Reg
= Opcode
& 0x07;
577 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
582 /* Make sure this is the right instruction */
583 ASSERT((Opcode
& 0xF8) == 0x90);
585 /* Exchange the values */
590 Value
= State
->GeneralRegs
[Reg
].Long
;
591 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
592 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
598 Value
= State
->GeneralRegs
[Reg
].LowWord
;
599 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
600 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
606 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
608 BOOLEAN Jump
= FALSE
;
610 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
612 /* Make sure this is the right instruction */
613 ASSERT((Opcode
& 0xF0) == 0x70);
617 /* Fetch the offset */
618 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
620 /* An exception occurred */
624 switch ((Opcode
& 0x0F) >> 1)
629 Jump
= State
->Flags
.Of
;
636 Jump
= State
->Flags
.Cf
;
643 Jump
= State
->Flags
.Zf
;
650 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
657 Jump
= State
->Flags
.Sf
;
664 Jump
= State
->Flags
.Pf
;
671 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
678 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
685 /* Invert the result */
691 /* Move the instruction pointer */
692 State
->InstPtr
.Long
+= Offset
;
696 /* Clear the top half of EIP */
697 State
->InstPtr
.Long
&= 0xFFFF;
705 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
707 /* Make sure this is the right instruction */
708 ASSERT(Opcode
== 0xF8);
710 /* No prefixes allowed */
711 if (State
->PrefixFlags
)
713 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
717 /* Clear CF and return success */
718 State
->Flags
.Cf
= FALSE
;
722 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
724 /* Make sure this is the right instruction */
725 ASSERT(Opcode
== 0xF9);
727 /* No prefixes allowed */
728 if (State
->PrefixFlags
)
730 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
734 /* Set CF and return success*/
735 State
->Flags
.Cf
= TRUE
;
739 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
741 /* Make sure this is the right instruction */
742 ASSERT(Opcode
== 0xF5);
744 /* No prefixes allowed */
745 if (State
->PrefixFlags
)
747 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
751 /* Toggle CF and return success */
752 State
->Flags
.Cf
= !State
->Flags
.Cf
;
756 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
758 /* Make sure this is the right instruction */
759 ASSERT(Opcode
== 0xFA);
761 /* No prefixes allowed */
762 if (State
->PrefixFlags
)
764 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
768 /* Check for protected mode */
769 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
772 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
774 /* Clear the interrupt flag */
775 State
->Flags
.If
= FALSE
;
779 /* General Protection Fault */
780 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
786 /* Just clear the interrupt flag */
787 State
->Flags
.If
= FALSE
;
794 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
796 /* Make sure this is the right instruction */
797 ASSERT(Opcode
== 0xFB);
799 /* No prefixes allowed */
800 if (State
->PrefixFlags
)
802 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
806 /* Check for protected mode */
807 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
810 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
812 /* Set the interrupt flag */
813 State
->Flags
.If
= TRUE
;
817 /* General Protection Fault */
818 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
824 /* Just set the interrupt flag */
825 State
->Flags
.If
= TRUE
;
832 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
834 /* Make sure this is the right instruction */
835 ASSERT(Opcode
== 0xFC);
837 /* No prefixes allowed */
838 if (State
->PrefixFlags
)
840 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
844 /* Clear DF and return success */
845 State
->Flags
.Df
= FALSE
;
849 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
851 /* Make sure this is the right instruction */
852 ASSERT(Opcode
== 0xFD);
854 /* No prefixes allowed */
855 if (State
->PrefixFlags
)
857 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
861 /* Set DF and return success*/
862 State
->Flags
.Df
= TRUE
;
866 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
868 /* Make sure this is the right instruction */
869 ASSERT(Opcode
== 0xF4);
871 /* No prefixes allowed */
872 if (State
->PrefixFlags
)
874 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
878 /* Privileged instructions can only be executed under CPL = 0 */
879 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
881 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
886 // TODO: Halt the CPU until an interrupt occurs, using IdleCallback if needed.
892 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
897 /* Make sure this is the right instruction */
898 ASSERT((Opcode
& 0xF7) == 0xE4);
902 /* Fetch the parameter */
903 if (!Fast486FetchByte(State
, &Data
))
905 /* Exception occurred */
909 /* Set the port number to the parameter */
914 /* The port number is in DX */
915 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
918 /* Read a byte from the I/O port */
919 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
921 /* Store the result in AL */
922 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
927 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
930 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
932 /* Make sure this is the right instruction */
933 ASSERT((Opcode
& 0xF7) == 0xE5);
942 /* Fetch the parameter */
943 if (!Fast486FetchByte(State
, &Data
))
945 /* Exception occurred */
949 /* Set the port number to the parameter */
954 /* The port number is in DX */
955 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
962 /* Read a dword from the I/O port */
963 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
965 /* Store the value in EAX */
966 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
972 /* Read a word from the I/O port */
973 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
975 /* Store the value in AX */
976 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
982 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
987 /* Make sure this is the right instruction */
988 ASSERT((Opcode
& 0xF7) == 0xE6);
992 /* Fetch the parameter */
993 if (!Fast486FetchByte(State
, &Data
))
995 /* Exception occurred */
999 /* Set the port number to the parameter */
1004 /* The port number is in DX */
1005 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1008 /* Read the value from AL */
1009 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1011 /* Write the byte to the I/O port */
1012 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
1017 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1020 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1022 /* Make sure this is the right instruction */
1023 ASSERT((Opcode
& 0xF7) == 0xE7);
1025 TOGGLE_OPSIZE(Size
);
1032 /* Fetch the parameter */
1033 if (!Fast486FetchByte(State
, &Data
))
1035 /* Exception occurred */
1039 /* Set the port number to the parameter */
1044 /* The port number is in DX */
1045 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1050 /* Get the value from EAX */
1051 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1053 /* Write a dword to the I/O port */
1054 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1058 /* Get the value from AX */
1059 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1061 /* Write a word to the I/O port */
1062 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1068 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1071 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1073 TOGGLE_OPSIZE(Size
);
1075 /* Make sure this is the right instruction */
1076 ASSERT(Opcode
== 0xEB);
1078 /* Fetch the offset */
1079 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1081 /* An exception occurred */
1085 /* Move the instruction pointer */
1086 State
->InstPtr
.Long
+= Offset
;
1090 /* Clear the top half of EIP */
1091 State
->InstPtr
.Long
&= 0xFFFF;
1097 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1099 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1101 /* Make sure this is the right instruction */
1102 ASSERT((Opcode
& 0xF8) == 0xB8);
1104 TOGGLE_OPSIZE(Size
);
1111 /* Fetch the dword */
1112 if (!Fast486FetchDword(State
, &Value
))
1114 /* Exception occurred */
1118 /* Store the value in the register */
1119 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1125 /* Fetch the word */
1126 if (!Fast486FetchWord(State
, &Value
))
1128 /* Exception occurred */
1132 /* Store the value in the register */
1133 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1139 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1143 /* Make sure this is the right instruction */
1144 ASSERT((Opcode
& 0xF8) == 0xB0);
1146 if (State
->PrefixFlags
!= 0)
1148 /* Invalid prefix */
1149 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1153 /* Fetch the byte */
1154 if (!Fast486FetchByte(State
, &Value
))
1156 /* Exception occurred */
1162 /* AH, CH, DH or BH */
1163 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1167 /* AL, CL, DL or BL */
1168 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1174 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1176 UCHAR FirstValue
, SecondValue
, Result
;
1177 FAST486_MOD_REG_RM ModRegRm
;
1178 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1180 /* Make sure this is the right instruction */
1181 ASSERT((Opcode
& 0xFD) == 0x00);
1183 TOGGLE_ADSIZE(AddressSize
);
1185 /* Get the operands */
1186 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1188 /* Exception occurred */
1192 if (!Fast486ReadModrmByteOperands(State
,
1197 /* Exception occurred */
1201 /* Calculate the result */
1202 Result
= FirstValue
+ SecondValue
;
1204 /* Update the flags */
1205 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1206 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1207 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1208 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1209 State
->Flags
.Zf
= (Result
== 0);
1210 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1211 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1213 /* Write back the result */
1214 return Fast486WriteModrmByteOperands(State
,
1216 Opcode
& FAST486_OPCODE_WRITE_REG
,
1220 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1222 FAST486_MOD_REG_RM ModRegRm
;
1223 BOOLEAN OperandSize
, AddressSize
;
1225 /* Make sure this is the right instruction */
1226 ASSERT((Opcode
& 0xFD) == 0x01);
1228 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1230 TOGGLE_ADSIZE(AddressSize
);
1231 TOGGLE_OPSIZE(OperandSize
);
1233 /* Get the operands */
1234 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1236 /* Exception occurred */
1240 /* Check the operand size */
1243 ULONG FirstValue
, SecondValue
, Result
;
1245 if (!Fast486ReadModrmDwordOperands(State
,
1250 /* Exception occurred */
1254 /* Calculate the result */
1255 Result
= FirstValue
+ SecondValue
;
1257 /* Update the flags */
1258 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1259 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1260 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1261 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1262 State
->Flags
.Zf
= (Result
== 0);
1263 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1264 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1266 /* Write back the result */
1267 return Fast486WriteModrmDwordOperands(State
,
1269 Opcode
& FAST486_OPCODE_WRITE_REG
,
1274 USHORT FirstValue
, SecondValue
, Result
;
1276 if (!Fast486ReadModrmWordOperands(State
,
1281 /* Exception occurred */
1285 /* Calculate the result */
1286 Result
= FirstValue
+ SecondValue
;
1288 /* Update the flags */
1289 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1290 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1291 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1292 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1293 State
->Flags
.Zf
= (Result
== 0);
1294 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1295 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1297 /* Write back the result */
1298 return Fast486WriteModrmWordOperands(State
,
1300 Opcode
& FAST486_OPCODE_WRITE_REG
,
1305 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1307 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1308 UCHAR SecondValue
, Result
;
1310 /* Make sure this is the right instruction */
1311 ASSERT(Opcode
== 0x04);
1313 if (State
->PrefixFlags
)
1315 /* This opcode doesn't take any prefixes */
1316 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1320 if (!Fast486FetchByte(State
, &SecondValue
))
1322 /* Exception occurred */
1326 /* Calculate the result */
1327 Result
= FirstValue
+ SecondValue
;
1329 /* Update the flags */
1330 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1331 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1332 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1333 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1334 State
->Flags
.Zf
= (Result
== 0);
1335 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1336 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1338 /* Write back the result */
1339 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1344 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1346 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1348 /* Make sure this is the right instruction */
1349 ASSERT(Opcode
== 0x05);
1352 TOGGLE_OPSIZE(Size
);
1356 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1357 ULONG SecondValue
, Result
;
1359 if (!Fast486FetchDword(State
, &SecondValue
))
1361 /* Exception occurred */
1365 /* Calculate the result */
1366 Result
= FirstValue
+ SecondValue
;
1368 /* Update the flags */
1369 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1370 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1371 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1372 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1373 State
->Flags
.Zf
= (Result
== 0);
1374 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1375 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1377 /* Write back the result */
1378 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1382 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1383 USHORT SecondValue
, Result
;
1385 if (!Fast486FetchWord(State
, &SecondValue
))
1387 /* Exception occurred */
1391 /* Calculate the result */
1392 Result
= FirstValue
+ SecondValue
;
1394 /* Update the flags */
1395 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1396 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1397 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1398 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1399 State
->Flags
.Zf
= (Result
== 0);
1400 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1401 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1403 /* Write back the result */
1404 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1410 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1412 UCHAR FirstValue
, SecondValue
, Result
;
1413 FAST486_MOD_REG_RM ModRegRm
;
1414 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1416 /* Make sure this is the right instruction */
1417 ASSERT((Opcode
& 0xFD) == 0x08);
1419 TOGGLE_ADSIZE(AddressSize
);
1421 /* Get the operands */
1422 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1424 /* Exception occurred */
1428 if (!Fast486ReadModrmByteOperands(State
,
1433 /* Exception occurred */
1437 /* Calculate the result */
1438 Result
= FirstValue
| SecondValue
;
1440 /* Update the flags */
1441 State
->Flags
.Cf
= FALSE
;
1442 State
->Flags
.Of
= FALSE
;
1443 State
->Flags
.Zf
= (Result
== 0);
1444 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1445 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1447 /* Write back the result */
1448 return Fast486WriteModrmByteOperands(State
,
1450 Opcode
& FAST486_OPCODE_WRITE_REG
,
1454 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1456 FAST486_MOD_REG_RM ModRegRm
;
1457 BOOLEAN OperandSize
, AddressSize
;
1459 /* Make sure this is the right instruction */
1460 ASSERT((Opcode
& 0xFD) == 0x09);
1462 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1464 TOGGLE_ADSIZE(AddressSize
);
1465 TOGGLE_OPSIZE(OperandSize
);
1467 /* Get the operands */
1468 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1470 /* Exception occurred */
1474 /* Check the operand size */
1477 ULONG FirstValue
, SecondValue
, Result
;
1479 if (!Fast486ReadModrmDwordOperands(State
,
1484 /* Exception occurred */
1488 /* Calculate the result */
1489 Result
= FirstValue
| SecondValue
;
1491 /* Update the flags */
1492 State
->Flags
.Cf
= FALSE
;
1493 State
->Flags
.Of
= FALSE
;
1494 State
->Flags
.Zf
= (Result
== 0);
1495 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1496 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1498 /* Write back the result */
1499 return Fast486WriteModrmDwordOperands(State
,
1501 Opcode
& FAST486_OPCODE_WRITE_REG
,
1506 USHORT FirstValue
, SecondValue
, Result
;
1508 if (!Fast486ReadModrmWordOperands(State
,
1513 /* Exception occurred */
1517 /* Calculate the result */
1518 Result
= FirstValue
| SecondValue
;
1520 /* Update the flags */
1521 State
->Flags
.Cf
= FALSE
;
1522 State
->Flags
.Of
= FALSE
;
1523 State
->Flags
.Zf
= (Result
== 0);
1524 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1525 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1527 /* Write back the result */
1528 return Fast486WriteModrmWordOperands(State
,
1530 Opcode
& FAST486_OPCODE_WRITE_REG
,
1535 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1537 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1538 UCHAR SecondValue
, Result
;
1540 /* Make sure this is the right instruction */
1541 ASSERT(Opcode
== 0x0C);
1543 if (State
->PrefixFlags
)
1545 /* This opcode doesn't take any prefixes */
1546 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1550 if (!Fast486FetchByte(State
, &SecondValue
))
1552 /* Exception occurred */
1556 /* Calculate the result */
1557 Result
= FirstValue
| SecondValue
;
1559 /* Update the flags */
1560 State
->Flags
.Cf
= FALSE
;
1561 State
->Flags
.Of
= FALSE
;
1562 State
->Flags
.Zf
= (Result
== 0);
1563 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1564 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1566 /* Write back the result */
1567 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1572 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1574 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1576 /* Make sure this is the right instruction */
1577 ASSERT(Opcode
== 0x0D);
1580 TOGGLE_OPSIZE(Size
);
1584 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1585 ULONG SecondValue
, Result
;
1587 if (!Fast486FetchDword(State
, &SecondValue
))
1589 /* Exception occurred */
1593 /* Calculate the result */
1594 Result
= FirstValue
| SecondValue
;
1596 /* Update the flags */
1597 State
->Flags
.Cf
= FALSE
;
1598 State
->Flags
.Of
= FALSE
;
1599 State
->Flags
.Zf
= (Result
== 0);
1600 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1601 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1603 /* Write back the result */
1604 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1608 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1609 USHORT SecondValue
, Result
;
1611 if (!Fast486FetchWord(State
, &SecondValue
))
1613 /* Exception occurred */
1617 /* Calculate the result */
1618 Result
= FirstValue
| SecondValue
;
1620 /* Update the flags */
1621 State
->Flags
.Cf
= FALSE
;
1622 State
->Flags
.Of
= FALSE
;
1623 State
->Flags
.Zf
= (Result
== 0);
1624 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1625 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1627 /* Write back the result */
1628 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1634 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1636 UCHAR FirstValue
, SecondValue
, Result
;
1637 FAST486_MOD_REG_RM ModRegRm
;
1638 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1640 /* Make sure this is the right instruction */
1641 ASSERT((Opcode
& 0xFD) == 0x20);
1643 TOGGLE_ADSIZE(AddressSize
);
1645 /* Get the operands */
1646 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1648 /* Exception occurred */
1652 if (!Fast486ReadModrmByteOperands(State
,
1657 /* Exception occurred */
1661 /* Calculate the result */
1662 Result
= FirstValue
& SecondValue
;
1664 /* Update the flags */
1665 State
->Flags
.Cf
= FALSE
;
1666 State
->Flags
.Of
= FALSE
;
1667 State
->Flags
.Zf
= (Result
== 0);
1668 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1669 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1671 /* Write back the result */
1672 return Fast486WriteModrmByteOperands(State
,
1674 Opcode
& FAST486_OPCODE_WRITE_REG
,
1678 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1680 FAST486_MOD_REG_RM ModRegRm
;
1681 BOOLEAN OperandSize
, AddressSize
;
1683 /* Make sure this is the right instruction */
1684 ASSERT((Opcode
& 0xFD) == 0x21);
1686 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1688 TOGGLE_ADSIZE(AddressSize
);
1689 TOGGLE_OPSIZE(OperandSize
);
1691 /* Get the operands */
1692 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1694 /* Exception occurred */
1698 /* Check the operand size */
1701 ULONG FirstValue
, SecondValue
, Result
;
1703 if (!Fast486ReadModrmDwordOperands(State
,
1708 /* Exception occurred */
1712 /* Calculate the result */
1713 Result
= FirstValue
& SecondValue
;
1715 /* Update the flags */
1716 State
->Flags
.Cf
= FALSE
;
1717 State
->Flags
.Of
= FALSE
;
1718 State
->Flags
.Zf
= (Result
== 0);
1719 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1720 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1722 /* Write back the result */
1723 return Fast486WriteModrmDwordOperands(State
,
1725 Opcode
& FAST486_OPCODE_WRITE_REG
,
1730 USHORT FirstValue
, SecondValue
, Result
;
1732 if (!Fast486ReadModrmWordOperands(State
,
1737 /* Exception occurred */
1741 /* Calculate the result */
1742 Result
= FirstValue
& SecondValue
;
1744 /* Update the flags */
1745 State
->Flags
.Cf
= FALSE
;
1746 State
->Flags
.Of
= FALSE
;
1747 State
->Flags
.Zf
= (Result
== 0);
1748 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1749 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1751 /* Write back the result */
1752 return Fast486WriteModrmWordOperands(State
,
1754 Opcode
& FAST486_OPCODE_WRITE_REG
,
1759 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1761 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1762 UCHAR SecondValue
, Result
;
1764 /* Make sure this is the right instruction */
1765 ASSERT(Opcode
== 0x24);
1769 if (!Fast486FetchByte(State
, &SecondValue
))
1771 /* Exception occurred */
1775 /* Calculate the result */
1776 Result
= FirstValue
& SecondValue
;
1778 /* Update the flags */
1779 State
->Flags
.Cf
= FALSE
;
1780 State
->Flags
.Of
= FALSE
;
1781 State
->Flags
.Zf
= (Result
== 0);
1782 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1783 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1785 /* Write back the result */
1786 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1791 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1793 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1795 /* Make sure this is the right instruction */
1796 ASSERT(Opcode
== 0x25);
1799 TOGGLE_OPSIZE(Size
);
1803 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1804 ULONG SecondValue
, Result
;
1806 if (!Fast486FetchDword(State
, &SecondValue
))
1808 /* Exception occurred */
1812 /* Calculate the result */
1813 Result
= FirstValue
& SecondValue
;
1815 /* Update the flags */
1816 State
->Flags
.Cf
= FALSE
;
1817 State
->Flags
.Of
= FALSE
;
1818 State
->Flags
.Zf
= (Result
== 0);
1819 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1820 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1822 /* Write back the result */
1823 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1827 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1828 USHORT SecondValue
, Result
;
1830 if (!Fast486FetchWord(State
, &SecondValue
))
1832 /* Exception occurred */
1836 /* Calculate the result */
1837 Result
= FirstValue
& SecondValue
;
1839 /* Update the flags */
1840 State
->Flags
.Cf
= FALSE
;
1841 State
->Flags
.Of
= FALSE
;
1842 State
->Flags
.Zf
= (Result
== 0);
1843 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1844 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1846 /* Write back the result */
1847 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1853 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1855 UCHAR FirstValue
, SecondValue
, Result
;
1856 FAST486_MOD_REG_RM ModRegRm
;
1857 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1859 /* Make sure this is the right instruction */
1860 ASSERT((Opcode
& 0xFD) == 0x30);
1862 TOGGLE_ADSIZE(AddressSize
);
1864 /* Get the operands */
1865 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1867 /* Exception occurred */
1871 if (!Fast486ReadModrmByteOperands(State
,
1876 /* Exception occurred */
1880 /* Calculate the result */
1881 Result
= FirstValue
^ SecondValue
;
1883 /* Update the flags */
1884 State
->Flags
.Cf
= FALSE
;
1885 State
->Flags
.Of
= FALSE
;
1886 State
->Flags
.Zf
= (Result
== 0);
1887 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1888 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1890 /* Write back the result */
1891 return Fast486WriteModrmByteOperands(State
,
1893 Opcode
& FAST486_OPCODE_WRITE_REG
,
1897 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1899 FAST486_MOD_REG_RM ModRegRm
;
1900 BOOLEAN OperandSize
, AddressSize
;
1902 /* Make sure this is the right instruction */
1903 ASSERT((Opcode
& 0xFD) == 0x31);
1905 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1907 TOGGLE_ADSIZE(AddressSize
);
1908 TOGGLE_OPSIZE(OperandSize
);
1910 /* Get the operands */
1911 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1913 /* Exception occurred */
1917 /* Check the operand size */
1920 ULONG FirstValue
, SecondValue
, Result
;
1922 if (!Fast486ReadModrmDwordOperands(State
,
1927 /* Exception occurred */
1931 /* Calculate the result */
1932 Result
= FirstValue
^ SecondValue
;
1934 /* Update the flags */
1935 State
->Flags
.Cf
= FALSE
;
1936 State
->Flags
.Of
= FALSE
;
1937 State
->Flags
.Zf
= (Result
== 0);
1938 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1939 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1941 /* Write back the result */
1942 return Fast486WriteModrmDwordOperands(State
,
1944 Opcode
& FAST486_OPCODE_WRITE_REG
,
1949 USHORT FirstValue
, SecondValue
, Result
;
1951 if (!Fast486ReadModrmWordOperands(State
,
1956 /* Exception occurred */
1960 /* Calculate the result */
1961 Result
= FirstValue
^ SecondValue
;
1963 /* Update the flags */
1964 State
->Flags
.Cf
= FALSE
;
1965 State
->Flags
.Of
= FALSE
;
1966 State
->Flags
.Zf
= (Result
== 0);
1967 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1968 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1970 /* Write back the result */
1971 return Fast486WriteModrmWordOperands(State
,
1973 Opcode
& FAST486_OPCODE_WRITE_REG
,
1978 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1980 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1981 UCHAR SecondValue
, Result
;
1983 /* Make sure this is the right instruction */
1984 ASSERT(Opcode
== 0x34);
1986 if (State
->PrefixFlags
)
1988 /* This opcode doesn't take any prefixes */
1989 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1993 if (!Fast486FetchByte(State
, &SecondValue
))
1995 /* Exception occurred */
1999 /* Calculate the result */
2000 Result
= FirstValue
^ SecondValue
;
2002 /* Update the flags */
2003 State
->Flags
.Cf
= FALSE
;
2004 State
->Flags
.Of
= FALSE
;
2005 State
->Flags
.Zf
= (Result
== 0);
2006 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2007 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2009 /* Write back the result */
2010 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2015 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2017 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2019 /* Make sure this is the right instruction */
2020 ASSERT(Opcode
== 0x35);
2023 TOGGLE_OPSIZE(Size
);
2027 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2028 ULONG SecondValue
, Result
;
2030 if (!Fast486FetchDword(State
, &SecondValue
))
2032 /* Exception occurred */
2036 /* Calculate the result */
2037 Result
= FirstValue
^ SecondValue
;
2039 /* Update the flags */
2040 State
->Flags
.Cf
= FALSE
;
2041 State
->Flags
.Of
= FALSE
;
2042 State
->Flags
.Zf
= (Result
== 0);
2043 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2044 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2046 /* Write back the result */
2047 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2051 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2052 USHORT SecondValue
, Result
;
2054 if (!Fast486FetchWord(State
, &SecondValue
))
2056 /* Exception occurred */
2060 /* Calculate the result */
2061 Result
= FirstValue
^ SecondValue
;
2063 /* Update the flags */
2064 State
->Flags
.Cf
= FALSE
;
2065 State
->Flags
.Of
= FALSE
;
2066 State
->Flags
.Zf
= (Result
== 0);
2067 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2068 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2070 /* Write back the result */
2071 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2077 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2079 UCHAR FirstValue
, SecondValue
, Result
;
2080 FAST486_MOD_REG_RM ModRegRm
;
2081 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2083 /* Make sure this is the right instruction */
2084 ASSERT(Opcode
== 0x84);
2086 TOGGLE_ADSIZE(AddressSize
);
2088 /* Get the operands */
2089 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2091 /* Exception occurred */
2095 if (!Fast486ReadModrmByteOperands(State
,
2100 /* Exception occurred */
2103 /* Calculate the result */
2104 Result
= FirstValue
& SecondValue
;
2106 /* Update the flags */
2107 State
->Flags
.Cf
= FALSE
;
2108 State
->Flags
.Of
= FALSE
;
2109 State
->Flags
.Zf
= (Result
== 0);
2110 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2111 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2113 /* The result is discarded */
2117 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2119 FAST486_MOD_REG_RM ModRegRm
;
2120 BOOLEAN OperandSize
, AddressSize
;
2122 /* Make sure this is the right instruction */
2123 ASSERT(Opcode
== 0x85);
2125 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2127 TOGGLE_ADSIZE(AddressSize
);
2128 TOGGLE_OPSIZE(OperandSize
);
2130 /* Get the operands */
2131 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2133 /* Exception occurred */
2137 /* Check the operand size */
2140 ULONG FirstValue
, SecondValue
, Result
;
2142 if (!Fast486ReadModrmDwordOperands(State
,
2147 /* Exception occurred */
2151 /* Calculate the result */
2152 Result
= FirstValue
& SecondValue
;
2154 /* Update the flags */
2155 State
->Flags
.Cf
= FALSE
;
2156 State
->Flags
.Of
= FALSE
;
2157 State
->Flags
.Zf
= (Result
== 0);
2158 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2159 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2163 USHORT FirstValue
, SecondValue
, Result
;
2165 if (!Fast486ReadModrmWordOperands(State
,
2170 /* Exception occurred */
2174 /* Calculate the result */
2175 Result
= FirstValue
& SecondValue
;
2177 /* Update the flags */
2178 State
->Flags
.Cf
= FALSE
;
2179 State
->Flags
.Of
= FALSE
;
2180 State
->Flags
.Zf
= (Result
== 0);
2181 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2182 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2185 /* The result is discarded */
2189 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2191 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2192 UCHAR SecondValue
, Result
;
2194 /* Make sure this is the right instruction */
2195 ASSERT(Opcode
== 0xA8);
2197 if (State
->PrefixFlags
)
2199 /* This opcode doesn't take any prefixes */
2200 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2204 if (!Fast486FetchByte(State
, &SecondValue
))
2206 /* Exception occurred */
2210 /* Calculate the result */
2211 Result
= FirstValue
& SecondValue
;
2213 /* Update the flags */
2214 State
->Flags
.Cf
= FALSE
;
2215 State
->Flags
.Of
= FALSE
;
2216 State
->Flags
.Zf
= (Result
== 0);
2217 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2218 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2220 /* The result is discarded */
2224 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2226 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2228 /* Make sure this is the right instruction */
2229 ASSERT(Opcode
== 0xA9);
2232 TOGGLE_OPSIZE(Size
);
2236 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2237 ULONG SecondValue
, Result
;
2239 if (!Fast486FetchDword(State
, &SecondValue
))
2241 /* Exception occurred */
2245 /* Calculate the result */
2246 Result
= FirstValue
& SecondValue
;
2248 /* Update the flags */
2249 State
->Flags
.Cf
= FALSE
;
2250 State
->Flags
.Of
= FALSE
;
2251 State
->Flags
.Zf
= (Result
== 0);
2252 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2253 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2257 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2258 USHORT SecondValue
, Result
;
2260 if (!Fast486FetchWord(State
, &SecondValue
))
2262 /* Exception occurred */
2266 /* Calculate the result */
2267 Result
= FirstValue
& SecondValue
;
2269 /* Update the flags */
2270 State
->Flags
.Cf
= FALSE
;
2271 State
->Flags
.Of
= FALSE
;
2272 State
->Flags
.Zf
= (Result
== 0);
2273 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2274 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2277 /* The result is discarded */
2281 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2283 UCHAR FirstValue
, SecondValue
;
2284 FAST486_MOD_REG_RM ModRegRm
;
2285 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2287 /* Make sure this is the right instruction */
2288 ASSERT(Opcode
== 0x86);
2290 TOGGLE_ADSIZE(AddressSize
);
2292 /* Get the operands */
2293 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2295 /* Exception occurred */
2299 if (!Fast486ReadModrmByteOperands(State
,
2304 /* Exception occurred */
2308 /* Write the value from the register to the R/M */
2309 if (!Fast486WriteModrmByteOperands(State
,
2314 /* Exception occurred */
2318 /* Write the value from the R/M to the register */
2319 if (!Fast486WriteModrmByteOperands(State
,
2324 /* Exception occurred */
2331 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2333 FAST486_MOD_REG_RM ModRegRm
;
2334 BOOLEAN OperandSize
, AddressSize
;
2336 /* Make sure this is the right instruction */
2337 ASSERT(Opcode
== 0x87);
2339 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2341 TOGGLE_ADSIZE(AddressSize
);
2342 TOGGLE_OPSIZE(OperandSize
);
2344 /* Get the operands */
2345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2347 /* Exception occurred */
2351 /* Check the operand size */
2354 ULONG FirstValue
, SecondValue
;
2356 if (!Fast486ReadModrmDwordOperands(State
,
2361 /* Exception occurred */
2365 /* Write the value from the register to the R/M */
2366 if (!Fast486WriteModrmDwordOperands(State
,
2371 /* Exception occurred */
2375 /* Write the value from the R/M to the register */
2376 if (!Fast486WriteModrmDwordOperands(State
,
2381 /* Exception occurred */
2387 USHORT FirstValue
, SecondValue
;
2389 if (!Fast486ReadModrmWordOperands(State
,
2394 /* Exception occurred */
2398 /* Write the value from the register to the R/M */
2399 if (!Fast486WriteModrmWordOperands(State
,
2404 /* Exception occurred */
2408 /* Write the value from the R/M to the register */
2409 if (!Fast486WriteModrmWordOperands(State
,
2414 /* Exception occurred */
2419 /* The result is discarded */
2423 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2425 /* Call the internal API */
2426 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2429 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2433 if (!Fast486StackPop(State
, &NewSelector
))
2435 /* Exception occurred */
2439 /* Call the internal API */
2440 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2443 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2445 /* Call the internal API */
2446 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2449 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2451 UCHAR FirstValue
, SecondValue
, Result
;
2452 FAST486_MOD_REG_RM ModRegRm
;
2453 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2455 /* Make sure this is the right instruction */
2456 ASSERT((Opcode
& 0xFD) == 0x10);
2458 TOGGLE_ADSIZE(AddressSize
);
2460 /* Get the operands */
2461 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2463 /* Exception occurred */
2467 if (!Fast486ReadModrmByteOperands(State
,
2472 /* Exception occurred */
2476 /* Calculate the result */
2477 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2479 /* Special exception for CF */
2480 State
->Flags
.Cf
= State
->Flags
.Cf
2481 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2483 /* Update the flags */
2484 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2485 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2486 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2487 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2488 State
->Flags
.Zf
= (Result
== 0);
2489 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2490 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2492 /* Write back the result */
2493 return Fast486WriteModrmByteOperands(State
,
2495 Opcode
& FAST486_OPCODE_WRITE_REG
,
2499 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2501 FAST486_MOD_REG_RM ModRegRm
;
2502 BOOLEAN OperandSize
, AddressSize
;
2504 /* Make sure this is the right instruction */
2505 ASSERT((Opcode
& 0xFD) == 0x11);
2507 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2509 TOGGLE_ADSIZE(AddressSize
);
2510 TOGGLE_OPSIZE(OperandSize
);
2512 /* Get the operands */
2513 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2515 /* Exception occurred */
2519 /* Check the operand size */
2522 ULONG FirstValue
, SecondValue
, Result
;
2524 if (!Fast486ReadModrmDwordOperands(State
,
2529 /* Exception occurred */
2533 /* Calculate the result */
2534 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2536 /* Special exception for CF */
2537 State
->Flags
.Cf
= State
->Flags
.Cf
2538 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2540 /* Update the flags */
2541 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2542 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2543 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2544 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2545 State
->Flags
.Zf
= (Result
== 0);
2546 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2547 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2549 /* Write back the result */
2550 return Fast486WriteModrmDwordOperands(State
,
2552 Opcode
& FAST486_OPCODE_WRITE_REG
,
2557 USHORT FirstValue
, SecondValue
, Result
;
2559 if (!Fast486ReadModrmWordOperands(State
,
2564 /* Exception occurred */
2568 /* Calculate the result */
2569 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2571 /* Special exception for CF */
2572 State
->Flags
.Cf
= State
->Flags
.Cf
2573 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2575 /* Update the flags */
2576 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2577 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2578 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2579 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2580 State
->Flags
.Zf
= (Result
== 0);
2581 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2582 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2584 /* Write back the result */
2585 return Fast486WriteModrmWordOperands(State
,
2587 Opcode
& FAST486_OPCODE_WRITE_REG
,
2593 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2595 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2596 UCHAR SecondValue
, Result
;
2598 /* Make sure this is the right instruction */
2599 ASSERT(Opcode
== 0x14);
2601 if (State
->PrefixFlags
)
2603 /* This opcode doesn't take any prefixes */
2604 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2608 if (!Fast486FetchByte(State
, &SecondValue
))
2610 /* Exception occurred */
2614 /* Calculate the result */
2615 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2617 /* Special exception for CF */
2618 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2619 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2621 /* Update the flags */
2622 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2623 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2624 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2625 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2626 State
->Flags
.Zf
= (Result
== 0);
2627 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2628 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2630 /* Write back the result */
2631 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2636 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2638 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2640 /* Make sure this is the right instruction */
2641 ASSERT(Opcode
== 0x15);
2644 TOGGLE_OPSIZE(Size
);
2648 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2649 ULONG SecondValue
, Result
;
2651 if (!Fast486FetchDword(State
, &SecondValue
))
2653 /* Exception occurred */
2657 /* Calculate the result */
2658 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2660 /* Special exception for CF */
2661 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2662 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2664 /* Update the flags */
2665 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2666 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2667 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2668 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2669 State
->Flags
.Zf
= (Result
== 0);
2670 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2671 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2673 /* Write back the result */
2674 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2678 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2679 USHORT SecondValue
, Result
;
2681 if (!Fast486FetchWord(State
, &SecondValue
))
2683 /* Exception occurred */
2687 /* Calculate the result */
2688 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2690 /* Special exception for CF */
2691 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2692 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2694 /* Update the flags */
2695 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2696 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2697 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2698 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2699 State
->Flags
.Zf
= (Result
== 0);
2700 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2701 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2703 /* Write back the result */
2704 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2710 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2712 /* Call the internal API */
2713 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2716 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2720 if (!Fast486StackPop(State
, &NewSelector
))
2722 /* Exception occurred */
2726 /* Call the internal API */
2727 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2730 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2732 UCHAR FirstValue
, SecondValue
, Result
;
2733 FAST486_MOD_REG_RM ModRegRm
;
2734 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2735 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2737 /* Make sure this is the right instruction */
2738 ASSERT((Opcode
& 0xFD) == 0x18);
2740 TOGGLE_ADSIZE(AddressSize
);
2742 /* Get the operands */
2743 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2745 /* Exception occurred */
2749 if (!Fast486ReadModrmByteOperands(State
,
2754 /* Exception occurred */
2758 /* Check if this is the instruction that writes to R/M */
2759 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2761 /* Swap the order */
2762 SWAP(FirstValue
, SecondValue
);
2765 /* Calculate the result */
2766 Result
= FirstValue
- SecondValue
- Carry
;
2768 /* Update the flags */
2769 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2770 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2771 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2772 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2773 State
->Flags
.Zf
= (Result
== 0);
2774 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2775 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2777 /* Write back the result */
2778 return Fast486WriteModrmByteOperands(State
,
2780 Opcode
& FAST486_OPCODE_WRITE_REG
,
2784 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2786 FAST486_MOD_REG_RM ModRegRm
;
2787 BOOLEAN OperandSize
, AddressSize
;
2788 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2790 /* Make sure this is the right instruction */
2791 ASSERT((Opcode
& 0xFD) == 0x19);
2793 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2795 TOGGLE_ADSIZE(AddressSize
);
2796 TOGGLE_OPSIZE(OperandSize
);
2798 /* Get the operands */
2799 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2801 /* Exception occurred */
2805 /* Check the operand size */
2808 ULONG FirstValue
, SecondValue
, Result
;
2810 if (!Fast486ReadModrmDwordOperands(State
,
2815 /* Exception occurred */
2819 /* Check if this is the instruction that writes to R/M */
2820 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2822 /* Swap the order */
2823 SWAP(FirstValue
, SecondValue
);
2826 /* Calculate the result */
2827 Result
= FirstValue
- SecondValue
- Carry
;
2829 /* Update the flags */
2830 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2831 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2832 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2833 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2834 State
->Flags
.Zf
= (Result
== 0);
2835 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2836 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2838 /* Write back the result */
2839 return Fast486WriteModrmDwordOperands(State
,
2841 Opcode
& FAST486_OPCODE_WRITE_REG
,
2846 USHORT FirstValue
, SecondValue
, Result
;
2848 if (!Fast486ReadModrmWordOperands(State
,
2853 /* Exception occurred */
2857 /* Check if this is the instruction that writes to R/M */
2858 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2860 /* Swap the order */
2861 SWAP(FirstValue
, SecondValue
);
2864 /* Calculate the result */
2865 Result
= FirstValue
- SecondValue
- Carry
;
2867 /* Update the flags */
2868 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2869 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2870 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2871 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2872 State
->Flags
.Zf
= (Result
== 0);
2873 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2874 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2876 /* Write back the result */
2877 return Fast486WriteModrmWordOperands(State
,
2879 Opcode
& FAST486_OPCODE_WRITE_REG
,
2884 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2886 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2887 UCHAR SecondValue
, Result
;
2888 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2890 /* Make sure this is the right instruction */
2891 ASSERT(Opcode
== 0x1C);
2893 if (State
->PrefixFlags
)
2895 /* This opcode doesn't take any prefixes */
2896 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2900 if (!Fast486FetchByte(State
, &SecondValue
))
2902 /* Exception occurred */
2906 /* Calculate the result */
2907 Result
= FirstValue
- SecondValue
- Carry
;
2909 /* Update the flags */
2910 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2911 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2912 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2913 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2914 State
->Flags
.Zf
= (Result
== 0);
2915 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2916 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2918 /* Write back the result */
2919 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2925 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2927 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2928 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2930 /* Make sure this is the right instruction */
2931 ASSERT(Opcode
== 0x1D);
2934 TOGGLE_OPSIZE(Size
);
2938 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2939 ULONG SecondValue
, Result
;
2941 if (!Fast486FetchDword(State
, &SecondValue
))
2943 /* Exception occurred */
2947 /* Calculate the result */
2948 Result
= FirstValue
- SecondValue
- Carry
;
2950 /* Update the flags */
2951 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2952 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2953 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2954 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2955 State
->Flags
.Zf
= (Result
== 0);
2956 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2957 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2959 /* Write back the result */
2960 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2964 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2965 USHORT SecondValue
, Result
;
2967 if (!Fast486FetchWord(State
, &SecondValue
))
2969 /* Exception occurred */
2973 /* Calculate the result */
2974 Result
= FirstValue
- SecondValue
- Carry
;
2976 /* Update the flags */
2977 State
->Flags
.Cf
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
2978 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2979 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2980 State
->Flags
.Af
= ((FirstValue
^ SecondValue
^ Result
) & 0x10) != 0;
2981 State
->Flags
.Zf
= (Result
== 0);
2982 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2983 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2985 /* Write back the result */
2986 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2993 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2995 /* Call the internal API */
2996 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2999 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3003 if (!Fast486StackPop(State
, &NewSelector
))
3005 /* Exception occurred */
3009 /* Call the internal API */
3010 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3013 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3015 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3016 BOOLEAN Carry
= State
->Flags
.Cf
;
3018 /* Clear the carry flag */
3019 State
->Flags
.Cf
= FALSE
;
3021 /* Check if the first BCD digit is invalid or there was a carry from it */
3022 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3025 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3026 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3028 /* A carry occurred */
3029 State
->Flags
.Cf
= TRUE
;
3032 /* Set the adjust flag */
3033 State
->Flags
.Af
= TRUE
;
3036 /* Check if the second BCD digit is invalid or there was a carry from it */
3037 if ((Value
> 0x99) || Carry
)
3040 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3042 /* There was a carry */
3043 State
->Flags
.Cf
= TRUE
;
3046 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3048 /* Update the flags */
3049 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3050 State
->Flags
.Zf
= (Value
== 0);
3051 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3056 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3058 UCHAR FirstValue
, SecondValue
, Result
;
3059 FAST486_MOD_REG_RM ModRegRm
;
3060 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3062 /* Make sure this is the right instruction */
3063 ASSERT((Opcode
& 0xED) == 0x28);
3065 TOGGLE_ADSIZE(AddressSize
);
3067 /* Get the operands */
3068 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3070 /* Exception occurred */
3074 if (!Fast486ReadModrmByteOperands(State
,
3079 /* Exception occurred */
3083 /* Check if this is the instruction that writes to R/M */
3084 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3086 /* Swap the order */
3087 SWAP(FirstValue
, SecondValue
);
3090 /* Calculate the result */
3091 Result
= FirstValue
- SecondValue
;
3093 /* Update the flags */
3094 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3095 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3096 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3097 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3098 State
->Flags
.Zf
= (Result
== 0);
3099 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3100 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3102 /* Check if this is not a CMP */
3103 if (!(Opcode
& 0x10))
3105 /* Write back the result */
3106 return Fast486WriteModrmByteOperands(State
,
3108 Opcode
& FAST486_OPCODE_WRITE_REG
,
3113 /* Discard the result */
3118 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3120 FAST486_MOD_REG_RM ModRegRm
;
3121 BOOLEAN OperandSize
, AddressSize
;
3123 /* Make sure this is the right instruction */
3124 ASSERT((Opcode
& 0xED) == 0x29);
3126 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3128 TOGGLE_ADSIZE(AddressSize
);
3129 TOGGLE_OPSIZE(OperandSize
);
3131 /* Get the operands */
3132 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3134 /* Exception occurred */
3138 /* Check the operand size */
3141 ULONG FirstValue
, SecondValue
, Result
;
3143 if (!Fast486ReadModrmDwordOperands(State
,
3148 /* Exception occurred */
3152 /* Check if this is the instruction that writes to R/M */
3153 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3155 /* Swap the order */
3156 SWAP(FirstValue
, SecondValue
);
3159 /* Calculate the result */
3160 Result
= FirstValue
- SecondValue
;
3162 /* Update the flags */
3163 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3164 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3165 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3166 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3167 State
->Flags
.Zf
= (Result
== 0);
3168 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3169 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3171 /* Check if this is not a CMP */
3172 if (!(Opcode
& 0x10))
3174 /* Write back the result */
3175 return Fast486WriteModrmDwordOperands(State
,
3177 Opcode
& FAST486_OPCODE_WRITE_REG
,
3182 /* Discard the result */
3188 USHORT FirstValue
, SecondValue
, Result
;
3190 if (!Fast486ReadModrmWordOperands(State
,
3195 /* Exception occurred */
3199 /* Check if this is the instruction that writes to R/M */
3200 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3202 /* Swap the order */
3203 SWAP(FirstValue
, SecondValue
);
3206 /* Calculate the result */
3207 Result
= FirstValue
- SecondValue
;
3209 /* Update the flags */
3210 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3211 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3212 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3213 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3214 State
->Flags
.Zf
= (Result
== 0);
3215 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3216 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3218 /* Check if this is not a CMP */
3219 if (!(Opcode
& 0x10))
3221 /* Write back the result */
3222 return Fast486WriteModrmWordOperands(State
,
3224 Opcode
& FAST486_OPCODE_WRITE_REG
,
3229 /* Discard the result */
3235 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3237 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3238 UCHAR SecondValue
, Result
;
3240 /* Make sure this is the right instruction */
3241 ASSERT((Opcode
& 0xEF) == 0x2C);
3243 if (State
->PrefixFlags
)
3245 /* This opcode doesn't take any prefixes */
3246 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3250 if (!Fast486FetchByte(State
, &SecondValue
))
3252 /* Exception occurred */
3256 /* Calculate the result */
3257 Result
= FirstValue
- SecondValue
;
3259 /* Update the flags */
3260 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3261 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3262 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3263 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3264 State
->Flags
.Zf
= (Result
== 0);
3265 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3266 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3268 /* Check if this is not a CMP */
3269 if (!(Opcode
& 0x10))
3271 /* Write back the result */
3272 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3278 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3280 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3282 /* Make sure this is the right instruction */
3283 ASSERT((Opcode
& 0xEF) == 0x2D);
3286 TOGGLE_OPSIZE(Size
);
3290 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3291 ULONG SecondValue
, Result
;
3293 if (!Fast486FetchDword(State
, &SecondValue
))
3295 /* Exception occurred */
3299 /* Calculate the result */
3300 Result
= FirstValue
- SecondValue
;
3302 /* Update the flags */
3303 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3304 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3305 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3306 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3307 State
->Flags
.Zf
= (Result
== 0);
3308 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3309 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3311 /* Check if this is not a CMP */
3312 if (!(Opcode
& 0x10))
3314 /* Write back the result */
3315 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3320 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3321 USHORT SecondValue
, Result
;
3323 if (!Fast486FetchWord(State
, &SecondValue
))
3325 /* Exception occurred */
3329 /* Calculate the result */
3330 Result
= FirstValue
- SecondValue
;
3332 /* Update the flags */
3333 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3334 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3335 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3336 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3337 State
->Flags
.Zf
= (Result
== 0);
3338 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3339 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3341 /* Check if this is not a CMP */
3342 if (!(Opcode
& 0x10))
3344 /* Write back the result */
3345 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3352 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3354 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3355 BOOLEAN Carry
= State
->Flags
.Cf
;
3357 /* Clear the carry flag */
3358 State
->Flags
.Cf
= FALSE
;
3360 /* Check if the first BCD digit is invalid or there was a borrow */
3361 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3364 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3365 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3367 /* A borrow occurred */
3368 State
->Flags
.Cf
= TRUE
;
3371 /* Set the adjust flag */
3372 State
->Flags
.Af
= TRUE
;
3375 /* Check if the second BCD digit is invalid or there was a borrow */
3376 if ((Value
> 0x99) || Carry
)
3379 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3381 /* There was a borrow */
3382 State
->Flags
.Cf
= TRUE
;
3385 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3387 /* Update the flags */
3388 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3389 State
->Flags
.Zf
= (Value
== 0);
3390 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3395 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3397 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3400 * Check if the value in AL is not a valid BCD digit,
3401 * or there was a carry from the lowest 4 bits of AL
3403 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3406 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3407 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3410 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3414 /* Clear CF and AF */
3415 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3418 /* Keep only the lowest 4 bits of AL */
3419 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3424 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3426 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3429 * Check if the value in AL is not a valid BCD digit,
3430 * or there was a borrow from the lowest 4 bits of AL
3432 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3435 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3436 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3439 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3443 /* Clear CF and AF */
3444 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3447 /* Keep only the lowest 4 bits of AL */
3448 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3453 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3456 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3457 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3459 /* Make sure this is the right instruction */
3460 ASSERT(Opcode
== 0x60);
3462 TOGGLE_OPSIZE(Size
);
3465 /* Push all the registers in order */
3466 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3468 if (i
== FAST486_REG_ESP
)
3470 /* Use the saved ESP instead */
3471 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3473 /* Exception occurred */
3479 /* Push the register */
3480 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3481 : State
->GeneralRegs
[i
].LowWord
))
3483 /* Exception occurred */
3492 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3495 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3498 /* Make sure this is the right instruction */
3499 ASSERT(Opcode
== 0x61);
3501 TOGGLE_OPSIZE(Size
);
3504 /* Pop all the registers in reverse order */
3505 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3508 if (!Fast486StackPop(State
, &Value
))
3510 /* Exception occurred */
3514 /* Don't modify ESP */
3515 if (i
!= FAST486_REG_ESP
)
3517 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3518 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3525 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3527 BOOLEAN OperandSize
, AddressSize
;
3528 FAST486_MOD_REG_RM ModRegRm
;
3529 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
3531 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3534 TOGGLE_OPSIZE(OperandSize
);
3535 TOGGLE_ADSIZE(AddressSize
);
3537 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3539 /* Exception occurred */
3543 if (!ModRegRm
.Memory
)
3546 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3550 /* Check for the segment override */
3551 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
3553 /* Use the override segment instead */
3554 Segment
= State
->SegmentOverride
;
3559 LONG Index
, LowerBound
, UpperBound
;
3561 /* Read the operands */
3562 if (!Fast486ReadModrmDwordOperands(State
,
3565 (PULONG
)&LowerBound
))
3567 /* Exception occurred */
3571 if (!Fast486ReadMemory(State
,
3573 ModRegRm
.MemoryAddress
+ sizeof(ULONG
),
3578 /* Exception occurred */
3582 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3585 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3591 SHORT Index
, LowerBound
, UpperBound
;
3593 /* Read the operands */
3594 if (!Fast486ReadModrmWordOperands(State
,
3597 (PUSHORT
)&LowerBound
))
3599 /* Exception occurred */
3603 if (!Fast486ReadMemory(State
,
3605 ModRegRm
.MemoryAddress
+ sizeof(USHORT
),
3610 /* Exception occurred */
3614 if ((Index
< LowerBound
) || (Index
> UpperBound
))
3617 Fast486Exception(State
, FAST486_EXCEPTION_BR
);
3625 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3627 USHORT FirstValue
, SecondValue
;
3628 FAST486_MOD_REG_RM ModRegRm
;
3629 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3631 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3633 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3635 /* Cannot be used in real mode or with a LOCK prefix */
3636 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3640 TOGGLE_ADSIZE(AddressSize
);
3642 /* Get the operands */
3643 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3645 /* Exception occurred */
3649 /* Read the operands */
3650 if (!Fast486ReadModrmWordOperands(State
,
3655 /* Exception occurred */
3659 /* Check if the RPL needs adjusting */
3660 if ((SecondValue
& 3) < (FirstValue
& 3))
3662 /* Adjust the RPL */
3664 SecondValue
|= FirstValue
& 3;
3667 State
->Flags
.Zf
= TRUE
;
3669 /* Write back the result */
3670 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3675 State
->Flags
.Zf
= FALSE
;
3680 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3682 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3684 /* Make sure this is the right instruction */
3685 ASSERT(Opcode
== 0x68);
3688 TOGGLE_OPSIZE(Size
);
3694 if (!Fast486FetchDword(State
, &Data
))
3696 /* Exception occurred */
3700 /* Call the internal API */
3701 return Fast486StackPush(State
, Data
);
3707 if (!Fast486FetchWord(State
, (PUSHORT
)&Data
))
3709 /* Exception occurred */
3713 /* Call the internal API */
3714 return Fast486StackPush(State
, Data
);
3718 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3720 BOOLEAN OperandSize
, AddressSize
;
3721 FAST486_MOD_REG_RM ModRegRm
;
3724 /* Make sure this is the right instruction */
3725 ASSERT((Opcode
& 0xFD) == 0x69);
3727 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3729 TOGGLE_ADSIZE(AddressSize
);
3730 TOGGLE_OPSIZE(OperandSize
);
3732 /* Fetch the parameters */
3733 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3735 /* Exception occurred */
3743 /* Fetch the immediate operand */
3744 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3746 /* Exception occurred */
3750 Multiplier
= (LONG
)Byte
;
3758 /* Fetch the immediate operand */
3759 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3761 /* Exception occurred */
3771 /* Fetch the immediate operand */
3772 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3774 /* Exception occurred */
3778 Multiplier
= (LONG
)Word
;
3784 LONG RegValue
, Multiplicand
;
3787 /* Read the operands */
3788 if (!Fast486ReadModrmDwordOperands(State
,
3791 (PULONG
)&Multiplicand
))
3793 /* Exception occurred */
3798 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3800 /* Check for carry/overflow */
3801 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3803 /* Write-back the result */
3804 return Fast486WriteModrmDwordOperands(State
,
3807 (ULONG
)((LONG
)Product
));
3811 SHORT RegValue
, Multiplicand
;
3814 /* Read the operands */
3815 if (!Fast486ReadModrmWordOperands(State
,
3818 (PUSHORT
)&Multiplicand
))
3820 /* Exception occurred */
3825 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3827 /* Check for carry/overflow */
3828 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3830 /* Write-back the result */
3831 return Fast486WriteModrmWordOperands(State
,
3834 (USHORT
)((SHORT
)Product
));
3838 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3842 /* Make sure this is the right instruction */
3843 ASSERT(Opcode
== 0x6A);
3845 if (!Fast486FetchByte(State
, (PUCHAR
)&Data
))
3847 /* Exception occurred */
3851 /* Call the internal API */
3852 return Fast486StackPush(State
, Data
);
3855 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3857 UCHAR FirstValue
, SecondValue
, Result
;
3858 FAST486_MOD_REG_RM ModRegRm
;
3859 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3861 /* Make sure this is the right instruction */
3862 ASSERT((Opcode
& 0xFD) == 0x88);
3864 TOGGLE_ADSIZE(AddressSize
);
3866 /* Get the operands */
3867 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3869 /* Exception occurred */
3873 if (!Fast486ReadModrmByteOperands(State
,
3878 /* Exception occurred */
3882 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3883 else Result
= FirstValue
;
3885 /* Write back the result */
3886 return Fast486WriteModrmByteOperands(State
,
3888 Opcode
& FAST486_OPCODE_WRITE_REG
,
3893 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3895 FAST486_MOD_REG_RM ModRegRm
;
3896 BOOLEAN OperandSize
, AddressSize
;
3898 /* Make sure this is the right instruction */
3899 ASSERT((Opcode
& 0xFD) == 0x89);
3901 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3903 TOGGLE_ADSIZE(AddressSize
);
3904 TOGGLE_OPSIZE(OperandSize
);
3906 /* Get the operands */
3907 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3909 /* Exception occurred */
3913 /* Check the operand size */
3916 ULONG FirstValue
, SecondValue
, Result
;
3918 if (!Fast486ReadModrmDwordOperands(State
,
3923 /* Exception occurred */
3927 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3928 else Result
= FirstValue
;
3930 /* Write back the result */
3931 return Fast486WriteModrmDwordOperands(State
,
3933 Opcode
& FAST486_OPCODE_WRITE_REG
,
3938 USHORT FirstValue
, SecondValue
, Result
;
3940 if (!Fast486ReadModrmWordOperands(State
,
3945 /* Exception occurred */
3949 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3950 else Result
= FirstValue
;
3952 /* Write back the result */
3953 return Fast486WriteModrmWordOperands(State
,
3955 Opcode
& FAST486_OPCODE_WRITE_REG
,
3960 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3962 BOOLEAN OperandSize
, AddressSize
;
3963 FAST486_MOD_REG_RM ModRegRm
;
3965 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3967 /* Make sure this is the right instruction */
3968 ASSERT(Opcode
== 0x8C);
3970 TOGGLE_ADSIZE(AddressSize
);
3971 TOGGLE_OPSIZE(OperandSize
);
3973 /* Get the operands */
3974 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3976 /* Exception occurred */
3980 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3983 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3989 return Fast486WriteModrmDwordOperands(State
,
3992 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3996 return Fast486WriteModrmWordOperands(State
,
3999 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4003 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
4005 FAST486_MOD_REG_RM ModRegRm
;
4006 BOOLEAN OperandSize
, AddressSize
;
4008 /* Make sure this is the right instruction */
4009 ASSERT(Opcode
== 0x8D);
4011 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4013 TOGGLE_ADSIZE(AddressSize
);
4014 TOGGLE_OPSIZE(OperandSize
);
4016 /* Get the operands */
4017 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4019 /* Exception occurred */
4023 /* The second operand must be memory */
4024 if (!ModRegRm
.Memory
)
4027 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4031 /* Write the address to the register */
4034 return Fast486WriteModrmDwordOperands(State
,
4037 ModRegRm
.MemoryAddress
);
4041 return Fast486WriteModrmWordOperands(State
,
4044 ModRegRm
.MemoryAddress
);
4049 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
4051 BOOLEAN OperandSize
, AddressSize
;
4052 FAST486_MOD_REG_RM ModRegRm
;
4054 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4056 /* Make sure this is the right instruction */
4057 ASSERT(Opcode
== 0x8E);
4059 TOGGLE_ADSIZE(AddressSize
);
4060 TOGGLE_OPSIZE(OperandSize
);
4062 /* Get the operands */
4063 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4065 /* Exception occurred */
4069 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4070 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
4073 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4081 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4083 /* Exception occurred */
4087 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4093 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4095 /* Exception occurred */
4099 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4103 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4105 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4107 /* Make sure this is the right instruction */
4108 ASSERT(Opcode
== 0x98);
4110 TOGGLE_OPSIZE(Size
);
4115 /* Sign extend AX to EAX */
4116 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4118 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4119 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4125 /* Sign extend AL to AX */
4126 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4127 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4134 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4136 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4138 /* Make sure this is the right instruction */
4139 ASSERT(Opcode
== 0x99);
4141 TOGGLE_OPSIZE(Size
);
4146 /* Sign extend EAX to EDX:EAX */
4147 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4148 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4149 ? 0xFFFFFFFF : 0x00000000;
4153 /* Sign extend AX to DX:AX */
4154 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4155 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4162 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4166 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4168 /* Make sure this is the right instruction */
4169 ASSERT(Opcode
== 0x9A);
4171 TOGGLE_OPSIZE(Size
);
4174 /* Fetch the offset */
4177 if (!Fast486FetchDword(State
, &Offset
))
4179 /* Exception occurred */
4185 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4187 /* Exception occurred */
4192 /* Fetch the segment */
4193 if (!Fast486FetchWord(State
, &Segment
))
4195 /* Exception occurred */
4199 /* Push the current code segment selector */
4200 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4202 /* Exception occurred */
4206 /* Push the current value of the instruction pointer */
4207 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4209 /* Exception occurred */
4213 /* Load the new CS */
4214 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4216 /* Exception occurred */
4220 /* Load new (E)IP */
4221 if (Size
) State
->InstPtr
.Long
= Offset
;
4222 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4227 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4229 // TODO: NOT IMPLEMENTED
4235 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4237 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4240 TOGGLE_OPSIZE(Size
);
4242 /* Check for VM86 mode when IOPL is not 3 */
4243 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4245 /* Call the VM86 monitor */
4246 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4250 /* Push the flags */
4251 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4252 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4255 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4257 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4258 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4259 FAST486_FLAGS_REG NewFlags
;
4262 TOGGLE_OPSIZE(Size
);
4264 /* Pop the new flags */
4265 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4267 /* Exception occurred */
4271 /* Check for VM86 mode when IOPL is not 3 */
4272 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4274 /* Call the VM86 monitor */
4275 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4279 State
->Flags
.Cf
= NewFlags
.Cf
;
4280 State
->Flags
.Pf
= NewFlags
.Pf
;
4281 State
->Flags
.Af
= NewFlags
.Af
;
4282 State
->Flags
.Zf
= NewFlags
.Zf
;
4283 State
->Flags
.Sf
= NewFlags
.Sf
;
4284 State
->Flags
.Tf
= NewFlags
.Tf
;
4285 State
->Flags
.Df
= NewFlags
.Df
;
4286 State
->Flags
.Of
= NewFlags
.Of
;
4287 State
->Flags
.Nt
= NewFlags
.Nt
;
4288 State
->Flags
.Ac
= NewFlags
.Ac
;
4290 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4291 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4296 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4298 /* Make sure this is the right instruction */
4299 ASSERT(Opcode
== 0x9E);
4301 /* Set the low-order byte of FLAGS to AH */
4302 State
->Flags
.Long
&= 0xFFFFFF00;
4303 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4305 /* Restore the reserved bits of FLAGS */
4306 State
->Flags
.AlwaysSet
= TRUE
;
4307 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4312 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4314 /* Make sure this is the right instruction */
4315 ASSERT(Opcode
== 0x9F);
4317 /* Set AH to the low-order byte of FLAGS */
4318 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4323 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4325 ULONG ReturnAddress
;
4326 USHORT BytesToPop
= 0;
4327 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4329 /* Make sure this is the right instruction */
4330 ASSERT((Opcode
& 0xFE) == 0xC2);
4333 TOGGLE_OPSIZE(Size
);
4337 /* Fetch the number of bytes to pop after the return */
4338 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4341 /* Pop the return address */
4342 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4344 /* Return to the calling procedure, and if necessary, pop the parameters */
4347 State
->InstPtr
.Long
= ReturnAddress
;
4348 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4352 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4353 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4359 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4361 UCHAR FarPointer
[6];
4362 BOOLEAN OperandSize
, AddressSize
;
4363 FAST486_MOD_REG_RM ModRegRm
;
4365 /* Make sure this is the right instruction */
4366 ASSERT((Opcode
& 0xFE) == 0xC4);
4368 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4370 TOGGLE_OPSIZE(OperandSize
);
4371 TOGGLE_ADSIZE(AddressSize
);
4373 /* Get the operands */
4374 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4376 /* Exception occurred */
4380 if (!ModRegRm
.Memory
)
4382 /* Check if this is a BOP and the host supports BOPs */
4383 if ((Opcode
== 0xC4)
4384 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4385 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4386 && (State
->BopCallback
!= NULL
))
4390 /* Fetch the BOP code */
4391 if (!Fast486FetchByte(State
, &BopCode
))
4393 /* Exception occurred */
4397 /* Call the BOP handler */
4398 State
->BopCallback(State
, BopCode
);
4401 * If an interrupt should occur at this time, delay it.
4402 * We must do this because if an interrupt begins and the BOP callback
4403 * changes the CS:IP, the interrupt handler won't execute and the
4404 * stack pointer will never be restored.
4406 if (State
->IntStatus
== FAST486_INT_EXECUTE
)
4408 State
->IntStatus
= FAST486_INT_DELAYED
;
4411 /* Return success */
4416 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4420 if (!Fast486ReadMemory(State
,
4421 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4422 ? State
->SegmentOverride
: FAST486_REG_DS
,
4423 ModRegRm
.MemoryAddress
,
4426 OperandSize
? 6 : 4))
4428 /* Exception occurred */
4434 ULONG Offset
= *((PULONG
)FarPointer
);
4435 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4437 /* Set the register to the offset */
4438 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4440 /* Load the segment */
4441 return Fast486LoadSegment(State
,
4443 ? FAST486_REG_ES
: FAST486_REG_DS
,
4448 USHORT Offset
= *((PUSHORT
)FarPointer
);
4449 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4451 /* Set the register to the offset */
4452 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4454 /* Load the segment */
4455 return Fast486LoadSegment(State
,
4457 ? FAST486_REG_ES
: FAST486_REG_DS
,
4462 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4465 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4468 FAST486_REG FramePointer
;
4470 /* Make sure this is the right instruction */
4471 ASSERT(Opcode
== 0xC8);
4474 TOGGLE_OPSIZE(Size
);
4476 if (!Fast486FetchWord(State
, &FrameSize
))
4478 /* Exception occurred */
4482 if (!Fast486FetchByte(State
, &NestingLevel
))
4484 /* Exception occurred */
4489 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4491 /* Exception occurred */
4496 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4498 /* Set up the nested procedure stacks */
4499 for (i
= 1; i
< NestingLevel
; i
++)
4503 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4504 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4508 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4509 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4513 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4515 /* Set EBP to the frame pointer */
4516 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4518 /* Reserve space for the frame */
4519 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4520 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4525 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4527 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4529 /* Make sure this is the right instruction */
4530 ASSERT(Opcode
== 0xC9);
4533 TOGGLE_OPSIZE(Size
);
4537 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4538 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4540 /* Pop the saved base pointer from the stack */
4541 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4547 /* Set the stack pointer (SP) to the base pointer (BP) */
4548 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4550 /* Pop the saved base pointer from the stack */
4551 if (Fast486StackPop(State
, &Value
))
4553 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4560 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4564 USHORT BytesToPop
= 0;
4565 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4567 /* Make sure this is the right instruction */
4568 ASSERT((Opcode
& 0xFE) == 0xCA);
4570 TOGGLE_OPSIZE(Size
);
4575 /* Fetch the number of bytes to pop after the return */
4576 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4579 /* Pop the offset */
4580 if (!Fast486StackPop(State
, &Offset
))
4582 /* Exception occurred */
4586 /* Pop the segment */
4587 if (!Fast486StackPop(State
, &Segment
))
4589 /* Exception occurred */
4593 /* Load the new CS */
4594 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4596 /* Exception occurred */
4600 /* Load new (E)IP, and if necessary, pop the parameters */
4603 State
->InstPtr
.Long
= Offset
;
4604 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4608 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4609 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4615 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4618 FAST486_IDT_ENTRY IdtEntry
;
4624 /* This is the INT3 instruction */
4631 /* Fetch the interrupt number */
4632 if (!Fast486FetchByte(State
, &IntNum
))
4634 /* Exception occurred */
4643 /* Don't do anything if OF is cleared */
4644 if (!State
->Flags
.Of
) return TRUE
;
4647 IntNum
= FAST486_EXCEPTION_OF
;
4654 /* Should not happen */
4659 /* Get the interrupt vector */
4660 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4662 /* Exception occurred */
4666 /* Perform the interrupt */
4667 if (!Fast486InterruptInternal(State
,
4669 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4672 /* Exception occurred */
4679 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4682 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4683 FAST486_FLAGS_REG NewFlags
;
4684 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4686 /* Make sure this is the right instruction */
4687 ASSERT(Opcode
== 0xCF);
4690 TOGGLE_OPSIZE(Size
);
4693 if (!Fast486StackPop(State
, &InstPtr
))
4695 /* Exception occurred */
4700 if (!Fast486StackPop(State
, &CodeSel
))
4702 /* Exception occurred */
4707 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4709 /* Exception occurred */
4713 /* Check for protected mode */
4714 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4716 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4718 if (State
->Flags
.Vm
)
4720 /* Return from VM86 mode */
4722 /* Check the IOPL */
4723 if (State
->Flags
.Iopl
== 3)
4726 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4729 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4731 /* Exception occurred */
4735 /* Set the new flags */
4736 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4737 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4738 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4739 State
->Flags
.Iopl
= 3;
4743 /* Call the VM86 monitor */
4744 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4751 if (State
->Flags
.Nt
)
4753 /* Nested task return */
4761 /* Return to VM86 mode */
4762 ULONG Es
, Ds
, Fs
, Gs
;
4764 /* Pop ESP, SS, ES, FS, GS */
4765 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4766 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4767 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4768 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4769 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4770 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4772 /* Set the new IP */
4773 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4775 /* Set the new flags */
4776 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4777 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4778 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4780 /* Load the new segments */
4781 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4782 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4783 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4784 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4785 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4786 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4791 /* Load the new CS */
4792 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4794 /* Exception occurred */
4799 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4800 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4802 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4805 if (!Fast486StackPop(State
, &StackPtr
))
4812 if (!Fast486StackPop(State
, &StackSel
))
4819 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4826 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4827 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4830 /* Set the new flags */
4831 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4832 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4833 State
->Flags
.AlwaysSet
= TRUE
;
4835 /* Set additional flags */
4836 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4837 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4839 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4841 /* Update the CPL */
4842 Cpl
= Fast486GetCurrentPrivLevel(State
);
4844 /* Check segment security */
4845 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4847 /* Don't check CS or SS */
4848 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4850 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4851 && (!State
->SegmentRegs
[i
].Executable
4852 || !State
->SegmentRegs
[i
].DirConf
))
4854 /* Load the NULL descriptor in the segment */
4855 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4862 if (Size
&& (InstPtr
& 0xFFFF0000))
4865 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4870 State
->InstPtr
.Long
= InstPtr
;
4873 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4875 /* Exception occurred */
4879 /* Set the new flags */
4880 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4881 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4882 State
->Flags
.AlwaysSet
= TRUE
;
4888 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4891 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4895 /* Fetch the base */
4896 if (!Fast486FetchByte(State
, &Base
))
4898 /* Exception occurred */
4902 /* Check if the base is zero */
4906 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4911 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4912 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4915 State
->Flags
.Af
= FALSE
;
4916 State
->Flags
.Zf
= (Value
== 0);
4917 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4918 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4923 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4926 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4930 /* Fetch the base */
4931 if (!Fast486FetchByte(State
, &Base
))
4933 /* Exception occurred */
4938 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4939 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4942 State
->Flags
.Af
= FALSE
;
4943 State
->Flags
.Zf
= (Value
== 0);
4944 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4945 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4950 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4953 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4955 TOGGLE_ADSIZE(AddressSize
);
4957 /* Read a byte from DS:[(E)BX + AL] */
4958 if (!Fast486ReadMemory(State
,
4960 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4961 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4962 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4967 /* Exception occurred */
4971 /* Set AL to the result */
4972 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4974 /* Return success */
4978 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4981 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4984 /* Make sure this is the right instruction */
4985 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4988 TOGGLE_ADSIZE(Size
);
4990 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4991 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4995 /* Additional rule for LOOPNZ */
4996 if (State
->Flags
.Zf
) Condition
= FALSE
;
5001 /* Additional rule for LOOPZ */
5002 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5005 /* Fetch the offset */
5006 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5008 /* An exception occurred */
5014 /* Move the instruction pointer */
5015 if (Size
) State
->InstPtr
.Long
+= Offset
;
5016 else State
->InstPtr
.LowWord
+= Offset
;
5022 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5025 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5028 /* Make sure this is the right instruction */
5029 ASSERT(Opcode
== 0xE3);
5032 TOGGLE_ADSIZE(Size
);
5034 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5035 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5037 /* Fetch the offset */
5038 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5040 /* An exception occurred */
5046 /* Move the instruction pointer */
5047 if (Size
) State
->InstPtr
.Long
+= Offset
;
5048 else State
->InstPtr
.LowWord
+= Offset
;
5054 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5056 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5058 /* Make sure this is the right instruction */
5059 ASSERT(Opcode
== 0xE8);
5061 TOGGLE_OPSIZE(Size
);
5068 /* Fetch the offset */
5069 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5071 /* An exception occurred */
5075 /* Push the current value of the instruction pointer */
5076 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5078 /* Exception occurred */
5082 /* Move the instruction pointer */
5083 State
->InstPtr
.Long
+= Offset
;
5089 /* Fetch the offset */
5090 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5092 /* An exception occurred */
5096 /* Push the current value of the instruction pointer */
5097 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5099 /* Exception occurred */
5103 /* Move the instruction pointer */
5104 State
->InstPtr
.LowWord
+= Offset
;
5110 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5112 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5114 /* Make sure this is the right instruction */
5115 ASSERT(Opcode
== 0xE9);
5117 TOGGLE_OPSIZE(Size
);
5124 /* Fetch the offset */
5125 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5127 /* An exception occurred */
5131 /* Move the instruction pointer */
5132 State
->InstPtr
.Long
+= Offset
;
5138 /* Fetch the offset */
5139 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5141 /* An exception occurred */
5145 /* Move the instruction pointer */
5146 State
->InstPtr
.Long
+= Offset
;
5148 /* Clear the top half of EIP */
5149 State
->InstPtr
.Long
&= 0xFFFF;
5155 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5159 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5161 /* Make sure this is the right instruction */
5162 ASSERT(Opcode
== 0xEA);
5164 TOGGLE_OPSIZE(Size
);
5167 /* Fetch the offset */
5170 if (!Fast486FetchDword(State
, &Offset
))
5172 /* Exception occurred */
5178 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5180 /* Exception occurred */
5185 /* Fetch the segment */
5186 if (!Fast486FetchWord(State
, &Segment
))
5188 /* Exception occurred */
5192 /* Load the new CS */
5193 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5195 /* Exception occurred */
5200 State
->InstPtr
.Long
= Offset
;
5205 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5207 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5210 /* Make sure this is the right instruction */
5211 ASSERT(Opcode
== 0xA0);
5213 TOGGLE_ADSIZE(AddressSize
);
5217 if (!Fast486FetchDword(State
, &Offset
))
5219 /* Exception occurred */
5227 if (!Fast486FetchWord(State
, &WordOffset
))
5229 /* Exception occurred */
5233 Offset
= (ULONG
)WordOffset
;
5236 /* Read from memory */
5237 return Fast486ReadMemory(State
,
5238 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5239 State
->SegmentOverride
: FAST486_REG_DS
,
5242 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5246 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5248 BOOLEAN OperandSize
, AddressSize
;
5250 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5252 /* Make sure this is the right instruction */
5253 ASSERT(Opcode
== 0xA1);
5255 TOGGLE_OPSIZE(OperandSize
);
5256 TOGGLE_ADSIZE(AddressSize
);
5262 if (!Fast486FetchDword(State
, &Offset
))
5264 /* Exception occurred */
5268 /* Read from memory */
5271 return Fast486ReadMemory(State
,
5272 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5273 State
->SegmentOverride
: FAST486_REG_DS
,
5276 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5281 return Fast486ReadMemory(State
,
5282 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5283 State
->SegmentOverride
: FAST486_REG_DS
,
5286 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5294 if (!Fast486FetchWord(State
, &Offset
))
5296 /* Exception occurred */
5300 /* Read from memory */
5303 return Fast486ReadMemory(State
,
5304 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5305 State
->SegmentOverride
: FAST486_REG_DS
,
5308 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5313 return Fast486ReadMemory(State
,
5314 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5315 State
->SegmentOverride
: FAST486_REG_DS
,
5318 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5324 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5326 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5329 /* Make sure this is the right instruction */
5330 ASSERT(Opcode
== 0xA2);
5332 TOGGLE_ADSIZE(AddressSize
);
5336 if (!Fast486FetchDword(State
, &Offset
))
5338 /* Exception occurred */
5346 if (!Fast486FetchWord(State
, &WordOffset
))
5348 /* Exception occurred */
5352 Offset
= (ULONG
)WordOffset
;
5355 /* Write to memory */
5356 return Fast486WriteMemory(State
,
5357 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5358 State
->SegmentOverride
: FAST486_REG_DS
,
5360 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5364 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5366 BOOLEAN OperandSize
, AddressSize
;
5368 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5370 /* Make sure this is the right instruction */
5371 ASSERT(Opcode
== 0xA3);
5373 TOGGLE_OPSIZE(OperandSize
);
5374 TOGGLE_ADSIZE(AddressSize
);
5380 if (!Fast486FetchDword(State
, &Offset
))
5382 /* Exception occurred */
5386 /* Write to memory */
5389 return Fast486WriteMemory(State
,
5390 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5391 State
->SegmentOverride
: FAST486_REG_DS
,
5393 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5398 return Fast486WriteMemory(State
,
5399 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5400 State
->SegmentOverride
: FAST486_REG_DS
,
5402 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5410 if (!Fast486FetchWord(State
, &Offset
))
5412 /* Exception occurred */
5416 /* Write to memory */
5419 return Fast486WriteMemory(State
,
5420 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5421 State
->SegmentOverride
: FAST486_REG_DS
,
5423 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5428 return Fast486WriteMemory(State
,
5429 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5430 State
->SegmentOverride
: FAST486_REG_DS
,
5432 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5438 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5440 /* Make sure this is the right instruction */
5441 ASSERT(Opcode
== 0xD6);
5445 /* Set all the bits of AL to CF */
5446 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5451 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5453 ULONG Data
, DataSize
;
5454 BOOLEAN OperandSize
, AddressSize
;
5455 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5457 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5459 /* Make sure this is the right instruction */
5460 ASSERT((Opcode
& 0xFE) == 0xA4);
5462 TOGGLE_OPSIZE(OperandSize
);
5463 TOGGLE_ADSIZE(AddressSize
);
5465 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5467 /* Use the override segment instead of DS */
5468 Segment
= State
->SegmentOverride
;
5471 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5473 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5474 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5481 /* Calculate the size */
5482 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5483 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5485 /* Read from the source operand */
5486 if (!Fast486ReadMemory(State
,
5488 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5489 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5494 /* Exception occurred */
5498 /* Write to the destination operand */
5499 if (!Fast486WriteMemory(State
,
5501 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5502 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5506 /* Exception occurred */
5510 /* Increment/decrement ESI and EDI */
5513 if (!State
->Flags
.Df
)
5515 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5516 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5520 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5521 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5526 if (!State
->Flags
.Df
)
5528 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5529 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5533 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5534 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5538 // FIXME: This method is slow!
5539 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5543 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5545 /* Repeat the instruction */
5546 State
->InstPtr
= State
->SavedInstPtr
;
5551 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5553 /* Repeat the instruction */
5554 State
->InstPtr
= State
->SavedInstPtr
;
5559 /* Return success */
5563 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5565 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5566 ULONG DataSize
, DataMask
, SignFlag
;
5567 BOOLEAN OperandSize
, AddressSize
;
5568 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5570 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5572 /* Make sure this is the right instruction */
5573 ASSERT((Opcode
& 0xFE) == 0xA6);
5575 TOGGLE_OPSIZE(OperandSize
);
5576 TOGGLE_ADSIZE(AddressSize
);
5578 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5580 /* Use the override segment instead of DS */
5581 Segment
= State
->SegmentOverride
;
5584 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5585 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5587 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5588 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5595 /* Calculate the size */
5596 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5597 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5599 /* Calculate the mask and sign flag */
5600 SignFlag
= 1 << ((DataSize
* 8) - 1);
5601 DataMask
= SignFlag
| (SignFlag
- 1);
5603 /* Read from the first source operand */
5604 if (!Fast486ReadMemory(State
,
5606 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5607 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5612 /* Exception occurred */
5616 /* Read from the second source operand */
5617 if (!Fast486ReadMemory(State
,
5619 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5620 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5625 /* Exception occurred */
5629 /* Calculate the result */
5630 FirstValue
&= DataMask
;
5631 SecondValue
&= DataMask
;
5632 Result
= (FirstValue
- SecondValue
) & DataMask
;
5634 /* Update the flags */
5635 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5636 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5637 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5638 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5639 State
->Flags
.Zf
= (Result
== 0);
5640 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5641 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5643 /* Increment/decrement ESI and EDI */
5646 if (!State
->Flags
.Df
)
5648 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5649 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5653 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5654 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5659 if (!State
->Flags
.Df
)
5661 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5662 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5666 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5667 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5671 // FIXME: This method is slow!
5672 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5673 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5675 BOOLEAN Repeat
= TRUE
;
5679 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5687 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5694 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5695 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5697 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5703 /* Repeat the instruction */
5704 State
->InstPtr
= State
->SavedInstPtr
;
5708 /* Return success */
5712 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5715 BOOLEAN OperandSize
, AddressSize
;
5717 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5719 /* Make sure this is the right instruction */
5720 ASSERT((Opcode
& 0xFE) == 0xAA);
5722 TOGGLE_OPSIZE(OperandSize
);
5723 TOGGLE_ADSIZE(AddressSize
);
5725 /* Calculate the size */
5726 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5727 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5729 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5731 UCHAR Block
[STRING_BLOCK_SIZE
];
5732 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5733 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5735 /* Fill the memory block with the data */
5736 if (DataSize
== sizeof(UCHAR
))
5738 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5744 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5746 if (DataSize
== sizeof(USHORT
))
5748 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5752 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5757 /* Transfer until finished */
5760 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5762 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5765 ULONG MaxBytes
= State
->Flags
.Df
5766 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5767 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5769 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5770 if (Processed
== 0) Processed
= 1;
5773 if (State
->Flags
.Df
)
5775 /* Set EDI to the starting location */
5776 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5777 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5780 /* Write to memory */
5781 if (!Fast486WriteMemory(State
,
5783 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5784 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5786 Processed
* DataSize
))
5789 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5790 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5792 /* Exception occurred */
5796 if (!State
->Flags
.Df
)
5798 /* Increase EDI by the number of bytes transfered */
5799 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5800 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5805 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5806 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5809 /* Reduce the total count by the number processed in this run */
5814 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5815 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5819 /* Write to the destination operand */
5820 if (!Fast486WriteMemory(State
,
5822 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5823 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5824 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5827 /* Exception occurred */
5831 /* Increment/decrement EDI */
5834 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5835 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5839 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5840 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5844 /* Return success */
5848 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5851 BOOLEAN OperandSize
, AddressSize
;
5852 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5854 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5856 /* Make sure this is the right instruction */
5857 ASSERT((Opcode
& 0xFE) == 0xAC);
5859 TOGGLE_OPSIZE(OperandSize
);
5860 TOGGLE_ADSIZE(AddressSize
);
5862 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5864 /* Use the override segment instead of DS */
5865 Segment
= State
->SegmentOverride
;
5868 /* Calculate the size */
5869 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5870 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5872 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5874 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5875 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5877 /* If the count is 0, do nothing */
5878 if (Count
== 0) return TRUE
;
5880 /* Only the last entry will be loaded */
5881 if (!State
->Flags
.Df
)
5883 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5884 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5888 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5889 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5893 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5894 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5897 /* Read from the source operand */
5898 if (!Fast486ReadMemory(State
,
5900 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5901 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5903 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5906 /* Exception occurred */
5910 /* Increment/decrement ESI */
5913 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5914 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5918 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5919 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5922 /* Return success */
5926 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5928 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5929 ULONG SecondValue
= 0;
5931 ULONG DataSize
, DataMask
, SignFlag
;
5932 BOOLEAN OperandSize
, AddressSize
;
5934 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5936 /* Make sure this is the right instruction */
5937 ASSERT((Opcode
& 0xFE) == 0xAE);
5939 TOGGLE_OPSIZE(OperandSize
);
5940 TOGGLE_ADSIZE(AddressSize
);
5942 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5943 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5945 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5946 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5953 /* Calculate the size */
5954 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5955 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5957 /* Calculate the mask and sign flag */
5958 SignFlag
= 1 << ((DataSize
* 8) - 1);
5959 DataMask
= SignFlag
| (SignFlag
- 1);
5961 /* Read from the source operand */
5962 if (!Fast486ReadMemory(State
,
5964 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5965 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5970 /* Exception occurred */
5974 /* Calculate the result */
5975 FirstValue
&= DataMask
;
5976 SecondValue
&= DataMask
;
5977 Result
= (FirstValue
- SecondValue
) & DataMask
;
5979 /* Update the flags */
5980 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5981 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5982 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5983 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5984 State
->Flags
.Zf
= (Result
== 0);
5985 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5986 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5988 /* Increment/decrement EDI */
5991 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5992 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5996 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5997 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6000 // FIXME: This method is slow!
6001 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
6002 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
6004 BOOLEAN Repeat
= TRUE
;
6008 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6016 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6023 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6024 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6026 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6032 /* Repeat the instruction */
6033 State
->InstPtr
= State
->SavedInstPtr
;
6037 /* Return success */
6041 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6044 BOOLEAN OperandSize
, AddressSize
;
6046 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6048 /* Make sure this is the right instruction */
6049 ASSERT((Opcode
& 0xFE) == 0x6C);
6051 TOGGLE_OPSIZE(OperandSize
);
6052 TOGGLE_ADSIZE(AddressSize
);
6054 /* Calculate the size */
6055 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6056 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6058 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6060 UCHAR Block
[STRING_BLOCK_SIZE
];
6061 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6062 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6064 /* Clear the memory block */
6065 RtlZeroMemory(Block
, sizeof(Block
));
6067 /* Transfer until finished */
6070 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6072 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6075 ULONG MaxBytes
= State
->Flags
.Df
6076 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6077 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6079 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6080 if (Processed
== 0) Processed
= 1;
6083 /* Read from the I/O port */
6084 State
->IoReadCallback(State
,
6085 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6090 if (State
->Flags
.Df
)
6094 /* Reduce EDI by the number of bytes to transfer */
6095 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6096 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6098 /* Reverse the block data */
6099 for (i
= 0; i
< Processed
/ 2; i
++)
6101 /* Swap the values */
6102 for (j
= 0; j
< DataSize
; j
++)
6104 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6105 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6106 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6111 /* Write to memory */
6112 if (!Fast486WriteMemory(State
,
6114 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6115 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6117 Processed
* DataSize
))
6120 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6121 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6123 /* Exception occurred */
6127 if (!State
->Flags
.Df
)
6129 /* Increase EDI by the number of bytes transfered */
6130 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6131 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6134 /* Reduce the total count by the number processed in this run */
6139 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6140 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6146 /* Read from the I/O port */
6147 State
->IoReadCallback(State
,
6148 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6153 /* Write to the destination operand */
6154 if (!Fast486WriteMemory(State
,
6156 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6157 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6161 /* Exception occurred */
6165 /* Increment/decrement EDI */
6168 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6169 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6173 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6174 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6178 /* Return success */
6182 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6185 BOOLEAN OperandSize
, AddressSize
;
6187 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6189 /* Make sure this is the right instruction */
6190 ASSERT((Opcode
& 0xFE) == 0x6E);
6192 TOGGLE_OPSIZE(OperandSize
);
6193 TOGGLE_ADSIZE(AddressSize
);
6195 /* Calculate the size */
6196 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6197 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6199 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6201 UCHAR Block
[STRING_BLOCK_SIZE
];
6202 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6203 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6205 /* Clear the memory block */
6206 RtlZeroMemory(Block
, sizeof(Block
));
6208 /* Transfer until finished */
6211 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6213 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6216 ULONG MaxBytes
= State
->Flags
.Df
6217 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6218 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6220 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6221 if (Processed
== 0) Processed
= 1;
6224 /* Read from memory */
6225 if (!Fast486ReadMemory(State
,
6227 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6228 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6231 Processed
* DataSize
))
6234 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6235 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6237 /* Exception occurred */
6241 if (State
->Flags
.Df
)
6245 /* Reduce EDI by the number of bytes to transfer */
6246 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6247 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6249 /* Reverse the block data */
6250 for (i
= 0; i
< Processed
/ 2; i
++)
6252 /* Swap the values */
6253 for (j
= 0; j
< DataSize
; j
++)
6255 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6256 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6257 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6262 /* Write to the I/O port */
6263 State
->IoWriteCallback(State
,
6264 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6269 if (!State
->Flags
.Df
)
6271 /* Increase EDI by the number of bytes transfered */
6272 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6273 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6276 /* Reduce the total count by the number processed in this run */
6281 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6282 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6288 /* Read from the source operand */
6289 if (!Fast486ReadMemory(State
,
6291 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6292 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6297 /* Exception occurred */
6301 /* Write to the I/O port */
6302 State
->IoWriteCallback(State
,
6303 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6308 /* Increment/decrement ESI */
6311 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6312 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6316 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6317 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6321 /* Return success */