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
^ SecondValue
^ Result
) & 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
^ SecondValue
^ Result
) & 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
^ SecondValue
^ Result
) & 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
^ SecondValue
^ Result
) & 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
^ SecondValue
^ Result
) & 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
^ SecondValue
^ Result
) & 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
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
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
^ SecondValue
^ Result
) & 0x10) != 0;
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
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
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
^ SecondValue
^ Result
) & 0x10) != 0;
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
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
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
^ SecondValue
^ Result
) & 0x10) != 0;
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
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
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
^ SecondValue
^ Result
) & 0x10) != 0;
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
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
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
^ SecondValue
^ Result
) & 0x10) != 0;
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
= Carry
? (FirstValue
<= SecondValue
) : (FirstValue
< SecondValue
);
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
^ SecondValue
^ Result
) & 0x10) != 0;
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
;
3045 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3047 /* Update the flags */
3048 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3049 State
->Flags
.Zf
= (Value
== 0);
3050 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3055 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubByteModrm
)
3057 UCHAR FirstValue
, SecondValue
, Result
;
3058 FAST486_MOD_REG_RM ModRegRm
;
3059 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3061 /* Make sure this is the right instruction */
3062 ASSERT((Opcode
& 0xED) == 0x28);
3064 TOGGLE_ADSIZE(AddressSize
);
3066 /* Get the operands */
3067 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3069 /* Exception occurred */
3073 if (!Fast486ReadModrmByteOperands(State
,
3078 /* Exception occurred */
3082 /* Check if this is the instruction that writes to R/M */
3083 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3085 /* Swap the order */
3086 SWAP(FirstValue
, SecondValue
);
3089 /* Calculate the result */
3090 Result
= FirstValue
- SecondValue
;
3092 /* Update the flags */
3093 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3094 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3095 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3096 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3097 State
->Flags
.Zf
= (Result
== 0);
3098 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3099 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3101 /* Check if this is not a CMP */
3102 if (!(Opcode
& 0x10))
3104 /* Write back the result */
3105 return Fast486WriteModrmByteOperands(State
,
3107 Opcode
& FAST486_OPCODE_WRITE_REG
,
3112 /* Discard the result */
3117 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubModrm
)
3119 FAST486_MOD_REG_RM ModRegRm
;
3120 BOOLEAN OperandSize
, AddressSize
;
3122 /* Make sure this is the right instruction */
3123 ASSERT((Opcode
& 0xED) == 0x29);
3125 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3127 TOGGLE_ADSIZE(AddressSize
);
3128 TOGGLE_OPSIZE(OperandSize
);
3130 /* Get the operands */
3131 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3133 /* Exception occurred */
3137 /* Check the operand size */
3140 ULONG FirstValue
, SecondValue
, Result
;
3142 if (!Fast486ReadModrmDwordOperands(State
,
3147 /* Exception occurred */
3151 /* Check if this is the instruction that writes to R/M */
3152 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3154 /* Swap the order */
3155 SWAP(FirstValue
, SecondValue
);
3158 /* Calculate the result */
3159 Result
= FirstValue
- SecondValue
;
3161 /* Update the flags */
3162 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3163 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3164 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3165 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3166 State
->Flags
.Zf
= (Result
== 0);
3167 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3168 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3170 /* Check if this is not a CMP */
3171 if (!(Opcode
& 0x10))
3173 /* Write back the result */
3174 return Fast486WriteModrmDwordOperands(State
,
3176 Opcode
& FAST486_OPCODE_WRITE_REG
,
3181 /* Discard the result */
3187 USHORT FirstValue
, SecondValue
, Result
;
3189 if (!Fast486ReadModrmWordOperands(State
,
3194 /* Exception occurred */
3198 /* Check if this is the instruction that writes to R/M */
3199 if (!(Opcode
& FAST486_OPCODE_WRITE_REG
))
3201 /* Swap the order */
3202 SWAP(FirstValue
, SecondValue
);
3205 /* Calculate the result */
3206 Result
= FirstValue
- SecondValue
;
3208 /* Update the flags */
3209 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3210 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3211 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3212 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3213 State
->Flags
.Zf
= (Result
== 0);
3214 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3215 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3217 /* Check if this is not a CMP */
3218 if (!(Opcode
& 0x10))
3220 /* Write back the result */
3221 return Fast486WriteModrmWordOperands(State
,
3223 Opcode
& FAST486_OPCODE_WRITE_REG
,
3228 /* Discard the result */
3234 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubAl
)
3236 UCHAR FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3237 UCHAR SecondValue
, Result
;
3239 /* Make sure this is the right instruction */
3240 ASSERT((Opcode
& 0xEF) == 0x2C);
3242 if (State
->PrefixFlags
)
3244 /* This opcode doesn't take any prefixes */
3245 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3249 if (!Fast486FetchByte(State
, &SecondValue
))
3251 /* Exception occurred */
3255 /* Calculate the result */
3256 Result
= FirstValue
- SecondValue
;
3258 /* Update the flags */
3259 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3260 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3261 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3262 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3263 State
->Flags
.Zf
= (Result
== 0);
3264 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_BYTE
) != 0);
3265 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3267 /* Check if this is not a CMP */
3268 if (!(Opcode
& 0x10))
3270 /* Write back the result */
3271 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Result
;
3277 FAST486_OPCODE_HANDLER(Fast486OpcodeCmpSubEax
)
3279 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3281 /* Make sure this is the right instruction */
3282 ASSERT((Opcode
& 0xEF) == 0x2D);
3285 TOGGLE_OPSIZE(Size
);
3289 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
3290 ULONG SecondValue
, Result
;
3292 if (!Fast486FetchDword(State
, &SecondValue
))
3294 /* Exception occurred */
3298 /* Calculate the result */
3299 Result
= FirstValue
- SecondValue
;
3301 /* Update the flags */
3302 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3303 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3304 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3305 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3306 State
->Flags
.Zf
= (Result
== 0);
3307 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_LONG
) != 0);
3308 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3310 /* Check if this is not a CMP */
3311 if (!(Opcode
& 0x10))
3313 /* Write back the result */
3314 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= Result
;
3319 USHORT FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
3320 USHORT SecondValue
, Result
;
3322 if (!Fast486FetchWord(State
, &SecondValue
))
3324 /* Exception occurred */
3328 /* Calculate the result */
3329 Result
= FirstValue
- SecondValue
;
3331 /* Update the flags */
3332 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
3333 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3334 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3335 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3336 State
->Flags
.Zf
= (Result
== 0);
3337 State
->Flags
.Sf
= ((Result
& SIGN_FLAG_WORD
) != 0);
3338 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
3340 /* Check if this is not a CMP */
3341 if (!(Opcode
& 0x10))
3343 /* Write back the result */
3344 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Result
;
3351 FAST486_OPCODE_HANDLER(Fast486OpcodeDas
)
3353 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3354 BOOLEAN Carry
= State
->Flags
.Cf
;
3356 /* Clear the carry flag */
3357 State
->Flags
.Cf
= FALSE
;
3359 /* Check if the first BCD digit is invalid or there was a borrow */
3360 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3363 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x06;
3364 if (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
> 0xFB)
3366 /* A borrow occurred */
3367 State
->Flags
.Cf
= TRUE
;
3370 /* Set the adjust flag */
3371 State
->Flags
.Af
= TRUE
;
3374 /* Check if the second BCD digit is invalid or there was a borrow */
3375 if ((Value
> 0x99) || Carry
)
3378 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
-= 0x60;
3380 /* There was a borrow */
3381 State
->Flags
.Cf
= TRUE
;
3384 Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3386 /* Update the flags */
3387 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) != 0;
3388 State
->Flags
.Zf
= (Value
== 0);
3389 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
3394 FAST486_OPCODE_HANDLER(Fast486OpcodeAaa
)
3396 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3399 * Check if the value in AL is not a valid BCD digit,
3400 * or there was a carry from the lowest 4 bits of AL
3402 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3405 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
+= 0x06;
3406 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
++;
3409 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3413 /* Clear CF and AF */
3414 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3417 /* Keep only the lowest 4 bits of AL */
3418 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3423 FAST486_OPCODE_HANDLER(Fast486OpcodeAas
)
3425 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
3428 * Check if the value in AL is not a valid BCD digit,
3429 * or there was a borrow from the lowest 4 bits of AL
3431 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3434 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
-= 0x06;
3435 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
--;
3438 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3442 /* Clear CF and AF */
3443 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3446 /* Keep only the lowest 4 bits of AL */
3447 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
&= 0x0F;
3452 FAST486_OPCODE_HANDLER(Fast486OpcodePushAll
)
3455 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3456 FAST486_REG SavedEsp
= State
->GeneralRegs
[FAST486_REG_ESP
];
3458 /* Make sure this is the right instruction */
3459 ASSERT(Opcode
== 0x60);
3461 TOGGLE_OPSIZE(Size
);
3464 /* Push all the registers in order */
3465 for (i
= 0; i
< FAST486_NUM_GEN_REGS
; i
++)
3467 if (i
== FAST486_REG_ESP
)
3469 /* Use the saved ESP instead */
3470 if (!Fast486StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3472 /* Exception occurred */
3478 /* Push the register */
3479 if (!Fast486StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3480 : State
->GeneralRegs
[i
].LowWord
))
3482 /* Exception occurred */
3491 FAST486_OPCODE_HANDLER(Fast486OpcodePopAll
)
3494 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3497 /* Make sure this is the right instruction */
3498 ASSERT(Opcode
== 0x61);
3500 TOGGLE_OPSIZE(Size
);
3503 /* Pop all the registers in reverse order */
3504 for (i
= FAST486_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3507 if (!Fast486StackPop(State
, &Value
))
3509 /* Exception occurred */
3513 /* Don't modify ESP */
3514 if (i
!= FAST486_REG_ESP
)
3516 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3517 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3524 FAST486_OPCODE_HANDLER(Fast486OpcodeBound
)
3526 // TODO: NOT IMPLEMENTED
3532 FAST486_OPCODE_HANDLER(Fast486OpcodeArpl
)
3534 USHORT FirstValue
, SecondValue
;
3535 FAST486_MOD_REG_RM ModRegRm
;
3536 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3538 if (!(State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
3540 || (State
->PrefixFlags
& FAST486_PREFIX_LOCK
))
3542 /* Cannot be used in real mode or with a LOCK prefix */
3543 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3547 TOGGLE_ADSIZE(AddressSize
);
3549 /* Get the operands */
3550 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3552 /* Exception occurred */
3556 /* Read the operands */
3557 if (!Fast486ReadModrmWordOperands(State
,
3562 /* Exception occurred */
3566 /* Check if the RPL needs adjusting */
3567 if ((SecondValue
& 3) < (FirstValue
& 3))
3569 /* Adjust the RPL */
3571 SecondValue
|= FirstValue
& 3;
3574 State
->Flags
.Zf
= TRUE
;
3576 /* Write back the result */
3577 return Fast486WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3582 State
->Flags
.Zf
= FALSE
;
3587 FAST486_OPCODE_HANDLER(Fast486OpcodePushImm
)
3589 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3591 /* Make sure this is the right instruction */
3592 ASSERT(Opcode
== 0x68);
3595 TOGGLE_OPSIZE(Size
);
3601 if (!Fast486FetchDword(State
, &Data
))
3603 /* Exception occurred */
3607 /* Call the internal API */
3608 return Fast486StackPush(State
, Data
);
3614 if (!Fast486FetchWord(State
, &Data
))
3616 /* Exception occurred */
3620 /* Call the internal API */
3621 return Fast486StackPush(State
, Data
);
3625 FAST486_OPCODE_HANDLER(Fast486OpcodeImulModrmImm
)
3627 BOOLEAN OperandSize
, AddressSize
;
3628 FAST486_MOD_REG_RM ModRegRm
;
3631 /* Make sure this is the right instruction */
3632 ASSERT((Opcode
& 0xFD) == 0x69);
3634 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3636 TOGGLE_ADSIZE(AddressSize
);
3637 TOGGLE_OPSIZE(OperandSize
);
3639 /* Fetch the parameters */
3640 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3642 /* Exception occurred */
3650 /* Fetch the immediate operand */
3651 if (!Fast486FetchByte(State
, (PUCHAR
)&Byte
))
3653 /* Exception occurred */
3657 Multiplier
= (LONG
)Byte
;
3665 /* Fetch the immediate operand */
3666 if (!Fast486FetchDword(State
, (PULONG
)&Dword
))
3668 /* Exception occurred */
3678 /* Fetch the immediate operand */
3679 if (!Fast486FetchWord(State
, (PUSHORT
)&Word
))
3681 /* Exception occurred */
3685 Multiplier
= (LONG
)Word
;
3691 LONG RegValue
, Multiplicand
;
3694 /* Read the operands */
3695 if (!Fast486ReadModrmDwordOperands(State
,
3698 (PULONG
)&Multiplicand
))
3700 /* Exception occurred */
3705 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3707 /* Check for carry/overflow */
3708 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINLONG
) || (Product
> MAXLONG
));
3710 /* Write-back the result */
3711 return Fast486WriteModrmDwordOperands(State
,
3714 (ULONG
)((LONG
)Product
));
3718 SHORT RegValue
, Multiplicand
;
3721 /* Read the operands */
3722 if (!Fast486ReadModrmWordOperands(State
,
3725 (PUSHORT
)&Multiplicand
))
3727 /* Exception occurred */
3732 Product
= (LONG
)Multiplicand
* (LONG
)Multiplier
;
3734 /* Check for carry/overflow */
3735 State
->Flags
.Cf
= State
->Flags
.Of
= ((Product
< MINSHORT
) || (Product
> MAXSHORT
));
3737 /* Write-back the result */
3738 return Fast486WriteModrmWordOperands(State
,
3741 (USHORT
)((SHORT
)Product
));
3745 FAST486_OPCODE_HANDLER(Fast486OpcodePushByteImm
)
3749 /* Make sure this is the right instruction */
3750 ASSERT(Opcode
== 0x6A);
3752 if (!Fast486FetchByte(State
, &Data
))
3754 /* Exception occurred */
3758 /* Call the internal API */
3759 return Fast486StackPush(State
, Data
);
3762 FAST486_OPCODE_HANDLER(Fast486OpcodeMovByteModrm
)
3764 UCHAR FirstValue
, SecondValue
, Result
;
3765 FAST486_MOD_REG_RM ModRegRm
;
3766 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3768 /* Make sure this is the right instruction */
3769 ASSERT((Opcode
& 0xFD) == 0x88);
3771 TOGGLE_ADSIZE(AddressSize
);
3773 /* Get the operands */
3774 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3776 /* Exception occurred */
3780 if (!Fast486ReadModrmByteOperands(State
,
3785 /* Exception occurred */
3789 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3790 else Result
= FirstValue
;
3792 /* Write back the result */
3793 return Fast486WriteModrmByteOperands(State
,
3795 Opcode
& FAST486_OPCODE_WRITE_REG
,
3800 FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm
)
3802 FAST486_MOD_REG_RM ModRegRm
;
3803 BOOLEAN OperandSize
, AddressSize
;
3805 /* Make sure this is the right instruction */
3806 ASSERT((Opcode
& 0xFD) == 0x89);
3808 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3810 TOGGLE_ADSIZE(AddressSize
);
3811 TOGGLE_OPSIZE(OperandSize
);
3813 /* Get the operands */
3814 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3816 /* Exception occurred */
3820 /* Check the operand size */
3823 ULONG FirstValue
, SecondValue
, Result
;
3825 if (!Fast486ReadModrmDwordOperands(State
,
3830 /* Exception occurred */
3834 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3835 else Result
= FirstValue
;
3837 /* Write back the result */
3838 return Fast486WriteModrmDwordOperands(State
,
3840 Opcode
& FAST486_OPCODE_WRITE_REG
,
3845 USHORT FirstValue
, SecondValue
, Result
;
3847 if (!Fast486ReadModrmWordOperands(State
,
3852 /* Exception occurred */
3856 if (Opcode
& FAST486_OPCODE_WRITE_REG
) Result
= SecondValue
;
3857 else Result
= FirstValue
;
3859 /* Write back the result */
3860 return Fast486WriteModrmWordOperands(State
,
3862 Opcode
& FAST486_OPCODE_WRITE_REG
,
3867 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg
)
3869 BOOLEAN OperandSize
, AddressSize
;
3870 FAST486_MOD_REG_RM ModRegRm
;
3872 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3874 /* Make sure this is the right instruction */
3875 ASSERT(Opcode
== 0x8C);
3877 TOGGLE_ADSIZE(AddressSize
);
3878 TOGGLE_OPSIZE(OperandSize
);
3880 /* Get the operands */
3881 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3883 /* Exception occurred */
3887 if (ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3890 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3896 return Fast486WriteModrmDwordOperands(State
,
3899 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3903 return Fast486WriteModrmWordOperands(State
,
3906 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
3910 FAST486_OPCODE_HANDLER(Fast486OpcodeLea
)
3912 FAST486_MOD_REG_RM ModRegRm
;
3913 BOOLEAN OperandSize
, AddressSize
;
3915 /* Make sure this is the right instruction */
3916 ASSERT(Opcode
== 0x8D);
3918 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3920 TOGGLE_ADSIZE(AddressSize
);
3921 TOGGLE_OPSIZE(OperandSize
);
3923 /* Get the operands */
3924 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3926 /* Exception occurred */
3930 /* The second operand must be memory */
3931 if (!ModRegRm
.Memory
)
3934 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3938 /* Write the address to the register */
3941 return Fast486WriteModrmDwordOperands(State
,
3944 ModRegRm
.MemoryAddress
);
3948 return Fast486WriteModrmWordOperands(State
,
3951 ModRegRm
.MemoryAddress
);
3956 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg
)
3958 BOOLEAN OperandSize
, AddressSize
;
3959 FAST486_MOD_REG_RM ModRegRm
;
3961 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
3963 /* Make sure this is the right instruction */
3964 ASSERT(Opcode
== 0x8E);
3966 TOGGLE_ADSIZE(AddressSize
);
3967 TOGGLE_OPSIZE(OperandSize
);
3969 /* Get the operands */
3970 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3972 /* Exception occurred */
3976 if ((ModRegRm
.Register
>= FAST486_NUM_SEG_REGS
)
3977 || ((FAST486_SEG_REGS
)ModRegRm
.Register
== FAST486_REG_CS
))
3980 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
3988 if (!Fast486ReadModrmDwordOperands(State
, &ModRegRm
, NULL
, &Selector
))
3990 /* Exception occurred */
3994 return Fast486LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4000 if (!Fast486ReadModrmWordOperands(State
, &ModRegRm
, NULL
, &Selector
))
4002 /* Exception occurred */
4006 return Fast486LoadSegment(State
, ModRegRm
.Register
, Selector
);
4010 FAST486_OPCODE_HANDLER(Fast486OpcodeCwde
)
4012 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4014 /* Make sure this is the right instruction */
4015 ASSERT(Opcode
== 0x98);
4017 TOGGLE_OPSIZE(Size
);
4022 /* Sign extend AX to EAX */
4023 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= MAKELONG
4025 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
4026 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4032 /* Sign extend AL to AX */
4033 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
=
4034 (State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4041 FAST486_OPCODE_HANDLER(Fast486OpcodeCdq
)
4043 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4045 /* Make sure this is the right instruction */
4046 ASSERT(Opcode
== 0x99);
4048 TOGGLE_OPSIZE(Size
);
4053 /* Sign extend EAX to EDX:EAX */
4054 State
->GeneralRegs
[FAST486_REG_EDX
].Long
=
4055 (State
->GeneralRegs
[FAST486_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4056 ? 0xFFFFFFFF : 0x00000000;
4060 /* Sign extend AX to DX:AX */
4061 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
=
4062 (State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4069 FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs
)
4073 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4075 /* Make sure this is the right instruction */
4076 ASSERT(Opcode
== 0x9A);
4078 TOGGLE_OPSIZE(Size
);
4081 /* Fetch the offset */
4084 if (!Fast486FetchDword(State
, &Offset
))
4086 /* Exception occurred */
4092 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
4094 /* Exception occurred */
4099 /* Fetch the segment */
4100 if (!Fast486FetchWord(State
, &Segment
))
4102 /* Exception occurred */
4106 /* Push the current code segment selector */
4107 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
))
4109 /* Exception occurred */
4113 /* Push the current value of the instruction pointer */
4114 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
4116 /* Exception occurred */
4120 /* Load the new CS */
4121 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4123 /* Exception occurred */
4127 /* Load new (E)IP */
4128 if (Size
) State
->InstPtr
.Long
= Offset
;
4129 else State
->InstPtr
.LowWord
= LOWORD(Offset
);
4134 FAST486_OPCODE_HANDLER(Fast486OpcodeWait
)
4136 // TODO: NOT IMPLEMENTED
4142 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags
)
4144 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4147 TOGGLE_OPSIZE(Size
);
4149 /* Check for VM86 mode when IOPL is not 3 */
4150 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4152 /* Call the VM86 monitor */
4153 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4157 /* Push the flags */
4158 if (Size
) return Fast486StackPush(State
, State
->Flags
.Long
);
4159 else return Fast486StackPush(State
, LOWORD(State
->Flags
.Long
));
4162 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags
)
4164 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4165 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4169 TOGGLE_OPSIZE(Size
);
4171 /* Pop the new flags */
4172 if (!Fast486StackPop(State
, &NewFlags
))
4174 /* Exception occurred */
4178 if (!State
->Flags
.Vm
)
4180 /* Check the current privilege level */
4188 /* Memorize the old state of RF */
4189 BOOLEAN OldRf
= State
->Flags
.Rf
;
4191 State
->Flags
.Long
= NewFlags
;
4193 /* Restore VM and RF */
4194 State
->Flags
.Vm
= FALSE
;
4195 State
->Flags
.Rf
= OldRf
;
4197 /* Clear VIF and VIP */
4198 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4200 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4202 /* Restore the reserved bits */
4203 State
->Flags
.AlwaysSet
= TRUE
;
4204 State
->Flags
.Reserved0
= FALSE
;
4205 State
->Flags
.Reserved1
= FALSE
;
4211 /* Memorize the old state of IF and IOPL */
4212 BOOLEAN OldIf
= State
->Flags
.If
;
4213 UINT OldIopl
= State
->Flags
.Iopl
;
4218 /* Memorize the old state of RF */
4219 BOOLEAN OldRf
= State
->Flags
.Rf
;
4221 State
->Flags
.Long
= NewFlags
;
4223 /* Restore VM and RF */
4224 State
->Flags
.Vm
= FALSE
;
4225 State
->Flags
.Rf
= OldRf
;
4227 /* Clear VIF and VIP */
4228 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4230 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4232 /* Restore the reserved bits and IOPL */
4233 State
->Flags
.AlwaysSet
= TRUE
;
4234 State
->Flags
.Reserved0
= FALSE
;
4235 State
->Flags
.Reserved1
= FALSE
;
4236 State
->Flags
.Iopl
= OldIopl
;
4238 /* Check if the user doesn't have the privilege to change IF */
4239 if (Cpl
> State
->Flags
.Iopl
)
4242 State
->Flags
.If
= OldIf
;
4248 /* Check the IOPL */
4249 if (State
->Flags
.Iopl
== 3)
4253 /* Memorize the old state of RF, VIF and VIP */
4254 BOOLEAN OldRf
= State
->Flags
.Rf
;
4255 BOOLEAN OldVif
= State
->Flags
.Vif
;
4256 BOOLEAN OldVip
= State
->Flags
.Vip
;
4258 State
->Flags
.Long
= NewFlags
;
4260 /* Restore VM, RF, VIF and VIP */
4261 State
->Flags
.Vm
= TRUE
;
4262 State
->Flags
.Rf
= OldRf
;
4263 State
->Flags
.Vif
= OldVif
;
4264 State
->Flags
.Vip
= OldVip
;
4266 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4268 /* Restore the reserved bits and IOPL */
4269 State
->Flags
.AlwaysSet
= TRUE
;
4270 State
->Flags
.Reserved0
= FALSE
;
4271 State
->Flags
.Reserved1
= FALSE
;
4272 State
->Flags
.Iopl
= 3;
4276 /* Call the VM86 monitor */
4277 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4285 FAST486_OPCODE_HANDLER(Fast486OpcodeSahf
)
4287 /* Make sure this is the right instruction */
4288 ASSERT(Opcode
== 0x9E);
4290 /* Set the low-order byte of FLAGS to AH */
4291 State
->Flags
.Long
&= 0xFFFFFF00;
4292 State
->Flags
.Long
|= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
;
4294 /* Restore the reserved bits of FLAGS */
4295 State
->Flags
.AlwaysSet
= TRUE
;
4296 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4301 FAST486_OPCODE_HANDLER(Fast486OpcodeLahf
)
4303 /* Make sure this is the right instruction */
4304 ASSERT(Opcode
== 0x9F);
4306 /* Set AH to the low-order byte of FLAGS */
4307 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4312 FAST486_OPCODE_HANDLER(Fast486OpcodeRet
)
4314 ULONG ReturnAddress
;
4315 USHORT BytesToPop
= 0;
4316 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4318 /* Make sure this is the right instruction */
4319 ASSERT((Opcode
& 0xFE) == 0xC2);
4322 TOGGLE_OPSIZE(Size
);
4326 /* Fetch the number of bytes to pop after the return */
4327 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4330 /* Pop the return address */
4331 if (!Fast486StackPop(State
, &ReturnAddress
)) return FALSE
;
4333 /* Return to the calling procedure, and if necessary, pop the parameters */
4336 State
->InstPtr
.Long
= ReturnAddress
;
4337 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4341 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4342 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4348 FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes
)
4350 UCHAR FarPointer
[6];
4351 BOOLEAN OperandSize
, AddressSize
;
4352 FAST486_MOD_REG_RM ModRegRm
;
4354 /* Make sure this is the right instruction */
4355 ASSERT((Opcode
& 0xFE) == 0xC4);
4357 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4359 TOGGLE_OPSIZE(OperandSize
);
4360 TOGGLE_ADSIZE(AddressSize
);
4362 /* Get the operands */
4363 if (!Fast486ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4365 /* Exception occurred */
4369 if (!ModRegRm
.Memory
)
4371 /* Check if this is a BOP and the host supports BOPs */
4372 if ((Opcode
== 0xC4)
4373 && (ModRegRm
.Register
== FAST486_REG_EAX
)
4374 && (ModRegRm
.SecondRegister
== FAST486_REG_ESP
)
4375 && (State
->BopCallback
!= NULL
))
4379 /* Fetch the BOP code */
4380 if (!Fast486FetchByte(State
, &BopCode
))
4382 /* Exception occurred */
4386 /* Call the BOP handler */
4387 State
->BopCallback(State
, BopCode
);
4389 /* Return success */
4394 Fast486Exception(State
, FAST486_EXCEPTION_UD
);
4398 if (!Fast486ReadMemory(State
,
4399 (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
4400 ? State
->SegmentOverride
: FAST486_REG_DS
,
4401 ModRegRm
.MemoryAddress
,
4404 OperandSize
? 6 : 4))
4406 /* Exception occurred */
4412 ULONG Offset
= *((PULONG
)FarPointer
);
4413 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4415 /* Set the register to the offset */
4416 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4418 /* Load the segment */
4419 return Fast486LoadSegment(State
,
4421 ? FAST486_REG_ES
: FAST486_REG_DS
,
4426 USHORT Offset
= *((PUSHORT
)FarPointer
);
4427 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4429 /* Set the register to the offset */
4430 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4432 /* Load the segment */
4433 return Fast486LoadSegment(State
,
4435 ? FAST486_REG_ES
: FAST486_REG_DS
,
4440 FAST486_OPCODE_HANDLER(Fast486OpcodeEnter
)
4443 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4446 FAST486_REG FramePointer
;
4448 /* Make sure this is the right instruction */
4449 ASSERT(Opcode
== 0xC8);
4452 TOGGLE_OPSIZE(Size
);
4454 if (!Fast486FetchWord(State
, &FrameSize
))
4456 /* Exception occurred */
4460 if (!Fast486FetchByte(State
, &NestingLevel
))
4462 /* Exception occurred */
4467 if (!Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
))
4469 /* Exception occurred */
4474 FramePointer
= State
->GeneralRegs
[FAST486_REG_ESP
];
4476 /* Set up the nested procedure stacks */
4477 for (i
= 1; i
< NestingLevel
; i
++)
4481 State
->GeneralRegs
[FAST486_REG_EBP
].Long
-= 4;
4482 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4486 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
-= 2;
4487 Fast486StackPush(State
, State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
);
4491 if (NestingLevel
> 0) Fast486StackPush(State
, FramePointer
.Long
);
4493 /* Set EBP to the frame pointer */
4494 State
->GeneralRegs
[FAST486_REG_EBP
] = FramePointer
;
4496 /* Reserve space for the frame */
4497 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4498 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
-= FrameSize
;
4503 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave
)
4505 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4507 /* Make sure this is the right instruction */
4508 ASSERT(Opcode
== 0xC9);
4511 TOGGLE_OPSIZE(Size
);
4515 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4516 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
4518 /* Pop the saved base pointer from the stack */
4519 return Fast486StackPop(State
, &State
->GeneralRegs
[FAST486_REG_EBP
].Long
);
4525 /* Set the stack pointer (SP) to the base pointer (BP) */
4526 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
4528 /* Pop the saved base pointer from the stack */
4529 if (Fast486StackPop(State
, &Value
))
4531 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= LOWORD(Value
);
4538 FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar
)
4542 USHORT BytesToPop
= 0;
4543 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4545 /* Make sure this is the right instruction */
4546 ASSERT((Opcode
& 0xFE) == 0xCA);
4548 TOGGLE_OPSIZE(Size
);
4553 /* Fetch the number of bytes to pop after the return */
4554 if (!Fast486FetchWord(State
, &BytesToPop
)) return FALSE
;
4557 /* Pop the offset */
4558 if (!Fast486StackPop(State
, &Offset
))
4560 /* Exception occurred */
4564 /* Pop the segment */
4565 if (!Fast486StackPop(State
, &Segment
))
4567 /* Exception occurred */
4571 /* Load the new CS */
4572 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
4574 /* Exception occurred */
4578 /* Load new (E)IP, and if necessary, pop the parameters */
4581 State
->InstPtr
.Long
= Offset
;
4582 State
->GeneralRegs
[FAST486_REG_ESP
].Long
+= BytesToPop
;
4586 State
->InstPtr
.LowWord
= LOWORD(Offset
);
4587 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
+= BytesToPop
;
4593 FAST486_OPCODE_HANDLER(Fast486OpcodeInt
)
4596 FAST486_IDT_ENTRY IdtEntry
;
4602 /* This is the INT3 instruction */
4609 /* Fetch the interrupt number */
4610 if (!Fast486FetchByte(State
, &IntNum
))
4612 /* Exception occurred */
4621 /* Don't do anything if OF is cleared */
4622 if (!State
->Flags
.Of
) return TRUE
;
4625 IntNum
= FAST486_EXCEPTION_OF
;
4632 /* Should not happen */
4637 /* Get the interrupt vector */
4638 if (!Fast486GetIntVector(State
, IntNum
, &IdtEntry
))
4640 /* Exception occurred */
4644 /* Perform the interrupt */
4645 if (!Fast486InterruptInternal(State
,
4647 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4650 /* Exception occurred */
4657 FAST486_OPCODE_HANDLER(Fast486OpcodeIret
)
4660 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4661 FAST486_FLAGS_REG NewFlags
;
4662 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4664 /* Make sure this is the right instruction */
4665 ASSERT(Opcode
== 0xCF);
4668 TOGGLE_OPSIZE(Size
);
4671 if (!Fast486StackPop(State
, &InstPtr
))
4673 /* Exception occurred */
4678 if (!Fast486StackPop(State
, &CodeSel
))
4680 /* Exception occurred */
4685 if (!Fast486StackPop(State
, &NewFlags
.Long
))
4687 /* Exception occurred */
4691 /* Check for protected mode */
4692 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
4694 INT Cpl
= Fast486GetCurrentPrivLevel(State
);
4696 if (State
->Flags
.Vm
)
4698 /* Return from VM86 mode */
4700 /* Check the IOPL */
4701 if (State
->Flags
.Iopl
== 3)
4704 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4707 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4709 /* Exception occurred */
4713 /* Set the new flags */
4714 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4715 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4716 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4717 State
->Flags
.Iopl
= 3;
4721 /* Call the VM86 monitor */
4722 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4729 if (State
->Flags
.Nt
)
4731 /* Nested task return */
4739 /* Return to VM86 mode */
4740 ULONG Es
, Ds
, Fs
, Gs
;
4742 /* Pop ESP, SS, ES, FS, GS */
4743 if (!Fast486StackPop(State
, &StackPtr
)) return FALSE
;
4744 if (!Fast486StackPop(State
, &StackSel
)) return FALSE
;
4745 if (!Fast486StackPop(State
, &Es
)) return FALSE
;
4746 if (!Fast486StackPop(State
, &Ds
)) return FALSE
;
4747 if (!Fast486StackPop(State
, &Fs
)) return FALSE
;
4748 if (!Fast486StackPop(State
, &Gs
)) return FALSE
;
4750 /* Set the new IP */
4751 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4753 /* Set the new flags */
4754 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4755 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4756 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4758 /* Load the new segments */
4759 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
)) return FALSE
;
4760 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
)) return FALSE
;
4761 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, Es
)) return FALSE
;
4762 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, Ds
)) return FALSE
;
4763 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, Fs
)) return FALSE
;
4764 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, Gs
)) return FALSE
;
4769 /* Load the new CS */
4770 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4772 /* Exception occurred */
4777 if (Size
) State
->InstPtr
.Long
= InstPtr
;
4778 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
4780 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4783 if (!Fast486StackPop(State
, &StackPtr
))
4790 if (!Fast486StackPop(State
, &StackSel
))
4797 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, StackSel
))
4804 if (Size
) State
->GeneralRegs
[FAST486_REG_ESP
].Long
= StackPtr
;
4805 else State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= LOWORD(StackPtr
);
4808 /* Set the new flags */
4809 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
4810 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
4811 State
->Flags
.AlwaysSet
= TRUE
;
4813 /* Set additional flags */
4814 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
4815 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
4817 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
4819 /* Update the CPL */
4820 Cpl
= Fast486GetCurrentPrivLevel(State
);
4822 /* Check segment security */
4823 for (i
= 0; i
< FAST486_NUM_SEG_REGS
; i
++)
4825 /* Don't check CS or SS */
4826 if ((i
== FAST486_REG_CS
) || (i
== FAST486_REG_SS
)) continue;
4828 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
4829 && (!State
->SegmentRegs
[i
].Executable
4830 || !State
->SegmentRegs
[i
].DirConf
))
4832 /* Load the NULL descriptor in the segment */
4833 if (!Fast486LoadSegment(State
, i
, 0)) return FALSE
;
4840 if (Size
&& (InstPtr
& 0xFFFF0000))
4843 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, 0);
4848 State
->InstPtr
.Long
= InstPtr
;
4851 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, CodeSel
))
4853 /* Exception occurred */
4857 /* Set the new flags */
4858 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4859 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4860 State
->Flags
.AlwaysSet
= TRUE
;
4866 FAST486_OPCODE_HANDLER(Fast486OpcodeAam
)
4869 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4873 /* Fetch the base */
4874 if (!Fast486FetchByte(State
, &Base
))
4876 /* Exception occurred */
4880 /* Check if the base is zero */
4884 Fast486Exception(State
, FAST486_EXCEPTION_DE
);
4889 State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
= Value
/ Base
;
4890 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
%= Base
;
4893 State
->Flags
.Af
= FALSE
;
4894 State
->Flags
.Zf
= (Value
== 0);
4895 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4896 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4901 FAST486_OPCODE_HANDLER(Fast486OpcodeAad
)
4904 UCHAR Value
= State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
;
4908 /* Fetch the base */
4909 if (!Fast486FetchByte(State
, &Base
))
4911 /* Exception occurred */
4916 Value
+= State
->GeneralRegs
[FAST486_REG_EAX
].HighByte
* Base
;
4917 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= Value
;
4920 State
->Flags
.Af
= FALSE
;
4921 State
->Flags
.Zf
= (Value
== 0);
4922 State
->Flags
.Sf
= ((Value
& SIGN_FLAG_BYTE
) != 0);
4923 State
->Flags
.Pf
= Fast486CalculateParity(Value
);
4928 FAST486_OPCODE_HANDLER(Fast486OpcodeXlat
)
4931 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4933 TOGGLE_ADSIZE(AddressSize
);
4935 /* Read a byte from DS:[(E)BX + AL] */
4936 if (!Fast486ReadMemory(State
,
4938 (AddressSize
? State
->GeneralRegs
[FAST486_REG_EBX
].Long
4939 : State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
)
4940 + State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
4945 /* Exception occurred */
4949 /* Set AL to the result */
4950 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= Value
;
4952 /* Return success */
4956 FAST486_OPCODE_HANDLER(Fast486OpcodeLoop
)
4959 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
4962 /* Make sure this is the right instruction */
4963 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
4966 TOGGLE_ADSIZE(Size
);
4968 if (Size
) Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) != 0);
4969 else Condition
= ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) != 0);
4973 /* Additional rule for LOOPNZ */
4974 if (State
->Flags
.Zf
) Condition
= FALSE
;
4979 /* Additional rule for LOOPZ */
4980 if (!State
->Flags
.Zf
) Condition
= FALSE
;
4983 /* Fetch the offset */
4984 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
4986 /* An exception occurred */
4992 /* Move the instruction pointer */
4993 if (Size
) State
->InstPtr
.Long
+= Offset
;
4994 else State
->InstPtr
.LowWord
+= Offset
;
5000 FAST486_OPCODE_HANDLER(Fast486OpcodeJecxz
)
5003 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5006 /* Make sure this is the right instruction */
5007 ASSERT(Opcode
== 0xE3);
5010 TOGGLE_ADSIZE(Size
);
5012 if (Size
) Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].Long
== 0);
5013 else Condition
= (State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
== 0);
5015 /* Fetch the offset */
5016 if (!Fast486FetchByte(State
, (PUCHAR
)&Offset
))
5018 /* An exception occurred */
5024 /* Move the instruction pointer */
5025 if (Size
) State
->InstPtr
.Long
+= Offset
;
5026 else State
->InstPtr
.LowWord
+= Offset
;
5032 FAST486_OPCODE_HANDLER(Fast486OpcodeCall
)
5034 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5036 /* Make sure this is the right instruction */
5037 ASSERT(Opcode
== 0xE8);
5039 TOGGLE_OPSIZE(Size
);
5046 /* Fetch the offset */
5047 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5049 /* An exception occurred */
5053 /* Push the current value of the instruction pointer */
5054 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5056 /* Exception occurred */
5060 /* Move the instruction pointer */
5061 State
->InstPtr
.Long
+= Offset
;
5067 /* Fetch the offset */
5068 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5070 /* An exception occurred */
5074 /* Push the current value of the instruction pointer */
5075 if (!Fast486StackPush(State
, State
->InstPtr
.Long
))
5077 /* Exception occurred */
5081 /* Move the instruction pointer */
5082 State
->InstPtr
.LowWord
+= Offset
;
5088 FAST486_OPCODE_HANDLER(Fast486OpcodeJmp
)
5090 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5092 /* Make sure this is the right instruction */
5093 ASSERT(Opcode
== 0xE9);
5095 TOGGLE_OPSIZE(Size
);
5102 /* Fetch the offset */
5103 if (!Fast486FetchDword(State
, (PULONG
)&Offset
))
5105 /* An exception occurred */
5109 /* Move the instruction pointer */
5110 State
->InstPtr
.Long
+= Offset
;
5116 /* Fetch the offset */
5117 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5119 /* An exception occurred */
5123 /* Move the instruction pointer */
5124 State
->InstPtr
.Long
+= Offset
;
5126 /* Clear the top half of EIP */
5127 State
->InstPtr
.Long
&= 0xFFFF;
5133 FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs
)
5137 BOOLEAN Size
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5139 /* Make sure this is the right instruction */
5140 ASSERT(Opcode
== 0xEA);
5142 TOGGLE_OPSIZE(Size
);
5145 /* Fetch the offset */
5148 if (!Fast486FetchDword(State
, &Offset
))
5150 /* Exception occurred */
5156 if (!Fast486FetchWord(State
, (PUSHORT
)&Offset
))
5158 /* Exception occurred */
5163 /* Fetch the segment */
5164 if (!Fast486FetchWord(State
, &Segment
))
5166 /* Exception occurred */
5170 /* Load the new CS */
5171 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Segment
))
5173 /* Exception occurred */
5178 State
->InstPtr
.Long
= Offset
;
5183 FAST486_OPCODE_HANDLER(Fast486OpcodeMovAlOffset
)
5185 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5188 /* Make sure this is the right instruction */
5189 ASSERT(Opcode
== 0xA0);
5191 TOGGLE_ADSIZE(AddressSize
);
5195 if (!Fast486FetchDword(State
, &Offset
))
5197 /* Exception occurred */
5205 if (!Fast486FetchWord(State
, &WordOffset
))
5207 /* Exception occurred */
5211 Offset
= (ULONG
)WordOffset
;
5214 /* Read from memory */
5215 return Fast486ReadMemory(State
,
5216 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5217 State
->SegmentOverride
: FAST486_REG_DS
,
5220 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5224 FAST486_OPCODE_HANDLER(Fast486OpcodeMovEaxOffset
)
5226 BOOLEAN OperandSize
, AddressSize
;
5228 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5230 /* Make sure this is the right instruction */
5231 ASSERT(Opcode
== 0xA1);
5233 TOGGLE_OPSIZE(OperandSize
);
5234 TOGGLE_ADSIZE(AddressSize
);
5240 if (!Fast486FetchDword(State
, &Offset
))
5242 /* Exception occurred */
5246 /* Read from memory */
5249 return Fast486ReadMemory(State
,
5250 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5251 State
->SegmentOverride
: FAST486_REG_DS
,
5254 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5259 return Fast486ReadMemory(State
,
5260 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5261 State
->SegmentOverride
: FAST486_REG_DS
,
5264 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5272 if (!Fast486FetchWord(State
, &Offset
))
5274 /* Exception occurred */
5278 /* Read from memory */
5281 return Fast486ReadMemory(State
,
5282 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5283 State
->SegmentOverride
: FAST486_REG_DS
,
5286 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5291 return Fast486ReadMemory(State
,
5292 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5293 State
->SegmentOverride
: FAST486_REG_DS
,
5296 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5302 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl
)
5304 BOOLEAN AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5307 /* Make sure this is the right instruction */
5308 ASSERT(Opcode
== 0xA2);
5310 TOGGLE_ADSIZE(AddressSize
);
5314 if (!Fast486FetchDword(State
, &Offset
))
5316 /* Exception occurred */
5324 if (!Fast486FetchWord(State
, &WordOffset
))
5326 /* Exception occurred */
5330 Offset
= (ULONG
)WordOffset
;
5333 /* Write to memory */
5334 return Fast486WriteMemory(State
,
5335 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5336 State
->SegmentOverride
: FAST486_REG_DS
,
5338 &State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
,
5342 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax
)
5344 BOOLEAN OperandSize
, AddressSize
;
5346 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5348 /* Make sure this is the right instruction */
5349 ASSERT(Opcode
== 0xA3);
5351 TOGGLE_OPSIZE(OperandSize
);
5352 TOGGLE_ADSIZE(AddressSize
);
5358 if (!Fast486FetchDword(State
, &Offset
))
5360 /* Exception occurred */
5364 /* Write to memory */
5367 return Fast486WriteMemory(State
,
5368 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5369 State
->SegmentOverride
: FAST486_REG_DS
,
5371 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5376 return Fast486WriteMemory(State
,
5377 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5378 State
->SegmentOverride
: FAST486_REG_DS
,
5380 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5388 if (!Fast486FetchWord(State
, &Offset
))
5390 /* Exception occurred */
5394 /* Write to memory */
5397 return Fast486WriteMemory(State
,
5398 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5399 State
->SegmentOverride
: FAST486_REG_DS
,
5401 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5406 return Fast486WriteMemory(State
,
5407 (State
->PrefixFlags
& FAST486_PREFIX_SEG
) ?
5408 State
->SegmentOverride
: FAST486_REG_DS
,
5410 &State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
,
5416 FAST486_OPCODE_HANDLER(Fast486OpcodeSalc
)
5418 /* Make sure this is the right instruction */
5419 ASSERT(Opcode
== 0xD6);
5423 /* Set all the bits of AL to CF */
5424 State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5429 FAST486_OPCODE_HANDLER(Fast486OpcodeMovs
)
5431 ULONG Data
, DataSize
;
5432 BOOLEAN OperandSize
, AddressSize
;
5433 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5435 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5437 /* Make sure this is the right instruction */
5438 ASSERT((Opcode
& 0xFE) == 0xA4);
5440 TOGGLE_OPSIZE(OperandSize
);
5441 TOGGLE_ADSIZE(AddressSize
);
5443 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5445 /* Use the override segment instead of DS */
5446 Segment
= State
->SegmentOverride
;
5449 /* Calculate the size */
5450 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5451 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5453 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5455 UCHAR Block
[STRING_BLOCK_SIZE
];
5456 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5457 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5459 /* Clear the memory block */
5460 RtlZeroMemory(Block
, sizeof(Block
));
5462 /* Transfer until finished */
5465 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5467 /* Simulate the 16-bit wrap-around of SI and DI in 16-bit address mode */
5470 ULONG MaxBytesSrc
= State
->Flags
.Df
5471 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
5472 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
);
5473 ULONG MaxBytesDest
= State
->Flags
.Df
5474 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5475 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5478 Processed
= min(Processed
, min(MaxBytesSrc
, MaxBytesDest
) / DataSize
);
5479 if (Processed
== 0) Processed
= 1;
5482 if (State
->Flags
.Df
)
5484 /* Reduce ESI and EDI by the number of bytes to transfer */
5487 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= Processed
* DataSize
;
5488 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5492 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= Processed
* DataSize
;
5493 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5497 /* Read from memory */
5498 if (!Fast486ReadMemory(State
,
5500 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5501 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5504 Processed
* DataSize
))
5507 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5508 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5510 /* Exception occurred */
5514 /* Write to memory */
5515 if (!Fast486WriteMemory(State
,
5517 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5518 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5520 Processed
* DataSize
))
5523 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5524 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5526 /* Exception occurred */
5530 if (!State
->Flags
.Df
)
5532 /* Increase ESI and EDI by the number of bytes transfered */
5535 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= Processed
* DataSize
;
5536 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5540 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= Processed
* DataSize
;
5541 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5545 /* Reduce the total count by the number processed in this run */
5550 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5551 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5555 /* Read from the source operand */
5556 if (!Fast486ReadMemory(State
,
5558 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5559 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5564 /* Exception occurred */
5568 /* Write to the destination operand */
5569 if (!Fast486WriteMemory(State
,
5571 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5572 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5576 /* Exception occurred */
5580 /* Increment/decrement ESI and EDI */
5583 if (!State
->Flags
.Df
)
5585 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5586 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5590 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5591 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5596 if (!State
->Flags
.Df
)
5598 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5599 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5603 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5604 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5609 /* Return success */
5613 FAST486_OPCODE_HANDLER(Fast486OpcodeCmps
)
5615 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5616 ULONG DataSize
, DataMask
, SignFlag
;
5617 BOOLEAN OperandSize
, AddressSize
;
5618 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5620 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5622 /* Make sure this is the right instruction */
5623 ASSERT((Opcode
& 0xFE) == 0xA6);
5625 TOGGLE_OPSIZE(OperandSize
);
5626 TOGGLE_ADSIZE(AddressSize
);
5628 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5630 /* Use the override segment instead of DS */
5631 Segment
= State
->SegmentOverride
;
5634 /* Calculate the size */
5635 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
5636 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5638 /* Calculate the mask and sign flag */
5639 SignFlag
= 1 << ((DataSize
* 8) - 1);
5640 DataMask
= SignFlag
| (SignFlag
- 1);
5642 /* Read from the first source operand */
5643 if (!Fast486ReadMemory(State
,
5645 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5646 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5651 /* Exception occurred */
5655 /* Read from the second source operand */
5656 if (!Fast486ReadMemory(State
,
5658 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5659 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5664 /* Exception occurred */
5668 /* Calculate the result */
5669 FirstValue
&= DataMask
;
5670 SecondValue
&= DataMask
;
5671 Result
= (FirstValue
- SecondValue
) & DataMask
;
5673 /* Update the flags */
5674 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
5675 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
5676 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
5677 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
5678 State
->Flags
.Zf
= (Result
== 0);
5679 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
5680 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
5682 /* Increment/decrement ESI and EDI */
5685 if (!State
->Flags
.Df
)
5687 State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5688 State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5692 State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5693 State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5698 if (!State
->Flags
.Df
)
5700 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5701 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5705 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5706 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5710 // FIXME: This method is slow!
5711 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
5712 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
5714 BOOLEAN Repeat
= TRUE
;
5718 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
5726 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
5733 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
5734 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
5736 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
5742 /* Repeat the instruction */
5743 State
->InstPtr
= State
->SavedInstPtr
;
5747 /* Return success */
5751 FAST486_OPCODE_HANDLER(Fast486OpcodeStos
)
5754 BOOLEAN OperandSize
, AddressSize
;
5756 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5758 /* Make sure this is the right instruction */
5759 ASSERT((Opcode
& 0xFE) == 0xAA);
5761 TOGGLE_OPSIZE(OperandSize
);
5762 TOGGLE_ADSIZE(AddressSize
);
5764 /* Calculate the size */
5765 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
5766 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5768 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5770 UCHAR Block
[STRING_BLOCK_SIZE
];
5771 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5772 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5774 /* Fill the memory block with the data */
5775 if (DataSize
== sizeof(UCHAR
))
5777 RtlFillMemory(Block
, sizeof(Block
), State
->GeneralRegs
[FAST486_REG_EAX
].LowByte
);
5783 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
5785 if (DataSize
== sizeof(USHORT
))
5787 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
5791 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5796 /* Transfer until finished */
5799 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
5801 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
5804 ULONG MaxBytes
= State
->Flags
.Df
5805 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
5806 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
5808 Processed
= min(Processed
, MaxBytes
/ DataSize
);
5809 if (Processed
== 0) Processed
= 1;
5812 if (State
->Flags
.Df
)
5814 /* Reduce EDI by the number of bytes to transfer */
5815 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
5816 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
5819 /* Write to memory */
5820 if (!Fast486WriteMemory(State
,
5822 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5823 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5825 Processed
* DataSize
))
5828 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
5829 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
5831 /* Exception occurred */
5835 if (!State
->Flags
.Df
)
5837 /* Increase EDI by the number of bytes transfered */
5838 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
5839 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
5842 /* Reduce the total count by the number processed in this run */
5847 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5848 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5852 /* Write to the destination operand */
5853 if (!Fast486WriteMemory(State
,
5855 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5856 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5857 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5860 /* Exception occurred */
5864 /* Increment/decrement EDI */
5867 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
5868 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
5872 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
5873 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
5877 /* Return success */
5881 FAST486_OPCODE_HANDLER(Fast486OpcodeLods
)
5884 BOOLEAN OperandSize
, AddressSize
;
5885 FAST486_SEG_REGS Segment
= FAST486_REG_DS
;
5887 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5889 /* Make sure this is the right instruction */
5890 ASSERT((Opcode
& 0xFE) == 0xAC);
5892 TOGGLE_OPSIZE(OperandSize
);
5893 TOGGLE_ADSIZE(AddressSize
);
5895 if (State
->PrefixFlags
& FAST486_PREFIX_SEG
)
5897 /* Use the override segment instead of DS */
5898 Segment
= State
->SegmentOverride
;
5901 /* Calculate the size */
5902 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
5903 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5905 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
5907 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
5908 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
5910 /* If the count is 0, do nothing */
5911 if (Count
== 0) return TRUE
;
5913 /* Only the last entry will be loaded */
5914 if (!State
->Flags
.Df
)
5916 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
5917 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
5921 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
5922 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
5926 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
5927 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
5930 /* Read from the source operand */
5931 if (!Fast486ReadMemory(State
,
5933 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
5934 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
5936 &State
->GeneralRegs
[FAST486_REG_EAX
].Long
,
5939 /* Exception occurred */
5943 /* Increment/decrement ESI */
5946 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
5947 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
5951 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
5952 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
5955 /* Return success */
5959 FAST486_OPCODE_HANDLER(Fast486OpcodeScas
)
5961 ULONG FirstValue
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
5962 ULONG SecondValue
= 0;
5964 ULONG DataSize
, DataMask
, SignFlag
;
5965 BOOLEAN OperandSize
, AddressSize
;
5967 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
5969 /* Make sure this is the right instruction */
5970 ASSERT((Opcode
& 0xFE) == 0xAE);
5972 TOGGLE_OPSIZE(OperandSize
);
5973 TOGGLE_ADSIZE(AddressSize
);
5975 /* Calculate the size */
5976 if (Opcode
== 0xAE) DataSize
= sizeof(UCHAR
);
5977 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5979 /* Calculate the mask and sign flag */
5980 SignFlag
= 1 << ((DataSize
* 8) - 1);
5981 DataMask
= SignFlag
| (SignFlag
- 1);
5983 /* Read from the source operand */
5984 if (!Fast486ReadMemory(State
,
5986 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
5987 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
5992 /* Exception occurred */
5996 /* Calculate the result */
5997 FirstValue
&= DataMask
;
5998 SecondValue
&= DataMask
;
5999 Result
= (FirstValue
- SecondValue
) & DataMask
;
6001 /* Update the flags */
6002 State
->Flags
.Cf
= (FirstValue
< SecondValue
);
6003 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
6004 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
6005 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
6006 State
->Flags
.Zf
= (Result
== 0);
6007 State
->Flags
.Sf
= ((Result
& SignFlag
) != 0);
6008 State
->Flags
.Pf
= Fast486CalculateParity(Result
);
6010 /* Increment/decrement EDI */
6013 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6014 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6018 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6019 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6022 // FIXME: This method is slow!
6023 if ((State
->PrefixFlags
& FAST486_PREFIX_REP
)
6024 || (State
->PrefixFlags
& FAST486_PREFIX_REPNZ
))
6026 BOOLEAN Repeat
= TRUE
;
6030 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].Long
) == 0)
6038 if ((--State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
) == 0)
6045 if (((State
->PrefixFlags
& FAST486_PREFIX_REP
) && !State
->Flags
.Zf
)
6046 || ((State
->PrefixFlags
& FAST486_PREFIX_REPNZ
) && State
->Flags
.Zf
))
6048 /* REPZ with ZF = 0 or REPNZ with ZF = 1 */
6054 /* Repeat the instruction */
6055 State
->InstPtr
= State
->SavedInstPtr
;
6059 /* Return success */
6063 FAST486_OPCODE_HANDLER(Fast486OpcodeIns
)
6066 BOOLEAN OperandSize
, AddressSize
;
6068 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6070 /* Make sure this is the right instruction */
6071 ASSERT((Opcode
& 0xFE) == 0x6C);
6073 TOGGLE_OPSIZE(OperandSize
);
6074 TOGGLE_ADSIZE(AddressSize
);
6076 /* Calculate the size */
6077 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6078 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6080 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6082 UCHAR Block
[STRING_BLOCK_SIZE
];
6083 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6084 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6086 /* Clear the memory block */
6087 RtlZeroMemory(Block
, sizeof(Block
));
6089 /* Transfer until finished */
6092 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6094 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6097 ULONG MaxBytes
= State
->Flags
.Df
6098 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6099 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6101 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6102 if (Processed
== 0) Processed
= 1;
6105 /* Read from the I/O port */
6106 State
->IoReadCallback(State
,
6107 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6112 if (State
->Flags
.Df
)
6116 /* Reduce EDI by the number of bytes to transfer */
6117 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6118 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6120 /* Reverse the block data */
6121 for (i
= 0; i
< Processed
/ 2; i
++)
6123 /* Swap the values */
6124 for (j
= 0; j
< DataSize
; j
++)
6126 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6127 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6128 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6133 /* Write to memory */
6134 if (!Fast486WriteMemory(State
,
6136 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6137 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6139 Processed
* DataSize
))
6142 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6143 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6145 /* Exception occurred */
6149 if (!State
->Flags
.Df
)
6151 /* Increase EDI by the number of bytes transfered */
6152 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6153 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6156 /* Reduce the total count by the number processed in this run */
6161 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6162 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6168 /* Read from the I/O port */
6169 State
->IoReadCallback(State
,
6170 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6175 /* Write to the destination operand */
6176 if (!Fast486WriteMemory(State
,
6178 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6179 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6183 /* Exception occurred */
6187 /* Increment/decrement EDI */
6190 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= DataSize
;
6191 else State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= DataSize
;
6195 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= DataSize
;
6196 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= DataSize
;
6200 /* Return success */
6204 FAST486_OPCODE_HANDLER(Fast486OpcodeOuts
)
6207 BOOLEAN OperandSize
, AddressSize
;
6209 OperandSize
= AddressSize
= State
->SegmentRegs
[FAST486_REG_CS
].Size
;
6211 /* Make sure this is the right instruction */
6212 ASSERT((Opcode
& 0xFE) == 0x6E);
6214 TOGGLE_OPSIZE(OperandSize
);
6215 TOGGLE_ADSIZE(AddressSize
);
6217 /* Calculate the size */
6218 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6219 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6221 if (State
->PrefixFlags
& FAST486_PREFIX_REP
)
6223 UCHAR Block
[STRING_BLOCK_SIZE
];
6224 ULONG Count
= AddressSize
? State
->GeneralRegs
[FAST486_REG_ECX
].Long
6225 : State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
6227 /* Clear the memory block */
6228 RtlZeroMemory(Block
, sizeof(Block
));
6230 /* Transfer until finished */
6233 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6235 /* Simulate the 16-bit wrap-around of DI in 16-bit address mode */
6238 ULONG MaxBytes
= State
->Flags
.Df
6239 ? (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
6240 : (0x10000 - (ULONG
)State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
);
6242 Processed
= min(Processed
, MaxBytes
/ DataSize
);
6243 if (Processed
== 0) Processed
= 1;
6246 /* Read from memory */
6247 if (!Fast486ReadMemory(State
,
6249 AddressSize
? State
->GeneralRegs
[FAST486_REG_EDI
].Long
6250 : State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
,
6253 Processed
* DataSize
))
6256 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= Count
;
6257 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= LOWORD(Count
);
6259 /* Exception occurred */
6263 if (State
->Flags
.Df
)
6267 /* Reduce EDI by the number of bytes to transfer */
6268 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
-= Processed
* DataSize
;
6269 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
-= Processed
* DataSize
;
6271 /* Reverse the block data */
6272 for (i
= 0; i
< Processed
/ 2; i
++)
6274 /* Swap the values */
6275 for (j
= 0; j
< DataSize
; j
++)
6277 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6278 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6279 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6284 /* Write to the I/O port */
6285 State
->IoWriteCallback(State
,
6286 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6291 if (!State
->Flags
.Df
)
6293 /* Increase EDI by the number of bytes transfered */
6294 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_EDI
].Long
+= Processed
* DataSize
;
6295 else State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
+= Processed
* DataSize
;
6298 /* Reduce the total count by the number processed in this run */
6303 if (AddressSize
) State
->GeneralRegs
[FAST486_REG_ECX
].Long
= 0;
6304 else State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= 0;
6310 /* Read from the source operand */
6311 if (!Fast486ReadMemory(State
,
6313 AddressSize
? State
->GeneralRegs
[FAST486_REG_ESI
].Long
6314 : State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
,
6319 /* Exception occurred */
6323 /* Write to the I/O port */
6324 State
->IoWriteCallback(State
,
6325 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
,
6330 /* Increment/decrement ESI */
6333 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].Long
+= DataSize
;
6334 else State
->GeneralRegs
[FAST486_REG_ESI
].Long
-= DataSize
;
6338 if (!State
->Flags
.Df
) State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
+= DataSize
;
6339 else State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
-= DataSize
;
6343 /* Return success */