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 *******************************************************************/
35 /* PUBLIC VARIABLES ***********************************************************/
37 FAST486_OPCODE_HANDLER_PROC
38 Fast486OpcodeHandlers
[FAST486_NUM_OPCODE_HANDLERS
] =
40 Fast486OpcodeAddByteModrm
,
41 Fast486OpcodeAddModrm
,
42 Fast486OpcodeAddByteModrm
,
43 Fast486OpcodeAddModrm
,
48 Fast486OpcodeOrByteModrm
,
50 Fast486OpcodeOrByteModrm
,
55 Fast486OpcodeExtended
,
56 Fast486OpcodeAdcByteModrm
,
57 Fast486OpcodeAdcModrm
,
58 Fast486OpcodeAdcByteModrm
,
59 Fast486OpcodeAdcModrm
,
64 Fast486OpcodeSbbByteModrm
,
65 Fast486OpcodeSbbModrm
,
66 Fast486OpcodeSbbByteModrm
,
67 Fast486OpcodeSbbModrm
,
72 Fast486OpcodeAndByteModrm
,
73 Fast486OpcodeAndModrm
,
74 Fast486OpcodeAndByteModrm
,
75 Fast486OpcodeAndModrm
,
80 Fast486OpcodeCmpSubByteModrm
,
81 Fast486OpcodeCmpSubModrm
,
82 Fast486OpcodeCmpSubByteModrm
,
83 Fast486OpcodeCmpSubModrm
,
84 Fast486OpcodeCmpSubAl
,
85 Fast486OpcodeCmpSubEax
,
88 Fast486OpcodeXorByteModrm
,
89 Fast486OpcodeXorModrm
,
90 Fast486OpcodeXorByteModrm
,
91 Fast486OpcodeXorModrm
,
96 Fast486OpcodeCmpSubByteModrm
,
97 Fast486OpcodeCmpSubModrm
,
98 Fast486OpcodeCmpSubByteModrm
,
99 Fast486OpcodeCmpSubModrm
,
100 Fast486OpcodeCmpSubAl
,
101 Fast486OpcodeCmpSubEax
,
104 Fast486OpcodeIncrement
,
105 Fast486OpcodeIncrement
,
106 Fast486OpcodeIncrement
,
107 Fast486OpcodeIncrement
,
108 Fast486OpcodeIncrement
,
109 Fast486OpcodeIncrement
,
110 Fast486OpcodeIncrement
,
111 Fast486OpcodeIncrement
,
112 Fast486OpcodeDecrement
,
113 Fast486OpcodeDecrement
,
114 Fast486OpcodeDecrement
,
115 Fast486OpcodeDecrement
,
116 Fast486OpcodeDecrement
,
117 Fast486OpcodeDecrement
,
118 Fast486OpcodeDecrement
,
119 Fast486OpcodeDecrement
,
120 Fast486OpcodePushReg
,
121 Fast486OpcodePushReg
,
122 Fast486OpcodePushReg
,
123 Fast486OpcodePushReg
,
124 Fast486OpcodePushReg
,
125 Fast486OpcodePushReg
,
126 Fast486OpcodePushReg
,
127 Fast486OpcodePushReg
,
136 Fast486OpcodePushAll
,
144 Fast486OpcodePushImm
,
145 Fast486OpcodeImulModrmImm
,
146 Fast486OpcodePushByteImm
,
147 Fast486OpcodeImulModrmImm
,
152 Fast486OpcodeShortConditionalJmp
,
153 Fast486OpcodeShortConditionalJmp
,
154 Fast486OpcodeShortConditionalJmp
,
155 Fast486OpcodeShortConditionalJmp
,
156 Fast486OpcodeShortConditionalJmp
,
157 Fast486OpcodeShortConditionalJmp
,
158 Fast486OpcodeShortConditionalJmp
,
159 Fast486OpcodeShortConditionalJmp
,
160 Fast486OpcodeShortConditionalJmp
,
161 Fast486OpcodeShortConditionalJmp
,
162 Fast486OpcodeShortConditionalJmp
,
163 Fast486OpcodeShortConditionalJmp
,
164 Fast486OpcodeShortConditionalJmp
,
165 Fast486OpcodeShortConditionalJmp
,
166 Fast486OpcodeShortConditionalJmp
,
167 Fast486OpcodeShortConditionalJmp
,
168 Fast486OpcodeGroup8082
,
169 Fast486OpcodeGroup81
,
170 Fast486OpcodeGroup8082
,
171 Fast486OpcodeGroup83
,
172 Fast486OpcodeTestByteModrm
,
173 Fast486OpcodeTestModrm
,
174 Fast486OpcodeXchgByteModrm
,
175 Fast486OpcodeXchgModrm
,
176 Fast486OpcodeMovByteModrm
,
177 Fast486OpcodeMovModrm
,
178 Fast486OpcodeMovByteModrm
,
179 Fast486OpcodeMovModrm
,
180 Fast486OpcodeMovStoreSeg
,
182 Fast486OpcodeMovLoadSeg
,
183 Fast486OpcodeGroup8F
,
185 Fast486OpcodeExchangeEax
,
186 Fast486OpcodeExchangeEax
,
187 Fast486OpcodeExchangeEax
,
188 Fast486OpcodeExchangeEax
,
189 Fast486OpcodeExchangeEax
,
190 Fast486OpcodeExchangeEax
,
191 Fast486OpcodeExchangeEax
,
194 Fast486OpcodeCallAbs
,
196 Fast486OpcodePushFlags
,
197 Fast486OpcodePopFlags
,
200 Fast486OpcodeMovAlOffset
,
201 Fast486OpcodeMovEaxOffset
,
202 Fast486OpcodeMovOffsetAl
,
203 Fast486OpcodeMovOffsetEax
,
209 Fast486OpcodeTestEax
,
216 Fast486OpcodeMovByteRegImm
,
217 Fast486OpcodeMovByteRegImm
,
218 Fast486OpcodeMovByteRegImm
,
219 Fast486OpcodeMovByteRegImm
,
220 Fast486OpcodeMovByteRegImm
,
221 Fast486OpcodeMovByteRegImm
,
222 Fast486OpcodeMovByteRegImm
,
223 Fast486OpcodeMovByteRegImm
,
224 Fast486OpcodeMovRegImm
,
225 Fast486OpcodeMovRegImm
,
226 Fast486OpcodeMovRegImm
,
227 Fast486OpcodeMovRegImm
,
228 Fast486OpcodeMovRegImm
,
229 Fast486OpcodeMovRegImm
,
230 Fast486OpcodeMovRegImm
,
231 Fast486OpcodeMovRegImm
,
232 Fast486OpcodeGroupC0
,
233 Fast486OpcodeGroupC1
,
238 Fast486OpcodeGroupC6
,
239 Fast486OpcodeGroupC7
,
248 Fast486OpcodeGroupD0
,
249 Fast486OpcodeGroupD1
,
250 Fast486OpcodeGroupD2
,
251 Fast486OpcodeGroupD3
,
256 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
257 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
258 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
259 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
260 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
261 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
262 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
263 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
270 Fast486OpcodeOutByte
,
275 Fast486OpcodeShortJump
,
278 Fast486OpcodeOutByte
,
285 Fast486OpcodeComplCarry
,
286 Fast486OpcodeGroupF6
,
287 Fast486OpcodeGroupF7
,
288 Fast486OpcodeClearCarry
,
289 Fast486OpcodeSetCarry
,
290 Fast486OpcodeClearInt
,
292 Fast486OpcodeClearDir
,
294 Fast486OpcodeGroupFE
,
295 Fast486OpcodeGroupFF
,
298 /* PUBLIC FUNCTIONS ***********************************************************/
300 FAST486_OPCODE_HANDLER(Fast486OpcodePrefix
)
302 BOOLEAN Valid
= FALSE
;
309 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
311 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
312 State
->SegmentOverride
= FAST486_REG_ES
;
322 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
324 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
325 State
->SegmentOverride
= FAST486_REG_CS
;
335 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
337 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
338 State
->SegmentOverride
= FAST486_REG_SS
;
348 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
350 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
351 State
->SegmentOverride
= FAST486_REG_DS
;
361 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
363 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
364 State
->SegmentOverride
= FAST486_REG_FS
;
374 if (!(State
->PrefixFlags
& FAST486_PREFIX_SEG
))
376 State
->PrefixFlags
|= FAST486_PREFIX_SEG
;
377 State
->SegmentOverride
= FAST486_REG_GS
;
387 if (!(State
->PrefixFlags
& FAST486_PREFIX_OPSIZE
))
389 State
->PrefixFlags
|= FAST486_PREFIX_OPSIZE
;
399 if (!(State
->PrefixFlags
& FAST486_PREFIX_ADSIZE
))
401 State
->PrefixFlags
|= FAST486_PREFIX_ADSIZE
;
410 if (!(State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
412 State
->PrefixFlags
|= FAST486_PREFIX_LOCK
;
422 /* Mutually exclusive with REP */
423 if (!(State
->PrefixFlags
424 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
426 State
->PrefixFlags
|= FAST486_PREFIX_REPNZ
;
436 /* Mutually exclusive with REPNZ */
437 if (!(State
->PrefixFlags
438 & (FAST486_PREFIX_REPNZ
| FAST486_PREFIX_REP
)))
440 State
->PrefixFlags
|= FAST486_PREFIX_REP
;
450 /* Clear all prefixes */
451 State
->PrefixFlags
= 0;
453 /* Throw an exception */
454 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
461 FAST486_OPCODE_HANDLER(Fast486OpcodeIncrement
)
464 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
469 /* Make sure this is the right instruction */
470 ASSERT((Opcode
& 0xF8) == 0x40);
474 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
476 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
);
477 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
481 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
483 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
);
484 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
487 State
->Flags
.Zf
= (Value
== 0);
488 State
->Flags
.Af
= ((Value
& 0x0F) == 0);
489 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
495 FAST486_OPCODE_HANDLER(Fast486OpcodeDecrement
)
498 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
503 /* Make sure this is the right instruction */
504 ASSERT((Opcode
& 0xF8) == 0x48);
508 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
510 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1));
511 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_LONG
) != 0);
515 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
517 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1));
518 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_WORD
) != 0);
521 State
->Flags
.Zf
= (Value
== 0);
522 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F);
523 State
->Flags
.Pf
= Fast486CalculateParity(LOBYTE(Value
));
529 FAST486_OPCODE_HANDLER(Fast486OpcodePushReg
)
533 /* Make sure this is the right instruction */
534 ASSERT((Opcode
& 0xF8) == 0x50);
536 /* Call the internal function */
537 return Fast486StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
540 FAST486_OPCODE_HANDLER(Fast486OpcodePopReg
)
543 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_SS
].Size
;
548 /* Make sure this is the right instruction */
549 ASSERT((Opcode
& 0xF8) == 0x58);
551 /* Call the internal function */
552 if (!Fast486StackPop(State
, &Value
)) return FALSE
;
554 /* Store the value */
555 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
556 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
562 FAST486_OPCODE_HANDLER(Fast486OpcodeNop
)
564 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
567 State
->IdleCallback(State
);
573 FAST486_OPCODE_HANDLER(Fast486OpcodeExchangeEax
)
575 INT Reg
= Opcode
& 0x07;
576 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
581 /* Make sure this is the right instruction */
582 ASSERT((Opcode
& 0xF8) == 0x90);
584 /* Exchange the values */
589 Value
= State
->GeneralRegs
[Reg
].Long
;
590 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
591 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Value
;
597 Value
= State
->GeneralRegs
[Reg
].LowWord
;
598 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
599 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
605 FAST486_OPCODE_HANDLER(Fast486OpcodeShortConditionalJmp
)
607 BOOLEAN Jump
= FALSE
;
609 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
611 /* Make sure this is the right instruction */
612 ASSERT((Opcode
& 0xF0) == 0x70);
616 /* Fetch the offset */
617 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
619 /* An exception occurred */
623 switch ((Opcode
& 0x0F) >> 1)
628 Jump
= State
->Flags
.Of
;
635 Jump
= State
->Flags
.Cf
;
642 Jump
= State
->Flags
.Zf
;
649 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
656 Jump
= State
->Flags
.Sf
;
663 Jump
= State
->Flags
.Pf
;
670 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
677 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
684 /* Invert the result */
690 /* Move the instruction pointer */
691 State
->InstPtr
.Long
+= Offset
;
695 /* Clear the top half of EIP */
696 State
->InstPtr
.Long
&= 0xFFFF;
704 FAST486_OPCODE_HANDLER(Fast486OpcodeClearCarry
)
706 /* Make sure this is the right instruction */
707 ASSERT(Opcode
== 0xF8);
709 /* No prefixes allowed */
710 if (State
->PrefixFlags
)
712 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
716 /* Clear CF and return success */
717 State
->Flags
.Cf
= FALSE
;
721 FAST486_OPCODE_HANDLER(Fast486OpcodeSetCarry
)
723 /* Make sure this is the right instruction */
724 ASSERT(Opcode
== 0xF9);
726 /* No prefixes allowed */
727 if (State
->PrefixFlags
)
729 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
733 /* Set CF and return success*/
734 State
->Flags
.Cf
= TRUE
;
738 FAST486_OPCODE_HANDLER(Fast486OpcodeComplCarry
)
740 /* Make sure this is the right instruction */
741 ASSERT(Opcode
== 0xF5);
743 /* No prefixes allowed */
744 if (State
->PrefixFlags
)
746 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
750 /* Toggle CF and return success */
751 State
->Flags
.Cf
= !State
->Flags
.Cf
;
755 FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt
)
757 /* Make sure this is the right instruction */
758 ASSERT(Opcode
== 0xFA);
760 /* No prefixes allowed */
761 if (State
->PrefixFlags
)
763 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
767 /* Check for protected mode */
768 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
771 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
773 /* Clear the interrupt flag */
774 State
->Flags
.If
= FALSE
;
778 /* General Protection Fault */
779 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
785 /* Just clear the interrupt flag */
786 State
->Flags
.If
= FALSE
;
793 FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt
)
795 /* Make sure this is the right instruction */
796 ASSERT(Opcode
== 0xFB);
798 /* No prefixes allowed */
799 if (State
->PrefixFlags
)
801 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
805 /* Check for protected mode */
806 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
809 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[FAST486_REG_CS
].Dpl
)
811 /* Set the interrupt flag */
812 State
->Flags
.If
= TRUE
;
816 /* General Protection Fault */
817 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
823 /* Just set the interrupt flag */
824 State
->Flags
.If
= TRUE
;
831 FAST486_OPCODE_HANDLER(Fast486OpcodeClearDir
)
833 /* Make sure this is the right instruction */
834 ASSERT(Opcode
== 0xFC);
836 /* No prefixes allowed */
837 if (State
->PrefixFlags
)
839 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
843 /* Clear DF and return success */
844 State
->Flags
.Df
= FALSE
;
848 FAST486_OPCODE_HANDLER(Fast486OpcodeSetDir
)
850 /* Make sure this is the right instruction */
851 ASSERT(Opcode
== 0xFD);
853 /* No prefixes allowed */
854 if (State
->PrefixFlags
)
856 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
860 /* Set DF and return success*/
861 State
->Flags
.Df
= TRUE
;
865 FAST486_OPCODE_HANDLER(Fast486OpcodeHalt
)
867 /* Make sure this is the right instruction */
868 ASSERT(Opcode
== 0xF4);
870 /* No prefixes allowed */
871 if (State
->PrefixFlags
)
873 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
877 /* Privileged instructions can only be executed under CPL = 0 */
878 if (State
->SegmentRegs
[FAST486_REG_CS
].Dpl
!= 0)
880 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
885 while (State
->IntStatus
!= FAST486_INT_SIGNAL
) State
->IdleCallback(State
);
891 FAST486_OPCODE_HANDLER(Fast486OpcodeInByte
)
896 /* Make sure this is the right instruction */
897 ASSERT((Opcode
& 0xF7) == 0xE4);
901 /* Fetch the parameter */
902 if (!Fast486FetchByte(State
, &Data
))
904 /* Exception occurred */
908 /* Set the port number to the parameter */
913 /* The port number is in DX */
914 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
917 /* Read a byte from the I/O port */
918 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
920 /* Store the result in AL */
921 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Data
;
926 FAST486_OPCODE_HANDLER(Fast486OpcodeIn
)
929 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
931 /* Make sure this is the right instruction */
932 ASSERT((Opcode
& 0xF7) == 0xE5);
941 /* Fetch the parameter */
942 if (!Fast486FetchByte(State
, &Data
))
944 /* Exception occurred */
948 /* Set the port number to the parameter */
953 /* The port number is in DX */
954 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
961 /* Read a dword from the I/O port */
962 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
964 /* Store the value in EAX */
965 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Data
;
971 /* Read a word from the I/O port */
972 State
->IoReadCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
974 /* Store the value in AX */
975 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Data
;
981 FAST486_OPCODE_HANDLER(Fast486OpcodeOutByte
)
986 /* Make sure this is the right instruction */
987 ASSERT((Opcode
& 0xF7) == 0xE6);
991 /* Fetch the parameter */
992 if (!Fast486FetchByte(State
, &Data
))
994 /* Exception occurred */
998 /* Set the port number to the parameter */
1003 /* The port number is in DX */
1004 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1007 /* Read the value from AL */
1008 Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1010 /* Write the byte to the I/O port */
1011 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(UCHAR
));
1016 FAST486_OPCODE_HANDLER(Fast486OpcodeOut
)
1019 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1021 /* Make sure this is the right instruction */
1022 ASSERT((Opcode
& 0xF7) == 0xE7);
1024 TOGGLE_OPSIZE(Size
);
1031 /* Fetch the parameter */
1032 if (!Fast486FetchByte(State
, &Data
))
1034 /* Exception occurred */
1038 /* Set the port number to the parameter */
1043 /* The port number is in DX */
1044 Port
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
1049 /* Get the value from EAX */
1050 ULONG Data
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1052 /* Write a dword to the I/O port */
1053 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(ULONG
));
1057 /* Get the value from AX */
1058 USHORT Data
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1060 /* Write a word to the I/O port */
1061 State
->IoWriteCallback(State
, Port
, &Data
, 1, sizeof(USHORT
));
1067 FAST486_OPCODE_HANDLER(Fast486OpcodeShortJump
)
1070 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1072 TOGGLE_OPSIZE(Size
);
1074 /* Make sure this is the right instruction */
1075 ASSERT(Opcode
== 0xEB);
1077 /* Fetch the offset */
1078 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
1080 /* An exception occurred */
1084 /* Move the instruction pointer */
1085 State
->InstPtr
.Long
+= Offset
;
1089 /* Clear the top half of EIP */
1090 State
->InstPtr
.Long
&= 0xFFFF;
1096 FAST486_OPCODE_HANDLER(Fast486OpcodeMovRegImm
)
1098 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1100 /* Make sure this is the right instruction */
1101 ASSERT((Opcode
& 0xF8) == 0xB8);
1103 TOGGLE_OPSIZE(Size
);
1110 /* Fetch the dword */
1111 if (!Fast486FetchDword(State
, &Value
))
1113 /* Exception occurred */
1117 /* Store the value in the register */
1118 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1124 /* Fetch the word */
1125 if (!Fast486FetchWord(State
, &Value
))
1127 /* Exception occurred */
1131 /* Store the value in the register */
1132 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1138 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteRegImm
)
1142 /* Make sure this is the right instruction */
1143 ASSERT((Opcode
& 0xF8) == 0xB0);
1145 if (State
->PrefixFlags
!= 0)
1147 /* Invalid prefix */
1148 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1152 /* Fetch the byte */
1153 if (!Fast486FetchByte(State
, &Value
))
1155 /* Exception occurred */
1161 /* AH, CH, DH or BH */
1162 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1166 /* AL, CL, DL or BL */
1167 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1173 FAST486_OPCODE_HANDLER(Fast486OpcodeAddByteModrm
)
1175 UCHAR FirstValue
, SecondValue
, Result
;
1176 FAST486_MOD_REG_RM ModRegRm
;
1177 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1179 /* Make sure this is the right instruction */
1180 ASSERT((Opcode
& 0xFD) == 0x00);
1182 TOGGLE_ADSIZE(AddressSize
);
1184 /* Get the operands */
1185 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1187 /* Exception occurred */
1191 if (!Fast486ReadModrmByteOperands(State
,
1196 /* Exception occurred */
1200 /* Calculate the result */
1201 Result
= FirstValue
+ SecondValue
;
1203 /* Update the flags */
1204 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1205 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1206 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1207 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1208 State
->Flags
.Zf
= (Result
== 0);
1209 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1210 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1212 /* Write back the result */
1213 return Fast486WriteModrmByteOperands(State
,
1215 Opcode
& FAST486_OPCODE_WRITE_REG
,
1219 FAST486_OPCODE_HANDLER(Fast486OpcodeAddModrm
)
1221 FAST486_MOD_REG_RM ModRegRm
;
1222 BOOLEAN OperandSize
, AddressSize
;
1224 /* Make sure this is the right instruction */
1225 ASSERT((Opcode
& 0xFD) == 0x01);
1227 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1229 TOGGLE_ADSIZE(AddressSize
);
1230 TOGGLE_OPSIZE(OperandSize
);
1232 /* Get the operands */
1233 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1235 /* Exception occurred */
1239 /* Check the operand size */
1242 ULONG FirstValue
, SecondValue
, Result
;
1244 if (!Fast486ReadModrmDwordOperands(State
,
1249 /* Exception occurred */
1253 /* Calculate the result */
1254 Result
= FirstValue
+ SecondValue
;
1256 /* Update the flags */
1257 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1258 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1259 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1260 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1261 State
->Flags
.Zf
= (Result
== 0);
1262 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1263 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1265 /* Write back the result */
1266 return Fast486WriteModrmDwordOperands(State
,
1268 Opcode
& FAST486_OPCODE_WRITE_REG
,
1273 USHORT FirstValue
, SecondValue
, Result
;
1275 if (!Fast486ReadModrmWordOperands(State
,
1280 /* Exception occurred */
1284 /* Calculate the result */
1285 Result
= FirstValue
+ SecondValue
;
1287 /* Update the flags */
1288 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1289 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1290 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1291 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1292 State
->Flags
.Zf
= (Result
== 0);
1293 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1294 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1296 /* Write back the result */
1297 return Fast486WriteModrmWordOperands(State
,
1299 Opcode
& FAST486_OPCODE_WRITE_REG
,
1304 FAST486_OPCODE_HANDLER(Fast486OpcodeAddAl
)
1306 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1307 UCHAR SecondValue
, Result
;
1309 /* Make sure this is the right instruction */
1310 ASSERT(Opcode
== 0x04);
1312 if (State
->PrefixFlags
)
1314 /* This opcode doesn't take any prefixes */
1315 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1319 if (!Fast486FetchByte(State
, &SecondValue
))
1321 /* Exception occurred */
1325 /* Calculate the result */
1326 Result
= FirstValue
+ SecondValue
;
1328 /* Update the flags */
1329 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1330 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1331 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1332 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1333 State
->Flags
.Zf
= (Result
== 0);
1334 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1335 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1337 /* Write back the result */
1338 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1343 FAST486_OPCODE_HANDLER(Fast486OpcodeAddEax
)
1345 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1347 /* Make sure this is the right instruction */
1348 ASSERT(Opcode
== 0x05);
1351 TOGGLE_OPSIZE(Size
);
1355 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1356 ULONG SecondValue
, Result
;
1358 if (!Fast486FetchDword(State
, &SecondValue
))
1360 /* Exception occurred */
1364 /* Calculate the result */
1365 Result
= FirstValue
+ SecondValue
;
1367 /* Update the flags */
1368 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1369 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1370 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1371 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1372 State
->Flags
.Zf
= (Result
== 0);
1373 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1374 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1376 /* Write back the result */
1377 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1381 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1382 USHORT SecondValue
, Result
;
1384 if (!Fast486FetchWord(State
, &SecondValue
))
1386 /* Exception occurred */
1390 /* Calculate the result */
1391 Result
= FirstValue
+ SecondValue
;
1393 /* Update the flags */
1394 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1395 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1396 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1397 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
1398 State
->Flags
.Zf
= (Result
== 0);
1399 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1400 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1402 /* Write back the result */
1403 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1409 FAST486_OPCODE_HANDLER(Fast486OpcodeOrByteModrm
)
1411 UCHAR FirstValue
, SecondValue
, Result
;
1412 FAST486_MOD_REG_RM ModRegRm
;
1413 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1415 /* Make sure this is the right instruction */
1416 ASSERT((Opcode
& 0xFD) == 0x08);
1418 TOGGLE_ADSIZE(AddressSize
);
1420 /* Get the operands */
1421 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1423 /* Exception occurred */
1427 if (!Fast486ReadModrmByteOperands(State
,
1432 /* Exception occurred */
1436 /* Calculate the result */
1437 Result
= FirstValue
| SecondValue
;
1439 /* Update the flags */
1440 State
->Flags
.Cf
= FALSE
;
1441 State
->Flags
.Of
= FALSE
;
1442 State
->Flags
.Zf
= (Result
== 0);
1443 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1444 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1446 /* Write back the result */
1447 return Fast486WriteModrmByteOperands(State
,
1449 Opcode
& FAST486_OPCODE_WRITE_REG
,
1453 FAST486_OPCODE_HANDLER(Fast486OpcodeOrModrm
)
1455 FAST486_MOD_REG_RM ModRegRm
;
1456 BOOLEAN OperandSize
, AddressSize
;
1458 /* Make sure this is the right instruction */
1459 ASSERT((Opcode
& 0xFD) == 0x09);
1461 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1463 TOGGLE_ADSIZE(AddressSize
);
1464 TOGGLE_OPSIZE(OperandSize
);
1466 /* Get the operands */
1467 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1469 /* Exception occurred */
1473 /* Check the operand size */
1476 ULONG FirstValue
, SecondValue
, Result
;
1478 if (!Fast486ReadModrmDwordOperands(State
,
1483 /* Exception occurred */
1487 /* Calculate the result */
1488 Result
= FirstValue
| SecondValue
;
1490 /* Update the flags */
1491 State
->Flags
.Cf
= FALSE
;
1492 State
->Flags
.Of
= FALSE
;
1493 State
->Flags
.Zf
= (Result
== 0);
1494 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1495 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1497 /* Write back the result */
1498 return Fast486WriteModrmDwordOperands(State
,
1500 Opcode
& FAST486_OPCODE_WRITE_REG
,
1505 USHORT FirstValue
, SecondValue
, Result
;
1507 if (!Fast486ReadModrmWordOperands(State
,
1512 /* Exception occurred */
1516 /* Calculate the result */
1517 Result
= FirstValue
| SecondValue
;
1519 /* Update the flags */
1520 State
->Flags
.Cf
= FALSE
;
1521 State
->Flags
.Of
= FALSE
;
1522 State
->Flags
.Zf
= (Result
== 0);
1523 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1524 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1526 /* Write back the result */
1527 return Fast486WriteModrmWordOperands(State
,
1529 Opcode
& FAST486_OPCODE_WRITE_REG
,
1534 FAST486_OPCODE_HANDLER(Fast486OpcodeOrAl
)
1536 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1537 UCHAR SecondValue
, Result
;
1539 /* Make sure this is the right instruction */
1540 ASSERT(Opcode
== 0x0C);
1542 if (State
->PrefixFlags
)
1544 /* This opcode doesn't take any prefixes */
1545 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1549 if (!Fast486FetchByte(State
, &SecondValue
))
1551 /* Exception occurred */
1555 /* Calculate the result */
1556 Result
= FirstValue
| SecondValue
;
1558 /* Update the flags */
1559 State
->Flags
.Cf
= FALSE
;
1560 State
->Flags
.Of
= FALSE
;
1561 State
->Flags
.Zf
= (Result
== 0);
1562 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1563 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1565 /* Write back the result */
1566 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1571 FAST486_OPCODE_HANDLER(Fast486OpcodeOrEax
)
1573 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1575 /* Make sure this is the right instruction */
1576 ASSERT(Opcode
== 0x0D);
1579 TOGGLE_OPSIZE(Size
);
1583 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1584 ULONG SecondValue
, Result
;
1586 if (!Fast486FetchDword(State
, &SecondValue
))
1588 /* Exception occurred */
1592 /* Calculate the result */
1593 Result
= FirstValue
| SecondValue
;
1595 /* Update the flags */
1596 State
->Flags
.Cf
= FALSE
;
1597 State
->Flags
.Of
= FALSE
;
1598 State
->Flags
.Zf
= (Result
== 0);
1599 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1600 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1602 /* Write back the result */
1603 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1607 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1608 USHORT SecondValue
, Result
;
1610 if (!Fast486FetchWord(State
, &SecondValue
))
1612 /* Exception occurred */
1616 /* Calculate the result */
1617 Result
= FirstValue
| SecondValue
;
1619 /* Update the flags */
1620 State
->Flags
.Cf
= FALSE
;
1621 State
->Flags
.Of
= FALSE
;
1622 State
->Flags
.Zf
= (Result
== 0);
1623 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1624 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1626 /* Write back the result */
1627 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1633 FAST486_OPCODE_HANDLER(Fast486OpcodeAndByteModrm
)
1635 UCHAR FirstValue
, SecondValue
, Result
;
1636 FAST486_MOD_REG_RM ModRegRm
;
1637 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1639 /* Make sure this is the right instruction */
1640 ASSERT((Opcode
& 0xFD) == 0x20);
1642 TOGGLE_ADSIZE(AddressSize
);
1644 /* Get the operands */
1645 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1647 /* Exception occurred */
1651 if (!Fast486ReadModrmByteOperands(State
,
1656 /* Exception occurred */
1660 /* Calculate the result */
1661 Result
= FirstValue
& SecondValue
;
1663 /* Update the flags */
1664 State
->Flags
.Cf
= FALSE
;
1665 State
->Flags
.Of
= FALSE
;
1666 State
->Flags
.Zf
= (Result
== 0);
1667 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1668 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1670 /* Write back the result */
1671 return Fast486WriteModrmByteOperands(State
,
1673 Opcode
& FAST486_OPCODE_WRITE_REG
,
1677 FAST486_OPCODE_HANDLER(Fast486OpcodeAndModrm
)
1679 FAST486_MOD_REG_RM ModRegRm
;
1680 BOOLEAN OperandSize
, AddressSize
;
1682 /* Make sure this is the right instruction */
1683 ASSERT((Opcode
& 0xFD) == 0x21);
1685 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1687 TOGGLE_ADSIZE(AddressSize
);
1688 TOGGLE_OPSIZE(OperandSize
);
1690 /* Get the operands */
1691 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1693 /* Exception occurred */
1697 /* Check the operand size */
1700 ULONG FirstValue
, SecondValue
, Result
;
1702 if (!Fast486ReadModrmDwordOperands(State
,
1707 /* Exception occurred */
1711 /* Calculate the result */
1712 Result
= FirstValue
& SecondValue
;
1714 /* Update the flags */
1715 State
->Flags
.Cf
= FALSE
;
1716 State
->Flags
.Of
= FALSE
;
1717 State
->Flags
.Zf
= (Result
== 0);
1718 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1719 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1721 /* Write back the result */
1722 return Fast486WriteModrmDwordOperands(State
,
1724 Opcode
& FAST486_OPCODE_WRITE_REG
,
1729 USHORT FirstValue
, SecondValue
, Result
;
1731 if (!Fast486ReadModrmWordOperands(State
,
1736 /* Exception occurred */
1740 /* Calculate the result */
1741 Result
= FirstValue
& SecondValue
;
1743 /* Update the flags */
1744 State
->Flags
.Cf
= FALSE
;
1745 State
->Flags
.Of
= FALSE
;
1746 State
->Flags
.Zf
= (Result
== 0);
1747 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1748 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1750 /* Write back the result */
1751 return Fast486WriteModrmWordOperands(State
,
1753 Opcode
& FAST486_OPCODE_WRITE_REG
,
1758 FAST486_OPCODE_HANDLER(Fast486OpcodeAndAl
)
1760 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1761 UCHAR SecondValue
, Result
;
1763 /* Make sure this is the right instruction */
1764 ASSERT(Opcode
== 0x24);
1768 if (!Fast486FetchByte(State
, &SecondValue
))
1770 /* Exception occurred */
1774 /* Calculate the result */
1775 Result
= FirstValue
& SecondValue
;
1777 /* Update the flags */
1778 State
->Flags
.Cf
= FALSE
;
1779 State
->Flags
.Of
= FALSE
;
1780 State
->Flags
.Zf
= (Result
== 0);
1781 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1782 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1784 /* Write back the result */
1785 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
1790 FAST486_OPCODE_HANDLER(Fast486OpcodeAndEax
)
1792 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1794 /* Make sure this is the right instruction */
1795 ASSERT(Opcode
== 0x25);
1798 TOGGLE_OPSIZE(Size
);
1802 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
1803 ULONG SecondValue
, Result
;
1805 if (!Fast486FetchDword(State
, &SecondValue
))
1807 /* Exception occurred */
1811 /* Calculate the result */
1812 Result
= FirstValue
& SecondValue
;
1814 /* Update the flags */
1815 State
->Flags
.Cf
= FALSE
;
1816 State
->Flags
.Of
= FALSE
;
1817 State
->Flags
.Zf
= (Result
== 0);
1818 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1819 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1821 /* Write back the result */
1822 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
1826 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
1827 USHORT SecondValue
, Result
;
1829 if (!Fast486FetchWord(State
, &SecondValue
))
1831 /* Exception occurred */
1835 /* Calculate the result */
1836 Result
= FirstValue
& SecondValue
;
1838 /* Update the flags */
1839 State
->Flags
.Cf
= FALSE
;
1840 State
->Flags
.Of
= FALSE
;
1841 State
->Flags
.Zf
= (Result
== 0);
1842 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1843 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1845 /* Write back the result */
1846 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
1852 FAST486_OPCODE_HANDLER(Fast486OpcodeXorByteModrm
)
1854 UCHAR FirstValue
, SecondValue
, Result
;
1855 FAST486_MOD_REG_RM ModRegRm
;
1856 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1858 /* Make sure this is the right instruction */
1859 ASSERT((Opcode
& 0xFD) == 0x30);
1861 TOGGLE_ADSIZE(AddressSize
);
1863 /* Get the operands */
1864 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1866 /* Exception occurred */
1870 if (!Fast486ReadModrmByteOperands(State
,
1875 /* Exception occurred */
1879 /* Calculate the result */
1880 Result
= FirstValue
^ SecondValue
;
1882 /* Update the flags */
1883 State
->Flags
.Cf
= FALSE
;
1884 State
->Flags
.Of
= FALSE
;
1885 State
->Flags
.Zf
= (Result
== 0);
1886 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
1887 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1889 /* Write back the result */
1890 return Fast486WriteModrmByteOperands(State
,
1892 Opcode
& FAST486_OPCODE_WRITE_REG
,
1896 FAST486_OPCODE_HANDLER(Fast486OpcodeXorModrm
)
1898 FAST486_MOD_REG_RM ModRegRm
;
1899 BOOLEAN OperandSize
, AddressSize
;
1901 /* Make sure this is the right instruction */
1902 ASSERT((Opcode
& 0xFD) == 0x31);
1904 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
1906 TOGGLE_ADSIZE(AddressSize
);
1907 TOGGLE_OPSIZE(OperandSize
);
1909 /* Get the operands */
1910 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1912 /* Exception occurred */
1916 /* Check the operand size */
1919 ULONG FirstValue
, SecondValue
, Result
;
1921 if (!Fast486ReadModrmDwordOperands(State
,
1926 /* Exception occurred */
1930 /* Calculate the result */
1931 Result
= FirstValue
^ SecondValue
;
1933 /* Update the flags */
1934 State
->Flags
.Cf
= FALSE
;
1935 State
->Flags
.Of
= FALSE
;
1936 State
->Flags
.Zf
= (Result
== 0);
1937 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
1938 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1940 /* Write back the result */
1941 return Fast486WriteModrmDwordOperands(State
,
1943 Opcode
& FAST486_OPCODE_WRITE_REG
,
1948 USHORT FirstValue
, SecondValue
, Result
;
1950 if (!Fast486ReadModrmWordOperands(State
,
1955 /* Exception occurred */
1959 /* Calculate the result */
1960 Result
= FirstValue
^ SecondValue
;
1962 /* Update the flags */
1963 State
->Flags
.Cf
= FALSE
;
1964 State
->Flags
.Of
= FALSE
;
1965 State
->Flags
.Zf
= (Result
== 0);
1966 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
1967 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
1969 /* Write back the result */
1970 return Fast486WriteModrmWordOperands(State
,
1972 Opcode
& FAST486_OPCODE_WRITE_REG
,
1977 FAST486_OPCODE_HANDLER(Fast486OpcodeXorAl
)
1979 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
1980 UCHAR SecondValue
, Result
;
1982 /* Make sure this is the right instruction */
1983 ASSERT(Opcode
== 0x34);
1985 if (State
->PrefixFlags
)
1987 /* This opcode doesn't take any prefixes */
1988 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
1992 if (!Fast486FetchByte(State
, &SecondValue
))
1994 /* Exception occurred */
1998 /* Calculate the result */
1999 Result
= FirstValue
^ SecondValue
;
2001 /* Update the flags */
2002 State
->Flags
.Cf
= FALSE
;
2003 State
->Flags
.Of
= FALSE
;
2004 State
->Flags
.Zf
= (Result
== 0);
2005 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2006 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2008 /* Write back the result */
2009 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2014 FAST486_OPCODE_HANDLER(Fast486OpcodeXorEax
)
2016 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2018 /* Make sure this is the right instruction */
2019 ASSERT(Opcode
== 0x35);
2022 TOGGLE_OPSIZE(Size
);
2026 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2027 ULONG SecondValue
, Result
;
2029 if (!Fast486FetchDword(State
, &SecondValue
))
2031 /* Exception occurred */
2035 /* Calculate the result */
2036 Result
= FirstValue
^ SecondValue
;
2038 /* Update the flags */
2039 State
->Flags
.Cf
= FALSE
;
2040 State
->Flags
.Of
= FALSE
;
2041 State
->Flags
.Zf
= (Result
== 0);
2042 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2043 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2045 /* Write back the result */
2046 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2050 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2051 USHORT SecondValue
, Result
;
2053 if (!Fast486FetchWord(State
, &SecondValue
))
2055 /* Exception occurred */
2059 /* Calculate the result */
2060 Result
= FirstValue
^ SecondValue
;
2062 /* Update the flags */
2063 State
->Flags
.Cf
= FALSE
;
2064 State
->Flags
.Of
= FALSE
;
2065 State
->Flags
.Zf
= (Result
== 0);
2066 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2067 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2069 /* Write back the result */
2070 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2076 FAST486_OPCODE_HANDLER(Fast486OpcodeTestByteModrm
)
2078 UCHAR FirstValue
, SecondValue
, Result
;
2079 FAST486_MOD_REG_RM ModRegRm
;
2080 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2082 /* Make sure this is the right instruction */
2083 ASSERT(Opcode
== 0x84);
2085 TOGGLE_ADSIZE(AddressSize
);
2087 /* Get the operands */
2088 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2090 /* Exception occurred */
2094 if (!Fast486ReadModrmByteOperands(State
,
2099 /* Exception occurred */
2102 /* Calculate the result */
2103 Result
= FirstValue
& SecondValue
;
2105 /* Update the flags */
2106 State
->Flags
.Cf
= FALSE
;
2107 State
->Flags
.Of
= FALSE
;
2108 State
->Flags
.Zf
= (Result
== 0);
2109 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2110 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2112 /* The result is discarded */
2116 FAST486_OPCODE_HANDLER(Fast486OpcodeTestModrm
)
2118 FAST486_MOD_REG_RM ModRegRm
;
2119 BOOLEAN OperandSize
, AddressSize
;
2121 /* Make sure this is the right instruction */
2122 ASSERT(Opcode
== 0x85);
2124 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2126 TOGGLE_ADSIZE(AddressSize
);
2127 TOGGLE_OPSIZE(OperandSize
);
2129 /* Get the operands */
2130 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2132 /* Exception occurred */
2136 /* Check the operand size */
2139 ULONG FirstValue
, SecondValue
, Result
;
2141 if (!Fast486ReadModrmDwordOperands(State
,
2146 /* Exception occurred */
2150 /* Calculate the result */
2151 Result
= FirstValue
& SecondValue
;
2153 /* Update the flags */
2154 State
->Flags
.Cf
= FALSE
;
2155 State
->Flags
.Of
= FALSE
;
2156 State
->Flags
.Zf
= (Result
== 0);
2157 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2158 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2162 USHORT FirstValue
, SecondValue
, Result
;
2164 if (!Fast486ReadModrmWordOperands(State
,
2169 /* Exception occurred */
2173 /* Calculate the result */
2174 Result
= FirstValue
& SecondValue
;
2176 /* Update the flags */
2177 State
->Flags
.Cf
= FALSE
;
2178 State
->Flags
.Of
= FALSE
;
2179 State
->Flags
.Zf
= (Result
== 0);
2180 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2181 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2184 /* The result is discarded */
2188 FAST486_OPCODE_HANDLER(Fast486OpcodeTestAl
)
2190 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2191 UCHAR SecondValue
, Result
;
2193 /* Make sure this is the right instruction */
2194 ASSERT(Opcode
== 0xA8);
2196 if (State
->PrefixFlags
)
2198 /* This opcode doesn't take any prefixes */
2199 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2203 if (!Fast486FetchByte(State
, &SecondValue
))
2205 /* Exception occurred */
2209 /* Calculate the result */
2210 Result
= FirstValue
& SecondValue
;
2212 /* Update the flags */
2213 State
->Flags
.Cf
= FALSE
;
2214 State
->Flags
.Of
= FALSE
;
2215 State
->Flags
.Zf
= (Result
== 0);
2216 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2217 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2219 /* The result is discarded */
2223 FAST486_OPCODE_HANDLER(Fast486OpcodeTestEax
)
2225 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2227 /* Make sure this is the right instruction */
2228 ASSERT(Opcode
== 0xA9);
2231 TOGGLE_OPSIZE(Size
);
2235 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2236 ULONG SecondValue
, Result
;
2238 if (!Fast486FetchDword(State
, &SecondValue
))
2240 /* Exception occurred */
2244 /* Calculate the result */
2245 Result
= FirstValue
& SecondValue
;
2247 /* Update the flags */
2248 State
->Flags
.Cf
= FALSE
;
2249 State
->Flags
.Of
= FALSE
;
2250 State
->Flags
.Zf
= (Result
== 0);
2251 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2252 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2256 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2257 USHORT SecondValue
, Result
;
2259 if (!Fast486FetchWord(State
, &SecondValue
))
2261 /* Exception occurred */
2265 /* Calculate the result */
2266 Result
= FirstValue
& SecondValue
;
2268 /* Update the flags */
2269 State
->Flags
.Cf
= FALSE
;
2270 State
->Flags
.Of
= FALSE
;
2271 State
->Flags
.Zf
= (Result
== 0);
2272 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2273 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2276 /* The result is discarded */
2280 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgByteModrm
)
2282 UCHAR FirstValue
, SecondValue
;
2283 FAST486_MOD_REG_RM ModRegRm
;
2284 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2286 /* Make sure this is the right instruction */
2287 ASSERT(Opcode
== 0x86);
2289 TOGGLE_ADSIZE(AddressSize
);
2291 /* Get the operands */
2292 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2294 /* Exception occurred */
2298 if (!Fast486ReadModrmByteOperands(State
,
2303 /* Exception occurred */
2307 /* Write the value from the register to the R/M */
2308 if (!Fast486WriteModrmByteOperands(State
,
2313 /* Exception occurred */
2317 /* Write the value from the R/M to the register */
2318 if (!Fast486WriteModrmByteOperands(State
,
2323 /* Exception occurred */
2330 FAST486_OPCODE_HANDLER(Fast486OpcodeXchgModrm
)
2332 FAST486_MOD_REG_RM ModRegRm
;
2333 BOOLEAN OperandSize
, AddressSize
;
2335 /* Make sure this is the right instruction */
2336 ASSERT(Opcode
== 0x87);
2338 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2340 TOGGLE_ADSIZE(AddressSize
);
2341 TOGGLE_OPSIZE(OperandSize
);
2343 /* Get the operands */
2344 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2346 /* Exception occurred */
2350 /* Check the operand size */
2353 ULONG FirstValue
, SecondValue
;
2355 if (!Fast486ReadModrmDwordOperands(State
,
2360 /* Exception occurred */
2364 /* Write the value from the register to the R/M */
2365 if (!Fast486WriteModrmDwordOperands(State
,
2370 /* Exception occurred */
2374 /* Write the value from the R/M to the register */
2375 if (!Fast486WriteModrmDwordOperands(State
,
2380 /* Exception occurred */
2386 USHORT FirstValue
, SecondValue
;
2388 if (!Fast486ReadModrmWordOperands(State
,
2393 /* Exception occurred */
2397 /* Write the value from the register to the R/M */
2398 if (!Fast486WriteModrmWordOperands(State
,
2403 /* Exception occurred */
2407 /* Write the value from the R/M to the register */
2408 if (!Fast486WriteModrmWordOperands(State
,
2413 /* Exception occurred */
2418 /* The result is discarded */
2422 FAST486_OPCODE_HANDLER(Fast486OpcodePushEs
)
2424 /* Call the internal API */
2425 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
);
2428 FAST486_OPCODE_HANDLER(Fast486OpcodePopEs
)
2432 if (!Fast486StackPop(State
, &NewSelector
))
2434 /* Exception occurred */
2438 /* Call the internal API */
2439 return Fast486LoadSegment(State
, FAST486_REG_ES
, LOWORD(NewSelector
));
2442 FAST486_OPCODE_HANDLER(Fast486OpcodePushCs
)
2444 /* Call the internal API */
2445 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
);
2448 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcByteModrm
)
2450 UCHAR FirstValue
, SecondValue
, Result
;
2451 FAST486_MOD_REG_RM ModRegRm
;
2452 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2454 /* Make sure this is the right instruction */
2455 ASSERT((Opcode
& 0xFD) == 0x10);
2457 TOGGLE_ADSIZE(AddressSize
);
2459 /* Get the operands */
2460 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2462 /* Exception occurred */
2466 if (!Fast486ReadModrmByteOperands(State
,
2471 /* Exception occurred */
2475 /* Calculate the result */
2476 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2478 /* Special exception for CF */
2479 State
->Flags
.Cf
= State
->Flags
.Cf
2480 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2482 /* Update the flags */
2483 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2484 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2485 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2486 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2487 State
->Flags
.Zf
= (Result
== 0);
2488 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2489 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2491 /* Write back the result */
2492 return Fast486WriteModrmByteOperands(State
,
2494 Opcode
& FAST486_OPCODE_WRITE_REG
,
2498 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcModrm
)
2500 FAST486_MOD_REG_RM ModRegRm
;
2501 BOOLEAN OperandSize
, AddressSize
;
2503 /* Make sure this is the right instruction */
2504 ASSERT((Opcode
& 0xFD) == 0x11);
2506 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2508 TOGGLE_ADSIZE(AddressSize
);
2509 TOGGLE_OPSIZE(OperandSize
);
2511 /* Get the operands */
2512 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2514 /* Exception occurred */
2518 /* Check the operand size */
2521 ULONG FirstValue
, SecondValue
, Result
;
2523 if (!Fast486ReadModrmDwordOperands(State
,
2528 /* Exception occurred */
2532 /* Calculate the result */
2533 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2535 /* Special exception for CF */
2536 State
->Flags
.Cf
= State
->Flags
.Cf
2537 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2539 /* Update the flags */
2540 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2541 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2542 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2543 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2544 State
->Flags
.Zf
= (Result
== 0);
2545 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2546 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2548 /* Write back the result */
2549 return Fast486WriteModrmDwordOperands(State
,
2551 Opcode
& FAST486_OPCODE_WRITE_REG
,
2556 USHORT FirstValue
, SecondValue
, Result
;
2558 if (!Fast486ReadModrmWordOperands(State
,
2563 /* Exception occurred */
2567 /* Calculate the result */
2568 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2570 /* Special exception for CF */
2571 State
->Flags
.Cf
= State
->Flags
.Cf
2572 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2574 /* Update the flags */
2575 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2576 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2577 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2578 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2579 State
->Flags
.Zf
= (Result
== 0);
2580 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2581 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2583 /* Write back the result */
2584 return Fast486WriteModrmWordOperands(State
,
2586 Opcode
& FAST486_OPCODE_WRITE_REG
,
2592 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcAl
)
2594 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2595 UCHAR SecondValue
, Result
;
2597 /* Make sure this is the right instruction */
2598 ASSERT(Opcode
== 0x14);
2600 if (State
->PrefixFlags
)
2602 /* This opcode doesn't take any prefixes */
2603 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2607 if (!Fast486FetchByte(State
, &SecondValue
))
2609 /* Exception occurred */
2613 /* Calculate the result */
2614 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2616 /* Special exception for CF */
2617 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2618 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2620 /* Update the flags */
2621 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2622 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2623 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2624 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2625 State
->Flags
.Zf
= (Result
== 0);
2626 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2627 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2629 /* Write back the result */
2630 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2635 FAST486_OPCODE_HANDLER(Fast486OpcodeAdcEax
)
2637 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2639 /* Make sure this is the right instruction */
2640 ASSERT(Opcode
== 0x15);
2643 TOGGLE_OPSIZE(Size
);
2647 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2648 ULONG SecondValue
, Result
;
2650 if (!Fast486FetchDword(State
, &SecondValue
))
2652 /* Exception occurred */
2656 /* Calculate the result */
2657 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2659 /* Special exception for CF */
2660 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2661 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2663 /* Update the flags */
2664 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2665 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2666 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2667 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2668 State
->Flags
.Zf
= (Result
== 0);
2669 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2670 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2672 /* Write back the result */
2673 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2677 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2678 USHORT SecondValue
, Result
;
2680 if (!Fast486FetchWord(State
, &SecondValue
))
2682 /* Exception occurred */
2686 /* Calculate the result */
2687 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2689 /* Special exception for CF */
2690 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2691 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2693 /* Update the flags */
2694 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2695 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2696 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2697 State
->Flags
.Af
= ((((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) != 0);
2698 State
->Flags
.Zf
= (Result
== 0);
2699 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2700 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2702 /* Write back the result */
2703 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2709 FAST486_OPCODE_HANDLER(Fast486OpcodePushSs
)
2711 /* Call the internal API */
2712 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_SS
].Selector
);
2715 FAST486_OPCODE_HANDLER(Fast486OpcodePopSs
)
2719 if (!Fast486StackPop(State
, &NewSelector
))
2721 /* Exception occurred */
2725 /* Call the internal API */
2726 return Fast486LoadSegment(State
, FAST486_REG_SS
, LOWORD(NewSelector
));
2729 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm
)
2731 UCHAR FirstValue
, SecondValue
, Result
;
2732 FAST486_MOD_REG_RM ModRegRm
;
2733 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2734 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2736 /* Make sure this is the right instruction */
2737 ASSERT((Opcode
& 0xFD) == 0x18);
2739 TOGGLE_ADSIZE(AddressSize
);
2741 /* Get the operands */
2742 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2744 /* Exception occurred */
2748 if (!Fast486ReadModrmByteOperands(State
,
2753 /* Exception occurred */
2757 /* Check if this is the instruction that writes to R/M */
2758 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2760 /* Swap the order */
2761 SWAP(FirstValue
, SecondValue
);
2764 /* Calculate the result */
2765 Result
= FirstValue
- SecondValue
- Carry
;
2767 /* Update the flags */
2768 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ 1);
2769 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2770 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2771 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2772 State
->Flags
.Zf
= (Result
== 0);
2773 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2774 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2776 /* Write back the result */
2777 return Fast486WriteModrmByteOperands(State
,
2779 Opcode
& FAST486_OPCODE_WRITE_REG
,
2783 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbModrm
)
2785 FAST486_MOD_REG_RM ModRegRm
;
2786 BOOLEAN OperandSize
, AddressSize
;
2787 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2789 /* Make sure this is the right instruction */
2790 ASSERT((Opcode
& 0xFD) == 0x19);
2792 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2794 TOGGLE_ADSIZE(AddressSize
);
2795 TOGGLE_OPSIZE(OperandSize
);
2797 /* Get the operands */
2798 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2800 /* Exception occurred */
2804 /* Check the operand size */
2807 ULONG FirstValue
, SecondValue
, Result
;
2809 if (!Fast486ReadModrmDwordOperands(State
,
2814 /* Exception occurred */
2818 /* Check if this is the instruction that writes to R/M */
2819 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2821 /* Swap the order */
2822 SWAP(FirstValue
, SecondValue
);
2825 /* Calculate the result */
2826 Result
= FirstValue
- SecondValue
- Carry
;
2828 /* Update the flags */
2829 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2830 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2831 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2832 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2833 State
->Flags
.Zf
= (Result
== 0);
2834 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2835 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2837 /* Write back the result */
2838 return Fast486WriteModrmDwordOperands(State
,
2840 Opcode
& FAST486_OPCODE_WRITE_REG
,
2845 USHORT FirstValue
, SecondValue
, Result
;
2847 if (!Fast486ReadModrmWordOperands(State
,
2852 /* Exception occurred */
2856 /* Check if this is the instruction that writes to R/M */
2857 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
2859 /* Swap the order */
2860 SWAP(FirstValue
, SecondValue
);
2863 /* Calculate the result */
2864 Result
= FirstValue
- SecondValue
- Carry
;
2866 /* Update the flags */
2867 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2868 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2869 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2870 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2871 State
->Flags
.Zf
= (Result
== 0);
2872 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2873 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2875 /* Write back the result */
2876 return Fast486WriteModrmWordOperands(State
,
2878 Opcode
& FAST486_OPCODE_WRITE_REG
,
2883 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbAl
)
2885 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
2886 UCHAR SecondValue
, Result
;
2887 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2889 /* Make sure this is the right instruction */
2890 ASSERT(Opcode
== 0x1C);
2892 if (State
->PrefixFlags
)
2894 /* This opcode doesn't take any prefixes */
2895 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
2899 if (!Fast486FetchByte(State
, &SecondValue
))
2901 /* Exception occurred */
2905 /* Calculate the result */
2906 Result
= FirstValue
- SecondValue
- Carry
;
2908 /* Update the flags */
2909 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2910 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
2911 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2912 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
2913 State
->Flags
.Zf
= (Result
== 0);
2914 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
2915 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2917 /* Write back the result */
2918 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
2924 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbEax
)
2926 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
2927 INT Carry
= State
->Flags
.Cf
? 1 : 0;
2929 /* Make sure this is the right instruction */
2930 ASSERT(Opcode
== 0x1D);
2933 TOGGLE_OPSIZE(Size
);
2937 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
2938 ULONG SecondValue
, Result
;
2940 if (!Fast486FetchDword(State
, &SecondValue
))
2942 /* Exception occurred */
2946 /* Calculate the result */
2947 Result
= FirstValue
- SecondValue
- Carry
;
2949 /* Update the flags */
2950 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2951 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
2952 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2953 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
2954 State
->Flags
.Zf
= (Result
== 0);
2955 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
2956 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2958 /* Write back the result */
2959 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
2963 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
2964 USHORT SecondValue
, Result
;
2966 if (!Fast486FetchWord(State
, &SecondValue
))
2968 /* Exception occurred */
2972 /* Calculate the result */
2973 Result
= FirstValue
- SecondValue
- Carry
;
2975 /* Update the flags */
2976 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
2977 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
2978 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2979 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
2980 State
->Flags
.Zf
= (Result
== 0);
2981 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
2982 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
2984 /* Write back the result */
2985 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
2992 FAST486_OPCODE_HANDLER(Fast486OpcodePushDs
)
2994 /* Call the internal API */
2995 return Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
);
2998 FAST486_OPCODE_HANDLER(Fast486OpcodePopDs
)
3002 if (!Fast486StackPop(State
, &NewSelector
))
3004 /* Exception occurred */
3008 /* Call the internal API */
3009 return Fast486LoadSegment(State
, FAST486_REG_DS
, LOWORD(NewSelector
));
3012 FAST486_OPCODE_HANDLER(Fast486OpcodeDaa
)
3014 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3015 BOOLEAN Carry
= State
->Flags
.Cf
;
3017 /* Clear the carry flag */
3018 State
->Flags
.Cf
= FALSE
;
3020 /* Check if the first BCD digit is invalid or there was a carry from it */
3021 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3024 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3025 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
< 0x06)
3027 /* A carry occurred */
3028 State
->Flags
.Cf
= TRUE
;
3031 /* Set the adjust flag */
3032 State
->Flags
.Af
= TRUE
;
3035 /* Check if the second BCD digit is invalid or there was a carry from it */
3036 if ((Value
> 0x99) || Carry
)
3039 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x60;
3041 /* There was a carry */
3042 State
->Flags
.Cf
= TRUE
;
3048 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3050 UCHAR FirstValue
, SecondValue
, Result
;
3051 FAST486_MOD_REG_RM ModRegRm
;
3052 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3054 /* Make sure this is the right instruction */
3055 ASSERT((Opcode
& 0xED) == 0x28);
3057 TOGGLE_ADSIZE(AddressSize
);
3059 /* Get the operands */
3060 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3062 /* Exception occurred */
3066 if (!Fast486ReadModrmByteOperands(State
,
3071 /* Exception occurred */
3075 /* Check if this is the instruction that writes to R/M */
3076 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3078 /* Swap the order */
3079 SWAP(FirstValue
, SecondValue
);
3082 /* Calculate the result */
3083 Result
= FirstValue
- SecondValue
;
3085 /* Update the flags */
3086 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3087 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3088 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3089 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3090 State
->Flags
.Zf
= (Result
== 0);
3091 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3092 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3094 /* Check if this is not a CMP */
3095 if (!(Opcode
& 0x10))
3097 /* Write back the result */
3098 return Fast486WriteModrmByteOperands(State
,
3100 Opcode
& FAST486_OPCODE_WRITE_REG
,
3105 /* Discard the result */
3110 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3112 FAST486_MOD_REG_RM ModRegRm
;
3113 BOOLEAN OperandSize
, AddressSize
;
3115 /* Make sure this is the right instruction */
3116 ASSERT((Opcode
& 0xED) == 0x29);
3118 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3120 TOGGLE_ADSIZE(AddressSize
);
3121 TOGGLE_OPSIZE(OperandSize
);
3123 /* Get the operands */
3124 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3126 /* Exception occurred */
3130 /* Check the operand size */
3133 ULONG FirstValue
, SecondValue
, Result
;
3135 if (!Fast486ReadModrmDwordOperands(State
,
3140 /* Exception occurred */
3144 /* Check if this is the instruction that writes to R/M */
3145 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3147 /* Swap the order */
3148 SWAP(FirstValue
, SecondValue
);
3151 /* Calculate the result */
3152 Result
= FirstValue
- SecondValue
;
3154 /* Update the flags */
3155 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3156 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3157 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3158 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3159 State
->Flags
.Zf
= (Result
== 0);
3160 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3161 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3163 /* Check if this is not a CMP */
3164 if (!(Opcode
& 0x10))
3166 /* Write back the result */
3167 return Fast486WriteModrmDwordOperands(State
,
3169 Opcode
& FAST486_OPCODE_WRITE_REG
,
3174 /* Discard the result */
3180 USHORT FirstValue
, SecondValue
, Result
;
3182 if (!Fast486ReadModrmWordOperands(State
,
3187 /* Exception occurred */
3191 /* Check if this is the instruction that writes to R/M */
3192 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3194 /* Swap the order */
3195 SWAP(FirstValue
, SecondValue
);
3198 /* Calculate the result */
3199 Result
= FirstValue
- SecondValue
;
3201 /* Update the flags */
3202 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3203 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3204 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3205 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3206 State
->Flags
.Zf
= (Result
== 0);
3207 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3208 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3210 /* Check if this is not a CMP */
3211 if (!(Opcode
& 0x10))
3213 /* Write back the result */
3214 return Fast486WriteModrmWordOperands(State
,
3216 Opcode
& FAST486_OPCODE_WRITE_REG
,
3221 /* Discard the result */
3227 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3229 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3230 UCHAR SecondValue
, Result
;
3232 /* Make sure this is the right instruction */
3233 ASSERT((Opcode
& 0xEF) == 0x2C);
3235 if (State
->PrefixFlags
)
3237 /* This opcode doesn't take any prefixes */
3238 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3242 if (!Fast486FetchByte(State
, &SecondValue
))
3244 /* Exception occurred */
3248 /* Calculate the result */
3249 Result
= FirstValue
- SecondValue
;
3251 /* Update the flags */
3252 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3253 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3254 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3255 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3256 State
->Flags
.Zf
= (Result
== 0);
3257 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3258 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3260 /* Check if this is not a CMP */
3261 if (!(Opcode
& 0x10))
3263 /* Write back the result */
3264 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3270 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3272 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3274 /* Make sure this is the right instruction */
3275 ASSERT((Opcode
& 0xEF) == 0x2D);
3278 TOGGLE_OPSIZE(Size
);
3282 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3283 ULONG SecondValue
, Result
;
3285 if (!Fast486FetchDword(State
, &SecondValue
))
3287 /* Exception occurred */
3291 /* Calculate the result */
3292 Result
= FirstValue
- SecondValue
;
3294 /* Update the flags */
3295 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3296 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3297 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3298 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3299 State
->Flags
.Zf
= (Result
== 0);
3300 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3301 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3303 /* Check if this is not a CMP */
3304 if (!(Opcode
& 0x10))
3306 /* Write back the result */
3307 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3312 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3313 USHORT SecondValue
, Result
;
3315 if (!Fast486FetchWord(State
, &SecondValue
))
3317 /* Exception occurred */
3321 /* Calculate the result */
3322 Result
= FirstValue
- SecondValue
;
3324 /* Update the flags */
3325 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3326 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3327 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3328 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3329 State
->Flags
.Zf
= (Result
== 0);
3330 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3331 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3333 /* Check if this is not a CMP */
3334 if (!(Opcode
& 0x10))
3336 /* Write back the result */
3337 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3344 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3346 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3347 BOOLEAN Carry
= State
->Flags
.Cf
;
3349 /* Clear the carry flag */
3350 State
->Flags
.Cf
= FALSE
;
3352 /* Check if the first BCD digit is invalid or there was a borrow */
3353 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3356 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3357 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3359 /* A borrow occurred */
3360 State
->Flags
.Cf
= TRUE
;
3363 /* Set the adjust flag */
3364 State
->Flags
.Af
= TRUE
;
3367 /* Check if the second BCD digit is invalid or there was a borrow */
3368 if ((Value
> 0x99) || Carry
)
3371 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3373 /* There was a borrow */
3374 State
->Flags
.Cf
= TRUE
;
3380 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3382 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3385 * Check if the value in AL is not a valid BCD digit,
3386 * or there was a carry from the lowest 4 bits of AL
3388 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3391 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
+= 0x06;
3392 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3395 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3399 /* Clear CF and AF */
3400 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3403 /* Keep only the lowest 4 bits of AL */
3404 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3409 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3411 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3414 * Check if the value in AL is not a valid BCD digit,
3415 * or there was a borrow from the lowest 4 bits of AL
3417 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3420 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3421 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3424 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3428 /* Clear CF and AF */
3429 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3432 /* Keep only the lowest 4 bits of AL */
3433 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3438 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3441 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3442 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3444 /* Make sure this is the right instruction */
3445 ASSERT(Opcode
== 0x60);
3447 TOGGLE_OPSIZE(Size
);
3450 /* Push all the registers in order */
3451 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3453 if (i
== FAST486_REG_ESP
)
3455 /* Use the saved ESP instead */
3456 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3458 /* Exception occurred */
3464 /* Push the register */
3465 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3466 : State
->GeneralRegs
[i
].LowWord
))
3468 /* Exception occurred */
3477 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3480 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3483 /* Make sure this is the right instruction */
3484 ASSERT(Opcode
== 0x61);
3486 TOGGLE_OPSIZE(Size
);
3489 /* Pop all the registers in reverse order */
3490 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3493 if (!Fast486StackPop(State
, &Value
))
3495 /* Exception occurred */
3499 /* Don't modify ESP */
3500 if (i
!= FAST486_REG_ESP
)
3502 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3503 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3510 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3512 // TODO: NOT IMPLEMENTED
3518 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3520 USHORT FirstValue
, SecondValue
;
3521 FAST486_MOD_REG_RM ModRegRm
;
3522 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3524 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3526 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3528 /* Cannot be used in real mode or with a LOCK prefix */
3529 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3533 TOGGLE_ADSIZE(AddressSize
);
3535 /* Get the operands */
3536 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3538 /* Exception occurred */
3542 /* Read the operands */
3543 if (!Fast486ReadModrmWordOperands(State
,
3548 /* Exception occurred */
3552 /* Check if the RPL needs adjusting */
3553 if ((SecondValue
& 3) < (FirstValue
& 3))
3555 /* Adjust the RPL */
3557 SecondValue
|= FirstValue
& 3;
3560 State
->Flags
.Zf
= TRUE
;
3562 /* Write back the result */
3563 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3568 State
->Flags
.Zf
= FALSE
;
3573 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3575 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3577 /* Make sure this is the right instruction */
3578 ASSERT(Opcode
== 0x68);
3581 TOGGLE_OPSIZE(Size
);
3587 if (!Fast486FetchDword(State
, &Data
))
3589 /* Exception occurred */
3593 /* Call the internal API */
3594 return Fast486StackPush(State
, Data
);
3600 if (!Fast486FetchWord(State
, &Data
))
3602 /* Exception occurred */
3606 /* Call the internal API */
3607 return Fast486StackPush(State
, Data
);
3611 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3613 BOOLEAN OperandSize
, AddressSize
;
3614 FAST486_MOD_REG_RM ModRegRm
;
3617 /* Make sure this is the right instruction */
3618 ASSERT((Opcode
& 0xFD) == 0x69);
3620 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3622 TOGGLE_ADSIZE(AddressSize
);
3623 TOGGLE_OPSIZE(OperandSize
);
3625 /* Fetch the parameters */
3626 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3628 /* Exception occurred */
3636 /* Fetch the immediate operand */
3637 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3639 /* Exception occurred */
3643 Multiplier
= (LONG
)Byte
;
3651 /* Fetch the immediate operand */
3652 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3654 /* Exception occurred */
3664 /* Fetch the immediate operand */
3665 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3667 /* Exception occurred */
3671 Multiplier
= (LONG
)Word
;
3677 LONG RegValue
, Multiplicand
;
3680 /* Read the operands */
3681 if (!Fast486ReadModrmDwordOperands(State
,
3684 (PULONG
)&Multiplicand
))
3686 /* Exception occurred */
3691 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3693 /* Check for carry/overflow */
3694 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3696 /* Write-back the result */
3697 return Fast486WriteModrmDwordOperands(State
,
3700 (ULONG
)((LONG
)Product
));
3704 SHORT RegValue
, Multiplicand
;
3707 /* Read the operands */
3708 if (!Fast486ReadModrmWordOperands(State
,
3711 (PUSHORT
)&Multiplicand
))
3713 /* Exception occurred */
3718 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3720 /* Check for carry/overflow */
3721 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3723 /* Write-back the result */
3724 return Fast486WriteModrmWordOperands(State
,
3727 (USHORT
)((SHORT
)Product
));
3731 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3735 /* Make sure this is the right instruction */
3736 ASSERT(Opcode
== 0x6A);
3738 if (!Fast486FetchByte(State
, &Data
))
3740 /* Exception occurred */
3744 /* Call the internal API */
3745 return Fast486StackPush(State
, Data
);
3748 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3750 UCHAR FirstValue
, SecondValue
, Result
;
3751 FAST486_MOD_REG_RM ModRegRm
;
3752 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3754 /* Make sure this is the right instruction */
3755 ASSERT((Opcode
& 0xFD) == 0x88);
3757 TOGGLE_ADSIZE(AddressSize
);
3759 /* Get the operands */
3760 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3762 /* Exception occurred */
3766 if (!Fast486ReadModrmByteOperands(State
,
3771 /* Exception occurred */
3775 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3776 else Result
= FirstValue
;
3778 /* Write back the result */
3779 return Fast486WriteModrmByteOperands(State
,
3781 Opcode
& FAST486_OPCODE_WRITE_REG
,
3786 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3788 FAST486_MOD_REG_RM ModRegRm
;
3789 BOOLEAN OperandSize
, AddressSize
;
3791 /* Make sure this is the right instruction */
3792 ASSERT((Opcode
& 0xFD) == 0x89);
3794 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3796 TOGGLE_ADSIZE(AddressSize
);
3797 TOGGLE_OPSIZE(OperandSize
);
3799 /* Get the operands */
3800 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3802 /* Exception occurred */
3806 /* Check the operand size */
3809 ULONG FirstValue
, SecondValue
, Result
;
3811 if (!Fast486ReadModrmDwordOperands(State
,
3816 /* Exception occurred */
3820 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3821 else Result
= FirstValue
;
3823 /* Write back the result */
3824 return Fast486WriteModrmDwordOperands(State
,
3826 Opcode
& FAST486_OPCODE_WRITE_REG
,
3831 USHORT FirstValue
, SecondValue
, Result
;
3833 if (!Fast486ReadModrmWordOperands(State
,
3838 /* Exception occurred */
3842 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3843 else Result
= FirstValue
;
3845 /* Write back the result */
3846 return Fast486WriteModrmWordOperands(State
,
3848 Opcode
& FAST486_OPCODE_WRITE_REG
,
3853 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3855 BOOLEAN OperandSize
, AddressSize
;
3856 FAST486_MOD_REG_RM ModRegRm
;
3858 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3860 /* Make sure this is the right instruction */
3861 ASSERT(Opcode
== 0x8C);
3863 TOGGLE_ADSIZE(AddressSize
);
3864 TOGGLE_OPSIZE(OperandSize
);
3866 /* Get the operands */
3867 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3869 /* Exception occurred */
3873 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3876 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3882 return Fast486WriteModrmDwordOperands(State
,
3885 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3889 return Fast486WriteModrmWordOperands(State
,
3892 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3896 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3898 FAST486_MOD_REG_RM ModRegRm
;
3899 BOOLEAN OperandSize
, AddressSize
;
3901 /* Make sure this is the right instruction */
3902 ASSERT(Opcode
== 0x8D);
3904 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3906 TOGGLE_ADSIZE(AddressSize
);
3907 TOGGLE_OPSIZE(OperandSize
);
3909 /* Get the operands */
3910 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3912 /* Exception occurred */
3916 /* The second operand must be memory */
3917 if (!ModRegRm
.Memory
)
3920 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3924 /* Write the address to the register */
3927 return Fast486WriteModrmDwordOperands(State
,
3930 ModRegRm
.MemoryAddress
);
3934 return Fast486WriteModrmWordOperands(State
,
3937 ModRegRm
.MemoryAddress
);
3942 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3944 BOOLEAN OperandSize
, AddressSize
;
3945 FAST486_MOD_REG_RM ModRegRm
;
3947 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3949 /* Make sure this is the right instruction */
3950 ASSERT(Opcode
== 0x8E);
3952 TOGGLE_ADSIZE(AddressSize
);
3953 TOGGLE_OPSIZE(OperandSize
);
3955 /* Get the operands */
3956 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3958 /* Exception occurred */
3962 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3963 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3966 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3974 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
3976 /* Exception occurred */
3980 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
3986 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
3988 /* Exception occurred */
3992 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
3996 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
3998 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4000 /* Make sure this is the right instruction */
4001 ASSERT(Opcode
== 0x98);
4003 TOGGLE_OPSIZE(Size
);
4008 /* Sign extend AX to EAX */
4009 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4011 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4012 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4018 /* Sign extend AL to AX */
4019 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4020 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4027 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4029 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4031 /* Make sure this is the right instruction */
4032 ASSERT(Opcode
== 0x99);
4034 TOGGLE_OPSIZE(Size
);
4039 /* Sign extend EAX to EDX:EAX */
4040 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4041 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4042 ? 0xFFFFFFFF : 0x00000000;
4046 /* Sign extend AX to DX:AX */
4047 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4048 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4055 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4059 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4061 /* Make sure this is the right instruction */
4062 ASSERT(Opcode
== 0x9A);
4064 TOGGLE_OPSIZE(Size
);
4067 /* Fetch the offset */
4070 if (!Fast486FetchDword(State
, &Offset
))
4072 /* Exception occurred */
4078 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4080 /* Exception occurred */
4085 /* Fetch the segment */
4086 if (!Fast486FetchWord(State
, &Segment
))
4088 /* Exception occurred */
4092 /* Push the current code segment selector */
4093 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4095 /* Exception occurred */
4099 /* Push the current value of the instruction pointer */
4100 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4102 /* Exception occurred */
4106 /* Load the new CS */
4107 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4109 /* Exception occurred */
4113 /* Load new (E)IP */
4114 if (Size
) State
->InstPtr
.Long
= Offset
;
4115 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4120 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4122 // TODO: NOT IMPLEMENTED
4128 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4130 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4133 TOGGLE_OPSIZE(Size
);
4135 /* Check for VM86 mode when IOPL is not 3 */
4136 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4138 /* Call the VM86 monitor */
4139 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4143 /* Push the flags */
4144 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4145 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4148 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4150 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4151 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4155 TOGGLE_OPSIZE(Size
);
4157 /* Pop the new flags */
4158 if (!Fast486StackPop(State
, &NewFlags
))
4160 /* Exception occurred */
4164 if (!State
->Flags
.Vm
)
4166 /* Check the current privilege level */
4174 /* Memorize the old state of RF */
4175 BOOLEAN OldRf
= State
->Flags
.Rf
;
4177 State
->Flags
.Long
= NewFlags
;
4179 /* Restore VM and RF */
4180 State
->Flags
.Vm
= FALSE
;
4181 State
->Flags
.Rf
= OldRf
;
4183 /* Clear VIF and VIP */
4184 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4186 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4188 /* Restore the reserved bits */
4189 State
->Flags
.AlwaysSet
= TRUE
;
4190 State
->Flags
.Reserved0
= FALSE
;
4191 State
->Flags
.Reserved1
= FALSE
;
4197 /* Memorize the old state of IF and IOPL */
4198 BOOLEAN OldIf
= State
->Flags
.If
;
4199 UINT OldIopl
= State
->Flags
.Iopl
;
4204 /* Memorize the old state of RF */
4205 BOOLEAN OldRf
= State
->Flags
.Rf
;
4207 State
->Flags
.Long
= NewFlags
;
4209 /* Restore VM and RF */
4210 State
->Flags
.Vm
= FALSE
;
4211 State
->Flags
.Rf
= OldRf
;
4213 /* Clear VIF and VIP */
4214 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4216 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4218 /* Restore the reserved bits and IOPL */
4219 State
->Flags
.AlwaysSet
= TRUE
;
4220 State
->Flags
.Reserved0
= FALSE
;
4221 State
->Flags
.Reserved1
= FALSE
;
4222 State
->Flags
.Iopl
= OldIopl
;
4224 /* Check if the user doesn't have the privilege to change IF */
4225 if (Cpl
> State
->Flags
.Iopl
)
4228 State
->Flags
.If
= OldIf
;
4234 /* Check the IOPL */
4235 if (State
->Flags
.Iopl
== 3)
4239 /* Memorize the old state of RF, VIF and VIP */
4240 BOOLEAN OldRf
= State
->Flags
.Rf
;
4241 BOOLEAN OldVif
= State
->Flags
.Vif
;
4242 BOOLEAN OldVip
= State
->Flags
.Vip
;
4244 State
->Flags
.Long
= NewFlags
;
4246 /* Restore VM, RF, VIF and VIP */
4247 State
->Flags
.Vm
= TRUE
;
4248 State
->Flags
.Rf
= OldRf
;
4249 State
->Flags
.Vif
= OldVif
;
4250 State
->Flags
.Vip
= OldVip
;
4252 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4254 /* Restore the reserved bits and IOPL */
4255 State
->Flags
.AlwaysSet
= TRUE
;
4256 State
->Flags
.Reserved0
= FALSE
;
4257 State
->Flags
.Reserved1
= FALSE
;
4258 State
->Flags
.Iopl
= 3;
4262 /* Call the VM86 monitor */
4263 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4271 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4273 /* Make sure this is the right instruction */
4274 ASSERT(Opcode
== 0x9E);
4276 /* Set the low-order byte of FLAGS to AH */
4277 State
->Flags
.Long
&= 0xFFFFFF00;
4278 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4280 /* Restore the reserved bits of FLAGS */
4281 State
->Flags
.AlwaysSet
= TRUE
;
4282 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4287 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4289 /* Make sure this is the right instruction */
4290 ASSERT(Opcode
== 0x9F);
4292 /* Set AH to the low-order byte of FLAGS */
4293 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4298 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4300 ULONG ReturnAddress
;
4301 USHORT BytesToPop
= 0;
4302 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4304 /* Make sure this is the right instruction */
4305 ASSERT((Opcode
& 0xFE) == 0xC2);
4308 TOGGLE_OPSIZE(Size
);
4312 /* Fetch the number of bytes to pop after the return */
4313 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4316 /* Pop the return address */
4317 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4319 /* Return to the calling procedure, and if necessary, pop the parameters */
4322 State
->InstPtr
.Long
= ReturnAddress
;
4323 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4327 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4328 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4334 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4336 UCHAR FarPointer
[6];
4337 BOOLEAN OperandSize
, AddressSize
;
4338 FAST486_MOD_REG_RM ModRegRm
;
4340 /* Make sure this is the right instruction */
4341 ASSERT((Opcode
& 0xFE) == 0xC4);
4343 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4345 TOGGLE_OPSIZE(OperandSize
);
4346 TOGGLE_ADSIZE(AddressSize
);
4348 /* Get the operands */
4349 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4351 /* Exception occurred */
4355 if (!ModRegRm
.Memory
)
4357 /* Check if this is a BOP and the host supports BOPs */
4358 if ((Opcode
== 0xC4)
4359 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4360 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4361 && (State
->BopCallback
!= NULL
))
4365 /* Fetch the BOP code */
4366 if (!Fast486FetchByte(State
, &BopCode
))
4368 /* Exception occurred */
4372 /* Call the BOP handler */
4373 State
->BopCallback(State
, BopCode
);
4375 /* Return success */
4380 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4384 if (!Fast486ReadMemory(State
,
4385 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4386 ? State
->SegmentOverride
: FAST486_REG_DS
,
4387 ModRegRm
.MemoryAddress
,
4390 OperandSize
? 6 : 4))
4392 /* Exception occurred */
4398 ULONG Offset
= *((PULONG
)FarPointer
);
4399 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4401 /* Set the register to the offset */
4402 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4404 /* Load the segment */
4405 return Fast486LoadSegment(State
,
4407 ? FAST486_REG_ES
: FAST486_REG_DS
,
4412 USHORT Offset
= *((PUSHORT
)FarPointer
);
4413 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4415 /* Set the register to the offset */
4416 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4418 /* Load the segment */
4419 return Fast486LoadSegment(State
,
4421 ? FAST486_REG_ES
: FAST486_REG_DS
,
4426 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4429 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4432 FAST486_REG FramePointer
;
4434 /* Make sure this is the right instruction */
4435 ASSERT(Opcode
== 0xC8);
4438 TOGGLE_OPSIZE(Size
);
4440 if (!Fast486FetchWord(State
, &FrameSize
))
4442 /* Exception occurred */
4446 if (!Fast486FetchByte(State
, &NestingLevel
))
4448 /* Exception occurred */
4453 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4455 /* Exception occurred */
4460 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4462 /* Set up the nested procedure stacks */
4463 for (i
= 1; i
< NestingLevel
; i
++)
4467 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4468 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4472 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4473 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4477 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4479 /* Set EBP to the frame pointer */
4480 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4482 /* Reserve space for the frame */
4483 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4484 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4489 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4491 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4493 /* Make sure this is the right instruction */
4494 ASSERT(Opcode
== 0xC9);
4497 TOGGLE_OPSIZE(Size
);
4501 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4502 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4504 /* Pop the saved base pointer from the stack */
4505 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4511 /* Set the stack pointer (SP) to the base pointer (BP) */
4512 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4514 /* Pop the saved base pointer from the stack */
4515 if (Fast486StackPop(State
, &Value
))
4517 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4524 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4528 USHORT BytesToPop
= 0;
4529 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4531 /* Make sure this is the right instruction */
4532 ASSERT((Opcode
& 0xFE) == 0xCA);
4534 TOGGLE_OPSIZE(Size
);
4539 /* Fetch the number of bytes to pop after the return */
4540 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4543 /* Pop the offset */
4544 if (!Fast486StackPop(State
, &Offset
))
4546 /* Exception occurred */
4550 /* Pop the segment */
4551 if (!Fast486StackPop(State
, &Segment
))
4553 /* Exception occurred */
4557 /* Load the new CS */
4558 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4560 /* Exception occurred */
4564 /* Load new (E)IP, and if necessary, pop the parameters */
4567 State
->InstPtr
.Long
= Offset
;
4568 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4572 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4573 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4579 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4582 FAST486_IDT_ENTRY IdtEntry
;
4588 /* This is the INT3 instruction */
4595 /* Fetch the interrupt number */
4596 if (!Fast486FetchByte(State
, &IntNum
))
4598 /* Exception occurred */
4607 /* Don't do anything if OF is cleared */
4608 if (!State
->Flags
.Of
) return TRUE
;
4611 IntNum
= FAST486_EXCEPTION_OF
;
4618 /* Should not happen */
4623 /* Get the interrupt vector */
4624 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4626 /* Exception occurred */
4630 /* Perform the interrupt */
4631 if (!Fast486InterruptInternal(State
,
4633 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4636 /* Exception occurred */
4643 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4646 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4647 FAST486_FLAGS_REG NewFlags
;
4648 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4650 /* Make sure this is the right instruction */
4651 ASSERT(Opcode
== 0xCF);
4654 TOGGLE_OPSIZE(Size
);
4657 if (!Fast486StackPop(State
, &InstPtr
))
4659 /* Exception occurred */
4664 if (!Fast486StackPop(State
, &CodeSel
))
4666 /* Exception occurred */
4671 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4673 /* Exception occurred */
4677 /* Check for protected mode */
4678 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4680 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4682 if (State
->Flags
.Vm
)
4684 /* Return from VM86 mode */
4686 /* Check the IOPL */
4687 if (State
->Flags
.Iopl
== 3)
4690 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4693 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4695 /* Exception occurred */
4699 /* Set the new flags */
4700 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4701 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4702 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4703 State
->Flags
.Iopl
= 3;
4707 /* Call the VM86 monitor */
4708 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4715 if (State
->Flags
.Nt
)
4717 /* Nested task return */
4725 /* Return to VM86 mode */
4726 ULONG Es
, Ds
, Fs
, Gs
;
4728 /* Pop ESP, SS, ES, FS, GS */
4729 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4730 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4731 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4732 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4733 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4734 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4736 /* Set the new IP */
4737 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4739 /* Set the new flags */
4740 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4741 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4742 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4744 /* Load the new segments */
4745 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4746 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4747 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4748 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4749 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4750 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4755 /* Load the new CS */
4756 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4758 /* Exception occurred */
4763 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4764 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4766 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4769 if (!Fast486StackPop(State
, &StackPtr
))
4776 if (!Fast486StackPop(State
, &StackSel
))
4783 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4790 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4791 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4794 /* Set the new flags */
4795 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4796 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4797 State
->Flags
.AlwaysSet
= TRUE
;
4799 /* Set additional flags */
4800 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4801 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4803 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4805 /* Update the CPL */
4806 Cpl
= Fast486GetCurrentPrivLevel(State
);
4808 /* Check segment security */
4809 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4811 /* Don't check CS or SS */
4812 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4814 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4815 && (!State
->SegmentRegs
[i
].Executable
4816 || !State
->SegmentRegs
[i
].DirConf
))
4818 /* Load the NULL descriptor in the segment */
4819 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4826 if (Size
&& (InstPtr
& 0xFFFF0000))
4829 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4834 State
->InstPtr
.Long
= InstPtr
;
4837 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4839 /* Exception occurred */
4843 /* Set the new flags */
4844 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4845 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4846 State
->Flags
.AlwaysSet
= TRUE
;
4852 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4855 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4859 /* Fetch the base */
4860 if (!Fast486FetchByte(State
, &Base
))
4862 /* Exception occurred */
4866 /* Check if the base is zero */
4870 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4875 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4876 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4879 State
->Flags
.Zf
= (Value
== 0);
4880 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4881 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4886 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4889 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4893 /* Fetch the base */
4894 if (!Fast486FetchByte(State
, &Base
))
4896 /* Exception occurred */
4901 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4902 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4905 State
->Flags
.Zf
= (Value
== 0);
4906 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4907 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4912 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4915 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4917 TOGGLE_ADSIZE(AddressSize
);
4919 /* Read a byte from DS:[(E)BX + AL] */
4920 if (!Fast486ReadMemory(State
,
4922 AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4923 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
4924 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4929 /* Exception occurred */
4933 /* Set AL to the result */
4934 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4936 /* Return success */
4940 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4943 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4946 /* Make sure this is the right instruction */
4947 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4950 TOGGLE_ADSIZE(Size
);
4952 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4953 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4957 /* Additional rule for LOOPNZ */
4958 if (State
->Flags
.Zf
) Condition
= FALSE
;
4963 /* Additional rule for LOOPZ */
4964 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4967 /* Fetch the offset */
4968 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4970 /* An exception occurred */
4976 /* Move the instruction pointer */
4977 if (Size
) State
->InstPtr
.Long
+= Offset
;
4978 else State
->InstPtr
.LowWord
+= Offset
;
4984 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
4987 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4990 /* Make sure this is the right instruction */
4991 ASSERT(Opcode
== 0xE3);
4994 TOGGLE_ADSIZE(Size
);
4996 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
4997 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
4999 /* Fetch the offset */
5000 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5002 /* An exception occurred */
5008 /* Move the instruction pointer */
5009 if (Size
) State
->InstPtr
.Long
+= Offset
;
5010 else State
->InstPtr
.LowWord
+= Offset
;
5016 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5018 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5020 /* Make sure this is the right instruction */
5021 ASSERT(Opcode
== 0xE8);
5023 TOGGLE_OPSIZE(Size
);
5030 /* Fetch the offset */
5031 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5033 /* An exception occurred */
5037 /* Push the current value of the instruction pointer */
5038 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5040 /* Exception occurred */
5044 /* Move the instruction pointer */
5045 State
->InstPtr
.Long
+= Offset
;
5051 /* Fetch the offset */
5052 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5054 /* An exception occurred */
5058 /* Push the current value of the instruction pointer */
5059 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5061 /* Exception occurred */
5065 /* Move the instruction pointer */
5066 State
->InstPtr
.LowWord
+= Offset
;
5072 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5074 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5076 /* Make sure this is the right instruction */
5077 ASSERT(Opcode
== 0xE9);
5079 TOGGLE_OPSIZE(Size
);
5086 /* Fetch the offset */
5087 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5089 /* An exception occurred */
5093 /* Move the instruction pointer */
5094 State
->InstPtr
.Long
+= Offset
;
5100 /* Fetch the offset */
5101 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5103 /* An exception occurred */
5107 /* Move the instruction pointer */
5108 State
->InstPtr
.Long
+= Offset
;
5110 /* Clear the top half of EIP */
5111 State
->InstPtr
.Long
&= 0xFFFF;
5117 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5121 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5123 /* Make sure this is the right instruction */
5124 ASSERT(Opcode
== 0xEA);
5126 TOGGLE_OPSIZE(Size
);
5129 /* Fetch the offset */
5132 if (!Fast486FetchDword(State
, &Offset
))
5134 /* Exception occurred */
5140 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5142 /* Exception occurred */
5147 /* Fetch the segment */
5148 if (!Fast486FetchWord(State
, &Segment
))
5150 /* Exception occurred */
5154 /* Load the new CS */
5155 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5157 /* Exception occurred */
5162 State
->InstPtr
.Long
= Offset
;
5167 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5169 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5172 /* Make sure this is the right instruction */
5173 ASSERT(Opcode
== 0xA0);
5175 TOGGLE_ADSIZE(AddressSize
);
5179 if (!Fast486FetchDword(State
, &Offset
))
5181 /* Exception occurred */
5189 if (!Fast486FetchWord(State
, &WordOffset
))
5191 /* Exception occurred */
5195 Offset
= (ULONG
)WordOffset
;
5198 /* Read from memory */
5199 return Fast486ReadMemory(State
,
5200 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5201 State
->SegmentOverride
: FAST486_REG_DS
,
5204 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5208 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5210 BOOLEAN OperandSize
, AddressSize
;
5212 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5214 /* Make sure this is the right instruction */
5215 ASSERT(Opcode
== 0xA1);
5217 TOGGLE_OPSIZE(OperandSize
);
5218 TOGGLE_ADSIZE(AddressSize
);
5224 if (!Fast486FetchDword(State
, &Offset
))
5226 /* Exception occurred */
5230 /* Read from memory */
5233 return Fast486ReadMemory(State
,
5234 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5235 State
->SegmentOverride
: FAST486_REG_DS
,
5238 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5243 return Fast486ReadMemory(State
,
5244 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5245 State
->SegmentOverride
: FAST486_REG_DS
,
5248 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5256 if (!Fast486FetchWord(State
, &Offset
))
5258 /* Exception occurred */
5262 /* Read from memory */
5265 return Fast486ReadMemory(State
,
5266 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5267 State
->SegmentOverride
: FAST486_REG_DS
,
5270 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5275 return Fast486ReadMemory(State
,
5276 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5277 State
->SegmentOverride
: FAST486_REG_DS
,
5280 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5286 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5288 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5291 /* Make sure this is the right instruction */
5292 ASSERT(Opcode
== 0xA2);
5294 TOGGLE_ADSIZE(AddressSize
);
5298 if (!Fast486FetchDword(State
, &Offset
))
5300 /* Exception occurred */
5308 if (!Fast486FetchWord(State
, &WordOffset
))
5310 /* Exception occurred */
5314 Offset
= (ULONG
)WordOffset
;
5317 /* Write to memory */
5318 return Fast486WriteMemory(State
,
5319 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5320 State
->SegmentOverride
: FAST486_REG_DS
,
5322 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5326 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5328 BOOLEAN OperandSize
, AddressSize
;
5330 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5332 /* Make sure this is the right instruction */
5333 ASSERT(Opcode
== 0xA3);
5335 TOGGLE_OPSIZE(OperandSize
);
5336 TOGGLE_ADSIZE(AddressSize
);
5342 if (!Fast486FetchDword(State
, &Offset
))
5344 /* Exception occurred */
5348 /* Write to memory */
5351 return Fast486WriteMemory(State
,
5352 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5353 State
->SegmentOverride
: FAST486_REG_DS
,
5355 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5360 return Fast486WriteMemory(State
,
5361 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5362 State
->SegmentOverride
: FAST486_REG_DS
,
5364 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5372 if (!Fast486FetchWord(State
, &Offset
))
5374 /* Exception occurred */
5378 /* Write to memory */
5381 return Fast486WriteMemory(State
,
5382 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5383 State
->SegmentOverride
: FAST486_REG_DS
,
5385 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5390 return Fast486WriteMemory(State
,
5391 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5392 State
->SegmentOverride
: FAST486_REG_DS
,
5394 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5400 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5402 /* Make sure this is the right instruction */
5403 ASSERT(Opcode
== 0xD6);
5407 /* Set all the bits of AL to CF */
5408 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5413 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5415 ULONG Data
, DataSize
;
5416 BOOLEAN OperandSize
, AddressSize
;
5417 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5419 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5421 /* Make sure this is the right instruction */
5422 ASSERT((Opcode
& 0xFE) == 0xA4);
5424 TOGGLE_OPSIZE(OperandSize
);
5425 TOGGLE_ADSIZE(AddressSize
);
5427 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5429 /* Use the override segment instead of DS */
5430 Segment
= State
->SegmentOverride
;
5433 /* Calculate the size */
5434 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5435 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5437 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5439 UCHAR Block
[STRING_BLOCK_SIZE
];
5440 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5441 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5443 /* Clear the memory block */
5444 RtlZeroMemory(Block
, sizeof(Block
));
5446 /* Transfer until finished */
5449 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5451 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5454 ULONG MaxBytesSrc
= State
->Flags
.Df
5455 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
5456 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
5457 ULONG MaxBytesDest
= State
->Flags
.Df
5458 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5459 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5462 Processed
= min(Processed
, min(MaxBytesSrc
, MaxBytesDest
) / DataSize
);
5463 if (Processed
== 0) Processed
= 1;
5466 if (State
->Flags
.Df
)
5468 /* Reduce ESI and EDI by the number of bytes to transfer */
5471 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
5472 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5476 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
5477 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5481 /* Read from memory */
5482 if (!Fast486ReadMemory(State
,
5484 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5485 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5488 Processed
* DataSize
))
5491 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5492 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5494 /* Exception occurred */
5498 /* Write to memory */
5499 if (!Fast486WriteMemory(State
,
5501 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5502 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5504 Processed
* DataSize
))
5507 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5508 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5510 /* Exception occurred */
5514 if (!State
->Flags
.Df
)
5516 /* Increase ESI and EDI by the number of bytes transfered */
5519 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
5520 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5524 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
5525 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5529 /* Reduce the total count by the number processed in this run */
5534 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5535 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5539 /* Read from the source operand */
5540 if (!Fast486ReadMemory(State
,
5542 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5543 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5548 /* Exception occurred */
5552 /* Write to the destination operand */
5553 if (!Fast486WriteMemory(State
,
5555 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5556 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5560 /* Exception occurred */
5564 /* Increment/decrement ESI and EDI */
5567 if (!State
->Flags
.Df
)
5569 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5570 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5574 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5575 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5580 if (!State
->Flags
.Df
)
5582 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5583 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5587 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5588 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5593 /* Return success */
5597 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5599 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5600 ULONG DataSize
, DataMask
, SignFlag
;
5601 BOOLEAN OperandSize
, AddressSize
;
5602 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5604 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5606 /* Make sure this is the right instruction */
5607 ASSERT((Opcode
& 0xFE) == 0xA6);
5609 TOGGLE_OPSIZE(OperandSize
);
5610 TOGGLE_ADSIZE(AddressSize
);
5612 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5614 /* Use the override segment instead of DS */
5615 Segment
= State
->SegmentOverride
;
5618 /* Calculate the size */
5619 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5620 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5622 /* Calculate the mask and sign flag */
5623 DataMask
= (1 << (DataSize
* 8)) - 1;
5624 SignFlag
= 1 << ((DataSize
* 8) - 1);
5626 /* Read from the first source operand */
5627 if (!Fast486ReadMemory(State
,
5629 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5630 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5635 /* Exception occurred */
5639 /* Read from the second source operand */
5640 if (!Fast486ReadMemory(State
,
5642 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5643 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5648 /* Exception occurred */
5652 /* Calculate the result */
5653 FirstValue
&= DataMask
;
5654 SecondValue
&= DataMask
;
5655 Result
= (FirstValue
- SecondValue
) & DataMask
;
5657 /* Update the flags */
5658 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5659 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5660 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5661 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5662 State
->Flags
.Zf
= (Result
== 0);
5663 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5664 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5666 /* Increment/decrement ESI and EDI */
5669 if (!State
->Flags
.Df
)
5671 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5672 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5676 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5677 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5682 if (!State
->Flags
.Df
)
5684 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5685 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5689 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5690 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5694 // FIXME: This method is slow!
5695 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5696 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5698 BOOLEAN Repeat
= TRUE
;
5702 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5710 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5717 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5718 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5720 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5726 /* Repeat the instruction */
5727 State
->InstPtr
= State
->SavedInstPtr
;
5731 /* Return success */
5735 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5738 BOOLEAN OperandSize
, AddressSize
;
5740 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5742 /* Make sure this is the right instruction */
5743 ASSERT((Opcode
& 0xFE) == 0xAA);
5745 TOGGLE_OPSIZE(OperandSize
);
5746 TOGGLE_ADSIZE(AddressSize
);
5748 /* Calculate the size */
5749 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5750 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5752 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5754 UCHAR Block
[STRING_BLOCK_SIZE
];
5755 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5756 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5758 /* Fill the memory block with the data */
5759 if (DataSize
== sizeof(UCHAR
))
5761 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5767 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5769 if (DataSize
== sizeof(USHORT
))
5771 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5775 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5780 /* Transfer until finished */
5783 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5785 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5788 ULONG MaxBytes
= State
->Flags
.Df
5789 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5790 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5792 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5793 if (Processed
== 0) Processed
= 1;
5796 if (State
->Flags
.Df
)
5798 /* Reduce EDI by the number of bytes to transfer */
5799 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5800 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5803 /* Write to memory */
5804 if (!Fast486WriteMemory(State
,
5806 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5807 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5809 Processed
* DataSize
))
5812 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5813 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5815 /* Exception occurred */
5819 if (!State
->Flags
.Df
)
5821 /* Increase EDI by the number of bytes transfered */
5822 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5823 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5826 /* Reduce the total count by the number processed in this run */
5831 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5832 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5836 /* Write to the destination operand */
5837 if (!Fast486WriteMemory(State
,
5839 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5840 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5841 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5844 /* Exception occurred */
5848 /* Increment/decrement EDI */
5851 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5852 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5856 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5857 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5861 /* Return success */
5865 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5868 BOOLEAN OperandSize
, AddressSize
;
5869 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5871 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5873 /* Make sure this is the right instruction */
5874 ASSERT((Opcode
& 0xFE) == 0xAC);
5876 TOGGLE_OPSIZE(OperandSize
);
5877 TOGGLE_ADSIZE(AddressSize
);
5879 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5881 /* Use the override segment instead of DS */
5882 Segment
= State
->SegmentOverride
;
5885 /* Calculate the size */
5886 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5887 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5889 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5891 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5892 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5894 /* If the count is 0, do nothing */
5895 if (Count
== 0) return TRUE
;
5897 /* Only the last entry will be loaded */
5898 if (!State
->Flags
.Df
)
5900 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5901 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5905 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5906 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5910 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5911 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5914 /* Read from the source operand */
5915 if (!Fast486ReadMemory(State
,
5917 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5918 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5920 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5923 /* Exception occurred */
5927 /* Increment/decrement ESI */
5930 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5931 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5935 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5936 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5939 /* Return success */
5943 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5945 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5946 ULONG SecondValue
= 0;
5948 ULONG DataSize
, DataMask
, SignFlag
;
5949 BOOLEAN OperandSize
, AddressSize
;
5951 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5953 /* Make sure this is the right instruction */
5954 ASSERT((Opcode
& 0xFE) == 0xAE);
5956 TOGGLE_OPSIZE(OperandSize
);
5957 TOGGLE_ADSIZE(AddressSize
);
5959 /* Calculate the size */
5960 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5961 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5963 /* Calculate the mask and sign flag */
5964 DataMask
= (1 << (DataSize
* 8)) - 1;
5965 SignFlag
= 1 << ((DataSize
* 8) - 1);
5967 /* Read from the source operand */
5968 if (!Fast486ReadMemory(State
,
5970 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5971 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5976 /* Exception occurred */
5980 /* Calculate the result */
5981 FirstValue
&= DataMask
;
5982 SecondValue
&= DataMask
;
5983 Result
= (FirstValue
- SecondValue
) & DataMask
;
5985 /* Update the flags */
5986 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5987 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5988 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5989 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5990 State
->Flags
.Zf
= (Result
== 0);
5991 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5992 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5994 /* Increment/decrement EDI */
5997 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5998 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6002 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6003 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6006 // FIXME: This method is slow!
6007 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
6008 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
6010 BOOLEAN Repeat
= TRUE
;
6014 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6022 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6029 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6030 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6032 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6038 /* Repeat the instruction */
6039 State
->InstPtr
= State
->SavedInstPtr
;
6043 /* Return success */
6047 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6050 BOOLEAN OperandSize
, AddressSize
;
6052 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6054 /* Make sure this is the right instruction */
6055 ASSERT((Opcode
& 0xFE) == 0x6C);
6057 TOGGLE_OPSIZE(OperandSize
);
6058 TOGGLE_ADSIZE(AddressSize
);
6060 /* Calculate the size */
6061 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6062 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6064 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6066 UCHAR Block
[STRING_BLOCK_SIZE
];
6067 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6068 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6070 /* Clear the memory block */
6071 RtlZeroMemory(Block
, sizeof(Block
));
6073 /* Transfer until finished */
6076 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6078 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6081 ULONG MaxBytes
= State
->Flags
.Df
6082 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6083 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6085 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6086 if (Processed
== 0) Processed
= 1;
6089 /* Read from the I/O port */
6090 State
->IoReadCallback(State
,
6091 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6096 if (State
->Flags
.Df
)
6100 /* Reduce EDI by the number of bytes to transfer */
6101 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6102 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6104 /* Reverse the block data */
6105 for (i
= 0; i
< Processed
/ 2; i
++)
6107 /* Swap the values */
6108 for (j
= 0; j
< DataSize
; j
++)
6110 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6111 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6112 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6117 /* Write to memory */
6118 if (!Fast486WriteMemory(State
,
6120 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6121 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6123 Processed
* DataSize
))
6126 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6127 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6129 /* Exception occurred */
6133 if (!State
->Flags
.Df
)
6135 /* Increase EDI by the number of bytes transfered */
6136 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6137 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6140 /* Reduce the total count by the number processed in this run */
6145 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6146 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6152 /* Read from the I/O port */
6153 State
->IoReadCallback(State
,
6154 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6159 /* Write to the destination operand */
6160 if (!Fast486WriteMemory(State
,
6162 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6163 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6167 /* Exception occurred */
6171 /* Increment/decrement EDI */
6174 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6175 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6179 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6180 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6184 /* Return success */
6188 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6191 BOOLEAN OperandSize
, AddressSize
;
6193 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6195 /* Make sure this is the right instruction */
6196 ASSERT((Opcode
& 0xFE) == 0x6E);
6198 TOGGLE_OPSIZE(OperandSize
);
6199 TOGGLE_ADSIZE(AddressSize
);
6201 /* Calculate the size */
6202 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6203 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6205 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6207 UCHAR Block
[STRING_BLOCK_SIZE
];
6208 ULONG Count
= OperandSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6209 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6211 /* Clear the memory block */
6212 RtlZeroMemory(Block
, sizeof(Block
));
6214 /* Transfer until finished */
6217 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6219 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6222 ULONG MaxBytes
= State
->Flags
.Df
6223 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6224 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6226 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6227 if (Processed
== 0) Processed
= 1;
6230 /* Read from memory */
6231 if (!Fast486ReadMemory(State
,
6233 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6234 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6237 Processed
* DataSize
))
6240 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6241 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6243 /* Exception occurred */
6247 if (State
->Flags
.Df
)
6251 /* Reduce EDI by the number of bytes to transfer */
6252 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6253 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6255 /* Reverse the block data */
6256 for (i
= 0; i
< Processed
/ 2; i
++)
6258 /* Swap the values */
6259 for (j
= 0; j
< DataSize
; j
++)
6261 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6262 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6263 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6268 /* Write to the I/O port */
6269 State
->IoWriteCallback(State
,
6270 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6275 if (!State
->Flags
.Df
)
6277 /* Increase EDI by the number of bytes transfered */
6278 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6279 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6282 /* Reduce the total count by the number processed in this run */
6287 if (OperandSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6288 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6294 /* Read from the source operand */
6295 if (!Fast486ReadMemory(State
,
6297 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6298 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6303 /* Exception occurred */
6307 /* Write to the I/O port */
6308 State
->IoWriteCallback(State
,
6309 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6314 /* Increment/decrement ESI */
6317 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6318 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6322 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6323 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6327 /* Return success */