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
, &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
, &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 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4273 /* Call the VM86 monitor */
4274 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4278 State
->Flags
.Cf
= NewFlags
.Cf
;
4279 State
->Flags
.Pf
= NewFlags
.Pf
;
4280 State
->Flags
.Af
= NewFlags
.Af
;
4281 State
->Flags
.Zf
= NewFlags
.Zf
;
4282 State
->Flags
.Sf
= NewFlags
.Sf
;
4283 State
->Flags
.Tf
= NewFlags
.Tf
;
4284 State
->Flags
.Df
= NewFlags
.Df
;
4285 State
->Flags
.Of
= NewFlags
.Of
;
4286 State
->Flags
.Nt
= NewFlags
.Nt
;
4287 State
->Flags
.Ac
= NewFlags
.Ac
;
4289 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4290 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4295 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4297 /* Make sure this is the right instruction */
4298 ASSERT(Opcode
== 0x9E);
4300 /* Set the low-order byte of FLAGS to AH */
4301 State
->Flags
.Long
&= 0xFFFFFF00;
4302 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4304 /* Restore the reserved bits of FLAGS */
4305 State
->Flags
.AlwaysSet
= TRUE
;
4306 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4311 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4313 /* Make sure this is the right instruction */
4314 ASSERT(Opcode
== 0x9F);
4316 /* Set AH to the low-order byte of FLAGS */
4317 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4322 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4324 ULONG ReturnAddress
;
4325 USHORT BytesToPop
= 0;
4326 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4328 /* Make sure this is the right instruction */
4329 ASSERT((Opcode
& 0xFE) == 0xC2);
4332 TOGGLE_OPSIZE(Size
);
4336 /* Fetch the number of bytes to pop after the return */
4337 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4340 /* Pop the return address */
4341 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4343 /* Return to the calling procedure, and if necessary, pop the parameters */
4346 State
->InstPtr
.Long
= ReturnAddress
;
4347 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4351 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4352 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4358 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4360 UCHAR FarPointer
[6];
4361 BOOLEAN OperandSize
, AddressSize
;
4362 FAST486_MOD_REG_RM ModRegRm
;
4364 /* Make sure this is the right instruction */
4365 ASSERT((Opcode
& 0xFE) == 0xC4);
4367 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4369 TOGGLE_OPSIZE(OperandSize
);
4370 TOGGLE_ADSIZE(AddressSize
);
4372 /* Get the operands */
4373 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4375 /* Exception occurred */
4379 if (!ModRegRm
.Memory
)
4381 /* Check if this is a BOP and the host supports BOPs */
4382 if ((Opcode
== 0xC4)
4383 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4384 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4385 && (State
->BopCallback
!= NULL
))
4389 /* Fetch the BOP code */
4390 if (!Fast486FetchByte(State
, &BopCode
))
4392 /* Exception occurred */
4396 /* Call the BOP handler */
4397 State
->BopCallback(State
, BopCode
);
4399 /* Return success */
4404 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4408 if (!Fast486ReadMemory(State
,
4409 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4410 ? State
->SegmentOverride
: FAST486_REG_DS
,
4411 ModRegRm
.MemoryAddress
,
4414 OperandSize
? 6 : 4))
4416 /* Exception occurred */
4422 ULONG Offset
= *((PULONG
)FarPointer
);
4423 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4425 /* Set the register to the offset */
4426 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4428 /* Load the segment */
4429 return Fast486LoadSegment(State
,
4431 ? FAST486_REG_ES
: FAST486_REG_DS
,
4436 USHORT Offset
= *((PUSHORT
)FarPointer
);
4437 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4439 /* Set the register to the offset */
4440 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4442 /* Load the segment */
4443 return Fast486LoadSegment(State
,
4445 ? FAST486_REG_ES
: FAST486_REG_DS
,
4450 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4453 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4456 FAST486_REG FramePointer
;
4458 /* Make sure this is the right instruction */
4459 ASSERT(Opcode
== 0xC8);
4462 TOGGLE_OPSIZE(Size
);
4464 if (!Fast486FetchWord(State
, &FrameSize
))
4466 /* Exception occurred */
4470 if (!Fast486FetchByte(State
, &NestingLevel
))
4472 /* Exception occurred */
4477 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4479 /* Exception occurred */
4484 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4486 /* Set up the nested procedure stacks */
4487 for (i
= 1; i
< NestingLevel
; i
++)
4491 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4492 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4496 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4497 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4501 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4503 /* Set EBP to the frame pointer */
4504 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4506 /* Reserve space for the frame */
4507 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4508 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4513 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4515 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4517 /* Make sure this is the right instruction */
4518 ASSERT(Opcode
== 0xC9);
4521 TOGGLE_OPSIZE(Size
);
4525 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4526 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4528 /* Pop the saved base pointer from the stack */
4529 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4535 /* Set the stack pointer (SP) to the base pointer (BP) */
4536 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4538 /* Pop the saved base pointer from the stack */
4539 if (Fast486StackPop(State
, &Value
))
4541 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4548 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4552 USHORT BytesToPop
= 0;
4553 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4555 /* Make sure this is the right instruction */
4556 ASSERT((Opcode
& 0xFE) == 0xCA);
4558 TOGGLE_OPSIZE(Size
);
4563 /* Fetch the number of bytes to pop after the return */
4564 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4567 /* Pop the offset */
4568 if (!Fast486StackPop(State
, &Offset
))
4570 /* Exception occurred */
4574 /* Pop the segment */
4575 if (!Fast486StackPop(State
, &Segment
))
4577 /* Exception occurred */
4581 /* Load the new CS */
4582 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4584 /* Exception occurred */
4588 /* Load new (E)IP, and if necessary, pop the parameters */
4591 State
->InstPtr
.Long
= Offset
;
4592 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4596 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4597 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4603 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4606 FAST486_IDT_ENTRY IdtEntry
;
4612 /* This is the INT3 instruction */
4619 /* Fetch the interrupt number */
4620 if (!Fast486FetchByte(State
, &IntNum
))
4622 /* Exception occurred */
4631 /* Don't do anything if OF is cleared */
4632 if (!State
->Flags
.Of
) return TRUE
;
4635 IntNum
= FAST486_EXCEPTION_OF
;
4642 /* Should not happen */
4647 /* Get the interrupt vector */
4648 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4650 /* Exception occurred */
4654 /* Perform the interrupt */
4655 if (!Fast486InterruptInternal(State
,
4657 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4660 /* Exception occurred */
4667 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4670 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4671 FAST486_FLAGS_REG NewFlags
;
4672 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4674 /* Make sure this is the right instruction */
4675 ASSERT(Opcode
== 0xCF);
4678 TOGGLE_OPSIZE(Size
);
4681 if (!Fast486StackPop(State
, &InstPtr
))
4683 /* Exception occurred */
4688 if (!Fast486StackPop(State
, &CodeSel
))
4690 /* Exception occurred */
4695 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4697 /* Exception occurred */
4701 /* Check for protected mode */
4702 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4704 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4706 if (State
->Flags
.Vm
)
4708 /* Return from VM86 mode */
4710 /* Check the IOPL */
4711 if (State
->Flags
.Iopl
== 3)
4714 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4717 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4719 /* Exception occurred */
4723 /* Set the new flags */
4724 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4725 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4726 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4727 State
->Flags
.Iopl
= 3;
4731 /* Call the VM86 monitor */
4732 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4739 if (State
->Flags
.Nt
)
4741 /* Nested task return */
4749 /* Return to VM86 mode */
4750 ULONG Es
, Ds
, Fs
, Gs
;
4752 /* Pop ESP, SS, ES, FS, GS */
4753 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4754 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4755 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4756 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4757 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4758 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4760 /* Set the new IP */
4761 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4763 /* Set the new flags */
4764 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4765 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4766 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4768 /* Load the new segments */
4769 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4770 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4771 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4772 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4773 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4774 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4779 /* Load the new CS */
4780 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4782 /* Exception occurred */
4787 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4788 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4790 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4793 if (!Fast486StackPop(State
, &StackPtr
))
4800 if (!Fast486StackPop(State
, &StackSel
))
4807 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4814 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4815 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4818 /* Set the new flags */
4819 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4820 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4821 State
->Flags
.AlwaysSet
= TRUE
;
4823 /* Set additional flags */
4824 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4825 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4827 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4829 /* Update the CPL */
4830 Cpl
= Fast486GetCurrentPrivLevel(State
);
4832 /* Check segment security */
4833 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4835 /* Don't check CS or SS */
4836 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4838 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4839 && (!State
->SegmentRegs
[i
].Executable
4840 || !State
->SegmentRegs
[i
].DirConf
))
4842 /* Load the NULL descriptor in the segment */
4843 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4850 if (Size
&& (InstPtr
& 0xFFFF0000))
4853 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4858 State
->InstPtr
.Long
= InstPtr
;
4861 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4863 /* Exception occurred */
4867 /* Set the new flags */
4868 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4869 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4870 State
->Flags
.AlwaysSet
= TRUE
;
4876 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4879 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4883 /* Fetch the base */
4884 if (!Fast486FetchByte(State
, &Base
))
4886 /* Exception occurred */
4890 /* Check if the base is zero */
4894 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4899 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4900 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4903 State
->Flags
.Af
= FALSE
;
4904 State
->Flags
.Zf
= (Value
== 0);
4905 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4906 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4911 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4914 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4918 /* Fetch the base */
4919 if (!Fast486FetchByte(State
, &Base
))
4921 /* Exception occurred */
4926 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4927 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4930 State
->Flags
.Af
= FALSE
;
4931 State
->Flags
.Zf
= (Value
== 0);
4932 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4933 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4938 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4941 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4943 TOGGLE_ADSIZE(AddressSize
);
4945 /* Read a byte from DS:[(E)BX + AL] */
4946 if (!Fast486ReadMemory(State
,
4948 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4949 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4950 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4955 /* Exception occurred */
4959 /* Set AL to the result */
4960 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4962 /* Return success */
4966 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4969 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4972 /* Make sure this is the right instruction */
4973 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4976 TOGGLE_ADSIZE(Size
);
4978 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4979 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4983 /* Additional rule for LOOPNZ */
4984 if (State
->Flags
.Zf
) Condition
= FALSE
;
4989 /* Additional rule for LOOPZ */
4990 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4993 /* Fetch the offset */
4994 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4996 /* An exception occurred */
5002 /* Move the instruction pointer */
5003 if (Size
) State
->InstPtr
.Long
+= Offset
;
5004 else State
->InstPtr
.LowWord
+= Offset
;
5010 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5013 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5016 /* Make sure this is the right instruction */
5017 ASSERT(Opcode
== 0xE3);
5020 TOGGLE_ADSIZE(Size
);
5022 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5023 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5025 /* Fetch the offset */
5026 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5028 /* An exception occurred */
5034 /* Move the instruction pointer */
5035 if (Size
) State
->InstPtr
.Long
+= Offset
;
5036 else State
->InstPtr
.LowWord
+= Offset
;
5042 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5044 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5046 /* Make sure this is the right instruction */
5047 ASSERT(Opcode
== 0xE8);
5049 TOGGLE_OPSIZE(Size
);
5056 /* Fetch the offset */
5057 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5059 /* An exception occurred */
5063 /* Push the current value of the instruction pointer */
5064 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5066 /* Exception occurred */
5070 /* Move the instruction pointer */
5071 State
->InstPtr
.Long
+= Offset
;
5077 /* Fetch the offset */
5078 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5080 /* An exception occurred */
5084 /* Push the current value of the instruction pointer */
5085 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5087 /* Exception occurred */
5091 /* Move the instruction pointer */
5092 State
->InstPtr
.LowWord
+= Offset
;
5098 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5100 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5102 /* Make sure this is the right instruction */
5103 ASSERT(Opcode
== 0xE9);
5105 TOGGLE_OPSIZE(Size
);
5112 /* Fetch the offset */
5113 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5115 /* An exception occurred */
5119 /* Move the instruction pointer */
5120 State
->InstPtr
.Long
+= Offset
;
5126 /* Fetch the offset */
5127 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5129 /* An exception occurred */
5133 /* Move the instruction pointer */
5134 State
->InstPtr
.Long
+= Offset
;
5136 /* Clear the top half of EIP */
5137 State
->InstPtr
.Long
&= 0xFFFF;
5143 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5147 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5149 /* Make sure this is the right instruction */
5150 ASSERT(Opcode
== 0xEA);
5152 TOGGLE_OPSIZE(Size
);
5155 /* Fetch the offset */
5158 if (!Fast486FetchDword(State
, &Offset
))
5160 /* Exception occurred */
5166 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5168 /* Exception occurred */
5173 /* Fetch the segment */
5174 if (!Fast486FetchWord(State
, &Segment
))
5176 /* Exception occurred */
5180 /* Load the new CS */
5181 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5183 /* Exception occurred */
5188 State
->InstPtr
.Long
= Offset
;
5193 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5195 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5198 /* Make sure this is the right instruction */
5199 ASSERT(Opcode
== 0xA0);
5201 TOGGLE_ADSIZE(AddressSize
);
5205 if (!Fast486FetchDword(State
, &Offset
))
5207 /* Exception occurred */
5215 if (!Fast486FetchWord(State
, &WordOffset
))
5217 /* Exception occurred */
5221 Offset
= (ULONG
)WordOffset
;
5224 /* Read from memory */
5225 return Fast486ReadMemory(State
,
5226 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5227 State
->SegmentOverride
: FAST486_REG_DS
,
5230 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5234 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5236 BOOLEAN OperandSize
, AddressSize
;
5238 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5240 /* Make sure this is the right instruction */
5241 ASSERT(Opcode
== 0xA1);
5243 TOGGLE_OPSIZE(OperandSize
);
5244 TOGGLE_ADSIZE(AddressSize
);
5250 if (!Fast486FetchDword(State
, &Offset
))
5252 /* Exception occurred */
5256 /* Read from memory */
5259 return Fast486ReadMemory(State
,
5260 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5261 State
->SegmentOverride
: FAST486_REG_DS
,
5264 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5269 return Fast486ReadMemory(State
,
5270 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5271 State
->SegmentOverride
: FAST486_REG_DS
,
5274 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5282 if (!Fast486FetchWord(State
, &Offset
))
5284 /* Exception occurred */
5288 /* Read from memory */
5291 return Fast486ReadMemory(State
,
5292 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5293 State
->SegmentOverride
: FAST486_REG_DS
,
5296 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5301 return Fast486ReadMemory(State
,
5302 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5303 State
->SegmentOverride
: FAST486_REG_DS
,
5306 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5312 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5314 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5317 /* Make sure this is the right instruction */
5318 ASSERT(Opcode
== 0xA2);
5320 TOGGLE_ADSIZE(AddressSize
);
5324 if (!Fast486FetchDword(State
, &Offset
))
5326 /* Exception occurred */
5334 if (!Fast486FetchWord(State
, &WordOffset
))
5336 /* Exception occurred */
5340 Offset
= (ULONG
)WordOffset
;
5343 /* Write to memory */
5344 return Fast486WriteMemory(State
,
5345 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5346 State
->SegmentOverride
: FAST486_REG_DS
,
5348 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5352 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5354 BOOLEAN OperandSize
, AddressSize
;
5356 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5358 /* Make sure this is the right instruction */
5359 ASSERT(Opcode
== 0xA3);
5361 TOGGLE_OPSIZE(OperandSize
);
5362 TOGGLE_ADSIZE(AddressSize
);
5368 if (!Fast486FetchDword(State
, &Offset
))
5370 /* Exception occurred */
5374 /* Write to memory */
5377 return Fast486WriteMemory(State
,
5378 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5379 State
->SegmentOverride
: FAST486_REG_DS
,
5381 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5386 return Fast486WriteMemory(State
,
5387 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5388 State
->SegmentOverride
: FAST486_REG_DS
,
5390 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5398 if (!Fast486FetchWord(State
, &Offset
))
5400 /* Exception occurred */
5404 /* Write to memory */
5407 return Fast486WriteMemory(State
,
5408 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5409 State
->SegmentOverride
: FAST486_REG_DS
,
5411 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5416 return Fast486WriteMemory(State
,
5417 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5418 State
->SegmentOverride
: FAST486_REG_DS
,
5420 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5426 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5428 /* Make sure this is the right instruction */
5429 ASSERT(Opcode
== 0xD6);
5433 /* Set all the bits of AL to CF */
5434 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5439 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5441 ULONG Data
, DataSize
;
5442 BOOLEAN OperandSize
, AddressSize
;
5443 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5445 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5447 /* Make sure this is the right instruction */
5448 ASSERT((Opcode
& 0xFE) == 0xA4);
5450 TOGGLE_OPSIZE(OperandSize
);
5451 TOGGLE_ADSIZE(AddressSize
);
5453 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5455 /* Use the override segment instead of DS */
5456 Segment
= State
->SegmentOverride
;
5459 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5461 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5462 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5469 /* Calculate the size */
5470 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5471 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5473 /* Read from the source operand */
5474 if (!Fast486ReadMemory(State
,
5476 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5477 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5482 /* Exception occurred */
5486 /* Write to the destination operand */
5487 if (!Fast486WriteMemory(State
,
5489 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5490 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5494 /* Exception occurred */
5498 /* Increment/decrement ESI and EDI */
5501 if (!State
->Flags
.Df
)
5503 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5504 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5508 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5509 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5514 if (!State
->Flags
.Df
)
5516 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5517 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5521 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5522 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5526 // FIXME: This method is slow!
5527 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5531 if (--State
->GeneralRegs
[FAST486_REG_ECX
].Long
)
5533 /* Repeat the instruction */
5534 State
->InstPtr
= State
->SavedInstPtr
;
5539 if (--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
)
5541 /* Repeat the instruction */
5542 State
->InstPtr
= State
->SavedInstPtr
;
5547 /* Return success */
5551 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5553 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5554 ULONG DataSize
, DataMask
, SignFlag
;
5555 BOOLEAN OperandSize
, AddressSize
;
5556 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5558 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5560 /* Make sure this is the right instruction */
5561 ASSERT((Opcode
& 0xFE) == 0xA6);
5563 TOGGLE_OPSIZE(OperandSize
);
5564 TOGGLE_ADSIZE(AddressSize
);
5566 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5568 /* Use the override segment instead of DS */
5569 Segment
= State
->SegmentOverride
;
5572 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5573 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5575 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5576 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5583 /* Calculate the size */
5584 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5585 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5587 /* Calculate the mask and sign flag */
5588 SignFlag
= 1 << ((DataSize
* 8) - 1);
5589 DataMask
= SignFlag
| (SignFlag
- 1);
5591 /* Read from the first source operand */
5592 if (!Fast486ReadMemory(State
,
5594 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5595 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5600 /* Exception occurred */
5604 /* Read from the second source operand */
5605 if (!Fast486ReadMemory(State
,
5607 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5608 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5613 /* Exception occurred */
5617 /* Calculate the result */
5618 FirstValue
&= DataMask
;
5619 SecondValue
&= DataMask
;
5620 Result
= (FirstValue
- SecondValue
) & DataMask
;
5622 /* Update the flags */
5623 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5624 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5625 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5626 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5627 State
->Flags
.Zf
= (Result
== 0);
5628 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5629 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5631 /* Increment/decrement ESI and EDI */
5634 if (!State
->Flags
.Df
)
5636 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5637 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5641 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5642 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5647 if (!State
->Flags
.Df
)
5649 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5650 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5654 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5655 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5659 // FIXME: This method is slow!
5660 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5661 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5663 BOOLEAN Repeat
= TRUE
;
5667 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5675 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5682 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5683 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5685 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5691 /* Repeat the instruction */
5692 State
->InstPtr
= State
->SavedInstPtr
;
5696 /* Return success */
5700 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5703 BOOLEAN OperandSize
, AddressSize
;
5705 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5707 /* Make sure this is the right instruction */
5708 ASSERT((Opcode
& 0xFE) == 0xAA);
5710 TOGGLE_OPSIZE(OperandSize
);
5711 TOGGLE_ADSIZE(AddressSize
);
5713 /* Calculate the size */
5714 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5715 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5717 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5719 UCHAR Block
[STRING_BLOCK_SIZE
];
5720 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5721 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5723 /* Fill the memory block with the data */
5724 if (DataSize
== sizeof(UCHAR
))
5726 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5732 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5734 if (DataSize
== sizeof(USHORT
))
5736 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5740 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5745 /* Transfer until finished */
5748 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5750 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5753 ULONG MaxBytes
= State
->Flags
.Df
5754 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5755 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5757 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5758 if (Processed
== 0) Processed
= 1;
5761 if (State
->Flags
.Df
)
5763 /* Set EDI to the starting location */
5764 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= (Processed
- 1) * DataSize
;
5765 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= (Processed
- 1) * DataSize
;
5768 /* Write to memory */
5769 if (!Fast486WriteMemory(State
,
5771 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5772 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5774 Processed
* DataSize
))
5777 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5778 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5780 /* Exception occurred */
5784 if (!State
->Flags
.Df
)
5786 /* Increase EDI by the number of bytes transfered */
5787 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5788 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5793 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5794 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5797 /* Reduce the total count by the number processed in this run */
5802 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5803 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5807 /* Write to the destination operand */
5808 if (!Fast486WriteMemory(State
,
5810 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5811 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5812 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5815 /* Exception occurred */
5819 /* Increment/decrement EDI */
5822 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5823 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5827 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5828 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5832 /* Return success */
5836 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5839 BOOLEAN OperandSize
, AddressSize
;
5840 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5842 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5844 /* Make sure this is the right instruction */
5845 ASSERT((Opcode
& 0xFE) == 0xAC);
5847 TOGGLE_OPSIZE(OperandSize
);
5848 TOGGLE_ADSIZE(AddressSize
);
5850 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5852 /* Use the override segment instead of DS */
5853 Segment
= State
->SegmentOverride
;
5856 /* Calculate the size */
5857 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5858 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5860 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5862 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5863 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5865 /* If the count is 0, do nothing */
5866 if (Count
== 0) return TRUE
;
5868 /* Only the last entry will be loaded */
5869 if (!State
->Flags
.Df
)
5871 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5872 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5876 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5877 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5881 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5882 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5885 /* Read from the source operand */
5886 if (!Fast486ReadMemory(State
,
5888 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5889 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5891 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5894 /* Exception occurred */
5898 /* Increment/decrement ESI */
5901 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5902 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5906 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5907 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5910 /* Return success */
5914 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5916 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5917 ULONG SecondValue
= 0;
5919 ULONG DataSize
, DataMask
, SignFlag
;
5920 BOOLEAN OperandSize
, AddressSize
;
5922 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5924 /* Make sure this is the right instruction */
5925 ASSERT((Opcode
& 0xFE) == 0xAE);
5927 TOGGLE_OPSIZE(OperandSize
);
5928 TOGGLE_ADSIZE(AddressSize
);
5930 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5931 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5933 if ((AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0))
5934 || (!AddressSize
&& (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0)))
5941 /* Calculate the size */
5942 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5943 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5945 /* Calculate the mask and sign flag */
5946 SignFlag
= 1 << ((DataSize
* 8) - 1);
5947 DataMask
= SignFlag
| (SignFlag
- 1);
5949 /* Read from the source operand */
5950 if (!Fast486ReadMemory(State
,
5952 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5953 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5958 /* Exception occurred */
5962 /* Calculate the result */
5963 FirstValue
&= DataMask
;
5964 SecondValue
&= DataMask
;
5965 Result
= (FirstValue
- SecondValue
) & DataMask
;
5967 /* Update the flags */
5968 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5969 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5970 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5971 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5972 State
->Flags
.Zf
= (Result
== 0);
5973 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5974 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5976 /* Increment/decrement EDI */
5979 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5980 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5984 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5985 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5988 // FIXME: This method is slow!
5989 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5990 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5992 BOOLEAN Repeat
= TRUE
;
5996 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6004 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6011 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6012 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6014 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6020 /* Repeat the instruction */
6021 State
->InstPtr
= State
->SavedInstPtr
;
6025 /* Return success */
6029 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6032 BOOLEAN OperandSize
, AddressSize
;
6034 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6036 /* Make sure this is the right instruction */
6037 ASSERT((Opcode
& 0xFE) == 0x6C);
6039 TOGGLE_OPSIZE(OperandSize
);
6040 TOGGLE_ADSIZE(AddressSize
);
6042 /* Calculate the size */
6043 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6044 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6046 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6048 UCHAR Block
[STRING_BLOCK_SIZE
];
6049 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6050 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6052 /* Clear the memory block */
6053 RtlZeroMemory(Block
, sizeof(Block
));
6055 /* Transfer until finished */
6058 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6060 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6063 ULONG MaxBytes
= State
->Flags
.Df
6064 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6065 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6067 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6068 if (Processed
== 0) Processed
= 1;
6071 /* Read from the I/O port */
6072 State
->IoReadCallback(State
,
6073 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6078 if (State
->Flags
.Df
)
6082 /* Reduce EDI by the number of bytes to transfer */
6083 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6084 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6086 /* Reverse the block data */
6087 for (i
= 0; i
< Processed
/ 2; i
++)
6089 /* Swap the values */
6090 for (j
= 0; j
< DataSize
; j
++)
6092 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6093 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6094 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6099 /* Write to memory */
6100 if (!Fast486WriteMemory(State
,
6102 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6103 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6105 Processed
* DataSize
))
6108 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6109 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6111 /* Exception occurred */
6115 if (!State
->Flags
.Df
)
6117 /* Increase EDI by the number of bytes transfered */
6118 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6119 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6122 /* Reduce the total count by the number processed in this run */
6127 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6128 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6134 /* Read from the I/O port */
6135 State
->IoReadCallback(State
,
6136 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6141 /* Write to the destination operand */
6142 if (!Fast486WriteMemory(State
,
6144 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6145 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6149 /* Exception occurred */
6153 /* Increment/decrement EDI */
6156 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6157 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6161 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6162 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6166 /* Return success */
6170 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6173 BOOLEAN OperandSize
, AddressSize
;
6175 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6177 /* Make sure this is the right instruction */
6178 ASSERT((Opcode
& 0xFE) == 0x6E);
6180 TOGGLE_OPSIZE(OperandSize
);
6181 TOGGLE_ADSIZE(AddressSize
);
6183 /* Calculate the size */
6184 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6185 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6187 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6189 UCHAR Block
[STRING_BLOCK_SIZE
];
6190 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6191 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6193 /* Clear the memory block */
6194 RtlZeroMemory(Block
, sizeof(Block
));
6196 /* Transfer until finished */
6199 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6201 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6204 ULONG MaxBytes
= State
->Flags
.Df
6205 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6206 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6208 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6209 if (Processed
== 0) Processed
= 1;
6212 /* Read from memory */
6213 if (!Fast486ReadMemory(State
,
6215 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6216 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6219 Processed
* DataSize
))
6222 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6223 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6225 /* Exception occurred */
6229 if (State
->Flags
.Df
)
6233 /* Reduce EDI by the number of bytes to transfer */
6234 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6235 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6237 /* Reverse the block data */
6238 for (i
= 0; i
< Processed
/ 2; i
++)
6240 /* Swap the values */
6241 for (j
= 0; j
< DataSize
; j
++)
6243 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6244 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6245 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6250 /* Write to the I/O port */
6251 State
->IoWriteCallback(State
,
6252 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6257 if (!State
->Flags
.Df
)
6259 /* Increase EDI by the number of bytes transfered */
6260 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6261 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6264 /* Reduce the total count by the number processed in this run */
6269 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6270 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6276 /* Read from the source operand */
6277 if (!Fast486ReadMemory(State
,
6279 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6280 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6285 /* Exception occurred */
6289 /* Write to the I/O port */
6290 State
->IoWriteCallback(State
,
6291 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6296 /* Increment/decrement ESI */
6299 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6300 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6304 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6305 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6309 /* Return success */