2 * Soft386 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 /* INCLUDES *******************************************************************/
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
37 /* PUBLIC VARIABLES ***********************************************************/
39 SOFT386_OPCODE_HANDLER_PROC
40 Soft386OpcodeHandlers
[SOFT386_NUM_OPCODE_HANDLERS
] =
42 Soft386OpcodeAddByteModrm
,
43 Soft386OpcodeAddModrm
,
44 Soft386OpcodeAddByteModrm
,
45 Soft386OpcodeAddModrm
,
50 Soft386OpcodeOrByteModrm
,
52 Soft386OpcodeOrByteModrm
,
57 NULL
, // TODO: OPCODE 0x0F NOT SUPPORTED
58 Soft386OpcodeAdcByteModrm
,
59 Soft386OpcodeAdcModrm
,
60 Soft386OpcodeAdcByteModrm
,
61 Soft386OpcodeAdcModrm
,
66 Soft386OpcodeSbbByteModrm
,
67 Soft386OpcodeSbbModrm
,
68 Soft386OpcodeSbbByteModrm
,
69 Soft386OpcodeSbbModrm
,
74 Soft386OpcodeAndByteModrm
,
75 Soft386OpcodeAndModrm
,
76 Soft386OpcodeAndByteModrm
,
77 Soft386OpcodeAndModrm
,
82 Soft386OpcodeCmpSubByteModrm
,
83 Soft386OpcodeCmpSubModrm
,
84 Soft386OpcodeCmpSubByteModrm
,
85 Soft386OpcodeCmpSubModrm
,
86 Soft386OpcodeCmpSubAl
,
87 Soft386OpcodeCmpSubEax
,
90 Soft386OpcodeXorByteModrm
,
91 Soft386OpcodeXorModrm
,
92 Soft386OpcodeXorByteModrm
,
93 Soft386OpcodeXorModrm
,
98 Soft386OpcodeCmpSubByteModrm
,
99 Soft386OpcodeCmpSubModrm
,
100 Soft386OpcodeCmpSubByteModrm
,
101 Soft386OpcodeCmpSubModrm
,
102 Soft386OpcodeCmpSubAl
,
103 Soft386OpcodeCmpSubEax
,
106 Soft386OpcodeIncrement
,
107 Soft386OpcodeIncrement
,
108 Soft386OpcodeIncrement
,
109 Soft386OpcodeIncrement
,
110 Soft386OpcodeIncrement
,
111 Soft386OpcodeIncrement
,
112 Soft386OpcodeIncrement
,
113 Soft386OpcodeIncrement
,
114 Soft386OpcodeDecrement
,
115 Soft386OpcodeDecrement
,
116 Soft386OpcodeDecrement
,
117 Soft386OpcodeDecrement
,
118 Soft386OpcodeDecrement
,
119 Soft386OpcodeDecrement
,
120 Soft386OpcodeDecrement
,
121 Soft386OpcodeDecrement
,
122 Soft386OpcodePushReg
,
123 Soft386OpcodePushReg
,
124 Soft386OpcodePushReg
,
125 Soft386OpcodePushReg
,
126 Soft386OpcodePushReg
,
127 Soft386OpcodePushReg
,
128 Soft386OpcodePushReg
,
129 Soft386OpcodePushReg
,
138 Soft386OpcodePushAll
,
146 Soft386OpcodePushImm
,
147 Soft386OpcodeImulModrmImm
,
148 Soft386OpcodePushByteImm
,
149 Soft386OpcodeImulModrmImm
,
150 NULL
, // TODO: OPCODE 0x6C NOT SUPPORTED
151 NULL
, // TODO: OPCODE 0x6D NOT SUPPORTED
152 NULL
, // TODO: OPCODE 0x6E NOT SUPPORTED
153 NULL
, // TODO: OPCODE 0x6F NOT SUPPORTED
154 Soft386OpcodeShortConditionalJmp
,
155 Soft386OpcodeShortConditionalJmp
,
156 Soft386OpcodeShortConditionalJmp
,
157 Soft386OpcodeShortConditionalJmp
,
158 Soft386OpcodeShortConditionalJmp
,
159 Soft386OpcodeShortConditionalJmp
,
160 Soft386OpcodeShortConditionalJmp
,
161 Soft386OpcodeShortConditionalJmp
,
162 Soft386OpcodeShortConditionalJmp
,
163 Soft386OpcodeShortConditionalJmp
,
164 Soft386OpcodeShortConditionalJmp
,
165 Soft386OpcodeShortConditionalJmp
,
166 Soft386OpcodeShortConditionalJmp
,
167 Soft386OpcodeShortConditionalJmp
,
168 Soft386OpcodeShortConditionalJmp
,
169 Soft386OpcodeShortConditionalJmp
,
170 Soft386OpcodeGroup8082
,
171 Soft386OpcodeGroup81
,
172 Soft386OpcodeGroup8082
,
173 Soft386OpcodeGroup83
,
174 Soft386OpcodeTestByteModrm
,
175 Soft386OpcodeTestModrm
,
176 Soft386OpcodeXchgByteModrm
,
177 Soft386OpcodeXchgModrm
,
178 Soft386OpcodeMovByteModrm
,
179 Soft386OpcodeMovModrm
,
180 Soft386OpcodeMovByteModrm
,
181 Soft386OpcodeMovModrm
,
182 Soft386OpcodeMovStoreSeg
,
184 Soft386OpcodeMovLoadSeg
,
185 Soft386OpcodeGroup8F
,
187 Soft386OpcodeExchangeEax
,
188 Soft386OpcodeExchangeEax
,
189 Soft386OpcodeExchangeEax
,
190 Soft386OpcodeExchangeEax
,
191 Soft386OpcodeExchangeEax
,
192 Soft386OpcodeExchangeEax
,
193 Soft386OpcodeExchangeEax
,
196 Soft386OpcodeCallAbs
,
198 Soft386OpcodePushFlags
,
199 Soft386OpcodePopFlags
,
202 Soft386OpcodeMovAlOffset
,
203 Soft386OpcodeMovEaxOffset
,
204 Soft386OpcodeMovOffsetAl
,
205 Soft386OpcodeMovOffsetEax
,
206 NULL
, // TODO: OPCODE 0xA4 NOT SUPPORTED
207 NULL
, // TODO: OPCODE 0xA5 NOT SUPPORTED
208 NULL
, // TODO: OPCODE 0xA6 NOT SUPPORTED
209 NULL
, // TODO: OPCODE 0xA7 NOT SUPPORTED
211 Soft386OpcodeTestEax
,
212 NULL
, // TODO: OPCODE 0xAA NOT SUPPORTED
213 NULL
, // TODO: OPCODE 0xAB NOT SUPPORTED
214 NULL
, // TODO: OPCODE 0xAC NOT SUPPORTED
215 NULL
, // TODO: OPCODE 0xAD NOT SUPPORTED
216 NULL
, // TODO: OPCODE 0xAE NOT SUPPORTED
217 NULL
, // TODO: OPCODE 0xAF NOT SUPPORTED
218 Soft386OpcodeMovByteRegImm
,
219 Soft386OpcodeMovByteRegImm
,
220 Soft386OpcodeMovByteRegImm
,
221 Soft386OpcodeMovByteRegImm
,
222 Soft386OpcodeMovByteRegImm
,
223 Soft386OpcodeMovByteRegImm
,
224 Soft386OpcodeMovByteRegImm
,
225 Soft386OpcodeMovByteRegImm
,
226 Soft386OpcodeMovRegImm
,
227 Soft386OpcodeMovRegImm
,
228 Soft386OpcodeMovRegImm
,
229 Soft386OpcodeMovRegImm
,
230 Soft386OpcodeMovRegImm
,
231 Soft386OpcodeMovRegImm
,
232 Soft386OpcodeMovRegImm
,
233 Soft386OpcodeMovRegImm
,
234 Soft386OpcodeGroupC0
,
235 Soft386OpcodeGroupC1
,
240 Soft386OpcodeGroupC6
,
241 Soft386OpcodeGroupC7
,
244 Soft386OpcodeRetFarImm
,
250 Soft386OpcodeGroupD0
,
251 Soft386OpcodeGroupD1
,
252 Soft386OpcodeGroupD2
,
253 Soft386OpcodeGroupD3
,
256 NULL
, // TODO: OPCODE 0xD6 NOT SUPPORTED
258 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
259 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
260 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
261 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
262 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
263 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
264 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
265 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
272 Soft386OpcodeOutByte
,
277 Soft386OpcodeShortJump
,
280 Soft386OpcodeOutByte
,
287 Soft386OpcodeComplCarry
,
288 Soft386OpcodeGroupF6
,
289 Soft386OpcodeGroupF7
,
290 Soft386OpcodeClearCarry
,
291 Soft386OpcodeSetCarry
,
292 Soft386OpcodeClearInt
,
294 Soft386OpcodeClearDir
,
296 Soft386OpcodeGroupFE
,
297 Soft386OpcodeGroupFF
,
300 /* PUBLIC FUNCTIONS ***********************************************************/
302 SOFT386_OPCODE_HANDLER(Soft386OpcodePrefix
)
304 BOOLEAN Valid
= FALSE
;
311 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
313 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
314 State
->SegmentOverride
= SOFT386_REG_ES
;
324 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
326 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
327 State
->SegmentOverride
= SOFT386_REG_CS
;
337 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
339 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
340 State
->SegmentOverride
= SOFT386_REG_SS
;
350 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
352 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
353 State
->SegmentOverride
= SOFT386_REG_DS
;
363 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
365 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
366 State
->SegmentOverride
= SOFT386_REG_FS
;
376 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
378 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
379 State
->SegmentOverride
= SOFT386_REG_GS
;
389 if (!(State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
))
391 State
->PrefixFlags
|= SOFT386_PREFIX_OPSIZE
;
401 if (!(State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
))
403 State
->PrefixFlags
|= SOFT386_PREFIX_ADSIZE
;
412 if (!(State
->PrefixFlags
& SOFT386_PREFIX_LOCK
))
414 State
->PrefixFlags
|= SOFT386_PREFIX_LOCK
;
424 /* Mutually exclusive with REP */
425 if (!(State
->PrefixFlags
426 & (SOFT386_PREFIX_REPNZ
| SOFT386_PREFIX_REP
)))
428 State
->PrefixFlags
|= SOFT386_PREFIX_REPNZ
;
438 /* Mutually exclusive with REPNZ */
439 if (!(State
->PrefixFlags
440 & (SOFT386_PREFIX_REPNZ
| SOFT386_PREFIX_REP
)))
442 State
->PrefixFlags
|= SOFT386_PREFIX_REP
;
452 /* Clear all prefixes */
453 State
->PrefixFlags
= 0;
455 /* Throw an exception */
456 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
463 SOFT386_OPCODE_HANDLER(Soft386OpcodeIncrement
)
466 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
468 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
470 /* The OPSIZE prefix toggles the size */
473 else if (State
->PrefixFlags
!= 0)
476 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
480 /* Make sure this is the right instruction */
481 ASSERT((Opcode
& 0xF8) == 0x40);
485 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
487 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
488 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
492 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
494 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
495 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
498 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
499 State
->Flags
.Af
= ((Value
& 0x0F) == 0) ? TRUE
: FALSE
;
500 State
->Flags
.Pf
= Soft386CalculateParity(LOBYTE(Value
));
506 SOFT386_OPCODE_HANDLER(Soft386OpcodeDecrement
)
509 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
511 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
513 /* The OPSIZE prefix toggles the size */
516 else if (State
->PrefixFlags
!= 0)
519 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
523 /* Make sure this is the right instruction */
524 ASSERT((Opcode
& 0xF8) == 0x48);
528 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
530 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1)) ? TRUE
: FALSE
;
531 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
535 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
537 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1)) ? TRUE
: FALSE
;
538 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
541 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
542 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F) ? TRUE
: FALSE
;
543 State
->Flags
.Pf
= Soft386CalculateParity(LOBYTE(Value
));
549 SOFT386_OPCODE_HANDLER(Soft386OpcodePushReg
)
551 if ((State
->PrefixFlags
!= SOFT386_PREFIX_OPSIZE
)
552 && (State
->PrefixFlags
!= 0))
555 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
559 /* Make sure this is the right instruction */
560 ASSERT((Opcode
& 0xF8) == 0x50);
562 /* Call the internal function */
563 return Soft386StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
566 SOFT386_OPCODE_HANDLER(Soft386OpcodePopReg
)
569 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_SS
].Size
;
571 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
573 /* The OPSIZE prefix toggles the size */
576 else if (State
->PrefixFlags
!= 0)
579 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
583 /* Make sure this is the right instruction */
584 ASSERT((Opcode
& 0xF8) == 0x58);
586 /* Call the internal function */
587 if (!Soft386StackPop(State
, &Value
)) return FALSE
;
589 /* Store the value */
590 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
591 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
597 SOFT386_OPCODE_HANDLER(Soft386OpcodeNop
)
599 if (State
->PrefixFlags
& ~(SOFT386_PREFIX_OPSIZE
| SOFT386_PREFIX_REP
))
601 /* Allowed prefixes are REP and OPSIZE */
602 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
606 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
609 State
->IdleCallback(State
);
615 SOFT386_OPCODE_HANDLER(Soft386OpcodeExchangeEax
)
617 INT Reg
= Opcode
& 0x07;
618 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
620 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
622 /* The OPSIZE prefix toggles the size */
625 else if (State
->PrefixFlags
!= 0)
628 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
632 /* Make sure this is the right instruction */
633 ASSERT((Opcode
& 0xF8) == 0x90);
635 /* Exchange the values */
640 Value
= State
->GeneralRegs
[Reg
].Long
;
641 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
642 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Value
;
648 Value
= State
->GeneralRegs
[Reg
].LowWord
;
649 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
650 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Value
;
656 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortConditionalJmp
)
658 BOOLEAN Jump
= FALSE
;
661 /* Make sure this is the right instruction */
662 ASSERT((Opcode
& 0xF0) == 0x70);
664 /* Fetch the offset */
665 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
667 /* An exception occurred */
671 switch ((Opcode
& 0x0F) >> 1)
676 Jump
= State
->Flags
.Of
;
683 Jump
= State
->Flags
.Cf
;
690 Jump
= State
->Flags
.Zf
;
697 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
704 Jump
= State
->Flags
.Sf
;
711 Jump
= State
->Flags
.Pf
;
718 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
725 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
732 /* Invert the result */
738 /* Move the instruction pointer */
739 State
->InstPtr
.Long
+= Offset
;
746 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearCarry
)
748 /* Make sure this is the right instruction */
749 ASSERT(Opcode
== 0xF8);
751 /* No prefixes allowed */
752 if (State
->PrefixFlags
)
754 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
758 /* Clear CF and return success */
759 State
->Flags
.Cf
= FALSE
;
763 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetCarry
)
765 /* Make sure this is the right instruction */
766 ASSERT(Opcode
== 0xF9);
768 /* No prefixes allowed */
769 if (State
->PrefixFlags
)
771 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
775 /* Set CF and return success*/
776 State
->Flags
.Cf
= TRUE
;
780 SOFT386_OPCODE_HANDLER(Soft386OpcodeComplCarry
)
782 /* Make sure this is the right instruction */
783 ASSERT(Opcode
== 0xF5);
785 /* No prefixes allowed */
786 if (State
->PrefixFlags
)
788 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
792 /* Toggle CF and return success */
793 State
->Flags
.Cf
= !State
->Flags
.Cf
;
797 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearInt
)
799 /* Make sure this is the right instruction */
800 ASSERT(Opcode
== 0xFA);
802 /* No prefixes allowed */
803 if (State
->PrefixFlags
)
805 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
809 /* Check for protected mode */
810 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
813 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
)
815 /* Clear the interrupt flag */
816 State
->Flags
.If
= FALSE
;
820 /* General Protection Fault */
821 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
827 /* Just clear the interrupt flag */
828 State
->Flags
.If
= FALSE
;
835 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetInt
)
837 /* Make sure this is the right instruction */
838 ASSERT(Opcode
== 0xFB);
840 /* No prefixes allowed */
841 if (State
->PrefixFlags
)
843 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
847 /* Check for protected mode */
848 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
851 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
)
853 /* Set the interrupt flag */
854 State
->Flags
.If
= TRUE
;
858 /* General Protection Fault */
859 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
865 /* Just set the interrupt flag */
866 State
->Flags
.If
= TRUE
;
873 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearDir
)
875 /* Make sure this is the right instruction */
876 ASSERT(Opcode
== 0xFC);
878 /* No prefixes allowed */
879 if (State
->PrefixFlags
)
881 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
885 /* Clear DF and return success */
886 State
->Flags
.Df
= FALSE
;
890 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetDir
)
892 /* Make sure this is the right instruction */
893 ASSERT(Opcode
== 0xFD);
895 /* No prefixes allowed */
896 if (State
->PrefixFlags
)
898 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
902 /* Set DF and return success*/
903 State
->Flags
.Df
= TRUE
;
907 SOFT386_OPCODE_HANDLER(Soft386OpcodeHalt
)
909 /* Make sure this is the right instruction */
910 ASSERT(Opcode
== 0xF4);
912 /* No prefixes allowed */
913 if (State
->PrefixFlags
)
915 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
919 /* Privileged instructions can only be executed under CPL = 0 */
920 if (State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
!= 0)
922 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
927 while (!State
->HardwareInt
) State
->IdleCallback(State
);
933 SOFT386_OPCODE_HANDLER(Soft386OpcodeInByte
)
938 /* Make sure this is the right instruction */
939 ASSERT((Opcode
& 0xF7) == 0xE4);
943 /* Fetch the parameter */
944 if (!Soft386FetchByte(State
, &Data
))
946 /* Exception occurred */
950 /* Set the port number to the parameter */
955 /* The port number is in DX */
956 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
959 /* Read a byte from the I/O port */
960 State
->IoReadCallback(State
, Port
, &Data
, sizeof(UCHAR
));
962 /* Store the result in AL */
963 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Data
;
968 SOFT386_OPCODE_HANDLER(Soft386OpcodeIn
)
971 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
973 /* Make sure this is the right instruction */
974 ASSERT((Opcode
& 0xF7) == 0xE5);
976 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
978 /* The OPSIZE prefix toggles the size */
981 else if (State
->PrefixFlags
!= 0)
984 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
992 /* Fetch the parameter */
993 if (!Soft386FetchByte(State
, &Data
))
995 /* Exception occurred */
999 /* Set the port number to the parameter */
1004 /* The port number is in DX */
1005 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1012 /* Read a dword from the I/O port */
1013 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1015 /* Store the value in EAX */
1016 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Data
;
1022 /* Read a word from the I/O port */
1023 State
->IoReadCallback(State
, Port
, &Data
, sizeof(USHORT
));
1025 /* Store the value in AX */
1026 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Data
;
1032 SOFT386_OPCODE_HANDLER(Soft386OpcodeOutByte
)
1037 /* Make sure this is the right instruction */
1038 ASSERT((Opcode
& 0xF7) == 0xE6);
1042 /* Fetch the parameter */
1043 if (!Soft386FetchByte(State
, &Data
))
1045 /* Exception occurred */
1049 /* Set the port number to the parameter */
1054 /* The port number is in DX */
1055 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1058 /* Read the value from AL */
1059 Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1061 /* Write the byte to the I/O port */
1062 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(UCHAR
));
1067 SOFT386_OPCODE_HANDLER(Soft386OpcodeOut
)
1070 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1072 /* Make sure this is the right instruction */
1073 ASSERT((Opcode
& 0xF7) == 0xE7);
1075 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
1077 /* The OPSIZE prefix toggles the size */
1080 else if (State
->PrefixFlags
!= 0)
1082 /* Invalid prefix */
1083 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1091 /* Fetch the parameter */
1092 if (!Soft386FetchByte(State
, &Data
))
1094 /* Exception occurred */
1098 /* Set the port number to the parameter */
1103 /* The port number is in DX */
1104 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1109 /* Get the value from EAX */
1110 ULONG Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1112 /* Write a dword to the I/O port */
1113 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1117 /* Get the value from AX */
1118 USHORT Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1120 /* Write a word to the I/O port */
1121 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(USHORT
));
1127 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortJump
)
1131 /* Make sure this is the right instruction */
1132 ASSERT(Opcode
== 0xEB);
1134 /* Fetch the offset */
1135 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
1137 /* An exception occurred */
1141 /* Move the instruction pointer */
1142 State
->InstPtr
.Long
+= Offset
;
1147 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovRegImm
)
1149 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1151 /* Make sure this is the right instruction */
1152 ASSERT((Opcode
& 0xF8) == 0xB8);
1154 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
1156 /* The OPSIZE prefix toggles the size */
1159 else if (State
->PrefixFlags
!= 0)
1161 /* Invalid prefix */
1162 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1170 /* Fetch the dword */
1171 if (!Soft386FetchDword(State
, &Value
))
1173 /* Exception occurred */
1177 /* Store the value in the register */
1178 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1184 /* Fetch the word */
1185 if (!Soft386FetchWord(State
, &Value
))
1187 /* Exception occurred */
1191 /* Store the value in the register */
1192 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1198 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteRegImm
)
1202 /* Make sure this is the right instruction */
1203 ASSERT((Opcode
& 0xF8) == 0xB0);
1205 if (State
->PrefixFlags
!= 0)
1207 /* Invalid prefix */
1208 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1212 /* Fetch the byte */
1213 if (!Soft386FetchByte(State
, &Value
))
1215 /* Exception occurred */
1221 /* AH, CH, DH or BH */
1222 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1226 /* AL, CL, DL or BL */
1227 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1233 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddByteModrm
)
1235 UCHAR FirstValue
, SecondValue
, Result
;
1236 SOFT386_MOD_REG_RM ModRegRm
;
1237 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1239 /* Make sure this is the right instruction */
1240 ASSERT((Opcode
& 0xFD) == 0x00);
1242 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1244 /* The ADSIZE prefix toggles the size */
1245 AddressSize
= !AddressSize
;
1247 else if (State
->PrefixFlags
1248 & ~(SOFT386_PREFIX_ADSIZE
1249 | SOFT386_PREFIX_SEG
1250 | SOFT386_PREFIX_LOCK
))
1252 /* Invalid prefix */
1253 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1257 /* Get the operands */
1258 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1260 /* Exception occurred */
1264 if (!Soft386ReadModrmByteOperands(State
,
1269 /* Exception occurred */
1273 /* Calculate the result */
1274 Result
= FirstValue
+ SecondValue
;
1276 /* Update the flags */
1277 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1278 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1279 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1280 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1281 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1282 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1283 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1285 /* Write back the result */
1286 return Soft386WriteModrmByteOperands(State
,
1288 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1292 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddModrm
)
1294 SOFT386_MOD_REG_RM ModRegRm
;
1295 BOOLEAN OperandSize
, AddressSize
;
1297 /* Make sure this is the right instruction */
1298 ASSERT((Opcode
& 0xFD) == 0x01);
1300 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1302 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1304 /* The ADSIZE prefix toggles the address size */
1305 AddressSize
= !AddressSize
;
1308 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1310 /* The OPSIZE prefix toggles the operand size */
1311 OperandSize
= !OperandSize
;
1314 if (State
->PrefixFlags
1315 & ~(SOFT386_PREFIX_ADSIZE
1316 | SOFT386_PREFIX_OPSIZE
1317 | SOFT386_PREFIX_SEG
1318 | SOFT386_PREFIX_LOCK
))
1320 /* Invalid prefix */
1321 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1325 /* Get the operands */
1326 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1328 /* Exception occurred */
1332 /* Check the operand size */
1335 ULONG FirstValue
, SecondValue
, Result
;
1337 if (!Soft386ReadModrmDwordOperands(State
,
1342 /* Exception occurred */
1346 /* Calculate the result */
1347 Result
= FirstValue
+ SecondValue
;
1349 /* Update the flags */
1350 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1351 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1352 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1353 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1354 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1355 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1356 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1358 /* Write back the result */
1359 return Soft386WriteModrmDwordOperands(State
,
1361 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1366 USHORT FirstValue
, SecondValue
, Result
;
1368 if (!Soft386ReadModrmWordOperands(State
,
1373 /* Exception occurred */
1377 /* Calculate the result */
1378 Result
= FirstValue
+ SecondValue
;
1380 /* Update the flags */
1381 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1382 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1383 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1384 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1385 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1386 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1387 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1389 /* Write back the result */
1390 return Soft386WriteModrmWordOperands(State
,
1392 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1397 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddAl
)
1399 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1400 UCHAR SecondValue
, Result
;
1402 /* Make sure this is the right instruction */
1403 ASSERT(Opcode
== 0x04);
1405 if (State
->PrefixFlags
)
1407 /* This opcode doesn't take any prefixes */
1408 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1412 if (!Soft386FetchByte(State
, &SecondValue
))
1414 /* Exception occurred */
1418 /* Calculate the result */
1419 Result
= FirstValue
+ SecondValue
;
1421 /* Update the flags */
1422 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1423 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1424 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1425 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1426 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1427 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1428 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1430 /* Write back the result */
1431 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1436 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddEax
)
1438 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1440 /* Make sure this is the right instruction */
1441 ASSERT(Opcode
== 0x05);
1443 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1445 /* Invalid prefix */
1446 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1450 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1452 /* The OPSIZE prefix toggles the size */
1458 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1459 ULONG SecondValue
, Result
;
1461 if (!Soft386FetchDword(State
, &SecondValue
))
1463 /* Exception occurred */
1467 /* Calculate the result */
1468 Result
= FirstValue
+ SecondValue
;
1470 /* Update the flags */
1471 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1472 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1473 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1474 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1475 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1476 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1477 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1479 /* Write back the result */
1480 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
1484 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1485 USHORT SecondValue
, Result
;
1487 if (!Soft386FetchWord(State
, &SecondValue
))
1489 /* Exception occurred */
1493 /* Calculate the result */
1494 Result
= FirstValue
+ SecondValue
;
1496 /* Update the flags */
1497 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1498 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1499 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1500 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1501 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1502 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1503 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1505 /* Write back the result */
1506 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
1512 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrByteModrm
)
1514 UCHAR FirstValue
, SecondValue
, Result
;
1515 SOFT386_MOD_REG_RM ModRegRm
;
1516 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1518 /* Make sure this is the right instruction */
1519 ASSERT((Opcode
& 0xFD) == 0x08);
1521 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1523 /* The ADSIZE prefix toggles the size */
1524 AddressSize
= !AddressSize
;
1526 else if (State
->PrefixFlags
1527 & ~(SOFT386_PREFIX_ADSIZE
1528 | SOFT386_PREFIX_SEG
1529 | SOFT386_PREFIX_LOCK
))
1531 /* Invalid prefix */
1532 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1536 /* Get the operands */
1537 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1539 /* Exception occurred */
1543 if (!Soft386ReadModrmByteOperands(State
,
1548 /* Exception occurred */
1552 /* Calculate the result */
1553 Result
= FirstValue
| SecondValue
;
1555 /* Update the flags */
1556 State
->Flags
.Cf
= FALSE
;
1557 State
->Flags
.Of
= FALSE
;
1558 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1559 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1560 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1562 /* Write back the result */
1563 return Soft386WriteModrmByteOperands(State
,
1565 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1569 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrModrm
)
1571 SOFT386_MOD_REG_RM ModRegRm
;
1572 BOOLEAN OperandSize
, AddressSize
;
1574 /* Make sure this is the right instruction */
1575 ASSERT((Opcode
& 0xFD) == 0x09);
1577 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1579 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1581 /* The ADSIZE prefix toggles the address size */
1582 AddressSize
= !AddressSize
;
1585 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1587 /* The OPSIZE prefix toggles the operand size */
1588 OperandSize
= !OperandSize
;
1591 if (State
->PrefixFlags
1592 & ~(SOFT386_PREFIX_ADSIZE
1593 | SOFT386_PREFIX_OPSIZE
1594 | SOFT386_PREFIX_SEG
1595 | SOFT386_PREFIX_LOCK
))
1597 /* Invalid prefix */
1598 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1602 /* Get the operands */
1603 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1605 /* Exception occurred */
1609 /* Check the operand size */
1612 ULONG FirstValue
, SecondValue
, Result
;
1614 if (!Soft386ReadModrmDwordOperands(State
,
1619 /* Exception occurred */
1623 /* Calculate the result */
1624 Result
= FirstValue
| SecondValue
;
1626 /* Update the flags */
1627 State
->Flags
.Cf
= FALSE
;
1628 State
->Flags
.Of
= FALSE
;
1629 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1630 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1631 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1633 /* Write back the result */
1634 return Soft386WriteModrmDwordOperands(State
,
1636 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1641 USHORT FirstValue
, SecondValue
, Result
;
1643 if (!Soft386ReadModrmWordOperands(State
,
1648 /* Exception occurred */
1652 /* Calculate the result */
1653 Result
= FirstValue
| SecondValue
;
1655 /* Update the flags */
1656 State
->Flags
.Cf
= FALSE
;
1657 State
->Flags
.Of
= FALSE
;
1658 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1659 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1660 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1662 /* Write back the result */
1663 return Soft386WriteModrmWordOperands(State
,
1665 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1670 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrAl
)
1672 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1673 UCHAR SecondValue
, Result
;
1675 /* Make sure this is the right instruction */
1676 ASSERT(Opcode
== 0x0C);
1678 if (State
->PrefixFlags
)
1680 /* This opcode doesn't take any prefixes */
1681 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1685 if (!Soft386FetchByte(State
, &SecondValue
))
1687 /* Exception occurred */
1691 /* Calculate the result */
1692 Result
= FirstValue
| SecondValue
;
1694 /* Update the flags */
1695 State
->Flags
.Cf
= FALSE
;
1696 State
->Flags
.Of
= FALSE
;
1697 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1698 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1699 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1701 /* Write back the result */
1702 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1707 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrEax
)
1709 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1711 /* Make sure this is the right instruction */
1712 ASSERT(Opcode
== 0x0D);
1714 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1716 /* Invalid prefix */
1717 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1721 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1723 /* The OPSIZE prefix toggles the size */
1729 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1730 ULONG SecondValue
, Result
;
1732 if (!Soft386FetchDword(State
, &SecondValue
))
1734 /* Exception occurred */
1738 /* Calculate the result */
1739 Result
= FirstValue
| SecondValue
;
1741 /* Update the flags */
1742 State
->Flags
.Cf
= FALSE
;
1743 State
->Flags
.Of
= FALSE
;
1744 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1745 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1746 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1748 /* Write back the result */
1749 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
1753 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1754 USHORT SecondValue
, Result
;
1756 if (!Soft386FetchWord(State
, &SecondValue
))
1758 /* Exception occurred */
1762 /* Calculate the result */
1763 Result
= FirstValue
| SecondValue
;
1765 /* Update the flags */
1766 State
->Flags
.Cf
= FALSE
;
1767 State
->Flags
.Of
= FALSE
;
1768 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1769 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1770 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1772 /* Write back the result */
1773 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
1779 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndByteModrm
)
1781 UCHAR FirstValue
, SecondValue
, Result
;
1782 SOFT386_MOD_REG_RM ModRegRm
;
1783 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1785 /* Make sure this is the right instruction */
1786 ASSERT((Opcode
& 0xFD) == 0x20);
1788 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1790 /* The ADSIZE prefix toggles the size */
1791 AddressSize
= !AddressSize
;
1793 else if (State
->PrefixFlags
1794 & ~(SOFT386_PREFIX_ADSIZE
1795 | SOFT386_PREFIX_SEG
1796 | SOFT386_PREFIX_LOCK
))
1798 /* Invalid prefix */
1799 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1803 /* Get the operands */
1804 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1806 /* Exception occurred */
1810 if (!Soft386ReadModrmByteOperands(State
,
1815 /* Exception occurred */
1819 /* Calculate the result */
1820 Result
= FirstValue
& SecondValue
;
1822 /* Update the flags */
1823 State
->Flags
.Cf
= FALSE
;
1824 State
->Flags
.Of
= FALSE
;
1825 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1826 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1827 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1829 /* Write back the result */
1830 return Soft386WriteModrmByteOperands(State
,
1832 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1836 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndModrm
)
1838 SOFT386_MOD_REG_RM ModRegRm
;
1839 BOOLEAN OperandSize
, AddressSize
;
1841 /* Make sure this is the right instruction */
1842 ASSERT((Opcode
& 0xFD) == 0x21);
1844 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1846 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1848 /* The ADSIZE prefix toggles the address size */
1849 AddressSize
= !AddressSize
;
1852 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1854 /* The OPSIZE prefix toggles the operand size */
1855 OperandSize
= !OperandSize
;
1858 if (State
->PrefixFlags
1859 & ~(SOFT386_PREFIX_ADSIZE
1860 | SOFT386_PREFIX_OPSIZE
1861 | SOFT386_PREFIX_SEG
1862 | SOFT386_PREFIX_LOCK
))
1864 /* Invalid prefix */
1865 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1869 /* Get the operands */
1870 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1872 /* Exception occurred */
1876 /* Check the operand size */
1879 ULONG FirstValue
, SecondValue
, Result
;
1881 if (!Soft386ReadModrmDwordOperands(State
,
1886 /* Exception occurred */
1890 /* Calculate the result */
1891 Result
= FirstValue
& SecondValue
;
1893 /* Update the flags */
1894 State
->Flags
.Cf
= FALSE
;
1895 State
->Flags
.Of
= FALSE
;
1896 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1897 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1898 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1900 /* Write back the result */
1901 return Soft386WriteModrmDwordOperands(State
,
1903 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1908 USHORT FirstValue
, SecondValue
, Result
;
1910 if (!Soft386ReadModrmWordOperands(State
,
1915 /* Exception occurred */
1919 /* Calculate the result */
1920 Result
= FirstValue
& SecondValue
;
1922 /* Update the flags */
1923 State
->Flags
.Cf
= FALSE
;
1924 State
->Flags
.Of
= FALSE
;
1925 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1926 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1927 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1929 /* Write back the result */
1930 return Soft386WriteModrmWordOperands(State
,
1932 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1937 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndAl
)
1939 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1940 UCHAR SecondValue
, Result
;
1942 /* Make sure this is the right instruction */
1943 ASSERT(Opcode
== 0x24);
1945 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1947 /* Invalid prefix */
1948 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1952 if (!Soft386FetchByte(State
, &SecondValue
))
1954 /* Exception occurred */
1958 /* Calculate the result */
1959 Result
= FirstValue
& SecondValue
;
1961 /* Update the flags */
1962 State
->Flags
.Cf
= FALSE
;
1963 State
->Flags
.Of
= FALSE
;
1964 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1965 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1966 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1968 /* Write back the result */
1969 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1974 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndEax
)
1976 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1978 /* Make sure this is the right instruction */
1979 ASSERT(Opcode
== 0x25);
1981 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1983 /* Invalid prefix */
1984 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1988 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1990 /* The OPSIZE prefix toggles the size */
1996 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1997 ULONG SecondValue
, Result
;
1999 if (!Soft386FetchDword(State
, &SecondValue
))
2001 /* Exception occurred */
2005 /* Calculate the result */
2006 Result
= FirstValue
& SecondValue
;
2008 /* Update the flags */
2009 State
->Flags
.Cf
= FALSE
;
2010 State
->Flags
.Of
= FALSE
;
2011 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2012 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2013 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2015 /* Write back the result */
2016 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
2020 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2021 USHORT SecondValue
, Result
;
2023 if (!Soft386FetchWord(State
, &SecondValue
))
2025 /* Exception occurred */
2029 /* Calculate the result */
2030 Result
= FirstValue
& SecondValue
;
2032 /* Update the flags */
2033 State
->Flags
.Cf
= FALSE
;
2034 State
->Flags
.Of
= FALSE
;
2035 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2036 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2037 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2039 /* Write back the result */
2040 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
2046 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorByteModrm
)
2048 UCHAR FirstValue
, SecondValue
, Result
;
2049 SOFT386_MOD_REG_RM ModRegRm
;
2050 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2052 /* Make sure this is the right instruction */
2053 ASSERT((Opcode
& 0xFD) == 0x30);
2055 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2057 /* The ADSIZE prefix toggles the size */
2058 AddressSize
= !AddressSize
;
2060 else if (State
->PrefixFlags
2061 & ~(SOFT386_PREFIX_ADSIZE
2062 | SOFT386_PREFIX_SEG
2063 | SOFT386_PREFIX_LOCK
))
2065 /* Invalid prefix */
2066 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2070 /* Get the operands */
2071 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2073 /* Exception occurred */
2077 if (!Soft386ReadModrmByteOperands(State
,
2082 /* Exception occurred */
2086 /* Calculate the result */
2087 Result
= FirstValue
^ SecondValue
;
2089 /* Update the flags */
2090 State
->Flags
.Cf
= FALSE
;
2091 State
->Flags
.Of
= FALSE
;
2092 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2093 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2094 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2096 /* Write back the result */
2097 return Soft386WriteModrmByteOperands(State
,
2099 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2103 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorModrm
)
2105 SOFT386_MOD_REG_RM ModRegRm
;
2106 BOOLEAN OperandSize
, AddressSize
;
2108 /* Make sure this is the right instruction */
2109 ASSERT((Opcode
& 0xFD) == 0x31);
2111 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2113 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2115 /* The ADSIZE prefix toggles the address size */
2116 AddressSize
= !AddressSize
;
2119 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2121 /* The OPSIZE prefix toggles the operand size */
2122 OperandSize
= !OperandSize
;
2125 if (State
->PrefixFlags
2126 & ~(SOFT386_PREFIX_ADSIZE
2127 | SOFT386_PREFIX_OPSIZE
2128 | SOFT386_PREFIX_SEG
2129 | SOFT386_PREFIX_LOCK
))
2131 /* Invalid prefix */
2132 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2136 /* Get the operands */
2137 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2139 /* Exception occurred */
2143 /* Check the operand size */
2146 ULONG FirstValue
, SecondValue
, Result
;
2148 if (!Soft386ReadModrmDwordOperands(State
,
2153 /* Exception occurred */
2157 /* Calculate the result */
2158 Result
= FirstValue
^ SecondValue
;
2160 /* Update the flags */
2161 State
->Flags
.Cf
= FALSE
;
2162 State
->Flags
.Of
= FALSE
;
2163 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2164 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2165 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2167 /* Write back the result */
2168 return Soft386WriteModrmDwordOperands(State
,
2170 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2175 USHORT FirstValue
, SecondValue
, Result
;
2177 if (!Soft386ReadModrmWordOperands(State
,
2182 /* Exception occurred */
2186 /* Calculate the result */
2187 Result
= FirstValue
^ SecondValue
;
2189 /* Update the flags */
2190 State
->Flags
.Cf
= FALSE
;
2191 State
->Flags
.Of
= FALSE
;
2192 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2193 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2194 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2196 /* Write back the result */
2197 return Soft386WriteModrmWordOperands(State
,
2199 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2204 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorAl
)
2206 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2207 UCHAR SecondValue
, Result
;
2209 /* Make sure this is the right instruction */
2210 ASSERT(Opcode
== 0x34);
2212 if (State
->PrefixFlags
)
2214 /* This opcode doesn't take any prefixes */
2215 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2219 if (!Soft386FetchByte(State
, &SecondValue
))
2221 /* Exception occurred */
2225 /* Calculate the result */
2226 Result
= FirstValue
^ SecondValue
;
2228 /* Update the flags */
2229 State
->Flags
.Cf
= FALSE
;
2230 State
->Flags
.Of
= FALSE
;
2231 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2232 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2233 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2235 /* Write back the result */
2236 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
2241 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax
)
2243 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2245 /* Make sure this is the right instruction */
2246 ASSERT(Opcode
== 0x35);
2248 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2250 /* Invalid prefix */
2251 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2255 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2257 /* The OPSIZE prefix toggles the size */
2263 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2264 ULONG SecondValue
, Result
;
2266 if (!Soft386FetchDword(State
, &SecondValue
))
2268 /* Exception occurred */
2272 /* Calculate the result */
2273 Result
= FirstValue
^ SecondValue
;
2275 /* Update the flags */
2276 State
->Flags
.Cf
= FALSE
;
2277 State
->Flags
.Of
= FALSE
;
2278 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2279 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2280 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2282 /* Write back the result */
2283 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
2287 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2288 USHORT SecondValue
, Result
;
2290 if (!Soft386FetchWord(State
, &SecondValue
))
2292 /* Exception occurred */
2296 /* Calculate the result */
2297 Result
= FirstValue
^ SecondValue
;
2299 /* Update the flags */
2300 State
->Flags
.Cf
= FALSE
;
2301 State
->Flags
.Of
= FALSE
;
2302 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2303 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2304 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2306 /* Write back the result */
2307 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
2313 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm
)
2315 UCHAR FirstValue
, SecondValue
, Result
;
2316 SOFT386_MOD_REG_RM ModRegRm
;
2317 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2319 /* Make sure this is the right instruction */
2320 ASSERT(Opcode
== 0x84);
2322 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2324 /* The ADSIZE prefix toggles the size */
2325 AddressSize
= !AddressSize
;
2327 else if (State
->PrefixFlags
2328 & ~(SOFT386_PREFIX_ADSIZE
2329 | SOFT386_PREFIX_SEG
2330 | SOFT386_PREFIX_LOCK
))
2332 /* Invalid prefix */
2333 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2337 /* Get the operands */
2338 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2340 /* Exception occurred */
2344 if (!Soft386ReadModrmByteOperands(State
,
2349 /* Exception occurred */
2352 /* Calculate the result */
2353 Result
= FirstValue
& SecondValue
;
2355 /* Update the flags */
2356 State
->Flags
.Cf
= FALSE
;
2357 State
->Flags
.Of
= FALSE
;
2358 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2359 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2360 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2362 /* The result is discarded */
2366 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm
)
2368 SOFT386_MOD_REG_RM ModRegRm
;
2369 BOOLEAN OperandSize
, AddressSize
;
2371 /* Make sure this is the right instruction */
2372 ASSERT(Opcode
== 0x85);
2374 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2376 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2378 /* The ADSIZE prefix toggles the address size */
2379 AddressSize
= !AddressSize
;
2382 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2384 /* The OPSIZE prefix toggles the operand size */
2385 OperandSize
= !OperandSize
;
2388 if (State
->PrefixFlags
2389 & ~(SOFT386_PREFIX_ADSIZE
2390 | SOFT386_PREFIX_OPSIZE
2391 | SOFT386_PREFIX_SEG
2392 | SOFT386_PREFIX_LOCK
))
2394 /* Invalid prefix */
2395 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2399 /* Get the operands */
2400 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2402 /* Exception occurred */
2406 /* Check the operand size */
2409 ULONG FirstValue
, SecondValue
, Result
;
2411 if (!Soft386ReadModrmDwordOperands(State
,
2416 /* Exception occurred */
2420 /* Calculate the result */
2421 Result
= FirstValue
& SecondValue
;
2423 /* Update the flags */
2424 State
->Flags
.Cf
= FALSE
;
2425 State
->Flags
.Of
= FALSE
;
2426 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2427 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2428 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2432 USHORT FirstValue
, SecondValue
, Result
;
2434 if (!Soft386ReadModrmWordOperands(State
,
2439 /* Exception occurred */
2443 /* Calculate the result */
2444 Result
= FirstValue
& SecondValue
;
2446 /* Update the flags */
2447 State
->Flags
.Cf
= FALSE
;
2448 State
->Flags
.Of
= FALSE
;
2449 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2450 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2451 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2454 /* The result is discarded */
2458 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestAl
)
2460 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2461 UCHAR SecondValue
, Result
;
2463 /* Make sure this is the right instruction */
2464 ASSERT(Opcode
== 0xA8);
2466 if (State
->PrefixFlags
)
2468 /* This opcode doesn't take any prefixes */
2469 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2473 if (!Soft386FetchByte(State
, &SecondValue
))
2475 /* Exception occurred */
2479 /* Calculate the result */
2480 Result
= FirstValue
& SecondValue
;
2482 /* Update the flags */
2483 State
->Flags
.Cf
= FALSE
;
2484 State
->Flags
.Of
= FALSE
;
2485 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2486 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2487 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2489 /* The result is discarded */
2493 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestEax
)
2495 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2497 /* Make sure this is the right instruction */
2498 ASSERT(Opcode
== 0xA9);
2500 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2502 /* Invalid prefix */
2503 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2507 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2509 /* The OPSIZE prefix toggles the size */
2515 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2516 ULONG SecondValue
, Result
;
2518 if (!Soft386FetchDword(State
, &SecondValue
))
2520 /* Exception occurred */
2524 /* Calculate the result */
2525 Result
= FirstValue
& SecondValue
;
2527 /* Update the flags */
2528 State
->Flags
.Cf
= FALSE
;
2529 State
->Flags
.Of
= FALSE
;
2530 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2531 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2532 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2536 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2537 USHORT SecondValue
, Result
;
2539 if (!Soft386FetchWord(State
, &SecondValue
))
2541 /* Exception occurred */
2545 /* Calculate the result */
2546 Result
= FirstValue
& SecondValue
;
2548 /* Update the flags */
2549 State
->Flags
.Cf
= FALSE
;
2550 State
->Flags
.Of
= FALSE
;
2551 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2552 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2553 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2556 /* The result is discarded */
2560 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm
)
2562 UCHAR FirstValue
, SecondValue
;
2563 SOFT386_MOD_REG_RM ModRegRm
;
2564 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2566 /* Make sure this is the right instruction */
2567 ASSERT(Opcode
== 0x86);
2569 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2571 /* The ADSIZE prefix toggles the size */
2572 AddressSize
= !AddressSize
;
2574 else if (State
->PrefixFlags
2575 & ~(SOFT386_PREFIX_ADSIZE
2576 | SOFT386_PREFIX_SEG
2577 | SOFT386_PREFIX_LOCK
))
2579 /* Invalid prefix */
2580 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2584 /* Get the operands */
2585 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2587 /* Exception occurred */
2591 if (!Soft386ReadModrmByteOperands(State
,
2596 /* Exception occurred */
2600 /* Write the value from the register to the R/M */
2601 if (!Soft386WriteModrmByteOperands(State
,
2606 /* Exception occurred */
2610 /* Write the value from the R/M to the register */
2611 if (!Soft386WriteModrmByteOperands(State
,
2616 /* Exception occurred */
2623 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm
)
2625 SOFT386_MOD_REG_RM ModRegRm
;
2626 BOOLEAN OperandSize
, AddressSize
;
2628 /* Make sure this is the right instruction */
2629 ASSERT(Opcode
== 0x87);
2631 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2633 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2635 /* The ADSIZE prefix toggles the address size */
2636 AddressSize
= !AddressSize
;
2639 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2641 /* The OPSIZE prefix toggles the operand size */
2642 OperandSize
= !OperandSize
;
2645 if (State
->PrefixFlags
2646 & ~(SOFT386_PREFIX_ADSIZE
2647 | SOFT386_PREFIX_OPSIZE
2648 | SOFT386_PREFIX_SEG
2649 | SOFT386_PREFIX_LOCK
))
2651 /* Invalid prefix */
2652 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2656 /* Get the operands */
2657 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2659 /* Exception occurred */
2663 /* Check the operand size */
2666 ULONG FirstValue
, SecondValue
;
2668 if (!Soft386ReadModrmDwordOperands(State
,
2673 /* Exception occurred */
2677 /* Write the value from the register to the R/M */
2678 if (!Soft386WriteModrmDwordOperands(State
,
2683 /* Exception occurred */
2687 /* Write the value from the R/M to the register */
2688 if (!Soft386WriteModrmDwordOperands(State
,
2693 /* Exception occurred */
2699 USHORT FirstValue
, SecondValue
;
2701 if (!Soft386ReadModrmWordOperands(State
,
2706 /* Exception occurred */
2710 /* Write the value from the register to the R/M */
2711 if (!Soft386WriteModrmWordOperands(State
,
2716 /* Exception occurred */
2720 /* Write the value from the R/M to the register */
2721 if (!Soft386WriteModrmWordOperands(State
,
2726 /* Exception occurred */
2731 /* The result is discarded */
2735 SOFT386_OPCODE_HANDLER(Soft386OpcodePushEs
)
2737 /* Call the internal API */
2738 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_ES
].Selector
);
2741 SOFT386_OPCODE_HANDLER(Soft386OpcodePopEs
)
2745 if (!Soft386StackPop(State
, &NewSelector
))
2747 /* Exception occurred */
2751 /* Call the internal API */
2752 return Soft386LoadSegment(State
, SOFT386_REG_ES
, LOWORD(NewSelector
));
2755 SOFT386_OPCODE_HANDLER(Soft386OpcodePushCs
)
2757 /* Call the internal API */
2758 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_CS
].Selector
);
2761 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcByteModrm
)
2763 UCHAR FirstValue
, SecondValue
, Result
;
2764 SOFT386_MOD_REG_RM ModRegRm
;
2765 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2767 /* Make sure this is the right instruction */
2768 ASSERT((Opcode
& 0xFD) == 0x10);
2770 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2772 /* The ADSIZE prefix toggles the size */
2773 AddressSize
= !AddressSize
;
2775 else if (State
->PrefixFlags
2776 & ~(SOFT386_PREFIX_ADSIZE
2777 | SOFT386_PREFIX_SEG
2778 | SOFT386_PREFIX_LOCK
))
2780 /* Invalid prefix */
2781 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2785 /* Get the operands */
2786 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2788 /* Exception occurred */
2792 if (!Soft386ReadModrmByteOperands(State
,
2797 /* Exception occurred */
2801 /* Calculate the result */
2802 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2804 /* Special exception for CF */
2805 State
->Flags
.Cf
= State
->Flags
.Cf
2806 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2808 /* Update the flags */
2809 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2810 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2811 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2812 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2813 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2814 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2815 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2817 /* Write back the result */
2818 return Soft386WriteModrmByteOperands(State
,
2820 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2824 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcModrm
)
2826 SOFT386_MOD_REG_RM ModRegRm
;
2827 BOOLEAN OperandSize
, AddressSize
;
2829 /* Make sure this is the right instruction */
2830 ASSERT((Opcode
& 0xFD) == 0x11);
2832 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2834 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2836 /* The ADSIZE prefix toggles the address size */
2837 AddressSize
= !AddressSize
;
2840 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2842 /* The OPSIZE prefix toggles the operand size */
2843 OperandSize
= !OperandSize
;
2846 if (State
->PrefixFlags
2847 & ~(SOFT386_PREFIX_ADSIZE
2848 | SOFT386_PREFIX_OPSIZE
2849 | SOFT386_PREFIX_SEG
2850 | SOFT386_PREFIX_LOCK
))
2852 /* Invalid prefix */
2853 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2857 /* Get the operands */
2858 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2860 /* Exception occurred */
2864 /* Check the operand size */
2867 ULONG FirstValue
, SecondValue
, Result
;
2869 if (!Soft386ReadModrmDwordOperands(State
,
2874 /* Exception occurred */
2878 /* Calculate the result */
2879 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2881 /* Special exception for CF */
2882 State
->Flags
.Cf
= State
->Flags
.Cf
2883 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2885 /* Update the flags */
2886 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2887 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2888 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2889 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2890 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2891 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2892 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2894 /* Write back the result */
2895 return Soft386WriteModrmDwordOperands(State
,
2897 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2902 USHORT FirstValue
, SecondValue
, Result
;
2904 if (!Soft386ReadModrmWordOperands(State
,
2909 /* Exception occurred */
2913 /* Calculate the result */
2914 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2916 /* Special exception for CF */
2917 State
->Flags
.Cf
= State
->Flags
.Cf
2918 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2920 /* Update the flags */
2921 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2922 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2923 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2924 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2925 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2926 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2927 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2929 /* Write back the result */
2930 return Soft386WriteModrmWordOperands(State
,
2932 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2938 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcAl
)
2940 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2941 UCHAR SecondValue
, Result
;
2943 /* Make sure this is the right instruction */
2944 ASSERT(Opcode
== 0x14);
2946 if (State
->PrefixFlags
)
2948 /* This opcode doesn't take any prefixes */
2949 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2953 if (!Soft386FetchByte(State
, &SecondValue
))
2955 /* Exception occurred */
2959 /* Calculate the result */
2960 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2962 /* Special exception for CF */
2963 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2964 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2966 /* Update the flags */
2967 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2968 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2969 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2970 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2971 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2972 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2973 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2975 /* Write back the result */
2976 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
2981 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcEax
)
2983 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2985 /* Make sure this is the right instruction */
2986 ASSERT(Opcode
== 0x15);
2988 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2990 /* Invalid prefix */
2991 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2995 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2997 /* The OPSIZE prefix toggles the size */
3003 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
3004 ULONG SecondValue
, Result
;
3006 if (!Soft386FetchDword(State
, &SecondValue
))
3008 /* Exception occurred */
3012 /* Calculate the result */
3013 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3015 /* Special exception for CF */
3016 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3017 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
3019 /* Update the flags */
3020 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3021 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
3022 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3023 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3024 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3025 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3026 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3028 /* Write back the result */
3029 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3033 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3034 USHORT SecondValue
, Result
;
3036 if (!Soft386FetchWord(State
, &SecondValue
))
3038 /* Exception occurred */
3042 /* Calculate the result */
3043 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3045 /* Special exception for CF */
3046 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3047 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
3049 /* Update the flags */
3050 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3051 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
3052 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3053 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3054 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3055 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3056 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3058 /* Write back the result */
3059 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3065 SOFT386_OPCODE_HANDLER(Soft386OpcodePushSs
)
3067 /* Call the internal API */
3068 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_SS
].Selector
);
3071 SOFT386_OPCODE_HANDLER(Soft386OpcodePopSs
)
3075 if (!Soft386StackPop(State
, &NewSelector
))
3077 /* Exception occurred */
3081 /* Call the internal API */
3082 return Soft386LoadSegment(State
, SOFT386_REG_SS
, LOWORD(NewSelector
));
3085 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm
)
3087 // TODO: NOT IMPLEMENTED
3093 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm
)
3095 // TODO: NOT IMPLEMENTED
3101 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl
)
3103 // TODO: NOT IMPLEMENTED
3109 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax
)
3111 // TODO: NOT IMPLEMENTED
3117 SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs
)
3119 /* Call the internal API */
3120 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_DS
].Selector
);
3123 SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs
)
3127 if (!Soft386StackPop(State
, &NewSelector
))
3129 /* Exception occurred */
3133 /* Call the internal API */
3134 return Soft386LoadSegment(State
, SOFT386_REG_DS
, LOWORD(NewSelector
));
3137 SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa
)
3139 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3140 BOOLEAN Carry
= State
->Flags
.Cf
;
3142 /* Clear the carry flag */
3143 State
->Flags
.Cf
= FALSE
;
3145 /* Check if the first BCD digit is invalid or there was a carry from it */
3146 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3149 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x06;
3150 if (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
< 0x06)
3152 /* A carry occurred */
3153 State
->Flags
.Cf
= TRUE
;
3156 /* Set the adjust flag */
3157 State
->Flags
.Af
= TRUE
;
3160 /* Check if the second BCD digit is invalid or there was a carry from it */
3161 if ((Value
> 0x99) || Carry
)
3164 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x60;
3166 /* There was a carry */
3167 State
->Flags
.Cf
= TRUE
;
3173 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm
)
3175 UCHAR FirstValue
, SecondValue
, Result
;
3176 SOFT386_MOD_REG_RM ModRegRm
;
3177 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3179 /* Make sure this is the right instruction */
3180 ASSERT((Opcode
& 0xED) == 0x28);
3182 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3184 /* The ADSIZE prefix toggles the size */
3185 AddressSize
= !AddressSize
;
3187 else if (State
->PrefixFlags
3188 & ~(SOFT386_PREFIX_ADSIZE
3189 | SOFT386_PREFIX_SEG
3190 | SOFT386_PREFIX_LOCK
))
3192 /* Invalid prefix */
3193 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3197 /* Get the operands */
3198 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3200 /* Exception occurred */
3204 if (!Soft386ReadModrmByteOperands(State
,
3209 /* Exception occurred */
3213 /* Check if this is the instruction that writes to R/M */
3214 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3216 /* Swap the order */
3217 FirstValue
^= SecondValue
;
3218 SecondValue
^= FirstValue
;
3219 FirstValue
^= SecondValue
;
3222 /* Calculate the result */
3223 Result
= FirstValue
- SecondValue
;
3225 /* Update the flags */
3226 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3227 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3228 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3229 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3230 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3231 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3232 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3234 /* Check if this is not a CMP */
3235 if (!(Opcode
& 0x10))
3237 /* Write back the result */
3238 return Soft386WriteModrmByteOperands(State
,
3240 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3245 /* Discard the result */
3250 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm
)
3252 SOFT386_MOD_REG_RM ModRegRm
;
3253 BOOLEAN OperandSize
, AddressSize
;
3255 /* Make sure this is the right instruction */
3256 ASSERT((Opcode
& 0xED) == 0x29);
3258 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3260 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3262 /* The ADSIZE prefix toggles the address size */
3263 AddressSize
= !AddressSize
;
3266 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3268 /* The OPSIZE prefix toggles the operand size */
3269 OperandSize
= !OperandSize
;
3272 if (State
->PrefixFlags
3273 & ~(SOFT386_PREFIX_ADSIZE
3274 | SOFT386_PREFIX_OPSIZE
3275 | SOFT386_PREFIX_SEG
3276 | SOFT386_PREFIX_LOCK
))
3278 /* Invalid prefix */
3279 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3283 /* Get the operands */
3284 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3286 /* Exception occurred */
3290 /* Check the operand size */
3293 ULONG FirstValue
, SecondValue
, Result
;
3295 if (!Soft386ReadModrmDwordOperands(State
,
3300 /* Exception occurred */
3304 /* Check if this is the instruction that writes to R/M */
3305 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3307 /* Swap the order */
3308 FirstValue
^= SecondValue
;
3309 SecondValue
^= FirstValue
;
3310 FirstValue
^= SecondValue
;
3313 /* Calculate the result */
3314 Result
= FirstValue
- SecondValue
;
3316 /* Update the flags */
3317 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3318 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3319 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3320 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3321 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3322 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3323 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3325 /* Check if this is not a CMP */
3326 if (!(Opcode
& 0x10))
3328 /* Write back the result */
3329 return Soft386WriteModrmDwordOperands(State
,
3331 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3336 /* Discard the result */
3342 USHORT FirstValue
, SecondValue
, Result
;
3344 if (!Soft386ReadModrmWordOperands(State
,
3349 /* Exception occurred */
3353 /* Check if this is the instruction that writes to R/M */
3354 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3356 /* Swap the order */
3357 FirstValue
^= SecondValue
;
3358 SecondValue
^= FirstValue
;
3359 FirstValue
^= SecondValue
;
3362 /* Calculate the result */
3363 Result
= FirstValue
- SecondValue
;
3365 /* Update the flags */
3366 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3367 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3368 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3369 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3370 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3371 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3372 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3374 /* Check if this is not a CMP */
3375 if (!(Opcode
& 0x10))
3377 /* Write back the result */
3378 return Soft386WriteModrmWordOperands(State
,
3380 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3385 /* Discard the result */
3392 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl
)
3394 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3395 UCHAR SecondValue
, Result
;
3397 /* Make sure this is the right instruction */
3398 ASSERT((Opcode
& 0xEF) == 0x2C);
3400 if (State
->PrefixFlags
)
3402 /* This opcode doesn't take any prefixes */
3403 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3407 if (!Soft386FetchByte(State
, &SecondValue
))
3409 /* Exception occurred */
3413 /* Calculate the result */
3414 Result
= FirstValue
- SecondValue
;
3416 /* Update the flags */
3417 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3418 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3419 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3420 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3421 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3422 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3423 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3425 /* Check if this is not a CMP */
3426 if (!(Opcode
& 0x10))
3428 /* Write back the result */
3429 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
3435 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax
)
3437 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3439 /* Make sure this is the right instruction */
3440 ASSERT((Opcode
& 0xEF) == 0x2D);
3442 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3444 /* Invalid prefix */
3445 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3449 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3451 /* The OPSIZE prefix toggles the size */
3457 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
3458 ULONG SecondValue
, Result
;
3460 if (!Soft386FetchDword(State
, &SecondValue
))
3462 /* Exception occurred */
3466 /* Calculate the result */
3467 Result
= FirstValue
- SecondValue
;
3469 /* Update the flags */
3470 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3471 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3472 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3473 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3474 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3475 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3476 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3478 /* Check if this is not a CMP */
3479 if (!(Opcode
& 0x10))
3481 /* Write back the result */
3482 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3487 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3488 USHORT SecondValue
, Result
;
3490 if (!Soft386FetchWord(State
, &SecondValue
))
3492 /* Exception occurred */
3496 /* Calculate the result */
3497 Result
= FirstValue
- SecondValue
;
3499 /* Update the flags */
3500 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3501 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3502 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3503 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3504 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3505 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3506 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3508 /* Write back the result */
3509 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3515 SOFT386_OPCODE_HANDLER(Soft386OpcodeDas
)
3517 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3518 BOOLEAN Carry
= State
->Flags
.Cf
;
3520 /* Clear the carry flag */
3521 State
->Flags
.Cf
= FALSE
;
3523 /* Check if the first BCD digit is invalid or there was a borrow */
3524 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3527 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x06;
3528 if (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
> 0xFB)
3530 /* A borrow occurred */
3531 State
->Flags
.Cf
= TRUE
;
3534 /* Set the adjust flag */
3535 State
->Flags
.Af
= TRUE
;
3538 /* Check if the second BCD digit is invalid or there was a borrow */
3539 if ((Value
> 0x99) || Carry
)
3542 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x60;
3544 /* There was a borrow */
3545 State
->Flags
.Cf
= TRUE
;
3551 SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa
)
3553 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3556 * Check if the value in AL is not a valid BCD digit,
3557 * or there was a carry from the lowest 4 bits of AL
3559 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3562 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x06;
3563 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
++;
3566 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3570 /* Clear CF and AF */
3571 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3574 /* Keep only the lowest 4 bits of AL */
3575 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
&= 0x0F;
3580 SOFT386_OPCODE_HANDLER(Soft386OpcodeAas
)
3582 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3585 * Check if the value in AL is not a valid BCD digit,
3586 * or there was a borrow from the lowest 4 bits of AL
3588 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3591 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x06;
3592 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
--;
3595 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3599 /* Clear CF and AF */
3600 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3603 /* Keep only the lowest 4 bits of AL */
3604 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
&= 0x0F;
3609 SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll
)
3612 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3613 SOFT386_REG SavedEsp
= State
->GeneralRegs
[SOFT386_REG_ESP
];
3615 /* Make sure this is the right instruction */
3616 ASSERT(Opcode
== 0x60);
3618 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
3620 /* The OPSIZE prefix toggles the size */
3625 /* Invalid prefix */
3626 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3630 /* Push all the registers in order */
3631 for (i
= 0; i
< SOFT386_NUM_GEN_REGS
; i
++)
3633 if (i
== SOFT386_REG_ESP
)
3635 /* Use the saved ESP instead */
3636 if (!Soft386StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3638 /* Exception occurred */
3644 /* Push the register */
3645 if (!Soft386StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3646 : State
->GeneralRegs
[i
].LowWord
))
3648 /* Exception occurred */
3657 SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll
)
3660 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3663 /* Make sure this is the right instruction */
3664 ASSERT(Opcode
== 0x61);
3666 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
3668 /* The OPSIZE prefix toggles the size */
3673 /* Invalid prefix */
3674 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3678 /* Pop all the registers in reverse order */
3679 for (i
= SOFT386_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3682 if (!Soft386StackPop(State
, &Value
))
3684 /* Exception occurred */
3688 /* Don't modify ESP */
3689 if (i
!= SOFT386_REG_ESP
)
3691 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3692 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3699 SOFT386_OPCODE_HANDLER(Soft386OpcodeBound
)
3701 // TODO: NOT IMPLEMENTED
3707 SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl
)
3709 USHORT FirstValue
, SecondValue
;
3710 SOFT386_MOD_REG_RM ModRegRm
;
3711 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3713 if (!(State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
3715 || (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
))
3717 /* Cannot be used in real mode or with a LOCK prefix */
3718 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3722 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3724 /* The ADSIZE prefix toggles the size */
3725 AddressSize
= !AddressSize
;
3728 /* Get the operands */
3729 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3731 /* Exception occurred */
3735 /* Read the operands */
3736 if (!Soft386ReadModrmWordOperands(State
,
3741 /* Exception occurred */
3745 /* Check if the RPL needs adjusting */
3746 if ((SecondValue
& 3) < (FirstValue
& 3))
3748 /* Adjust the RPL */
3750 SecondValue
|= FirstValue
& 3;
3753 State
->Flags
.Zf
= TRUE
;
3755 /* Write back the result */
3756 return Soft386WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3761 State
->Flags
.Zf
= FALSE
;
3766 SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm
)
3768 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3770 /* Make sure this is the right instruction */
3771 ASSERT(Opcode
== 0x68);
3773 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3775 /* Invalid prefix */
3776 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3780 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3782 /* The OPSIZE prefix toggles the size */
3790 if (!Soft386FetchDword(State
, &Data
))
3792 /* Exception occurred */
3796 /* Call the internal API */
3797 return Soft386StackPush(State
, Data
);
3803 if (!Soft386FetchWord(State
, &Data
))
3805 /* Exception occurred */
3809 /* Call the internal API */
3810 return Soft386StackPush(State
, Data
);
3814 SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm
)
3816 BOOLEAN OperandSize
, AddressSize
;
3817 SOFT386_MOD_REG_RM ModRegRm
;
3821 /* Make sure this is the right instruction */
3822 ASSERT((Opcode
& 0xFD) == 0x69);
3824 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3826 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3828 /* The ADSIZE prefix toggles the address size */
3829 AddressSize
= !AddressSize
;
3832 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3834 /* The OPSIZE prefix toggles the operand size */
3835 OperandSize
= !OperandSize
;
3838 /* Fetch the parameters */
3839 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3841 /* Exception occurred */
3849 /* Fetch the immediate operand */
3850 if (!Soft386FetchByte(State
, (PUCHAR
)&Byte
))
3852 /* Exception occurred */
3856 Multiplier
= (LONG
)Byte
;
3864 /* Fetch the immediate operand */
3865 if (!Soft386FetchDword(State
, (PULONG
)&Dword
))
3867 /* Exception occurred */
3877 /* Fetch the immediate operand */
3878 if (!Soft386FetchWord(State
, (PUSHORT
)&Word
))
3880 /* Exception occurred */
3884 Multiplier
= (LONG
)Word
;
3890 LONG RegValue
, Multiplicand
;
3892 /* Read the operands */
3893 if (!Soft386ReadModrmDwordOperands(State
,
3896 (PULONG
)&Multiplicand
))
3898 /* Exception occurred */
3903 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3907 SHORT RegValue
, Multiplicand
;
3909 /* Read the operands */
3910 if (!Soft386ReadModrmWordOperands(State
,
3913 (PUSHORT
)&Multiplicand
))
3915 /* Exception occurred */
3920 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3923 /* Check for carry/overflow */
3924 if ((Product
< LONG_MIN
) || (Product
> LONG_MAX
))
3926 State
->Flags
.Cf
= State
->Flags
.Of
= TRUE
;
3928 else State
->Flags
.Cf
= State
->Flags
.Of
= FALSE
;
3930 /* Write-back the result */
3931 return Soft386WriteModrmDwordOperands(State
,
3934 (ULONG
)((LONG
)Product
));
3937 SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm
)
3941 /* Make sure this is the right instruction */
3942 ASSERT(Opcode
== 0x6A);
3944 if (!Soft386FetchByte(State
, &Data
))
3946 /* Exception occurred */
3950 /* Call the internal API */
3951 return Soft386StackPush(State
, Data
);
3954 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm
)
3956 UCHAR FirstValue
, SecondValue
, Result
;
3957 SOFT386_MOD_REG_RM ModRegRm
;
3958 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3960 /* Make sure this is the right instruction */
3961 ASSERT((Opcode
& 0xFD) == 0x88);
3963 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3965 /* The ADSIZE prefix toggles the size */
3966 AddressSize
= !AddressSize
;
3968 else if (State
->PrefixFlags
3969 & ~(SOFT386_PREFIX_ADSIZE
3970 | SOFT386_PREFIX_SEG
3971 | SOFT386_PREFIX_LOCK
))
3973 /* Invalid prefix */
3974 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3978 /* Get the operands */
3979 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3981 /* Exception occurred */
3985 if (!Soft386ReadModrmByteOperands(State
,
3990 /* Exception occurred */
3994 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
3995 else Result
= FirstValue
;
3997 /* Write back the result */
3998 return Soft386WriteModrmByteOperands(State
,
4000 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4005 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm
)
4007 SOFT386_MOD_REG_RM ModRegRm
;
4008 BOOLEAN OperandSize
, AddressSize
;
4010 /* Make sure this is the right instruction */
4011 ASSERT((Opcode
& 0xFD) == 0x89);
4013 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4015 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4017 /* The ADSIZE prefix toggles the address size */
4018 AddressSize
= !AddressSize
;
4021 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4023 /* The OPSIZE prefix toggles the operand size */
4024 OperandSize
= !OperandSize
;
4027 if (State
->PrefixFlags
4028 & ~(SOFT386_PREFIX_ADSIZE
4029 | SOFT386_PREFIX_OPSIZE
4030 | SOFT386_PREFIX_SEG
4031 | SOFT386_PREFIX_LOCK
))
4033 /* Invalid prefix */
4034 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4038 /* Get the operands */
4039 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4041 /* Exception occurred */
4045 /* Check the operand size */
4048 ULONG FirstValue
, SecondValue
, Result
;
4050 if (!Soft386ReadModrmDwordOperands(State
,
4055 /* Exception occurred */
4059 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4060 else Result
= FirstValue
;
4062 /* Write back the result */
4063 return Soft386WriteModrmDwordOperands(State
,
4065 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4070 USHORT FirstValue
, SecondValue
, Result
;
4072 if (!Soft386ReadModrmWordOperands(State
,
4077 /* Exception occurred */
4081 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4082 else Result
= FirstValue
;
4084 /* Write back the result */
4085 return Soft386WriteModrmWordOperands(State
,
4087 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4092 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg
)
4094 BOOLEAN OperandSize
, AddressSize
;
4095 SOFT386_MOD_REG_RM ModRegRm
;
4097 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4099 /* Make sure this is the right instruction */
4100 ASSERT(Opcode
== 0x8C);
4102 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4104 /* The ADSIZE prefix toggles the address size */
4105 AddressSize
= !AddressSize
;
4108 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4110 /* The OPSIZE prefix toggles the operand size */
4111 OperandSize
= !OperandSize
;
4114 /* Get the operands */
4115 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4117 /* Exception occurred */
4121 if (ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4124 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4130 return Soft386WriteModrmDwordOperands(State
,
4133 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4137 return Soft386WriteModrmWordOperands(State
,
4140 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4144 SOFT386_OPCODE_HANDLER(Soft386OpcodeLea
)
4146 SOFT386_MOD_REG_RM ModRegRm
;
4147 BOOLEAN OperandSize
, AddressSize
;
4149 /* Make sure this is the right instruction */
4150 ASSERT(Opcode
== 0x8D);
4152 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4154 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4156 /* The ADSIZE prefix toggles the address size */
4157 AddressSize
= !AddressSize
;
4160 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4162 /* The OPSIZE prefix toggles the operand size */
4163 OperandSize
= !OperandSize
;
4166 /* Get the operands */
4167 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4169 /* Exception occurred */
4173 /* The second operand must be memory */
4174 if (!ModRegRm
.Memory
)
4177 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4181 /* Write the address to the register */
4184 return Soft386WriteModrmDwordOperands(State
,
4187 ModRegRm
.MemoryAddress
);
4191 return Soft386WriteModrmWordOperands(State
,
4194 ModRegRm
.MemoryAddress
);
4199 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg
)
4201 BOOLEAN OperandSize
, AddressSize
;
4202 SOFT386_MOD_REG_RM ModRegRm
;
4204 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4206 /* Make sure this is the right instruction */
4207 ASSERT(Opcode
== 0x8E);
4209 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4211 /* The ADSIZE prefix toggles the address size */
4212 AddressSize
= !AddressSize
;
4215 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4217 /* The OPSIZE prefix toggles the operand size */
4218 OperandSize
= !OperandSize
;
4221 /* Get the operands */
4222 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4224 /* Exception occurred */
4228 if ((ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4229 || ((SOFT386_SEG_REGS
)ModRegRm
.Register
== SOFT386_REG_CS
))
4232 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4238 ULONG Dummy
, Selector
;
4240 if (!Soft386ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4242 /* Exception occurred */
4246 return Soft386LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4250 USHORT Dummy
, Selector
;
4252 if (!Soft386ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4254 /* Exception occurred */
4258 return Soft386LoadSegment(State
, ModRegRm
.Register
, Selector
);
4262 SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde
)
4264 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4266 /* Make sure this is the right instruction */
4267 ASSERT(Opcode
== 0x98);
4269 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4271 /* The OPSIZE prefix toggles the size */
4274 else if (State
->PrefixFlags
!= 0)
4276 /* Invalid prefix */
4277 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4283 /* Sign extend AX to EAX */
4284 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= MAKELONG
4286 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
4287 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4293 /* Sign extend AL to AX */
4294 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
=
4295 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4302 SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq
)
4304 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4306 /* Make sure this is the right instruction */
4307 ASSERT(Opcode
== 0x99);
4309 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4311 /* The OPSIZE prefix toggles the size */
4314 else if (State
->PrefixFlags
!= 0)
4316 /* Invalid prefix */
4317 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4323 /* Sign extend EAX to EDX:EAX */
4324 State
->GeneralRegs
[SOFT386_REG_EDX
].Long
=
4325 (State
->GeneralRegs
[SOFT386_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4326 ? 0xFFFFFFFF : 0x00000000;
4330 /* Sign extend AX to DX:AX */
4331 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
=
4332 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4339 SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs
)
4341 // TODO: NOT IMPLEMENTED
4347 SOFT386_OPCODE_HANDLER(Soft386OpcodeWait
)
4349 // TODO: NOT IMPLEMENTED
4355 SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags
)
4357 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4359 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4361 /* Invalid prefix */
4362 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4366 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4368 /* This OPSIZE prefix toggles the size */
4372 /* Check for VM86 mode when IOPL is not 3 */
4373 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4375 /* Call the VM86 monitor */
4376 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4380 /* Push the flags */
4381 if (Size
) return Soft386StackPush(State
, State
->Flags
.Long
);
4382 else return Soft386StackPush(State
, LOWORD(State
->Flags
.Long
));
4385 SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags
)
4387 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4388 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4391 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4393 /* Invalid prefix */
4394 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4398 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4400 /* This OPSIZE prefix toggles the size */
4404 /* Pop the new flags */
4405 if (!Soft386StackPop(State
, &NewFlags
))
4407 /* Exception occurred */
4411 if (!State
->Flags
.Vm
)
4413 /* Check the current privilege level */
4421 /* Memorize the old state of RF */
4422 BOOLEAN OldRf
= State
->Flags
.Rf
;
4424 State
->Flags
.Long
= NewFlags
;
4426 /* Restore VM and RF */
4427 State
->Flags
.Vm
= FALSE
;
4428 State
->Flags
.Rf
= OldRf
;
4430 /* Clear VIF and VIP */
4431 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4433 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4435 /* Restore the reserved bits */
4436 State
->Flags
.AlwaysSet
= TRUE
;
4437 State
->Flags
.Reserved0
= FALSE
;
4438 State
->Flags
.Reserved1
= FALSE
;
4444 /* Memorize the old state of IF and IOPL */
4445 BOOLEAN OldIf
= State
->Flags
.If
;
4446 UINT OldIopl
= State
->Flags
.Iopl
;
4451 /* Memorize the old state of RF */
4452 BOOLEAN OldRf
= State
->Flags
.Rf
;
4454 State
->Flags
.Long
= NewFlags
;
4456 /* Restore VM and RF */
4457 State
->Flags
.Vm
= FALSE
;
4458 State
->Flags
.Rf
= OldRf
;
4460 /* Clear VIF and VIP */
4461 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4463 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4465 /* Restore the reserved bits and IOPL */
4466 State
->Flags
.AlwaysSet
= TRUE
;
4467 State
->Flags
.Reserved0
= FALSE
;
4468 State
->Flags
.Reserved1
= FALSE
;
4469 State
->Flags
.Iopl
= OldIopl
;
4471 /* Check if the user doesn't have the privilege to change IF */
4472 if (Cpl
> State
->Flags
.Iopl
)
4475 State
->Flags
.If
= OldIf
;
4481 /* Check the IOPL */
4482 if (State
->Flags
.Iopl
== 3)
4486 /* Memorize the old state of RF, VIF and VIP */
4487 BOOLEAN OldRf
= State
->Flags
.Rf
;
4488 BOOLEAN OldVif
= State
->Flags
.Vif
;
4489 BOOLEAN OldVip
= State
->Flags
.Vip
;
4491 State
->Flags
.Long
= NewFlags
;
4493 /* Restore VM, RF, VIF and VIP */
4494 State
->Flags
.Vm
= TRUE
;
4495 State
->Flags
.Rf
= OldRf
;
4496 State
->Flags
.Vif
= OldVif
;
4497 State
->Flags
.Vip
= OldVip
;
4499 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4501 /* Restore the reserved bits and IOPL */
4502 State
->Flags
.AlwaysSet
= TRUE
;
4503 State
->Flags
.Reserved0
= FALSE
;
4504 State
->Flags
.Reserved1
= FALSE
;
4505 State
->Flags
.Iopl
= 3;
4509 /* Call the VM86 monitor */
4510 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4518 SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf
)
4520 /* Make sure this is the right instruction */
4521 ASSERT(Opcode
== 0x9E);
4523 /* Set the low-order byte of FLAGS to AH */
4524 State
->Flags
.Long
&= 0xFFFFFF00;
4525 State
->Flags
.Long
|= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
;
4527 /* Restore the reserved bits of FLAGS */
4528 State
->Flags
.AlwaysSet
= TRUE
;
4529 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4534 SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf
)
4536 /* Make sure this is the right instruction */
4537 ASSERT(Opcode
== 0x9F);
4539 /* Set AH to the low-order byte of FLAGS */
4540 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4545 SOFT386_OPCODE_HANDLER(Soft386OpcodeRet
)
4547 ULONG ReturnAddress
;
4548 USHORT BytesToPop
= 0;
4549 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4551 /* Make sure this is the right instruction */
4552 ASSERT((Opcode
& 0xFE) == 0xC2);
4554 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4556 /* Invalid prefix */
4557 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4561 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4563 /* The OPSIZE prefix toggles the size */
4569 /* Fetch the number of bytes to pop after the return */
4570 if (!Soft386FetchWord(State
, &BytesToPop
)) return FALSE
;
4573 /* Pop the return address */
4574 if (!Soft386StackPop(State
, &ReturnAddress
)) return FALSE
;
4576 /* Return to the calling procedure, and if necessary, pop the parameters */
4579 State
->InstPtr
.Long
= ReturnAddress
;
4580 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
+= BytesToPop
;
4584 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4585 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
+= BytesToPop
;
4591 SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes
)
4593 UCHAR FarPointer
[6];
4594 BOOLEAN OperandSize
, AddressSize
;
4595 SOFT386_MOD_REG_RM ModRegRm
;
4597 /* Make sure this is the right instruction */
4598 ASSERT((Opcode
& 0xFE) == 0xC4);
4600 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4602 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4604 /* The ADSIZE prefix toggles the size */
4605 AddressSize
= !AddressSize
;
4608 /* Get the operands */
4609 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4611 /* Exception occurred */
4615 if (!ModRegRm
.Memory
)
4617 /* Check if this is a BOP and the host supports BOPs */
4618 if ((Opcode
== 0xC4)
4619 && (ModRegRm
.Register
== SOFT386_REG_EAX
)
4620 && (ModRegRm
.SecondRegister
== SOFT386_REG_ESP
)
4621 && (State
->BopCallback
!= NULL
))
4625 /* Fetch the BOP code */
4626 if (!Soft386FetchWord(State
, &BopCode
))
4628 /* Exception occurred */
4632 /* Call the BOP handler */
4633 State
->BopCallback(State
, BopCode
);
4635 /* Return success */
4640 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4644 if (!Soft386ReadMemory(State
,
4645 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
)
4646 ? State
->SegmentOverride
: SOFT386_REG_DS
,
4647 ModRegRm
.MemoryAddress
,
4650 OperandSize
? 6 : 4))
4652 /* Exception occurred */
4658 ULONG Offset
= *((PULONG
)FarPointer
);
4659 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4661 /* Set the register to the offset */
4662 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4664 /* Load the segment */
4665 return Soft386LoadSegment(State
,
4667 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4672 USHORT Offset
= *((PUSHORT
)FarPointer
);
4673 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4675 /* Set the register to the offset */
4676 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4678 /* Load the segment */
4679 return Soft386LoadSegment(State
,
4681 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4686 SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter
)
4689 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4692 SOFT386_REG FramePointer
;
4694 /* Make sure this is the right instruction */
4695 ASSERT(Opcode
== 0xC8);
4697 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4699 /* Invalid prefix */
4700 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4704 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4706 /* The OPSIZE prefix toggles the size */
4710 if (!Soft386FetchWord(State
, &FrameSize
))
4712 /* Exception occurred */
4716 if (!Soft386FetchByte(State
, &NestingLevel
))
4718 /* Exception occurred */
4723 if (!Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
))
4725 /* Exception occurred */
4730 FramePointer
= State
->GeneralRegs
[SOFT386_REG_ESP
];
4732 /* Set up the nested procedure stacks */
4733 for (i
= 1; i
< NestingLevel
; i
++)
4737 State
->GeneralRegs
[SOFT386_REG_EBP
].Long
-= 4;
4738 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
4742 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
-= 2;
4743 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
);
4747 if (NestingLevel
> 0) Soft386StackPush(State
, FramePointer
.Long
);
4749 /* Set EBP to the frame pointer */
4750 State
->GeneralRegs
[SOFT386_REG_EBP
] = FramePointer
;
4752 /* Reserve space for the frame */
4753 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4754 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
-= FrameSize
;
4759 SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave
)
4761 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4763 /* Make sure this is the right instruction */
4764 ASSERT(Opcode
== 0xC9);
4766 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4768 /* Invalid prefix */
4769 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4773 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4775 /* The OPSIZE prefix toggles the size */
4781 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4782 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= State
->GeneralRegs
[SOFT386_REG_EBP
].Long
;
4784 /* Pop the saved base pointer from the stack */
4785 return Soft386StackPop(State
, &State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
4791 /* Set the stack pointer (SP) to the base pointer (BP) */
4792 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
;
4794 /* Pop the saved base pointer from the stack */
4795 if (Soft386StackPop(State
, &Value
))
4797 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
= LOWORD(Value
);
4804 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm
)
4806 // TODO: NOT IMPLEMENTED
4812 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar
)
4814 // TODO: NOT IMPLEMENTED
4820 SOFT386_OPCODE_HANDLER(Soft386OpcodeInt
)
4823 SOFT386_IDT_ENTRY IdtEntry
;
4829 /* This is the INT3 instruction */
4836 /* Fetch the interrupt number */
4837 if (!Soft386FetchByte(State
, &IntNum
))
4839 /* Exception occurred */
4848 /* Don't do anything if OF is cleared */
4849 if (!State
->Flags
.Of
) return TRUE
;
4852 IntNum
= SOFT386_EXCEPTION_OF
;
4859 /* Should not happen */
4864 /* Get the interrupt vector */
4865 if (!Soft386GetIntVector(State
, IntNum
, &IdtEntry
))
4867 /* Exception occurred */
4871 /* Perform the interrupt */
4872 if (!Soft386InterruptInternal(State
,
4874 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4877 /* Exception occurred */
4884 SOFT386_OPCODE_HANDLER(Soft386OpcodeIret
)
4887 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4888 SOFT386_FLAGS_REG NewFlags
;
4889 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4891 /* Make sure this is the right instruction */
4892 ASSERT(Opcode
== 0xCF);
4894 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4896 /* Invalid prefix */
4897 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4901 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4903 /* The OPSIZE prefix toggles the size */
4908 if (!Soft386StackPop(State
, &InstPtr
))
4910 /* Exception occurred */
4915 if (!Soft386StackPop(State
, &CodeSel
))
4917 /* Exception occurred */
4922 if (!Soft386StackPop(State
, &NewFlags
.Long
))
4924 /* Exception occurred */
4928 /* Check for protected mode */
4929 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
4931 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4933 if (State
->Flags
.Vm
)
4935 /* Return from VM86 mode */
4937 /* Check the IOPL */
4938 if (State
->Flags
.Iopl
== 3)
4941 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4944 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
4946 /* Exception occurred */
4950 /* Set the new flags */
4951 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4952 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4953 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4954 State
->Flags
.Iopl
= 3;
4958 /* Call the VM86 monitor */
4959 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4966 if (State
->Flags
.Nt
)
4968 /* Nested task return */
4976 /* Return to VM86 mode */
4977 ULONG Es
, Ds
, Fs
, Gs
;
4979 /* Pop ESP, SS, ES, FS, GS */
4980 if (!Soft386StackPop(State
, &StackPtr
)) return FALSE
;
4981 if (!Soft386StackPop(State
, &StackSel
)) return FALSE
;
4982 if (!Soft386StackPop(State
, &Es
)) return FALSE
;
4983 if (!Soft386StackPop(State
, &Ds
)) return FALSE
;
4984 if (!Soft386StackPop(State
, &Fs
)) return FALSE
;
4985 if (!Soft386StackPop(State
, &Gs
)) return FALSE
;
4987 /* Set the new IP */
4988 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4990 /* Set the new flags */
4991 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4992 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4993 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4995 /* Load the new segments */
4996 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
)) return FALSE
;
4997 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
)) return FALSE
;
4998 if (!Soft386LoadSegment(State
, SOFT386_REG_ES
, Es
)) return FALSE
;
4999 if (!Soft386LoadSegment(State
, SOFT386_REG_DS
, Ds
)) return FALSE
;
5000 if (!Soft386LoadSegment(State
, SOFT386_REG_FS
, Fs
)) return FALSE
;
5001 if (!Soft386LoadSegment(State
, SOFT386_REG_GS
, Gs
)) return FALSE
;
5006 /* Load the new CS */
5007 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5009 /* Exception occurred */
5014 if (Size
) State
->InstPtr
.Long
= InstPtr
;
5015 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
5017 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5020 if (!Soft386StackPop(State
, &StackPtr
))
5027 if (!Soft386StackPop(State
, &StackSel
))
5034 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
))
5041 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= StackPtr
;
5042 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= LOWORD(StackPtr
);
5045 /* Set the new flags */
5046 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
5047 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
5048 State
->Flags
.AlwaysSet
= TRUE
;
5050 /* Set additional flags */
5051 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
5052 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
5054 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5056 /* Update the CPL */
5057 Cpl
= Soft386GetCurrentPrivLevel(State
);
5059 /* Check segment security */
5060 for (i
= 0; i
<= SOFT386_NUM_SEG_REGS
; i
++)
5062 /* Don't check CS or SS */
5063 if ((i
== SOFT386_REG_CS
) || (i
== SOFT386_REG_SS
)) continue;
5065 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
5066 && (!State
->SegmentRegs
[i
].Executable
5067 || !State
->SegmentRegs
[i
].DirConf
))
5069 /* Load the NULL descriptor in the segment */
5070 if (!Soft386LoadSegment(State
, i
, 0)) return FALSE
;
5077 if (Size
&& (InstPtr
& 0xFFFF0000))
5080 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
5085 State
->InstPtr
.Long
= InstPtr
;
5088 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5090 /* Exception occurred */
5094 /* Set the new flags */
5095 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5096 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5097 State
->Flags
.AlwaysSet
= TRUE
;
5103 SOFT386_OPCODE_HANDLER(Soft386OpcodeAam
)
5106 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5108 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5110 /* Invalid prefix */
5111 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5115 /* Fetch the base */
5116 if (!Soft386FetchByte(State
, &Base
))
5118 /* Exception occurred */
5122 /* Check if the base is zero */
5126 Soft386Exception(State
, SOFT386_EXCEPTION_DE
);
5131 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= Value
/ Base
;
5132 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
%= Base
;
5135 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5136 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5137 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5142 SOFT386_OPCODE_HANDLER(Soft386OpcodeAad
)
5145 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5147 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5149 /* Invalid prefix */
5150 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5154 /* Fetch the base */
5155 if (!Soft386FetchByte(State
, &Base
))
5157 /* Exception occurred */
5162 Value
+= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
* Base
;
5163 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
;
5166 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5167 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5168 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5173 SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat
)
5175 // TODO: NOT IMPLEMENTED
5181 SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop
)
5184 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5187 /* Make sure this is the right instruction */
5188 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
5190 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5192 /* Invalid prefix */
5193 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5197 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5199 /* The OPSIZE prefix toggles the size */
5203 if (Size
) Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].Long
) != 0);
5204 else Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
) != 0);
5208 /* Additional rule for LOOPNZ */
5209 if (State
->Flags
.Zf
) Condition
= FALSE
;
5214 /* Additional rule for LOOPZ */
5215 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5218 /* Fetch the offset */
5219 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5221 /* An exception occurred */
5227 /* Move the instruction pointer */
5228 State
->InstPtr
.Long
+= Offset
;
5234 SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz
)
5237 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5240 /* Make sure this is the right instruction */
5241 ASSERT(Opcode
== 0xE3);
5243 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5245 /* Invalid prefix */
5246 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5250 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5252 /* The OPSIZE prefix toggles the size */
5256 if (Size
) Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].Long
== 0);
5257 else Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
== 0);
5259 /* Fetch the offset */
5260 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5262 /* An exception occurred */
5268 /* Move the instruction pointer */
5269 State
->InstPtr
.Long
+= Offset
;
5275 SOFT386_OPCODE_HANDLER(Soft386OpcodeCall
)
5277 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5279 /* Make sure this is the right instruction */
5280 ASSERT(Opcode
== 0xE8);
5282 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5284 /* The OPSIZE prefix toggles the size */
5287 else if (State
->PrefixFlags
!= 0)
5289 /* Invalid prefix */
5290 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5298 /* Fetch the offset */
5299 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5301 /* An exception occurred */
5305 /* Push the current value of the instruction pointer */
5306 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5308 /* Exception occurred */
5312 /* Move the instruction pointer */
5313 State
->InstPtr
.Long
+= Offset
;
5319 /* Fetch the offset */
5320 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5322 /* An exception occurred */
5326 /* Push the current value of the instruction pointer */
5327 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5329 /* Exception occurred */
5333 /* Move the instruction pointer */
5334 State
->InstPtr
.LowWord
+= Offset
;
5340 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp
)
5342 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5344 /* Make sure this is the right instruction */
5345 ASSERT(Opcode
== 0xE9);
5347 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5349 /* The OPSIZE prefix toggles the size */
5352 else if (State
->PrefixFlags
!= 0)
5354 /* Invalid prefix */
5355 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5363 /* Fetch the offset */
5364 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5366 /* An exception occurred */
5370 /* Move the instruction pointer */
5371 State
->InstPtr
.Long
+= Offset
;
5377 /* Fetch the offset */
5378 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5380 /* An exception occurred */
5384 /* Move the instruction pointer */
5385 State
->InstPtr
.LowWord
+= Offset
;
5391 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs
)
5393 // TODO: NOT IMPLEMENTED
5399 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset
)
5401 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5404 /* Make sure this is the right instruction */
5405 ASSERT(Opcode
== 0xA0);
5407 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5409 /* The OPSIZE prefix toggles the size */
5415 if (!Soft386FetchDword(State
, &Offset
))
5417 /* Exception occurred */
5425 if (!Soft386FetchWord(State
, &WordOffset
))
5427 /* Exception occurred */
5431 Offset
= (ULONG
)WordOffset
;
5434 /* Read from memory */
5435 return Soft386ReadMemory(State
,
5436 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5437 State
->SegmentOverride
: SOFT386_REG_DS
,
5440 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5444 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset
)
5446 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5448 /* Make sure this is the right instruction */
5449 ASSERT(Opcode
== 0xA1);
5451 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5453 /* The OPSIZE prefix toggles the size */
5461 if (!Soft386FetchDword(State
, &Offset
))
5463 /* Exception occurred */
5467 /* Read from memory */
5468 return Soft386ReadMemory(State
,
5469 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5470 State
->SegmentOverride
: SOFT386_REG_DS
,
5473 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5480 if (!Soft386FetchWord(State
, &Offset
))
5482 /* Exception occurred */
5486 /* Read from memory */
5487 return Soft386ReadMemory(State
,
5488 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5489 State
->SegmentOverride
: SOFT386_REG_DS
,
5492 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
5497 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl
)
5499 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5502 /* Make sure this is the right instruction */
5503 ASSERT(Opcode
== 0xA2);
5505 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5507 /* The OPSIZE prefix toggles the size */
5513 if (!Soft386FetchDword(State
, &Offset
))
5515 /* Exception occurred */
5523 if (!Soft386FetchWord(State
, &WordOffset
))
5525 /* Exception occurred */
5529 Offset
= (ULONG
)WordOffset
;
5532 /* Write to memory */
5533 return Soft386WriteMemory(State
,
5534 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5535 State
->SegmentOverride
: SOFT386_REG_DS
,
5537 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5541 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax
)
5543 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5545 /* Make sure this is the right instruction */
5546 ASSERT(Opcode
== 0xA3);
5548 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5550 /* The OPSIZE prefix toggles the size */
5558 if (!Soft386FetchDword(State
, &Offset
))
5560 /* Exception occurred */
5564 /* Write to memory */
5565 return Soft386WriteMemory(State
,
5566 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5567 State
->SegmentOverride
: SOFT386_REG_DS
,
5569 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5576 if (!Soft386FetchWord(State
, &Offset
))
5578 /* Exception occurred */
5582 /* Write to memory */
5583 return Soft386WriteMemory(State
,
5584 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5585 State
->SegmentOverride
: SOFT386_REG_DS
,
5587 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,