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 *******************************************************************/
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
38 /* PUBLIC VARIABLES ***********************************************************/
40 FAST486_OPCODE_HANDLER_PROC
41 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
43 Fast486OpcodeAddByteModrm
,
44 Fast486OpcodeAddModrm
,
45 Fast486OpcodeAddByteModrm
,
46 Fast486OpcodeAddModrm
,
51 Fast486OpcodeOrByteModrm
,
53 Fast486OpcodeOrByteModrm
,
58 Fast486OpcodeExtended
,
59 Fast486OpcodeAdcByteModrm
,
60 Fast486OpcodeAdcModrm
,
61 Fast486OpcodeAdcByteModrm
,
62 Fast486OpcodeAdcModrm
,
67 Fast486OpcodeSbbByteModrm
,
68 Fast486OpcodeSbbModrm
,
69 Fast486OpcodeSbbByteModrm
,
70 Fast486OpcodeSbbModrm
,
75 Fast486OpcodeAndByteModrm
,
76 Fast486OpcodeAndModrm
,
77 Fast486OpcodeAndByteModrm
,
78 Fast486OpcodeAndModrm
,
83 Fast486OpcodeCmpSubByteModrm
,
84 Fast486OpcodeCmpSubModrm
,
85 Fast486OpcodeCmpSubByteModrm
,
86 Fast486OpcodeCmpSubModrm
,
87 Fast486OpcodeCmpSubAl
,
88 Fast486OpcodeCmpSubEax
,
91 Fast486OpcodeXorByteModrm
,
92 Fast486OpcodeXorModrm
,
93 Fast486OpcodeXorByteModrm
,
94 Fast486OpcodeXorModrm
,
99 Fast486OpcodeCmpSubByteModrm
,
100 Fast486OpcodeCmpSubModrm
,
101 Fast486OpcodeCmpSubByteModrm
,
102 Fast486OpcodeCmpSubModrm
,
103 Fast486OpcodeCmpSubAl
,
104 Fast486OpcodeCmpSubEax
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeIncrement
,
113 Fast486OpcodeIncrement
,
114 Fast486OpcodeIncrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodeDecrement
,
121 Fast486OpcodeDecrement
,
122 Fast486OpcodeDecrement
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
128 Fast486OpcodePushReg
,
129 Fast486OpcodePushReg
,
130 Fast486OpcodePushReg
,
139 Fast486OpcodePushAll
,
147 Fast486OpcodePushImm
,
148 Fast486OpcodeImulModrmImm
,
149 Fast486OpcodePushByteImm
,
150 Fast486OpcodeImulModrmImm
,
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 Fast486OpcodeShortConditionalJmp
,
170 Fast486OpcodeShortConditionalJmp
,
171 Fast486OpcodeGroup8082
,
172 Fast486OpcodeGroup81
,
173 Fast486OpcodeGroup8082
,
174 Fast486OpcodeGroup83
,
175 Fast486OpcodeTestByteModrm
,
176 Fast486OpcodeTestModrm
,
177 Fast486OpcodeXchgByteModrm
,
178 Fast486OpcodeXchgModrm
,
179 Fast486OpcodeMovByteModrm
,
180 Fast486OpcodeMovModrm
,
181 Fast486OpcodeMovByteModrm
,
182 Fast486OpcodeMovModrm
,
183 Fast486OpcodeMovStoreSeg
,
185 Fast486OpcodeMovLoadSeg
,
186 Fast486OpcodeGroup8F
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
192 Fast486OpcodeExchangeEax
,
193 Fast486OpcodeExchangeEax
,
194 Fast486OpcodeExchangeEax
,
197 Fast486OpcodeCallAbs
,
199 Fast486OpcodePushFlags
,
200 Fast486OpcodePopFlags
,
203 Fast486OpcodeMovAlOffset
,
204 Fast486OpcodeMovEaxOffset
,
205 Fast486OpcodeMovOffsetAl
,
206 Fast486OpcodeMovOffsetEax
,
212 Fast486OpcodeTestEax
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovByteRegImm
,
225 Fast486OpcodeMovByteRegImm
,
226 Fast486OpcodeMovByteRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeMovRegImm
,
233 Fast486OpcodeMovRegImm
,
234 Fast486OpcodeMovRegImm
,
235 Fast486OpcodeGroupC0
,
236 Fast486OpcodeGroupC1
,
241 Fast486OpcodeGroupC6
,
242 Fast486OpcodeGroupC7
,
251 Fast486OpcodeGroupD0
,
252 Fast486OpcodeGroupD1
,
253 Fast486OpcodeGroupD2
,
254 Fast486OpcodeGroupD3
,
259 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
260 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
261 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
262 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
263 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
264 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
265 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
266 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
273 Fast486OpcodeOutByte
,
278 Fast486OpcodeShortJump
,
281 Fast486OpcodeOutByte
,
288 Fast486OpcodeComplCarry
,
289 Fast486OpcodeGroupF6
,
290 Fast486OpcodeGroupF7
,
291 Fast486OpcodeClearCarry
,
292 Fast486OpcodeSetCarry
,
293 Fast486OpcodeClearInt
,
295 Fast486OpcodeClearDir
,
297 Fast486OpcodeGroupFE
,
298 Fast486OpcodeGroupFF
,
301 /* PUBLIC FUNCTIONS ***********************************************************/
303 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
305 BOOLEAN Valid
= FALSE
;
312 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
314 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
315 State
->SegmentOverride
= FAST486_REG_ES
;
325 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
327 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
328 State
->SegmentOverride
= FAST486_REG_CS
;
338 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
340 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
341 State
->SegmentOverride
= FAST486_REG_SS
;
351 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
353 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
354 State
->SegmentOverride
= FAST486_REG_DS
;
364 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
366 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
367 State
->SegmentOverride
= FAST486_REG_FS
;
377 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
379 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
380 State
->SegmentOverride
= FAST486_REG_GS
;
390 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
392 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
402 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
404 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
413 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
415 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
425 /* Mutually exclusive with REP */
426 if (!(State
->PrefixFlags
427 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
429 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
439 /* Mutually exclusive with REPNZ */
440 if (!(State
->PrefixFlags
441 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
443 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
453 /* Clear all prefixes */
454 State
->PrefixFlags
= 0;
456 /* Throw an exception */
457 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
464 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
467 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
469 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
471 /* The OPSIZE prefix toggles the size */
475 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
478 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
482 /* Make sure this is the right instruction */
483 ASSERT((Opcode
& 0xF8) == 0x40);
487 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
489 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
490 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
494 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
496 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
497 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
500 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
501 State
->Flags
.Af
= ((Value
& 0x0F) == 0) ? TRUE
: FALSE
;
502 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
508 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
511 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
513 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
515 /* The OPSIZE prefix toggles the size */
519 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
522 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
526 /* Make sure this is the right instruction */
527 ASSERT((Opcode
& 0xF8) == 0x48);
531 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
533 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1)) ? TRUE
: FALSE
;
534 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
538 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
540 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1)) ? TRUE
: FALSE
;
541 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
544 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
545 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F) ? TRUE
: FALSE
;
546 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
552 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
554 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
557 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
561 /* Make sure this is the right instruction */
562 ASSERT((Opcode
& 0xF8) == 0x50);
564 /* Call the internal function */
565 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
568 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
571 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_SS
].Size
;
573 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
575 /* The OPSIZE prefix toggles the size */
579 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
582 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
586 /* Make sure this is the right instruction */
587 ASSERT((Opcode
& 0xF8) == 0x58);
589 /* Call the internal function */
590 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
592 /* Store the value */
593 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
594 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
600 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
602 if (State
->PrefixFlags
& ~(FAST486_PREFIX_OPSIZE
| FAST486_PREFIX_REP
))
604 /* Allowed prefixes are REP and OPSIZE */
605 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
609 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
612 State
->IdleCallback(State
);
618 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
620 INT Reg
= Opcode
& 0x07;
621 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
623 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
625 /* The OPSIZE prefix toggles the size */
629 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
632 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
636 /* Make sure this is the right instruction */
637 ASSERT((Opcode
& 0xF8) == 0x90);
639 /* Exchange the values */
644 Value
= State
->GeneralRegs
[Reg
].Long
;
645 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
646 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
652 Value
= State
->GeneralRegs
[Reg
].LowWord
;
653 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
654 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
660 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
662 BOOLEAN Jump
= FALSE
;
665 /* Make sure this is the right instruction */
666 ASSERT((Opcode
& 0xF0) == 0x70);
668 /* Fetch the offset */
669 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
671 /* An exception occurred */
675 switch ((Opcode
& 0x0F) >> 1)
680 Jump
= State
->Flags
.Of
;
687 Jump
= State
->Flags
.Cf
;
694 Jump
= State
->Flags
.Zf
;
701 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
708 Jump
= State
->Flags
.Sf
;
715 Jump
= State
->Flags
.Pf
;
722 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
729 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
736 /* Invert the result */
742 /* Move the instruction pointer */
743 State
->InstPtr
.Long
+= Offset
;
750 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
752 /* Make sure this is the right instruction */
753 ASSERT(Opcode
== 0xF8);
755 /* No prefixes allowed */
756 if (State
->PrefixFlags
)
758 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
762 /* Clear CF and return success */
763 State
->Flags
.Cf
= FALSE
;
767 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
769 /* Make sure this is the right instruction */
770 ASSERT(Opcode
== 0xF9);
772 /* No prefixes allowed */
773 if (State
->PrefixFlags
)
775 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
779 /* Set CF and return success*/
780 State
->Flags
.Cf
= TRUE
;
784 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
786 /* Make sure this is the right instruction */
787 ASSERT(Opcode
== 0xF5);
789 /* No prefixes allowed */
790 if (State
->PrefixFlags
)
792 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
796 /* Toggle CF and return success */
797 State
->Flags
.Cf
= !State
->Flags
.Cf
;
801 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
803 /* Make sure this is the right instruction */
804 ASSERT(Opcode
== 0xFA);
806 /* No prefixes allowed */
807 if (State
->PrefixFlags
)
809 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
813 /* Check for protected mode */
814 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
817 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
819 /* Clear the interrupt flag */
820 State
->Flags
.If
= FALSE
;
824 /* General Protection Fault */
825 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
831 /* Just clear the interrupt flag */
832 State
->Flags
.If
= FALSE
;
839 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
841 /* Make sure this is the right instruction */
842 ASSERT(Opcode
== 0xFB);
844 /* No prefixes allowed */
845 if (State
->PrefixFlags
)
847 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
851 /* Check for protected mode */
852 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
855 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
857 /* Set the interrupt flag */
858 State
->Flags
.If
= TRUE
;
862 /* General Protection Fault */
863 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
869 /* Just set the interrupt flag */
870 State
->Flags
.If
= TRUE
;
877 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
879 /* Make sure this is the right instruction */
880 ASSERT(Opcode
== 0xFC);
882 /* No prefixes allowed */
883 if (State
->PrefixFlags
)
885 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
889 /* Clear DF and return success */
890 State
->Flags
.Df
= FALSE
;
894 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
896 /* Make sure this is the right instruction */
897 ASSERT(Opcode
== 0xFD);
899 /* No prefixes allowed */
900 if (State
->PrefixFlags
)
902 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
906 /* Set DF and return success*/
907 State
->Flags
.Df
= TRUE
;
911 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
913 /* Make sure this is the right instruction */
914 ASSERT(Opcode
== 0xF4);
916 /* No prefixes allowed */
917 if (State
->PrefixFlags
)
919 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
923 /* Privileged instructions can only be executed under CPL = 0 */
924 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
926 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
931 while (!State
->HardwareInt
) State
->IdleCallback(State
);
937 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
942 /* Make sure this is the right instruction */
943 ASSERT((Opcode
& 0xF7) == 0xE4);
947 /* Fetch the parameter */
948 if (!Fast486FetchByte(State
, &Data
))
950 /* Exception occurred */
954 /* Set the port number to the parameter */
959 /* The port number is in DX */
960 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
963 /* Read a byte from the I/O port */
964 State
->IoReadCallback(State
, Port
, &Data
, sizeof(UCHAR
));
966 /* Store the result in AL */
967 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
972 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
975 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
977 /* Make sure this is the right instruction */
978 ASSERT((Opcode
& 0xF7) == 0xE5);
980 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
982 /* The OPSIZE prefix toggles the size */
986 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
989 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
997 /* Fetch the parameter */
998 if (!Fast486FetchByte(State
, &Data
))
1000 /* Exception occurred */
1004 /* Set the port number to the parameter */
1009 /* The port number is in DX */
1010 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1017 /* Read a dword from the I/O port */
1018 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1020 /* Store the value in EAX */
1021 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
1027 /* Read a word from the I/O port */
1028 State
->IoReadCallback(State
, Port
, &Data
, sizeof(USHORT
));
1030 /* Store the value in AX */
1031 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
1037 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
1042 /* Make sure this is the right instruction */
1043 ASSERT((Opcode
& 0xF7) == 0xE6);
1047 /* Fetch the parameter */
1048 if (!Fast486FetchByte(State
, &Data
))
1050 /* Exception occurred */
1054 /* Set the port number to the parameter */
1059 /* The port number is in DX */
1060 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1063 /* Read the value from AL */
1064 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1066 /* Write the byte to the I/O port */
1067 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(UCHAR
));
1072 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1075 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1077 /* Make sure this is the right instruction */
1078 ASSERT((Opcode
& 0xF7) == 0xE7);
1080 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1082 /* The OPSIZE prefix toggles the size */
1086 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
1088 /* Invalid prefix */
1089 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1097 /* Fetch the parameter */
1098 if (!Fast486FetchByte(State
, &Data
))
1100 /* Exception occurred */
1104 /* Set the port number to the parameter */
1109 /* The port number is in DX */
1110 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1115 /* Get the value from EAX */
1116 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1118 /* Write a dword to the I/O port */
1119 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1123 /* Get the value from AX */
1124 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1126 /* Write a word to the I/O port */
1127 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(USHORT
));
1133 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1137 /* Make sure this is the right instruction */
1138 ASSERT(Opcode
== 0xEB);
1140 /* Fetch the offset */
1141 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1143 /* An exception occurred */
1147 /* Move the instruction pointer */
1148 State
->InstPtr
.Long
+= Offset
;
1153 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1155 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1157 /* Make sure this is the right instruction */
1158 ASSERT((Opcode
& 0xF8) == 0xB8);
1160 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1162 /* The OPSIZE prefix toggles the size */
1166 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
1168 /* Invalid prefix */
1169 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1177 /* Fetch the dword */
1178 if (!Fast486FetchDword(State
, &Value
))
1180 /* Exception occurred */
1184 /* Store the value in the register */
1185 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1191 /* Fetch the word */
1192 if (!Fast486FetchWord(State
, &Value
))
1194 /* Exception occurred */
1198 /* Store the value in the register */
1199 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1205 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1209 /* Make sure this is the right instruction */
1210 ASSERT((Opcode
& 0xF8) == 0xB0);
1212 if (State
->PrefixFlags
!= 0)
1214 /* Invalid prefix */
1215 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1219 /* Fetch the byte */
1220 if (!Fast486FetchByte(State
, &Value
))
1222 /* Exception occurred */
1228 /* AH, CH, DH or BH */
1229 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1233 /* AL, CL, DL or BL */
1234 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1240 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1242 UCHAR FirstValue
, SecondValue
, Result
;
1243 FAST486_MOD_REG_RM ModRegRm
;
1244 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1246 /* Make sure this is the right instruction */
1247 ASSERT((Opcode
& 0xFD) == 0x00);
1249 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
1251 /* The ADSIZE prefix toggles the size */
1252 AddressSize
= !AddressSize
;
1254 else if (State
->PrefixFlags
1255 & ~(FAST486_PREFIX_ADSIZE
1256 | FAST486_PREFIX_SEG
1257 | FAST486_PREFIX_LOCK
))
1259 /* Invalid prefix */
1260 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1264 /* Get the operands */
1265 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1267 /* Exception occurred */
1271 if (!Fast486ReadModrmByteOperands(State
,
1276 /* Exception occurred */
1280 /* Calculate the result */
1281 Result
= FirstValue
+ SecondValue
;
1283 /* Update the flags */
1284 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1285 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1286 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1287 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1288 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1289 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1290 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1292 /* Write back the result */
1293 return Fast486WriteModrmByteOperands(State
,
1295 Opcode
& FAST486_OPCODE_WRITE_REG
,
1299 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1301 FAST486_MOD_REG_RM ModRegRm
;
1302 BOOLEAN OperandSize
, AddressSize
;
1304 /* Make sure this is the right instruction */
1305 ASSERT((Opcode
& 0xFD) == 0x01);
1307 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1309 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
1311 /* The ADSIZE prefix toggles the address size */
1312 AddressSize
= !AddressSize
;
1315 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1317 /* The OPSIZE prefix toggles the operand size */
1318 OperandSize
= !OperandSize
;
1321 if (State
->PrefixFlags
1322 & ~(FAST486_PREFIX_ADSIZE
1323 | FAST486_PREFIX_OPSIZE
1324 | FAST486_PREFIX_SEG
1325 | FAST486_PREFIX_LOCK
))
1327 /* Invalid prefix */
1328 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1332 /* Get the operands */
1333 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1335 /* Exception occurred */
1339 /* Check the operand size */
1342 ULONG FirstValue
, SecondValue
, Result
;
1344 if (!Fast486ReadModrmDwordOperands(State
,
1349 /* Exception occurred */
1353 /* Calculate the result */
1354 Result
= FirstValue
+ SecondValue
;
1356 /* Update the flags */
1357 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1358 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1359 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1360 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1361 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1362 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1363 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1365 /* Write back the result */
1366 return Fast486WriteModrmDwordOperands(State
,
1368 Opcode
& FAST486_OPCODE_WRITE_REG
,
1373 USHORT FirstValue
, SecondValue
, Result
;
1375 if (!Fast486ReadModrmWordOperands(State
,
1380 /* Exception occurred */
1384 /* Calculate the result */
1385 Result
= FirstValue
+ SecondValue
;
1387 /* Update the flags */
1388 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1389 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1390 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1391 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1392 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1393 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1394 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1396 /* Write back the result */
1397 return Fast486WriteModrmWordOperands(State
,
1399 Opcode
& FAST486_OPCODE_WRITE_REG
,
1404 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1406 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1407 UCHAR SecondValue
, Result
;
1409 /* Make sure this is the right instruction */
1410 ASSERT(Opcode
== 0x04);
1412 if (State
->PrefixFlags
)
1414 /* This opcode doesn't take any prefixes */
1415 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1419 if (!Fast486FetchByte(State
, &SecondValue
))
1421 /* Exception occurred */
1425 /* Calculate the result */
1426 Result
= FirstValue
+ SecondValue
;
1428 /* Update the flags */
1429 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1430 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1431 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1432 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1433 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1434 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1435 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1437 /* Write back the result */
1438 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1443 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1445 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1447 /* Make sure this is the right instruction */
1448 ASSERT(Opcode
== 0x05);
1450 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
1452 /* Invalid prefix */
1453 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1457 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1459 /* The OPSIZE prefix toggles the size */
1465 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1466 ULONG SecondValue
, Result
;
1468 if (!Fast486FetchDword(State
, &SecondValue
))
1470 /* Exception occurred */
1474 /* Calculate the result */
1475 Result
= FirstValue
+ SecondValue
;
1477 /* Update the flags */
1478 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1479 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1480 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1481 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1482 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1483 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1484 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1486 /* Write back the result */
1487 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1491 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1492 USHORT SecondValue
, Result
;
1494 if (!Fast486FetchWord(State
, &SecondValue
))
1496 /* Exception occurred */
1500 /* Calculate the result */
1501 Result
= FirstValue
+ SecondValue
;
1503 /* Update the flags */
1504 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1505 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1506 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1507 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1508 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1509 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1510 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1512 /* Write back the result */
1513 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1519 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1521 UCHAR FirstValue
, SecondValue
, Result
;
1522 FAST486_MOD_REG_RM ModRegRm
;
1523 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1525 /* Make sure this is the right instruction */
1526 ASSERT((Opcode
& 0xFD) == 0x08);
1528 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
1530 /* The ADSIZE prefix toggles the size */
1531 AddressSize
= !AddressSize
;
1533 else if (State
->PrefixFlags
1534 & ~(FAST486_PREFIX_ADSIZE
1535 | FAST486_PREFIX_SEG
1536 | FAST486_PREFIX_LOCK
))
1538 /* Invalid prefix */
1539 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1543 /* Get the operands */
1544 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1546 /* Exception occurred */
1550 if (!Fast486ReadModrmByteOperands(State
,
1555 /* Exception occurred */
1559 /* Calculate the result */
1560 Result
= FirstValue
| SecondValue
;
1562 /* Update the flags */
1563 State
->Flags
.Cf
= FALSE
;
1564 State
->Flags
.Of
= FALSE
;
1565 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1566 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1567 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1569 /* Write back the result */
1570 return Fast486WriteModrmByteOperands(State
,
1572 Opcode
& FAST486_OPCODE_WRITE_REG
,
1576 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1578 FAST486_MOD_REG_RM ModRegRm
;
1579 BOOLEAN OperandSize
, AddressSize
;
1581 /* Make sure this is the right instruction */
1582 ASSERT((Opcode
& 0xFD) == 0x09);
1584 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1586 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
1588 /* The ADSIZE prefix toggles the address size */
1589 AddressSize
= !AddressSize
;
1592 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1594 /* The OPSIZE prefix toggles the operand size */
1595 OperandSize
= !OperandSize
;
1598 if (State
->PrefixFlags
1599 & ~(FAST486_PREFIX_ADSIZE
1600 | FAST486_PREFIX_OPSIZE
1601 | FAST486_PREFIX_SEG
1602 | FAST486_PREFIX_LOCK
))
1604 /* Invalid prefix */
1605 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1609 /* Get the operands */
1610 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1612 /* Exception occurred */
1616 /* Check the operand size */
1619 ULONG FirstValue
, SecondValue
, Result
;
1621 if (!Fast486ReadModrmDwordOperands(State
,
1626 /* Exception occurred */
1630 /* Calculate the result */
1631 Result
= FirstValue
| SecondValue
;
1633 /* Update the flags */
1634 State
->Flags
.Cf
= FALSE
;
1635 State
->Flags
.Of
= FALSE
;
1636 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1637 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1638 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1640 /* Write back the result */
1641 return Fast486WriteModrmDwordOperands(State
,
1643 Opcode
& FAST486_OPCODE_WRITE_REG
,
1648 USHORT FirstValue
, SecondValue
, Result
;
1650 if (!Fast486ReadModrmWordOperands(State
,
1655 /* Exception occurred */
1659 /* Calculate the result */
1660 Result
= FirstValue
| SecondValue
;
1662 /* Update the flags */
1663 State
->Flags
.Cf
= FALSE
;
1664 State
->Flags
.Of
= FALSE
;
1665 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1666 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1667 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1669 /* Write back the result */
1670 return Fast486WriteModrmWordOperands(State
,
1672 Opcode
& FAST486_OPCODE_WRITE_REG
,
1677 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1679 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1680 UCHAR SecondValue
, Result
;
1682 /* Make sure this is the right instruction */
1683 ASSERT(Opcode
== 0x0C);
1685 if (State
->PrefixFlags
)
1687 /* This opcode doesn't take any prefixes */
1688 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1692 if (!Fast486FetchByte(State
, &SecondValue
))
1694 /* Exception occurred */
1698 /* Calculate the result */
1699 Result
= FirstValue
| SecondValue
;
1701 /* Update the flags */
1702 State
->Flags
.Cf
= FALSE
;
1703 State
->Flags
.Of
= FALSE
;
1704 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1705 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1706 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1708 /* Write back the result */
1709 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1714 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1716 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1718 /* Make sure this is the right instruction */
1719 ASSERT(Opcode
== 0x0D);
1721 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
1723 /* Invalid prefix */
1724 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1728 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1730 /* The OPSIZE prefix toggles the size */
1736 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1737 ULONG SecondValue
, Result
;
1739 if (!Fast486FetchDword(State
, &SecondValue
))
1741 /* Exception occurred */
1745 /* Calculate the result */
1746 Result
= FirstValue
| SecondValue
;
1748 /* Update the flags */
1749 State
->Flags
.Cf
= FALSE
;
1750 State
->Flags
.Of
= FALSE
;
1751 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1752 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1753 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1755 /* Write back the result */
1756 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1760 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1761 USHORT SecondValue
, Result
;
1763 if (!Fast486FetchWord(State
, &SecondValue
))
1765 /* Exception occurred */
1769 /* Calculate the result */
1770 Result
= FirstValue
| SecondValue
;
1772 /* Update the flags */
1773 State
->Flags
.Cf
= FALSE
;
1774 State
->Flags
.Of
= FALSE
;
1775 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1776 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1777 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1779 /* Write back the result */
1780 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1786 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1788 UCHAR FirstValue
, SecondValue
, Result
;
1789 FAST486_MOD_REG_RM ModRegRm
;
1790 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1792 /* Make sure this is the right instruction */
1793 ASSERT((Opcode
& 0xFD) == 0x20);
1795 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
1797 /* The ADSIZE prefix toggles the size */
1798 AddressSize
= !AddressSize
;
1800 else if (State
->PrefixFlags
1801 & ~(FAST486_PREFIX_ADSIZE
1802 | FAST486_PREFIX_SEG
1803 | FAST486_PREFIX_LOCK
))
1805 /* Invalid prefix */
1806 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1810 /* Get the operands */
1811 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1813 /* Exception occurred */
1817 if (!Fast486ReadModrmByteOperands(State
,
1822 /* Exception occurred */
1826 /* Calculate the result */
1827 Result
= FirstValue
& SecondValue
;
1829 /* Update the flags */
1830 State
->Flags
.Cf
= FALSE
;
1831 State
->Flags
.Of
= FALSE
;
1832 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1833 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1834 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1836 /* Write back the result */
1837 return Fast486WriteModrmByteOperands(State
,
1839 Opcode
& FAST486_OPCODE_WRITE_REG
,
1843 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1845 FAST486_MOD_REG_RM ModRegRm
;
1846 BOOLEAN OperandSize
, AddressSize
;
1848 /* Make sure this is the right instruction */
1849 ASSERT((Opcode
& 0xFD) == 0x21);
1851 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1853 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
1855 /* The ADSIZE prefix toggles the address size */
1856 AddressSize
= !AddressSize
;
1859 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1861 /* The OPSIZE prefix toggles the operand size */
1862 OperandSize
= !OperandSize
;
1865 if (State
->PrefixFlags
1866 & ~(FAST486_PREFIX_ADSIZE
1867 | FAST486_PREFIX_OPSIZE
1868 | FAST486_PREFIX_SEG
1869 | FAST486_PREFIX_LOCK
))
1871 /* Invalid prefix */
1872 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1876 /* Get the operands */
1877 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1879 /* Exception occurred */
1883 /* Check the operand size */
1886 ULONG FirstValue
, SecondValue
, Result
;
1888 if (!Fast486ReadModrmDwordOperands(State
,
1893 /* Exception occurred */
1897 /* Calculate the result */
1898 Result
= FirstValue
& SecondValue
;
1900 /* Update the flags */
1901 State
->Flags
.Cf
= FALSE
;
1902 State
->Flags
.Of
= FALSE
;
1903 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1904 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1905 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1907 /* Write back the result */
1908 return Fast486WriteModrmDwordOperands(State
,
1910 Opcode
& FAST486_OPCODE_WRITE_REG
,
1915 USHORT FirstValue
, SecondValue
, Result
;
1917 if (!Fast486ReadModrmWordOperands(State
,
1922 /* Exception occurred */
1926 /* Calculate the result */
1927 Result
= FirstValue
& SecondValue
;
1929 /* Update the flags */
1930 State
->Flags
.Cf
= FALSE
;
1931 State
->Flags
.Of
= FALSE
;
1932 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1933 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1934 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1936 /* Write back the result */
1937 return Fast486WriteModrmWordOperands(State
,
1939 Opcode
& FAST486_OPCODE_WRITE_REG
,
1944 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1946 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1947 UCHAR SecondValue
, Result
;
1949 /* Make sure this is the right instruction */
1950 ASSERT(Opcode
== 0x24);
1952 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
1954 /* Invalid prefix */
1955 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1959 if (!Fast486FetchByte(State
, &SecondValue
))
1961 /* Exception occurred */
1965 /* Calculate the result */
1966 Result
= FirstValue
& SecondValue
;
1968 /* Update the flags */
1969 State
->Flags
.Cf
= FALSE
;
1970 State
->Flags
.Of
= FALSE
;
1971 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1972 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1973 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1975 /* Write back the result */
1976 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1981 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1983 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1985 /* Make sure this is the right instruction */
1986 ASSERT(Opcode
== 0x25);
1988 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
1990 /* Invalid prefix */
1991 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1995 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
1997 /* The OPSIZE prefix toggles the size */
2003 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2004 ULONG SecondValue
, Result
;
2006 if (!Fast486FetchDword(State
, &SecondValue
))
2008 /* Exception occurred */
2012 /* Calculate the result */
2013 Result
= FirstValue
& SecondValue
;
2015 /* Update the flags */
2016 State
->Flags
.Cf
= FALSE
;
2017 State
->Flags
.Of
= FALSE
;
2018 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2019 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2020 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2022 /* Write back the result */
2023 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2027 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2028 USHORT SecondValue
, Result
;
2030 if (!Fast486FetchWord(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) ? TRUE
: FALSE
;
2043 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2044 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2046 /* Write back the result */
2047 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2053 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
2055 UCHAR FirstValue
, SecondValue
, Result
;
2056 FAST486_MOD_REG_RM ModRegRm
;
2057 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2059 /* Make sure this is the right instruction */
2060 ASSERT((Opcode
& 0xFD) == 0x30);
2062 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2064 /* The ADSIZE prefix toggles the size */
2065 AddressSize
= !AddressSize
;
2067 else if (State
->PrefixFlags
2068 & ~(FAST486_PREFIX_ADSIZE
2069 | FAST486_PREFIX_SEG
2070 | FAST486_PREFIX_LOCK
))
2072 /* Invalid prefix */
2073 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2077 /* Get the operands */
2078 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2080 /* Exception occurred */
2084 if (!Fast486ReadModrmByteOperands(State
,
2089 /* Exception occurred */
2093 /* Calculate the result */
2094 Result
= FirstValue
^ SecondValue
;
2096 /* Update the flags */
2097 State
->Flags
.Cf
= FALSE
;
2098 State
->Flags
.Of
= FALSE
;
2099 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2100 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2101 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2103 /* Write back the result */
2104 return Fast486WriteModrmByteOperands(State
,
2106 Opcode
& FAST486_OPCODE_WRITE_REG
,
2110 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
2112 FAST486_MOD_REG_RM ModRegRm
;
2113 BOOLEAN OperandSize
, AddressSize
;
2115 /* Make sure this is the right instruction */
2116 ASSERT((Opcode
& 0xFD) == 0x31);
2118 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2120 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2122 /* The ADSIZE prefix toggles the address size */
2123 AddressSize
= !AddressSize
;
2126 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
2128 /* The OPSIZE prefix toggles the operand size */
2129 OperandSize
= !OperandSize
;
2132 if (State
->PrefixFlags
2133 & ~(FAST486_PREFIX_ADSIZE
2134 | FAST486_PREFIX_OPSIZE
2135 | FAST486_PREFIX_SEG
2136 | FAST486_PREFIX_LOCK
))
2138 /* Invalid prefix */
2139 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2143 /* Get the operands */
2144 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2146 /* Exception occurred */
2150 /* Check the operand size */
2153 ULONG FirstValue
, SecondValue
, Result
;
2155 if (!Fast486ReadModrmDwordOperands(State
,
2160 /* Exception occurred */
2164 /* Calculate the result */
2165 Result
= FirstValue
^ SecondValue
;
2167 /* Update the flags */
2168 State
->Flags
.Cf
= FALSE
;
2169 State
->Flags
.Of
= FALSE
;
2170 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2171 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2172 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2174 /* Write back the result */
2175 return Fast486WriteModrmDwordOperands(State
,
2177 Opcode
& FAST486_OPCODE_WRITE_REG
,
2182 USHORT FirstValue
, SecondValue
, Result
;
2184 if (!Fast486ReadModrmWordOperands(State
,
2189 /* Exception occurred */
2193 /* Calculate the result */
2194 Result
= FirstValue
^ SecondValue
;
2196 /* Update the flags */
2197 State
->Flags
.Cf
= FALSE
;
2198 State
->Flags
.Of
= FALSE
;
2199 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2200 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2201 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2203 /* Write back the result */
2204 return Fast486WriteModrmWordOperands(State
,
2206 Opcode
& FAST486_OPCODE_WRITE_REG
,
2211 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
2213 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2214 UCHAR SecondValue
, Result
;
2216 /* Make sure this is the right instruction */
2217 ASSERT(Opcode
== 0x34);
2219 if (State
->PrefixFlags
)
2221 /* This opcode doesn't take any prefixes */
2222 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2226 if (!Fast486FetchByte(State
, &SecondValue
))
2228 /* Exception occurred */
2232 /* Calculate the result */
2233 Result
= FirstValue
^ SecondValue
;
2235 /* Update the flags */
2236 State
->Flags
.Cf
= FALSE
;
2237 State
->Flags
.Of
= FALSE
;
2238 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2239 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2240 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2242 /* Write back the result */
2243 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2248 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2250 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2252 /* Make sure this is the right instruction */
2253 ASSERT(Opcode
== 0x35);
2255 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
2257 /* Invalid prefix */
2258 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2262 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
2264 /* The OPSIZE prefix toggles the size */
2270 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2271 ULONG SecondValue
, Result
;
2273 if (!Fast486FetchDword(State
, &SecondValue
))
2275 /* Exception occurred */
2279 /* Calculate the result */
2280 Result
= FirstValue
^ SecondValue
;
2282 /* Update the flags */
2283 State
->Flags
.Cf
= FALSE
;
2284 State
->Flags
.Of
= FALSE
;
2285 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2286 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2287 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2289 /* Write back the result */
2290 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2294 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2295 USHORT SecondValue
, Result
;
2297 if (!Fast486FetchWord(State
, &SecondValue
))
2299 /* Exception occurred */
2303 /* Calculate the result */
2304 Result
= FirstValue
^ SecondValue
;
2306 /* Update the flags */
2307 State
->Flags
.Cf
= FALSE
;
2308 State
->Flags
.Of
= FALSE
;
2309 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2310 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2311 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2313 /* Write back the result */
2314 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2320 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2322 UCHAR FirstValue
, SecondValue
, Result
;
2323 FAST486_MOD_REG_RM ModRegRm
;
2324 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2326 /* Make sure this is the right instruction */
2327 ASSERT(Opcode
== 0x84);
2329 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2331 /* The ADSIZE prefix toggles the size */
2332 AddressSize
= !AddressSize
;
2334 else if (State
->PrefixFlags
2335 & ~(FAST486_PREFIX_ADSIZE
2336 | FAST486_PREFIX_SEG
2337 | FAST486_PREFIX_LOCK
))
2339 /* Invalid prefix */
2340 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2344 /* Get the operands */
2345 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2347 /* Exception occurred */
2351 if (!Fast486ReadModrmByteOperands(State
,
2356 /* Exception occurred */
2359 /* Calculate the result */
2360 Result
= FirstValue
& SecondValue
;
2362 /* Update the flags */
2363 State
->Flags
.Cf
= FALSE
;
2364 State
->Flags
.Of
= FALSE
;
2365 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2366 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2367 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2369 /* The result is discarded */
2373 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2375 FAST486_MOD_REG_RM ModRegRm
;
2376 BOOLEAN OperandSize
, AddressSize
;
2378 /* Make sure this is the right instruction */
2379 ASSERT(Opcode
== 0x85);
2381 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2383 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2385 /* The ADSIZE prefix toggles the address size */
2386 AddressSize
= !AddressSize
;
2389 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
2391 /* The OPSIZE prefix toggles the operand size */
2392 OperandSize
= !OperandSize
;
2395 if (State
->PrefixFlags
2396 & ~(FAST486_PREFIX_ADSIZE
2397 | FAST486_PREFIX_OPSIZE
2398 | FAST486_PREFIX_SEG
2399 | FAST486_PREFIX_LOCK
))
2401 /* Invalid prefix */
2402 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2406 /* Get the operands */
2407 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2409 /* Exception occurred */
2413 /* Check the operand size */
2416 ULONG FirstValue
, SecondValue
, Result
;
2418 if (!Fast486ReadModrmDwordOperands(State
,
2423 /* Exception occurred */
2427 /* Calculate the result */
2428 Result
= FirstValue
& SecondValue
;
2430 /* Update the flags */
2431 State
->Flags
.Cf
= FALSE
;
2432 State
->Flags
.Of
= FALSE
;
2433 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2434 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2435 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2439 USHORT FirstValue
, SecondValue
, Result
;
2441 if (!Fast486ReadModrmWordOperands(State
,
2446 /* Exception occurred */
2450 /* Calculate the result */
2451 Result
= FirstValue
& SecondValue
;
2453 /* Update the flags */
2454 State
->Flags
.Cf
= FALSE
;
2455 State
->Flags
.Of
= FALSE
;
2456 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2457 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2458 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2461 /* The result is discarded */
2465 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2467 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2468 UCHAR SecondValue
, Result
;
2470 /* Make sure this is the right instruction */
2471 ASSERT(Opcode
== 0xA8);
2473 if (State
->PrefixFlags
)
2475 /* This opcode doesn't take any prefixes */
2476 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2480 if (!Fast486FetchByte(State
, &SecondValue
))
2482 /* Exception occurred */
2486 /* Calculate the result */
2487 Result
= FirstValue
& SecondValue
;
2489 /* Update the flags */
2490 State
->Flags
.Cf
= FALSE
;
2491 State
->Flags
.Of
= FALSE
;
2492 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2493 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2494 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2496 /* The result is discarded */
2500 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2502 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2504 /* Make sure this is the right instruction */
2505 ASSERT(Opcode
== 0xA9);
2507 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
2509 /* Invalid prefix */
2510 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2514 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
2516 /* The OPSIZE prefix toggles the size */
2522 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2523 ULONG SecondValue
, Result
;
2525 if (!Fast486FetchDword(State
, &SecondValue
))
2527 /* Exception occurred */
2531 /* Calculate the result */
2532 Result
= FirstValue
& SecondValue
;
2534 /* Update the flags */
2535 State
->Flags
.Cf
= FALSE
;
2536 State
->Flags
.Of
= FALSE
;
2537 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2538 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2539 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2543 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2544 USHORT SecondValue
, Result
;
2546 if (!Fast486FetchWord(State
, &SecondValue
))
2548 /* Exception occurred */
2552 /* Calculate the result */
2553 Result
= FirstValue
& SecondValue
;
2555 /* Update the flags */
2556 State
->Flags
.Cf
= FALSE
;
2557 State
->Flags
.Of
= FALSE
;
2558 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2559 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2560 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2563 /* The result is discarded */
2567 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2569 UCHAR FirstValue
, SecondValue
;
2570 FAST486_MOD_REG_RM ModRegRm
;
2571 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2573 /* Make sure this is the right instruction */
2574 ASSERT(Opcode
== 0x86);
2576 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2578 /* The ADSIZE prefix toggles the size */
2579 AddressSize
= !AddressSize
;
2581 else if (State
->PrefixFlags
2582 & ~(FAST486_PREFIX_ADSIZE
2583 | FAST486_PREFIX_SEG
2584 | FAST486_PREFIX_LOCK
))
2586 /* Invalid prefix */
2587 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2591 /* Get the operands */
2592 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2594 /* Exception occurred */
2598 if (!Fast486ReadModrmByteOperands(State
,
2603 /* Exception occurred */
2607 /* Write the value from the register to the R/M */
2608 if (!Fast486WriteModrmByteOperands(State
,
2613 /* Exception occurred */
2617 /* Write the value from the R/M to the register */
2618 if (!Fast486WriteModrmByteOperands(State
,
2623 /* Exception occurred */
2630 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2632 FAST486_MOD_REG_RM ModRegRm
;
2633 BOOLEAN OperandSize
, AddressSize
;
2635 /* Make sure this is the right instruction */
2636 ASSERT(Opcode
== 0x87);
2638 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2640 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2642 /* The ADSIZE prefix toggles the address size */
2643 AddressSize
= !AddressSize
;
2646 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
2648 /* The OPSIZE prefix toggles the operand size */
2649 OperandSize
= !OperandSize
;
2652 if (State
->PrefixFlags
2653 & ~(FAST486_PREFIX_ADSIZE
2654 | FAST486_PREFIX_OPSIZE
2655 | FAST486_PREFIX_SEG
2656 | FAST486_PREFIX_LOCK
))
2658 /* Invalid prefix */
2659 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2663 /* Get the operands */
2664 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2666 /* Exception occurred */
2670 /* Check the operand size */
2673 ULONG FirstValue
, SecondValue
;
2675 if (!Fast486ReadModrmDwordOperands(State
,
2680 /* Exception occurred */
2684 /* Write the value from the register to the R/M */
2685 if (!Fast486WriteModrmDwordOperands(State
,
2690 /* Exception occurred */
2694 /* Write the value from the R/M to the register */
2695 if (!Fast486WriteModrmDwordOperands(State
,
2700 /* Exception occurred */
2706 USHORT FirstValue
, SecondValue
;
2708 if (!Fast486ReadModrmWordOperands(State
,
2713 /* Exception occurred */
2717 /* Write the value from the register to the R/M */
2718 if (!Fast486WriteModrmWordOperands(State
,
2723 /* Exception occurred */
2727 /* Write the value from the R/M to the register */
2728 if (!Fast486WriteModrmWordOperands(State
,
2733 /* Exception occurred */
2738 /* The result is discarded */
2742 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2744 /* Call the internal API */
2745 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2748 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2752 if (!Fast486StackPop(State
, &NewSelector
))
2754 /* Exception occurred */
2758 /* Call the internal API */
2759 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2762 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2764 /* Call the internal API */
2765 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2768 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2770 UCHAR FirstValue
, SecondValue
, Result
;
2771 FAST486_MOD_REG_RM ModRegRm
;
2772 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2774 /* Make sure this is the right instruction */
2775 ASSERT((Opcode
& 0xFD) == 0x10);
2777 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2779 /* The ADSIZE prefix toggles the size */
2780 AddressSize
= !AddressSize
;
2782 else if (State
->PrefixFlags
2783 & ~(FAST486_PREFIX_ADSIZE
2784 | FAST486_PREFIX_SEG
2785 | FAST486_PREFIX_LOCK
))
2787 /* Invalid prefix */
2788 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2792 /* Get the operands */
2793 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2795 /* Exception occurred */
2799 if (!Fast486ReadModrmByteOperands(State
,
2804 /* Exception occurred */
2808 /* Calculate the result */
2809 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2811 /* Special exception for CF */
2812 State
->Flags
.Cf
= State
->Flags
.Cf
2813 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2815 /* Update the flags */
2816 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2817 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2818 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2819 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2820 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2821 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2822 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2824 /* Write back the result */
2825 return Fast486WriteModrmByteOperands(State
,
2827 Opcode
& FAST486_OPCODE_WRITE_REG
,
2831 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2833 FAST486_MOD_REG_RM ModRegRm
;
2834 BOOLEAN OperandSize
, AddressSize
;
2836 /* Make sure this is the right instruction */
2837 ASSERT((Opcode
& 0xFD) == 0x11);
2839 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2841 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
2843 /* The ADSIZE prefix toggles the address size */
2844 AddressSize
= !AddressSize
;
2847 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
2849 /* The OPSIZE prefix toggles the operand size */
2850 OperandSize
= !OperandSize
;
2853 if (State
->PrefixFlags
2854 & ~(FAST486_PREFIX_ADSIZE
2855 | FAST486_PREFIX_OPSIZE
2856 | FAST486_PREFIX_SEG
2857 | FAST486_PREFIX_LOCK
))
2859 /* Invalid prefix */
2860 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2864 /* Get the operands */
2865 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2867 /* Exception occurred */
2871 /* Check the operand size */
2874 ULONG FirstValue
, SecondValue
, Result
;
2876 if (!Fast486ReadModrmDwordOperands(State
,
2881 /* Exception occurred */
2885 /* Calculate the result */
2886 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2888 /* Special exception for CF */
2889 State
->Flags
.Cf
= State
->Flags
.Cf
2890 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2892 /* Update the flags */
2893 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2894 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2895 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2896 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2897 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2898 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2899 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2901 /* Write back the result */
2902 return Fast486WriteModrmDwordOperands(State
,
2904 Opcode
& FAST486_OPCODE_WRITE_REG
,
2909 USHORT FirstValue
, SecondValue
, Result
;
2911 if (!Fast486ReadModrmWordOperands(State
,
2916 /* Exception occurred */
2920 /* Calculate the result */
2921 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2923 /* Special exception for CF */
2924 State
->Flags
.Cf
= State
->Flags
.Cf
2925 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2927 /* Update the flags */
2928 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2929 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2930 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2931 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2932 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2933 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2934 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2936 /* Write back the result */
2937 return Fast486WriteModrmWordOperands(State
,
2939 Opcode
& FAST486_OPCODE_WRITE_REG
,
2945 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2947 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2948 UCHAR SecondValue
, Result
;
2950 /* Make sure this is the right instruction */
2951 ASSERT(Opcode
== 0x14);
2953 if (State
->PrefixFlags
)
2955 /* This opcode doesn't take any prefixes */
2956 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2960 if (!Fast486FetchByte(State
, &SecondValue
))
2962 /* Exception occurred */
2966 /* Calculate the result */
2967 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2969 /* Special exception for CF */
2970 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2971 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2973 /* Update the flags */
2974 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2975 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2976 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2977 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2978 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2979 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2980 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2982 /* Write back the result */
2983 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2988 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2990 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2992 /* Make sure this is the right instruction */
2993 ASSERT(Opcode
== 0x15);
2995 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
2997 /* Invalid prefix */
2998 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3002 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3004 /* The OPSIZE prefix toggles the size */
3010 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3011 ULONG SecondValue
, Result
;
3013 if (!Fast486FetchDword(State
, &SecondValue
))
3015 /* Exception occurred */
3019 /* Calculate the result */
3020 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3022 /* Special exception for CF */
3023 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3024 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
3026 /* Update the flags */
3027 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3028 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
3029 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3030 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3031 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3032 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3033 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3035 /* Write back the result */
3036 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3040 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3041 USHORT SecondValue
, Result
;
3043 if (!Fast486FetchWord(State
, &SecondValue
))
3045 /* Exception occurred */
3049 /* Calculate the result */
3050 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3052 /* Special exception for CF */
3053 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3054 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
3056 /* Update the flags */
3057 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3058 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
3059 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3060 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3061 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3062 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3063 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3065 /* Write back the result */
3066 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3072 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
3074 /* Call the internal API */
3075 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
3078 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
3082 if (!Fast486StackPop(State
, &NewSelector
))
3084 /* Exception occurred */
3088 /* Call the internal API */
3089 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
3092 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
3094 UCHAR FirstValue
, SecondValue
, Result
;
3095 FAST486_MOD_REG_RM ModRegRm
;
3096 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3097 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3099 /* Make sure this is the right instruction */
3100 ASSERT((Opcode
& 0xFD) == 0x18);
3102 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
3104 /* The ADSIZE prefix toggles the size */
3105 AddressSize
= !AddressSize
;
3108 /* Get the operands */
3109 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3111 /* Exception occurred */
3115 if (!Fast486ReadModrmByteOperands(State
,
3120 /* Exception occurred */
3124 /* Check if this is the instruction that writes to R/M */
3125 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3127 /* Swap the order */
3128 FirstValue
^= SecondValue
;
3129 SecondValue
^= FirstValue
;
3130 FirstValue
^= SecondValue
;
3133 /* Calculate the result */
3134 Result
= FirstValue
- SecondValue
- Carry
;
3136 /* Update the flags */
3137 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ 1);
3138 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3139 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3140 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3141 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3142 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3143 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3145 /* Write back the result */
3146 return Fast486WriteModrmByteOperands(State
,
3148 Opcode
& FAST486_OPCODE_WRITE_REG
,
3152 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
3154 FAST486_MOD_REG_RM ModRegRm
;
3155 BOOLEAN OperandSize
, AddressSize
;
3156 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3158 /* Make sure this is the right instruction */
3159 ASSERT((Opcode
& 0xFD) == 0x19);
3161 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3163 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
3165 /* The ADSIZE prefix toggles the address size */
3166 AddressSize
= !AddressSize
;
3169 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3171 /* The OPSIZE prefix toggles the operand size */
3172 OperandSize
= !OperandSize
;
3175 /* Get the operands */
3176 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3178 /* Exception occurred */
3182 /* Check the operand size */
3185 ULONG FirstValue
, SecondValue
, Result
;
3187 if (!Fast486ReadModrmDwordOperands(State
,
3192 /* Exception occurred */
3196 /* Check if this is the instruction that writes to R/M */
3197 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3199 /* Swap the order */
3200 FirstValue
^= SecondValue
;
3201 SecondValue
^= FirstValue
;
3202 FirstValue
^= SecondValue
;
3205 /* Calculate the result */
3206 Result
= FirstValue
- SecondValue
- Carry
;
3208 /* Update the flags */
3209 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3210 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3211 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3212 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3213 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3214 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3215 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3217 /* Write back the result */
3218 return Fast486WriteModrmDwordOperands(State
,
3220 Opcode
& FAST486_OPCODE_WRITE_REG
,
3225 USHORT FirstValue
, SecondValue
, Result
;
3227 if (!Fast486ReadModrmWordOperands(State
,
3232 /* Exception occurred */
3236 /* Check if this is the instruction that writes to R/M */
3237 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3239 /* Swap the order */
3240 FirstValue
^= SecondValue
;
3241 SecondValue
^= FirstValue
;
3242 FirstValue
^= SecondValue
;
3245 /* Calculate the result */
3246 Result
= FirstValue
- SecondValue
- Carry
;
3248 /* Update the flags */
3249 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3250 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3251 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3252 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3253 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3254 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3255 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3257 /* Write back the result */
3258 return Fast486WriteModrmWordOperands(State
,
3260 Opcode
& FAST486_OPCODE_WRITE_REG
,
3265 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
3267 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3268 UCHAR SecondValue
, Result
;
3269 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3271 /* Make sure this is the right instruction */
3272 ASSERT(Opcode
== 0x1C);
3274 if (State
->PrefixFlags
)
3276 /* This opcode doesn't take any prefixes */
3277 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3281 if (!Fast486FetchByte(State
, &SecondValue
))
3283 /* Exception occurred */
3287 /* Calculate the result */
3288 Result
= FirstValue
- SecondValue
- Carry
;
3290 /* Update the flags */
3291 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3292 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3293 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3294 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3295 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3296 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3297 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3299 /* Write back the result */
3300 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3306 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
3308 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3309 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3311 /* Make sure this is the right instruction */
3312 ASSERT(Opcode
== 0x1D);
3314 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
3316 /* Invalid prefix */
3317 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3321 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3323 /* The OPSIZE prefix toggles the size */
3329 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3330 ULONG SecondValue
, Result
;
3332 if (!Fast486FetchDword(State
, &SecondValue
))
3334 /* Exception occurred */
3338 /* Calculate the result */
3339 Result
= FirstValue
- SecondValue
- Carry
;
3341 /* Update the flags */
3342 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3343 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3344 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3345 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
3346 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3347 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3348 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3350 /* Write back the result */
3351 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3355 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3356 USHORT SecondValue
, Result
;
3358 if (!Fast486FetchWord(State
, &SecondValue
))
3360 /* Exception occurred */
3364 /* Calculate the result */
3365 Result
= FirstValue
- SecondValue
- Carry
;
3367 /* Update the flags */
3368 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3369 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3370 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3371 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
3372 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3373 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3374 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3376 /* Write back the result */
3377 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3384 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
3386 /* Call the internal API */
3387 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
3390 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3394 if (!Fast486StackPop(State
, &NewSelector
))
3396 /* Exception occurred */
3400 /* Call the internal API */
3401 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3404 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3406 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3407 BOOLEAN Carry
= State
->Flags
.Cf
;
3409 /* Clear the carry flag */
3410 State
->Flags
.Cf
= FALSE
;
3412 /* Check if the first BCD digit is invalid or there was a carry from it */
3413 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3416 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3417 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3419 /* A carry occurred */
3420 State
->Flags
.Cf
= TRUE
;
3423 /* Set the adjust flag */
3424 State
->Flags
.Af
= TRUE
;
3427 /* Check if the second BCD digit is invalid or there was a carry from it */
3428 if ((Value
> 0x99) || Carry
)
3431 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3433 /* There was a carry */
3434 State
->Flags
.Cf
= TRUE
;
3440 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3442 UCHAR FirstValue
, SecondValue
, Result
;
3443 FAST486_MOD_REG_RM ModRegRm
;
3444 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3446 /* Make sure this is the right instruction */
3447 ASSERT((Opcode
& 0xED) == 0x28);
3449 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
3451 /* The ADSIZE prefix toggles the size */
3452 AddressSize
= !AddressSize
;
3454 else if (State
->PrefixFlags
3455 & ~(FAST486_PREFIX_ADSIZE
3456 | FAST486_PREFIX_SEG
3457 | FAST486_PREFIX_LOCK
))
3459 /* Invalid prefix */
3460 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3464 /* Get the operands */
3465 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3467 /* Exception occurred */
3471 if (!Fast486ReadModrmByteOperands(State
,
3476 /* Exception occurred */
3480 /* Check if this is the instruction that writes to R/M */
3481 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3483 /* Swap the order */
3484 FirstValue
^= SecondValue
;
3485 SecondValue
^= FirstValue
;
3486 FirstValue
^= SecondValue
;
3489 /* Calculate the result */
3490 Result
= FirstValue
- SecondValue
;
3492 /* Update the flags */
3493 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3494 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3495 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3496 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3497 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3498 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3499 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3501 /* Check if this is not a CMP */
3502 if (!(Opcode
& 0x10))
3504 /* Write back the result */
3505 return Fast486WriteModrmByteOperands(State
,
3507 Opcode
& FAST486_OPCODE_WRITE_REG
,
3512 /* Discard the result */
3517 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3519 FAST486_MOD_REG_RM ModRegRm
;
3520 BOOLEAN OperandSize
, AddressSize
;
3522 /* Make sure this is the right instruction */
3523 ASSERT((Opcode
& 0xED) == 0x29);
3525 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3527 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
3529 /* The ADSIZE prefix toggles the address size */
3530 AddressSize
= !AddressSize
;
3533 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3535 /* The OPSIZE prefix toggles the operand size */
3536 OperandSize
= !OperandSize
;
3539 if (State
->PrefixFlags
3540 & ~(FAST486_PREFIX_ADSIZE
3541 | FAST486_PREFIX_OPSIZE
3542 | FAST486_PREFIX_SEG
3543 | FAST486_PREFIX_LOCK
))
3545 /* Invalid prefix */
3546 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3550 /* Get the operands */
3551 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3553 /* Exception occurred */
3557 /* Check the operand size */
3560 ULONG FirstValue
, SecondValue
, Result
;
3562 if (!Fast486ReadModrmDwordOperands(State
,
3567 /* Exception occurred */
3571 /* Check if this is the instruction that writes to R/M */
3572 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3574 /* Swap the order */
3575 FirstValue
^= SecondValue
;
3576 SecondValue
^= FirstValue
;
3577 FirstValue
^= SecondValue
;
3580 /* Calculate the result */
3581 Result
= FirstValue
- SecondValue
;
3583 /* Update the flags */
3584 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3585 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3586 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3587 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3588 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3589 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3590 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3592 /* Check if this is not a CMP */
3593 if (!(Opcode
& 0x10))
3595 /* Write back the result */
3596 return Fast486WriteModrmDwordOperands(State
,
3598 Opcode
& FAST486_OPCODE_WRITE_REG
,
3603 /* Discard the result */
3609 USHORT FirstValue
, SecondValue
, Result
;
3611 if (!Fast486ReadModrmWordOperands(State
,
3616 /* Exception occurred */
3620 /* Check if this is the instruction that writes to R/M */
3621 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3623 /* Swap the order */
3624 FirstValue
^= SecondValue
;
3625 SecondValue
^= FirstValue
;
3626 FirstValue
^= SecondValue
;
3629 /* Calculate the result */
3630 Result
= FirstValue
- SecondValue
;
3632 /* Update the flags */
3633 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3634 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3635 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3636 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3637 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3638 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3639 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3641 /* Check if this is not a CMP */
3642 if (!(Opcode
& 0x10))
3644 /* Write back the result */
3645 return Fast486WriteModrmWordOperands(State
,
3647 Opcode
& FAST486_OPCODE_WRITE_REG
,
3652 /* Discard the result */
3658 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3660 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3661 UCHAR SecondValue
, Result
;
3663 /* Make sure this is the right instruction */
3664 ASSERT((Opcode
& 0xEF) == 0x2C);
3666 if (State
->PrefixFlags
)
3668 /* This opcode doesn't take any prefixes */
3669 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3673 if (!Fast486FetchByte(State
, &SecondValue
))
3675 /* Exception occurred */
3679 /* Calculate the result */
3680 Result
= FirstValue
- SecondValue
;
3682 /* Update the flags */
3683 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3684 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3685 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3686 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3687 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3688 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3689 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3691 /* Check if this is not a CMP */
3692 if (!(Opcode
& 0x10))
3694 /* Write back the result */
3695 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3701 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3703 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3705 /* Make sure this is the right instruction */
3706 ASSERT((Opcode
& 0xEF) == 0x2D);
3708 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
3710 /* Invalid prefix */
3711 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3715 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3717 /* The OPSIZE prefix toggles the size */
3723 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3724 ULONG SecondValue
, Result
;
3726 if (!Fast486FetchDword(State
, &SecondValue
))
3728 /* Exception occurred */
3732 /* Calculate the result */
3733 Result
= FirstValue
- SecondValue
;
3735 /* Update the flags */
3736 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3737 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3738 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3739 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3740 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3741 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3742 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3744 /* Check if this is not a CMP */
3745 if (!(Opcode
& 0x10))
3747 /* Write back the result */
3748 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3753 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3754 USHORT SecondValue
, Result
;
3756 if (!Fast486FetchWord(State
, &SecondValue
))
3758 /* Exception occurred */
3762 /* Calculate the result */
3763 Result
= FirstValue
- SecondValue
;
3765 /* Update the flags */
3766 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3767 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3768 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3769 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3770 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3771 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3772 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3774 /* Check if this is not a CMP */
3775 if (!(Opcode
& 0x10))
3777 /* Write back the result */
3778 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3785 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3787 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3788 BOOLEAN Carry
= State
->Flags
.Cf
;
3790 /* Clear the carry flag */
3791 State
->Flags
.Cf
= FALSE
;
3793 /* Check if the first BCD digit is invalid or there was a borrow */
3794 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3797 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3798 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3800 /* A borrow occurred */
3801 State
->Flags
.Cf
= TRUE
;
3804 /* Set the adjust flag */
3805 State
->Flags
.Af
= TRUE
;
3808 /* Check if the second BCD digit is invalid or there was a borrow */
3809 if ((Value
> 0x99) || Carry
)
3812 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3814 /* There was a borrow */
3815 State
->Flags
.Cf
= TRUE
;
3821 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3823 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3826 * Check if the value in AL is not a valid BCD digit,
3827 * or there was a carry from the lowest 4 bits of AL
3829 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3832 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3833 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3836 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3840 /* Clear CF and AF */
3841 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3844 /* Keep only the lowest 4 bits of AL */
3845 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3850 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3852 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3855 * Check if the value in AL is not a valid BCD digit,
3856 * or there was a borrow from the lowest 4 bits of AL
3858 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3861 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3862 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3865 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3869 /* Clear CF and AF */
3870 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3873 /* Keep only the lowest 4 bits of AL */
3874 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3879 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3882 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3883 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3885 /* Make sure this is the right instruction */
3886 ASSERT(Opcode
== 0x60);
3888 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3890 /* The OPSIZE prefix toggles the size */
3894 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
3896 /* Invalid prefix */
3897 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3901 /* Push all the registers in order */
3902 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3904 if (i
== FAST486_REG_ESP
)
3906 /* Use the saved ESP instead */
3907 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3909 /* Exception occurred */
3915 /* Push the register */
3916 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3917 : State
->GeneralRegs
[i
].LowWord
))
3919 /* Exception occurred */
3928 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3931 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3934 /* Make sure this is the right instruction */
3935 ASSERT(Opcode
== 0x61);
3937 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
3939 /* The OPSIZE prefix toggles the size */
3943 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
3945 /* Invalid prefix */
3946 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3950 /* Pop all the registers in reverse order */
3951 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3954 if (!Fast486StackPop(State
, &Value
))
3956 /* Exception occurred */
3960 /* Don't modify ESP */
3961 if (i
!= FAST486_REG_ESP
)
3963 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3964 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3971 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3973 // TODO: NOT IMPLEMENTED
3979 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3981 USHORT FirstValue
, SecondValue
;
3982 FAST486_MOD_REG_RM ModRegRm
;
3983 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3985 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3987 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3989 /* Cannot be used in real mode or with a LOCK prefix */
3990 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3994 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
3996 /* The ADSIZE prefix toggles the size */
3997 AddressSize
= !AddressSize
;
4000 /* Get the operands */
4001 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4003 /* Exception occurred */
4007 /* Read the operands */
4008 if (!Fast486ReadModrmWordOperands(State
,
4013 /* Exception occurred */
4017 /* Check if the RPL needs adjusting */
4018 if ((SecondValue
& 3) < (FirstValue
& 3))
4020 /* Adjust the RPL */
4022 SecondValue
|= FirstValue
& 3;
4025 State
->Flags
.Zf
= TRUE
;
4027 /* Write back the result */
4028 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
4033 State
->Flags
.Zf
= FALSE
;
4038 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
4040 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4042 /* Make sure this is the right instruction */
4043 ASSERT(Opcode
== 0x68);
4045 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4047 /* Invalid prefix */
4048 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4052 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4054 /* The OPSIZE prefix toggles the size */
4062 if (!Fast486FetchDword(State
, &Data
))
4064 /* Exception occurred */
4068 /* Call the internal API */
4069 return Fast486StackPush(State
, Data
);
4075 if (!Fast486FetchWord(State
, &Data
))
4077 /* Exception occurred */
4081 /* Call the internal API */
4082 return Fast486StackPush(State
, Data
);
4086 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
4088 BOOLEAN OperandSize
, AddressSize
;
4089 FAST486_MOD_REG_RM ModRegRm
;
4093 /* Make sure this is the right instruction */
4094 ASSERT((Opcode
& 0xFD) == 0x69);
4096 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4098 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4100 /* The ADSIZE prefix toggles the address size */
4101 AddressSize
= !AddressSize
;
4104 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4106 /* The OPSIZE prefix toggles the operand size */
4107 OperandSize
= !OperandSize
;
4110 /* Fetch the parameters */
4111 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4113 /* Exception occurred */
4121 /* Fetch the immediate operand */
4122 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
4124 /* Exception occurred */
4128 Multiplier
= (LONG
)Byte
;
4136 /* Fetch the immediate operand */
4137 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
4139 /* Exception occurred */
4149 /* Fetch the immediate operand */
4150 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
4152 /* Exception occurred */
4156 Multiplier
= (LONG
)Word
;
4162 LONG RegValue
, Multiplicand
;
4164 /* Read the operands */
4165 if (!Fast486ReadModrmDwordOperands(State
,
4168 (PULONG
)&Multiplicand
))
4170 /* Exception occurred */
4175 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
4179 SHORT RegValue
, Multiplicand
;
4181 /* Read the operands */
4182 if (!Fast486ReadModrmWordOperands(State
,
4185 (PUSHORT
)&Multiplicand
))
4187 /* Exception occurred */
4192 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
4195 /* Check for carry/overflow */
4196 if ((Product
< LONG_MIN
) || (Product
> LONG_MAX
))
4198 State
->Flags
.Cf
= State
->Flags
.Of
= TRUE
;
4200 else State
->Flags
.Cf
= State
->Flags
.Of
= FALSE
;
4202 /* Write-back the result */
4203 return Fast486WriteModrmDwordOperands(State
,
4206 (ULONG
)((LONG
)Product
));
4209 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
4213 /* Make sure this is the right instruction */
4214 ASSERT(Opcode
== 0x6A);
4216 if (!Fast486FetchByte(State
, &Data
))
4218 /* Exception occurred */
4222 /* Call the internal API */
4223 return Fast486StackPush(State
, Data
);
4226 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
4228 UCHAR FirstValue
, SecondValue
, Result
;
4229 FAST486_MOD_REG_RM ModRegRm
;
4230 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4232 /* Make sure this is the right instruction */
4233 ASSERT((Opcode
& 0xFD) == 0x88);
4235 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4237 /* The ADSIZE prefix toggles the size */
4238 AddressSize
= !AddressSize
;
4240 else if (State
->PrefixFlags
4241 & ~(FAST486_PREFIX_ADSIZE
4242 | FAST486_PREFIX_SEG
4243 | FAST486_PREFIX_LOCK
))
4245 /* Invalid prefix */
4246 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4250 /* Get the operands */
4251 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4253 /* Exception occurred */
4257 if (!Fast486ReadModrmByteOperands(State
,
4262 /* Exception occurred */
4266 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
4267 else Result
= FirstValue
;
4269 /* Write back the result */
4270 return Fast486WriteModrmByteOperands(State
,
4272 Opcode
& FAST486_OPCODE_WRITE_REG
,
4277 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
4279 FAST486_MOD_REG_RM ModRegRm
;
4280 BOOLEAN OperandSize
, AddressSize
;
4282 /* Make sure this is the right instruction */
4283 ASSERT((Opcode
& 0xFD) == 0x89);
4285 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4287 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4289 /* The ADSIZE prefix toggles the address size */
4290 AddressSize
= !AddressSize
;
4293 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4295 /* The OPSIZE prefix toggles the operand size */
4296 OperandSize
= !OperandSize
;
4299 if (State
->PrefixFlags
4300 & ~(FAST486_PREFIX_ADSIZE
4301 | FAST486_PREFIX_OPSIZE
4302 | FAST486_PREFIX_SEG
4303 | FAST486_PREFIX_LOCK
))
4305 /* Invalid prefix */
4306 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4310 /* Get the operands */
4311 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4313 /* Exception occurred */
4317 /* Check the operand size */
4320 ULONG FirstValue
, SecondValue
, Result
;
4322 if (!Fast486ReadModrmDwordOperands(State
,
4327 /* Exception occurred */
4331 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
4332 else Result
= FirstValue
;
4334 /* Write back the result */
4335 return Fast486WriteModrmDwordOperands(State
,
4337 Opcode
& FAST486_OPCODE_WRITE_REG
,
4342 USHORT FirstValue
, SecondValue
, Result
;
4344 if (!Fast486ReadModrmWordOperands(State
,
4349 /* Exception occurred */
4353 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
4354 else Result
= FirstValue
;
4356 /* Write back the result */
4357 return Fast486WriteModrmWordOperands(State
,
4359 Opcode
& FAST486_OPCODE_WRITE_REG
,
4364 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
4366 BOOLEAN OperandSize
, AddressSize
;
4367 FAST486_MOD_REG_RM ModRegRm
;
4369 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4371 /* Make sure this is the right instruction */
4372 ASSERT(Opcode
== 0x8C);
4374 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4376 /* The ADSIZE prefix toggles the address size */
4377 AddressSize
= !AddressSize
;
4380 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4382 /* The OPSIZE prefix toggles the operand size */
4383 OperandSize
= !OperandSize
;
4386 /* Get the operands */
4387 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4389 /* Exception occurred */
4393 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4396 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4402 return Fast486WriteModrmDwordOperands(State
,
4405 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4409 return Fast486WriteModrmWordOperands(State
,
4412 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4416 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
4418 FAST486_MOD_REG_RM ModRegRm
;
4419 BOOLEAN OperandSize
, AddressSize
;
4421 /* Make sure this is the right instruction */
4422 ASSERT(Opcode
== 0x8D);
4424 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4426 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4428 /* The ADSIZE prefix toggles the address size */
4429 AddressSize
= !AddressSize
;
4432 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4434 /* The OPSIZE prefix toggles the operand size */
4435 OperandSize
= !OperandSize
;
4438 /* Get the operands */
4439 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4441 /* Exception occurred */
4445 /* The second operand must be memory */
4446 if (!ModRegRm
.Memory
)
4449 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4453 /* Write the address to the register */
4456 return Fast486WriteModrmDwordOperands(State
,
4459 ModRegRm
.MemoryAddress
);
4463 return Fast486WriteModrmWordOperands(State
,
4466 ModRegRm
.MemoryAddress
);
4471 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
4473 BOOLEAN OperandSize
, AddressSize
;
4474 FAST486_MOD_REG_RM ModRegRm
;
4476 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4478 /* Make sure this is the right instruction */
4479 ASSERT(Opcode
== 0x8E);
4481 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4483 /* The ADSIZE prefix toggles the address size */
4484 AddressSize
= !AddressSize
;
4487 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4489 /* The OPSIZE prefix toggles the operand size */
4490 OperandSize
= !OperandSize
;
4493 /* Get the operands */
4494 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4496 /* Exception occurred */
4500 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
4501 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
4504 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4510 ULONG Dummy
, Selector
;
4512 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4514 /* Exception occurred */
4518 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4522 USHORT Dummy
, Selector
;
4524 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4526 /* Exception occurred */
4530 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4534 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4536 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4538 /* Make sure this is the right instruction */
4539 ASSERT(Opcode
== 0x98);
4541 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4543 /* The OPSIZE prefix toggles the size */
4547 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4549 /* Invalid prefix */
4550 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4556 /* Sign extend AX to EAX */
4557 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4559 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4560 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4566 /* Sign extend AL to AX */
4567 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4568 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4575 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4577 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4579 /* Make sure this is the right instruction */
4580 ASSERT(Opcode
== 0x99);
4582 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4584 /* The OPSIZE prefix toggles the size */
4588 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4590 /* Invalid prefix */
4591 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4597 /* Sign extend EAX to EDX:EAX */
4598 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4599 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4600 ? 0xFFFFFFFF : 0x00000000;
4604 /* Sign extend AX to DX:AX */
4605 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4606 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4613 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4617 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4619 /* Make sure this is the right instruction */
4620 ASSERT(Opcode
== 0x9A);
4622 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4624 /* The OPSIZE prefix toggles the size */
4628 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4630 /* Invalid prefix */
4631 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4635 /* Fetch the offset */
4638 if (!Fast486FetchDword(State
, &Offset
))
4640 /* Exception occurred */
4646 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4648 /* Exception occurred */
4653 /* Fetch the segment */
4654 if (!Fast486FetchWord(State
, &Segment
))
4656 /* Exception occurred */
4660 /* Push the current code segment selector */
4661 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4663 /* Exception occurred */
4667 /* Push the current value of the instruction pointer */
4668 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4670 /* Exception occurred */
4674 /* Load the new CS */
4675 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4677 /* Exception occurred */
4681 /* Load new (E)IP */
4682 if (Size
) State
->InstPtr
.Long
= Offset
;
4683 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4688 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4690 // TODO: NOT IMPLEMENTED
4696 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4698 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4700 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4702 /* Invalid prefix */
4703 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4707 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4709 /* This OPSIZE prefix toggles the size */
4713 /* Check for VM86 mode when IOPL is not 3 */
4714 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4716 /* Call the VM86 monitor */
4717 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4721 /* Push the flags */
4722 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4723 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4726 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4728 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4729 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4732 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4734 /* Invalid prefix */
4735 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4739 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4741 /* This OPSIZE prefix toggles the size */
4745 /* Pop the new flags */
4746 if (!Fast486StackPop(State
, &NewFlags
))
4748 /* Exception occurred */
4752 if (!State
->Flags
.Vm
)
4754 /* Check the current privilege level */
4762 /* Memorize the old state of RF */
4763 BOOLEAN OldRf
= State
->Flags
.Rf
;
4765 State
->Flags
.Long
= NewFlags
;
4767 /* Restore VM and RF */
4768 State
->Flags
.Vm
= FALSE
;
4769 State
->Flags
.Rf
= OldRf
;
4771 /* Clear VIF and VIP */
4772 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4774 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4776 /* Restore the reserved bits */
4777 State
->Flags
.AlwaysSet
= TRUE
;
4778 State
->Flags
.Reserved0
= FALSE
;
4779 State
->Flags
.Reserved1
= FALSE
;
4785 /* Memorize the old state of IF and IOPL */
4786 BOOLEAN OldIf
= State
->Flags
.If
;
4787 UINT OldIopl
= State
->Flags
.Iopl
;
4792 /* Memorize the old state of RF */
4793 BOOLEAN OldRf
= State
->Flags
.Rf
;
4795 State
->Flags
.Long
= NewFlags
;
4797 /* Restore VM and RF */
4798 State
->Flags
.Vm
= FALSE
;
4799 State
->Flags
.Rf
= OldRf
;
4801 /* Clear VIF and VIP */
4802 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4804 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4806 /* Restore the reserved bits and IOPL */
4807 State
->Flags
.AlwaysSet
= TRUE
;
4808 State
->Flags
.Reserved0
= FALSE
;
4809 State
->Flags
.Reserved1
= FALSE
;
4810 State
->Flags
.Iopl
= OldIopl
;
4812 /* Check if the user doesn't have the privilege to change IF */
4813 if (Cpl
> State
->Flags
.Iopl
)
4816 State
->Flags
.If
= OldIf
;
4822 /* Check the IOPL */
4823 if (State
->Flags
.Iopl
== 3)
4827 /* Memorize the old state of RF, VIF and VIP */
4828 BOOLEAN OldRf
= State
->Flags
.Rf
;
4829 BOOLEAN OldVif
= State
->Flags
.Vif
;
4830 BOOLEAN OldVip
= State
->Flags
.Vip
;
4832 State
->Flags
.Long
= NewFlags
;
4834 /* Restore VM, RF, VIF and VIP */
4835 State
->Flags
.Vm
= TRUE
;
4836 State
->Flags
.Rf
= OldRf
;
4837 State
->Flags
.Vif
= OldVif
;
4838 State
->Flags
.Vip
= OldVip
;
4840 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4842 /* Restore the reserved bits and IOPL */
4843 State
->Flags
.AlwaysSet
= TRUE
;
4844 State
->Flags
.Reserved0
= FALSE
;
4845 State
->Flags
.Reserved1
= FALSE
;
4846 State
->Flags
.Iopl
= 3;
4850 /* Call the VM86 monitor */
4851 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4859 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4861 /* Make sure this is the right instruction */
4862 ASSERT(Opcode
== 0x9E);
4864 /* Set the low-order byte of FLAGS to AH */
4865 State
->Flags
.Long
&= 0xFFFFFF00;
4866 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4868 /* Restore the reserved bits of FLAGS */
4869 State
->Flags
.AlwaysSet
= TRUE
;
4870 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4875 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4877 /* Make sure this is the right instruction */
4878 ASSERT(Opcode
== 0x9F);
4880 /* Set AH to the low-order byte of FLAGS */
4881 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4886 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4888 ULONG ReturnAddress
;
4889 USHORT BytesToPop
= 0;
4890 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4892 /* Make sure this is the right instruction */
4893 ASSERT((Opcode
& 0xFE) == 0xC2);
4895 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
4897 /* Invalid prefix */
4898 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4902 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
4904 /* The OPSIZE prefix toggles the size */
4910 /* Fetch the number of bytes to pop after the return */
4911 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4914 /* Pop the return address */
4915 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4917 /* Return to the calling procedure, and if necessary, pop the parameters */
4920 State
->InstPtr
.Long
= ReturnAddress
;
4921 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4925 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4926 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4932 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4934 UCHAR FarPointer
[6];
4935 BOOLEAN OperandSize
, AddressSize
;
4936 FAST486_MOD_REG_RM ModRegRm
;
4938 /* Make sure this is the right instruction */
4939 ASSERT((Opcode
& 0xFE) == 0xC4);
4941 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4943 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
4945 /* The ADSIZE prefix toggles the size */
4946 AddressSize
= !AddressSize
;
4949 /* Get the operands */
4950 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4952 /* Exception occurred */
4956 if (!ModRegRm
.Memory
)
4958 /* Check if this is a BOP and the host supports BOPs */
4959 if ((Opcode
== 0xC4)
4960 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4961 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4962 && (State
->BopCallback
!= NULL
))
4966 /* Fetch the BOP code */
4967 if (!Fast486FetchWord(State
, &BopCode
))
4969 /* Exception occurred */
4973 /* Call the BOP handler */
4974 State
->BopCallback(State
, BopCode
);
4976 /* Return success */
4981 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4985 if (!Fast486ReadMemory(State
,
4986 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4987 ? State
->SegmentOverride
: FAST486_REG_DS
,
4988 ModRegRm
.MemoryAddress
,
4991 OperandSize
? 6 : 4))
4993 /* Exception occurred */
4999 ULONG Offset
= *((PULONG
)FarPointer
);
5000 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
5002 /* Set the register to the offset */
5003 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
5005 /* Load the segment */
5006 return Fast486LoadSegment(State
,
5008 ? FAST486_REG_ES
: FAST486_REG_DS
,
5013 USHORT Offset
= *((PUSHORT
)FarPointer
);
5014 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
5016 /* Set the register to the offset */
5017 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
5019 /* Load the segment */
5020 return Fast486LoadSegment(State
,
5022 ? FAST486_REG_ES
: FAST486_REG_DS
,
5027 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
5030 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5033 FAST486_REG FramePointer
;
5035 /* Make sure this is the right instruction */
5036 ASSERT(Opcode
== 0xC8);
5038 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5040 /* Invalid prefix */
5041 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5045 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5047 /* The OPSIZE prefix toggles the size */
5051 if (!Fast486FetchWord(State
, &FrameSize
))
5053 /* Exception occurred */
5057 if (!Fast486FetchByte(State
, &NestingLevel
))
5059 /* Exception occurred */
5064 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
5066 /* Exception occurred */
5071 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
5073 /* Set up the nested procedure stacks */
5074 for (i
= 1; i
< NestingLevel
; i
++)
5078 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
5079 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
5083 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
5084 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
5088 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
5090 /* Set EBP to the frame pointer */
5091 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
5093 /* Reserve space for the frame */
5094 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
5095 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
5100 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
5102 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5104 /* Make sure this is the right instruction */
5105 ASSERT(Opcode
== 0xC9);
5107 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5109 /* Invalid prefix */
5110 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5114 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5116 /* The OPSIZE prefix toggles the size */
5122 /* Set the stack pointer (ESP) to the base pointer (EBP) */
5123 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
5125 /* Pop the saved base pointer from the stack */
5126 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
5132 /* Set the stack pointer (SP) to the base pointer (BP) */
5133 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
5135 /* Pop the saved base pointer from the stack */
5136 if (Fast486StackPop(State
, &Value
))
5138 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
5145 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
5149 USHORT BytesToPop
= 0;
5150 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5152 /* Make sure this is the right instruction */
5153 ASSERT((Opcode
& 0xFE) == 0xCA);
5155 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5157 /* The OPSIZE prefix toggles the size */
5161 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5163 /* Invalid prefix */
5164 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5170 /* Fetch the number of bytes to pop after the return */
5171 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
5174 /* Pop the offset */
5175 if (!Fast486StackPop(State
, &Offset
))
5177 /* Exception occurred */
5181 /* Pop the segment */
5182 if (!Fast486StackPop(State
, &Segment
))
5184 /* Exception occurred */
5188 /* Load the new CS */
5189 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5191 /* Exception occurred */
5195 /* Load new (E)IP, and if necessary, pop the parameters */
5198 State
->InstPtr
.Long
= Offset
;
5199 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
5203 State
->InstPtr
.LowWord
= LOWORD(Offset
);
5204 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
5210 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
5213 FAST486_IDT_ENTRY IdtEntry
;
5219 /* This is the INT3 instruction */
5226 /* Fetch the interrupt number */
5227 if (!Fast486FetchByte(State
, &IntNum
))
5229 /* Exception occurred */
5238 /* Don't do anything if OF is cleared */
5239 if (!State
->Flags
.Of
) return TRUE
;
5242 IntNum
= FAST486_EXCEPTION_OF
;
5249 /* Should not happen */
5254 /* Get the interrupt vector */
5255 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
5257 /* Exception occurred */
5261 /* Perform the interrupt */
5262 if (!Fast486InterruptInternal(State
,
5264 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
5267 /* Exception occurred */
5274 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
5277 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
5278 FAST486_FLAGS_REG NewFlags
;
5279 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5281 /* Make sure this is the right instruction */
5282 ASSERT(Opcode
== 0xCF);
5284 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5286 /* Invalid prefix */
5287 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5291 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5293 /* The OPSIZE prefix toggles the size */
5298 if (!Fast486StackPop(State
, &InstPtr
))
5300 /* Exception occurred */
5305 if (!Fast486StackPop(State
, &CodeSel
))
5307 /* Exception occurred */
5312 if (!Fast486StackPop(State
, &NewFlags
.Long
))
5314 /* Exception occurred */
5318 /* Check for protected mode */
5319 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
5321 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
5323 if (State
->Flags
.Vm
)
5325 /* Return from VM86 mode */
5327 /* Check the IOPL */
5328 if (State
->Flags
.Iopl
== 3)
5331 State
->InstPtr
.Long
= LOWORD(InstPtr
);
5334 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
5336 /* Exception occurred */
5340 /* Set the new flags */
5341 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5342 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5343 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
5344 State
->Flags
.Iopl
= 3;
5348 /* Call the VM86 monitor */
5349 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
5356 if (State
->Flags
.Nt
)
5358 /* Nested task return */
5366 /* Return to VM86 mode */
5367 ULONG Es
, Ds
, Fs
, Gs
;
5369 /* Pop ESP, SS, ES, FS, GS */
5370 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
5371 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
5372 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
5373 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
5374 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
5375 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
5377 /* Set the new IP */
5378 State
->InstPtr
.Long
= LOWORD(InstPtr
);
5380 /* Set the new flags */
5381 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5382 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5383 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
5385 /* Load the new segments */
5386 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
5387 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
5388 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
5389 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
5390 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
5391 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
5396 /* Load the new CS */
5397 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
5399 /* Exception occurred */
5404 if (Size
) State
->InstPtr
.Long
= InstPtr
;
5405 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
5407 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5410 if (!Fast486StackPop(State
, &StackPtr
))
5417 if (!Fast486StackPop(State
, &StackSel
))
5424 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
5431 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
5432 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
5435 /* Set the new flags */
5436 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
5437 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
5438 State
->Flags
.AlwaysSet
= TRUE
;
5440 /* Set additional flags */
5441 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
5442 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
5444 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5446 /* Update the CPL */
5447 Cpl
= Fast486GetCurrentPrivLevel(State
);
5449 /* Check segment security */
5450 for (i
= 0; i
<= FAST486_NUM_SEG_REGS
; i
++)
5452 /* Don't check CS or SS */
5453 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
5455 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
5456 && (!State
->SegmentRegs
[i
].Executable
5457 || !State
->SegmentRegs
[i
].DirConf
))
5459 /* Load the NULL descriptor in the segment */
5460 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
5467 if (Size
&& (InstPtr
& 0xFFFF0000))
5470 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
5475 State
->InstPtr
.Long
= InstPtr
;
5478 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
5480 /* Exception occurred */
5484 /* Set the new flags */
5485 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5486 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5487 State
->Flags
.AlwaysSet
= TRUE
;
5493 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
5496 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
5498 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5500 /* Invalid prefix */
5501 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5505 /* Fetch the base */
5506 if (!Fast486FetchByte(State
, &Base
))
5508 /* Exception occurred */
5512 /* Check if the base is zero */
5516 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
5521 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
5522 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
5525 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5526 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5527 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
5532 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
5535 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
5537 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5539 /* Invalid prefix */
5540 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5544 /* Fetch the base */
5545 if (!Fast486FetchByte(State
, &Base
))
5547 /* Exception occurred */
5552 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
5553 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
5556 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5557 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5558 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
5563 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
5566 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5568 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
5570 /* The ADSIZE prefix toggles the size */
5571 AddressSize
= !AddressSize
;
5574 /* Read a byte from DS:[(E)BX + AL] */
5575 if (!Fast486ReadMemory(State
,
5577 AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
5578 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
5579 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5584 /* Exception occurred */
5588 /* Set AL to the result */
5589 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
5591 /* Return success */
5595 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
5598 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5601 /* Make sure this is the right instruction */
5602 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
5604 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5606 /* Invalid prefix */
5607 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5611 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5613 /* The OPSIZE prefix toggles the size */
5617 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
5618 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
5622 /* Additional rule for LOOPNZ */
5623 if (State
->Flags
.Zf
) Condition
= FALSE
;
5628 /* Additional rule for LOOPZ */
5629 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5632 /* Fetch the offset */
5633 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5635 /* An exception occurred */
5641 /* Move the instruction pointer */
5642 State
->InstPtr
.Long
+= Offset
;
5648 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5651 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5654 /* Make sure this is the right instruction */
5655 ASSERT(Opcode
== 0xE3);
5657 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5659 /* Invalid prefix */
5660 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5664 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5666 /* The OPSIZE prefix toggles the size */
5670 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5671 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5673 /* Fetch the offset */
5674 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5676 /* An exception occurred */
5682 /* Move the instruction pointer */
5683 State
->InstPtr
.Long
+= Offset
;
5689 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5691 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5693 /* Make sure this is the right instruction */
5694 ASSERT(Opcode
== 0xE8);
5696 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5698 /* The OPSIZE prefix toggles the size */
5702 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5704 /* Invalid prefix */
5705 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5713 /* Fetch the offset */
5714 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5716 /* An exception occurred */
5720 /* Push the current value of the instruction pointer */
5721 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5723 /* Exception occurred */
5727 /* Move the instruction pointer */
5728 State
->InstPtr
.Long
+= Offset
;
5734 /* Fetch the offset */
5735 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5737 /* An exception occurred */
5741 /* Push the current value of the instruction pointer */
5742 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5744 /* Exception occurred */
5748 /* Move the instruction pointer */
5749 State
->InstPtr
.LowWord
+= Offset
;
5755 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5757 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5759 /* Make sure this is the right instruction */
5760 ASSERT(Opcode
== 0xE9);
5762 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5764 /* The OPSIZE prefix toggles the size */
5768 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5770 /* Invalid prefix */
5771 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5779 /* Fetch the offset */
5780 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5782 /* An exception occurred */
5786 /* Move the instruction pointer */
5787 State
->InstPtr
.Long
+= Offset
;
5793 /* Fetch the offset */
5794 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5796 /* An exception occurred */
5800 /* Move the instruction pointer */
5801 State
->InstPtr
.LowWord
+= Offset
;
5807 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5811 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5813 /* Make sure this is the right instruction */
5814 ASSERT(Opcode
== 0xEA);
5816 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5818 /* The OPSIZE prefix toggles the size */
5822 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
5824 /* Invalid prefix */
5825 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
5829 /* Fetch the offset */
5832 if (!Fast486FetchDword(State
, &Offset
))
5834 /* Exception occurred */
5840 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5842 /* Exception occurred */
5847 /* Fetch the segment */
5848 if (!Fast486FetchWord(State
, &Segment
))
5850 /* Exception occurred */
5854 /* Load the new CS */
5855 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5857 /* Exception occurred */
5861 /* Load new (E)IP */
5862 if (Size
) State
->InstPtr
.Long
= Offset
;
5863 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
5868 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5870 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5873 /* Make sure this is the right instruction */
5874 ASSERT(Opcode
== 0xA0);
5876 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5878 /* The OPSIZE prefix toggles the size */
5884 if (!Fast486FetchDword(State
, &Offset
))
5886 /* Exception occurred */
5894 if (!Fast486FetchWord(State
, &WordOffset
))
5896 /* Exception occurred */
5900 Offset
= (ULONG
)WordOffset
;
5903 /* Read from memory */
5904 return Fast486ReadMemory(State
,
5905 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5906 State
->SegmentOverride
: FAST486_REG_DS
,
5909 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5913 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5915 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5917 /* Make sure this is the right instruction */
5918 ASSERT(Opcode
== 0xA1);
5920 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5922 /* The OPSIZE prefix toggles the size */
5930 if (!Fast486FetchDword(State
, &Offset
))
5932 /* Exception occurred */
5936 /* Read from memory */
5937 return Fast486ReadMemory(State
,
5938 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5939 State
->SegmentOverride
: FAST486_REG_DS
,
5942 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5949 if (!Fast486FetchWord(State
, &Offset
))
5951 /* Exception occurred */
5955 /* Read from memory */
5956 return Fast486ReadMemory(State
,
5957 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5958 State
->SegmentOverride
: FAST486_REG_DS
,
5961 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5966 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5968 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5971 /* Make sure this is the right instruction */
5972 ASSERT(Opcode
== 0xA2);
5974 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
5976 /* The OPSIZE prefix toggles the size */
5982 if (!Fast486FetchDword(State
, &Offset
))
5984 /* Exception occurred */
5992 if (!Fast486FetchWord(State
, &WordOffset
))
5994 /* Exception occurred */
5998 Offset
= (ULONG
)WordOffset
;
6001 /* Write to memory */
6002 return Fast486WriteMemory(State
,
6003 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
6004 State
->SegmentOverride
: FAST486_REG_DS
,
6006 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
6010 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
6012 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6014 /* Make sure this is the right instruction */
6015 ASSERT(Opcode
== 0xA3);
6017 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6019 /* The OPSIZE prefix toggles the size */
6027 if (!Fast486FetchDword(State
, &Offset
))
6029 /* Exception occurred */
6033 /* Write to memory */
6034 return Fast486WriteMemory(State
,
6035 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
6036 State
->SegmentOverride
: FAST486_REG_DS
,
6038 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
6045 if (!Fast486FetchWord(State
, &Offset
))
6047 /* Exception occurred */
6051 /* Write to memory */
6052 return Fast486WriteMemory(State
,
6053 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
6054 State
->SegmentOverride
: FAST486_REG_DS
,
6056 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
6061 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
6063 /* Make sure this is the right instruction */
6064 ASSERT(Opcode
== 0xD6);
6066 if (State
->PrefixFlags
& FAST486_PREFIX_LOCK
)
6068 /* Invalid prefix */
6069 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
6073 /* Set all the bits of AL to CF */
6074 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
6079 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
6081 ULONG Data
, DataSize
;
6082 BOOLEAN OperandSize
, AddressSize
;
6083 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
6085 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6087 /* Make sure this is the right instruction */
6088 ASSERT((Opcode
& 0xFE) == 0xA4);
6090 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6092 /* The OPSIZE prefix toggles the size */
6093 OperandSize
= !OperandSize
;
6096 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6098 /* The ADSIZE prefix toggles the size */
6099 AddressSize
= !AddressSize
;
6102 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6104 /* Use the override segment instead of DS */
6105 Segment
= State
->SegmentOverride
;
6108 /* Calculate the size */
6109 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
6110 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6112 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6114 UCHAR Block
[STRING_BLOCK_SIZE
];
6115 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6116 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6118 /* Clear the memory block */
6119 RtlZeroMemory(Block
, sizeof(Block
));
6121 /* Transfer until finished */
6124 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6126 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
6129 ULONG MaxBytesSrc
= State
->Flags
.Df
6130 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
6131 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
6132 ULONG MaxBytesDest
= State
->Flags
.Df
6133 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6134 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6137 Processed
= min(Processed
, min(MaxBytesSrc
, MaxBytesDest
) / DataSize
);
6138 if (Processed
== 0) Processed
= 1;
6141 if (State
->Flags
.Df
)
6143 /* Reduce ESI and EDI by the number of bytes to transfer */
6146 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
6147 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6151 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
6152 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6156 /* Read from memory */
6157 if (!Fast486ReadMemory(State
,
6159 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6160 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6163 Processed
* DataSize
))
6166 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6167 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6169 /* Exception occurred */
6173 /* Write to memory */
6174 if (!Fast486WriteMemory(State
,
6176 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6177 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6179 Processed
* DataSize
))
6182 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6183 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6185 /* Exception occurred */
6189 if (!State
->Flags
.Df
)
6191 /* Increase ESI and EDI by the number of bytes transfered */
6194 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
6195 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6199 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
6200 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6204 /* Reduce the total count by the number processed in this run */
6209 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6210 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6214 /* Read from the source operand */
6215 if (!Fast486ReadMemory(State
,
6217 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6218 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6223 /* Exception occurred */
6227 /* Write to the destination operand */
6228 if (!Fast486WriteMemory(State
,
6230 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6231 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6235 /* Exception occurred */
6239 /* Increment/decrement ESI and EDI */
6242 if (!State
->Flags
.Df
)
6244 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6245 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6249 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6250 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6255 if (!State
->Flags
.Df
)
6257 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6258 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6262 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6263 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6268 /* Return success */
6272 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
6274 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
6275 ULONG DataSize
, DataMask
, SignFlag
;
6276 BOOLEAN OperandSize
, AddressSize
;
6277 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
6279 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6281 /* Make sure this is the right instruction */
6282 ASSERT((Opcode
& 0xFE) == 0xA6);
6284 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6286 /* The OPSIZE prefix toggles the size */
6287 OperandSize
= !OperandSize
;
6290 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6292 /* The ADSIZE prefix toggles the size */
6293 AddressSize
= !AddressSize
;
6296 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6298 /* Use the override segment instead of DS */
6299 Segment
= State
->SegmentOverride
;
6302 /* Calculate the size */
6303 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
6304 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6306 /* Calculate the mask and sign flag */
6307 DataMask
= (1 << (DataSize
* 8)) - 1;
6308 SignFlag
= 1 << ((DataSize
* 8) - 1);
6310 /* Read from the first source operand */
6311 if (!Fast486ReadMemory(State
,
6313 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6314 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6319 /* Exception occurred */
6323 /* Read from the second source operand */
6324 if (!Fast486ReadMemory(State
,
6326 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6327 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6332 /* Exception occurred */
6336 /* Calculate the result */
6337 FirstValue
&= DataMask
;
6338 SecondValue
&= DataMask
;
6339 Result
= (FirstValue
- SecondValue
) & DataMask
;
6341 /* Update the flags */
6342 State
->Flags
.Cf
= FirstValue
< SecondValue
;
6343 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
6344 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
6345 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
6346 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
6347 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
6348 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
6350 /* Increment/decrement ESI and EDI */
6353 if (!State
->Flags
.Df
)
6355 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6356 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6360 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6361 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6366 if (!State
->Flags
.Df
)
6368 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6369 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6373 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6374 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6378 // FIXME: This method is slow!
6379 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
6380 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
6382 BOOLEAN Repeat
= TRUE
;
6386 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6394 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6401 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6402 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6404 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6410 /* Repeat the instruction */
6411 State
->InstPtr
= State
->SavedInstPtr
;
6415 /* Return success */
6419 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
6422 BOOLEAN OperandSize
, AddressSize
;
6424 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6426 /* Make sure this is the right instruction */
6427 ASSERT((Opcode
& 0xFE) == 0xAA);
6429 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6431 /* The OPSIZE prefix toggles the size */
6432 OperandSize
= !OperandSize
;
6435 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6437 /* The ADSIZE prefix toggles the size */
6438 AddressSize
= !AddressSize
;
6441 /* Calculate the size */
6442 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
6443 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6445 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6447 UCHAR Block
[STRING_BLOCK_SIZE
];
6448 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6449 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6451 /* Fill the memory block with the data */
6452 if (DataSize
== sizeof(UCHAR
))
6454 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
6460 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
6462 if (DataSize
== sizeof(USHORT
))
6464 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
6468 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
6473 /* Transfer until finished */
6476 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6478 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6481 ULONG MaxBytes
= State
->Flags
.Df
6482 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6483 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6485 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6486 if (Processed
== 0) Processed
= 1;
6489 if (State
->Flags
.Df
)
6491 /* Reduce EDI by the number of bytes to transfer */
6492 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6493 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6496 /* Write to memory */
6497 if (!Fast486WriteMemory(State
,
6499 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6500 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6502 Processed
* DataSize
))
6505 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6506 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6508 /* Exception occurred */
6512 if (!State
->Flags
.Df
)
6514 /* Increase EDI by the number of bytes transfered */
6515 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6516 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6519 /* Reduce the total count by the number processed in this run */
6524 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6525 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6529 /* Write to the destination operand */
6530 if (!Fast486WriteMemory(State
,
6532 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6533 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6534 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
6537 /* Exception occurred */
6541 /* Increment/decrement EDI */
6544 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6545 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6549 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6550 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6554 /* Return success */
6558 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
6561 BOOLEAN OperandSize
, AddressSize
;
6562 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
6564 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6566 /* Make sure this is the right instruction */
6567 ASSERT((Opcode
& 0xFE) == 0xAC);
6569 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6571 /* The OPSIZE prefix toggles the size */
6572 OperandSize
= !OperandSize
;
6575 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6577 /* The ADSIZE prefix toggles the size */
6578 AddressSize
= !AddressSize
;
6581 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
6583 /* Use the override segment instead of DS */
6584 Segment
= State
->SegmentOverride
;
6587 /* Calculate the size */
6588 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
6589 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6591 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6593 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6594 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6596 /* If the count is 0, do nothing */
6597 if (Count
== 0) return TRUE
;
6599 /* Only the last entry will be loaded */
6600 if (!State
->Flags
.Df
)
6602 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
6603 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
6607 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
6608 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
6612 /* Read from the source operand */
6613 if (!Fast486ReadMemory(State
,
6615 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6616 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6618 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
6621 /* Exception occurred */
6625 /* Increment/decrement ESI */
6628 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6629 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6633 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6634 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6637 /* Return success */
6641 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
6643 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
6644 ULONG SecondValue
= 0;
6646 ULONG DataSize
, DataMask
, SignFlag
;
6647 BOOLEAN OperandSize
, AddressSize
;
6649 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6651 /* Make sure this is the right instruction */
6652 ASSERT((Opcode
& 0xFE) == 0xAE);
6654 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6656 /* The OPSIZE prefix toggles the size */
6657 OperandSize
= !OperandSize
;
6660 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6662 /* The ADSIZE prefix toggles the size */
6663 AddressSize
= !AddressSize
;
6666 /* Calculate the size */
6667 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
6668 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6670 /* Calculate the mask and sign flag */
6671 DataMask
= (1 << (DataSize
* 8)) - 1;
6672 SignFlag
= 1 << ((DataSize
* 8) - 1);
6674 /* Read from the source operand */
6675 if (!Fast486ReadMemory(State
,
6677 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6678 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6683 /* Exception occurred */
6687 /* Calculate the result */
6688 FirstValue
&= DataMask
;
6689 SecondValue
&= DataMask
;
6690 Result
= (FirstValue
- SecondValue
) & DataMask
;
6692 /* Update the flags */
6693 State
->Flags
.Cf
= FirstValue
< SecondValue
;
6694 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
6695 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
6696 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
6697 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
6698 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
6699 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
6701 /* Increment/decrement EDI */
6704 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6705 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6709 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6710 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6713 // FIXME: This method is slow!
6714 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
6715 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
6717 BOOLEAN Repeat
= TRUE
;
6721 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6729 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6736 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6737 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6739 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6745 /* Repeat the instruction */
6746 State
->InstPtr
= State
->SavedInstPtr
;
6750 /* Return success */
6754 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6757 BOOLEAN OperandSize
, AddressSize
;
6759 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6761 /* Make sure this is the right instruction */
6762 ASSERT((Opcode
& 0xFE) == 0x6C);
6764 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6766 /* The OPSIZE prefix toggles the size */
6767 OperandSize
= !OperandSize
;
6770 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6772 /* The ADSIZE prefix toggles the size */
6773 AddressSize
= !AddressSize
;
6776 /* Calculate the size */
6777 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6778 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6780 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6782 UCHAR Block
[STRING_BLOCK_SIZE
];
6783 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6784 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6786 /* Clear the memory block */
6787 RtlZeroMemory(Block
, sizeof(Block
));
6789 /* Transfer until finished */
6792 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6794 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6797 ULONG MaxBytes
= State
->Flags
.Df
6798 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6799 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6801 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6802 if (Processed
== 0) Processed
= 1;
6805 /* Read from the I/O port */
6806 State
->IoReadCallback(State
,
6807 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6809 Processed
* DataSize
);
6811 if (State
->Flags
.Df
)
6815 /* Reduce EDI by the number of bytes to transfer */
6816 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6817 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6819 /* Reverse the block data */
6820 for (i
= 0; i
< Processed
/ 2; i
++)
6822 /* Swap the values */
6823 for (j
= 0; j
< DataSize
; j
++)
6825 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6826 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6827 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6832 /* Write to memory */
6833 if (!Fast486WriteMemory(State
,
6835 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6836 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6838 Processed
* DataSize
))
6841 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6842 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6844 /* Exception occurred */
6848 if (!State
->Flags
.Df
)
6850 /* Increase EDI by the number of bytes transfered */
6851 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6852 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6855 /* Reduce the total count by the number processed in this run */
6860 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6861 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6867 /* Read from the I/O port */
6868 State
->IoReadCallback(State
,
6869 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6873 /* Write to the destination operand */
6874 if (!Fast486WriteMemory(State
,
6876 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6877 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6881 /* Exception occurred */
6885 /* Increment/decrement EDI */
6888 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6889 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6893 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6894 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6898 /* Return success */
6902 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6905 BOOLEAN OperandSize
, AddressSize
;
6907 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6909 /* Make sure this is the right instruction */
6910 ASSERT((Opcode
& 0xFE) == 0x6E);
6912 if (State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
)
6914 /* The OPSIZE prefix toggles the size */
6915 OperandSize
= !OperandSize
;
6918 if (State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
)
6920 /* The ADSIZE prefix toggles the size */
6921 AddressSize
= !AddressSize
;
6924 /* Calculate the size */
6925 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6926 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6928 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6930 UCHAR Block
[STRING_BLOCK_SIZE
];
6931 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6932 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6934 /* Clear the memory block */
6935 RtlZeroMemory(Block
, sizeof(Block
));
6937 /* Transfer until finished */
6940 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6942 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6945 ULONG MaxBytes
= State
->Flags
.Df
6946 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6947 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6949 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6950 if (Processed
== 0) Processed
= 1;
6953 /* Read from memory */
6954 if (!Fast486ReadMemory(State
,
6956 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6957 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6960 Processed
* DataSize
))
6963 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6964 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6966 /* Exception occurred */
6970 if (State
->Flags
.Df
)
6974 /* Reduce EDI by the number of bytes to transfer */
6975 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6976 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6978 /* Reverse the block data */
6979 for (i
= 0; i
< Processed
/ 2; i
++)
6981 /* Swap the values */
6982 for (j
= 0; j
< DataSize
; j
++)
6984 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6985 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6986 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6991 /* Write to the I/O port */
6992 State
->IoWriteCallback(State
,
6993 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6995 Processed
* DataSize
);
6997 if (!State
->Flags
.Df
)
6999 /* Increase EDI by the number of bytes transfered */
7000 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
7001 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
7004 /* Reduce the total count by the number processed in this run */
7009 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
7010 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
7016 /* Read from the source operand */
7017 if (!Fast486ReadMemory(State
,
7019 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
7020 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
7025 /* Exception occurred */
7029 /* Write to the I/O port */
7030 State
->IoWriteCallback(State
,
7031 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
7035 /* Increment/decrement ESI */
7038 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
7039 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
7043 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
7044 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
7048 /* Return success */