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
38 /* PUBLIC VARIABLES ***********************************************************/
40 SOFT386_OPCODE_HANDLER_PROC
41 Soft386OpcodeHandlers
[SOFT386_NUM_OPCODE_HANDLERS
] =
43 Soft386OpcodeAddByteModrm
,
44 Soft386OpcodeAddModrm
,
45 Soft386OpcodeAddByteModrm
,
46 Soft386OpcodeAddModrm
,
51 Soft386OpcodeOrByteModrm
,
53 Soft386OpcodeOrByteModrm
,
58 Soft386OpcodeExtended
,
59 Soft386OpcodeAdcByteModrm
,
60 Soft386OpcodeAdcModrm
,
61 Soft386OpcodeAdcByteModrm
,
62 Soft386OpcodeAdcModrm
,
67 Soft386OpcodeSbbByteModrm
,
68 Soft386OpcodeSbbModrm
,
69 Soft386OpcodeSbbByteModrm
,
70 Soft386OpcodeSbbModrm
,
75 Soft386OpcodeAndByteModrm
,
76 Soft386OpcodeAndModrm
,
77 Soft386OpcodeAndByteModrm
,
78 Soft386OpcodeAndModrm
,
83 Soft386OpcodeCmpSubByteModrm
,
84 Soft386OpcodeCmpSubModrm
,
85 Soft386OpcodeCmpSubByteModrm
,
86 Soft386OpcodeCmpSubModrm
,
87 Soft386OpcodeCmpSubAl
,
88 Soft386OpcodeCmpSubEax
,
91 Soft386OpcodeXorByteModrm
,
92 Soft386OpcodeXorModrm
,
93 Soft386OpcodeXorByteModrm
,
94 Soft386OpcodeXorModrm
,
99 Soft386OpcodeCmpSubByteModrm
,
100 Soft386OpcodeCmpSubModrm
,
101 Soft386OpcodeCmpSubByteModrm
,
102 Soft386OpcodeCmpSubModrm
,
103 Soft386OpcodeCmpSubAl
,
104 Soft386OpcodeCmpSubEax
,
107 Soft386OpcodeIncrement
,
108 Soft386OpcodeIncrement
,
109 Soft386OpcodeIncrement
,
110 Soft386OpcodeIncrement
,
111 Soft386OpcodeIncrement
,
112 Soft386OpcodeIncrement
,
113 Soft386OpcodeIncrement
,
114 Soft386OpcodeIncrement
,
115 Soft386OpcodeDecrement
,
116 Soft386OpcodeDecrement
,
117 Soft386OpcodeDecrement
,
118 Soft386OpcodeDecrement
,
119 Soft386OpcodeDecrement
,
120 Soft386OpcodeDecrement
,
121 Soft386OpcodeDecrement
,
122 Soft386OpcodeDecrement
,
123 Soft386OpcodePushReg
,
124 Soft386OpcodePushReg
,
125 Soft386OpcodePushReg
,
126 Soft386OpcodePushReg
,
127 Soft386OpcodePushReg
,
128 Soft386OpcodePushReg
,
129 Soft386OpcodePushReg
,
130 Soft386OpcodePushReg
,
139 Soft386OpcodePushAll
,
147 Soft386OpcodePushImm
,
148 Soft386OpcodeImulModrmImm
,
149 Soft386OpcodePushByteImm
,
150 Soft386OpcodeImulModrmImm
,
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 Soft386OpcodeShortConditionalJmp
,
171 Soft386OpcodeGroup8082
,
172 Soft386OpcodeGroup81
,
173 Soft386OpcodeGroup8082
,
174 Soft386OpcodeGroup83
,
175 Soft386OpcodeTestByteModrm
,
176 Soft386OpcodeTestModrm
,
177 Soft386OpcodeXchgByteModrm
,
178 Soft386OpcodeXchgModrm
,
179 Soft386OpcodeMovByteModrm
,
180 Soft386OpcodeMovModrm
,
181 Soft386OpcodeMovByteModrm
,
182 Soft386OpcodeMovModrm
,
183 Soft386OpcodeMovStoreSeg
,
185 Soft386OpcodeMovLoadSeg
,
186 Soft386OpcodeGroup8F
,
188 Soft386OpcodeExchangeEax
,
189 Soft386OpcodeExchangeEax
,
190 Soft386OpcodeExchangeEax
,
191 Soft386OpcodeExchangeEax
,
192 Soft386OpcodeExchangeEax
,
193 Soft386OpcodeExchangeEax
,
194 Soft386OpcodeExchangeEax
,
197 Soft386OpcodeCallAbs
,
199 Soft386OpcodePushFlags
,
200 Soft386OpcodePopFlags
,
203 Soft386OpcodeMovAlOffset
,
204 Soft386OpcodeMovEaxOffset
,
205 Soft386OpcodeMovOffsetAl
,
206 Soft386OpcodeMovOffsetEax
,
212 Soft386OpcodeTestEax
,
219 Soft386OpcodeMovByteRegImm
,
220 Soft386OpcodeMovByteRegImm
,
221 Soft386OpcodeMovByteRegImm
,
222 Soft386OpcodeMovByteRegImm
,
223 Soft386OpcodeMovByteRegImm
,
224 Soft386OpcodeMovByteRegImm
,
225 Soft386OpcodeMovByteRegImm
,
226 Soft386OpcodeMovByteRegImm
,
227 Soft386OpcodeMovRegImm
,
228 Soft386OpcodeMovRegImm
,
229 Soft386OpcodeMovRegImm
,
230 Soft386OpcodeMovRegImm
,
231 Soft386OpcodeMovRegImm
,
232 Soft386OpcodeMovRegImm
,
233 Soft386OpcodeMovRegImm
,
234 Soft386OpcodeMovRegImm
,
235 Soft386OpcodeGroupC0
,
236 Soft386OpcodeGroupC1
,
241 Soft386OpcodeGroupC6
,
242 Soft386OpcodeGroupC7
,
245 Soft386OpcodeRetFarImm
,
251 Soft386OpcodeGroupD0
,
252 Soft386OpcodeGroupD1
,
253 Soft386OpcodeGroupD2
,
254 Soft386OpcodeGroupD3
,
259 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
260 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
261 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
262 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
263 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
264 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
265 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
266 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
273 Soft386OpcodeOutByte
,
278 Soft386OpcodeShortJump
,
281 Soft386OpcodeOutByte
,
288 Soft386OpcodeComplCarry
,
289 Soft386OpcodeGroupF6
,
290 Soft386OpcodeGroupF7
,
291 Soft386OpcodeClearCarry
,
292 Soft386OpcodeSetCarry
,
293 Soft386OpcodeClearInt
,
295 Soft386OpcodeClearDir
,
297 Soft386OpcodeGroupFE
,
298 Soft386OpcodeGroupFF
,
301 /* PUBLIC FUNCTIONS ***********************************************************/
303 SOFT386_OPCODE_HANDLER(Soft386OpcodePrefix
)
305 BOOLEAN Valid
= FALSE
;
312 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
314 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
315 State
->SegmentOverride
= SOFT386_REG_ES
;
325 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
327 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
328 State
->SegmentOverride
= SOFT386_REG_CS
;
338 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
340 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
341 State
->SegmentOverride
= SOFT386_REG_SS
;
351 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
353 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
354 State
->SegmentOverride
= SOFT386_REG_DS
;
364 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
366 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
367 State
->SegmentOverride
= SOFT386_REG_FS
;
377 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
379 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
380 State
->SegmentOverride
= SOFT386_REG_GS
;
390 if (!(State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
))
392 State
->PrefixFlags
|= SOFT386_PREFIX_OPSIZE
;
402 if (!(State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
))
404 State
->PrefixFlags
|= SOFT386_PREFIX_ADSIZE
;
413 if (!(State
->PrefixFlags
& SOFT386_PREFIX_LOCK
))
415 State
->PrefixFlags
|= SOFT386_PREFIX_LOCK
;
425 /* Mutually exclusive with REP */
426 if (!(State
->PrefixFlags
427 & (SOFT386_PREFIX_REPNZ
| SOFT386_PREFIX_REP
)))
429 State
->PrefixFlags
|= SOFT386_PREFIX_REPNZ
;
439 /* Mutually exclusive with REPNZ */
440 if (!(State
->PrefixFlags
441 & (SOFT386_PREFIX_REPNZ
| SOFT386_PREFIX_REP
)))
443 State
->PrefixFlags
|= SOFT386_PREFIX_REP
;
453 /* Clear all prefixes */
454 State
->PrefixFlags
= 0;
456 /* Throw an exception */
457 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
464 SOFT386_OPCODE_HANDLER(Soft386OpcodeIncrement
)
467 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
469 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
471 /* The OPSIZE prefix toggles the size */
474 else if (State
->PrefixFlags
!= 0)
477 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
481 /* Make sure this is the right instruction */
482 ASSERT((Opcode
& 0xF8) == 0x40);
486 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
488 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
489 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
493 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
495 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
496 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
499 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
500 State
->Flags
.Af
= ((Value
& 0x0F) == 0) ? TRUE
: FALSE
;
501 State
->Flags
.Pf
= Soft386CalculateParity(LOBYTE(Value
));
507 SOFT386_OPCODE_HANDLER(Soft386OpcodeDecrement
)
510 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
512 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
514 /* The OPSIZE prefix toggles the size */
517 else if (State
->PrefixFlags
!= 0)
520 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
524 /* Make sure this is the right instruction */
525 ASSERT((Opcode
& 0xF8) == 0x48);
529 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
531 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1)) ? TRUE
: FALSE
;
532 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
536 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
538 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1)) ? TRUE
: FALSE
;
539 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
542 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
543 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F) ? TRUE
: FALSE
;
544 State
->Flags
.Pf
= Soft386CalculateParity(LOBYTE(Value
));
550 SOFT386_OPCODE_HANDLER(Soft386OpcodePushReg
)
552 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
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 */
577 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
580 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
584 /* Make sure this is the right instruction */
585 ASSERT((Opcode
& 0xF8) == 0x58);
587 /* Call the internal function */
588 if (!Soft386StackPop(State
, &Value
)) return FALSE
;
590 /* Store the value */
591 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
592 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
598 SOFT386_OPCODE_HANDLER(Soft386OpcodeNop
)
600 if (State
->PrefixFlags
& ~(SOFT386_PREFIX_OPSIZE
| SOFT386_PREFIX_REP
))
602 /* Allowed prefixes are REP and OPSIZE */
603 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
607 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
610 State
->IdleCallback(State
);
616 SOFT386_OPCODE_HANDLER(Soft386OpcodeExchangeEax
)
618 INT Reg
= Opcode
& 0x07;
619 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
621 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
623 /* The OPSIZE prefix toggles the size */
626 else if (State
->PrefixFlags
!= 0)
629 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
633 /* Make sure this is the right instruction */
634 ASSERT((Opcode
& 0xF8) == 0x90);
636 /* Exchange the values */
641 Value
= State
->GeneralRegs
[Reg
].Long
;
642 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
643 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Value
;
649 Value
= State
->GeneralRegs
[Reg
].LowWord
;
650 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
651 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Value
;
657 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortConditionalJmp
)
659 BOOLEAN Jump
= FALSE
;
662 /* Make sure this is the right instruction */
663 ASSERT((Opcode
& 0xF0) == 0x70);
665 /* Fetch the offset */
666 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
668 /* An exception occurred */
672 switch ((Opcode
& 0x0F) >> 1)
677 Jump
= State
->Flags
.Of
;
684 Jump
= State
->Flags
.Cf
;
691 Jump
= State
->Flags
.Zf
;
698 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
705 Jump
= State
->Flags
.Sf
;
712 Jump
= State
->Flags
.Pf
;
719 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
726 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
733 /* Invert the result */
739 /* Move the instruction pointer */
740 State
->InstPtr
.Long
+= Offset
;
747 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearCarry
)
749 /* Make sure this is the right instruction */
750 ASSERT(Opcode
== 0xF8);
752 /* No prefixes allowed */
753 if (State
->PrefixFlags
)
755 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
759 /* Clear CF and return success */
760 State
->Flags
.Cf
= FALSE
;
764 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetCarry
)
766 /* Make sure this is the right instruction */
767 ASSERT(Opcode
== 0xF9);
769 /* No prefixes allowed */
770 if (State
->PrefixFlags
)
772 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
776 /* Set CF and return success*/
777 State
->Flags
.Cf
= TRUE
;
781 SOFT386_OPCODE_HANDLER(Soft386OpcodeComplCarry
)
783 /* Make sure this is the right instruction */
784 ASSERT(Opcode
== 0xF5);
786 /* No prefixes allowed */
787 if (State
->PrefixFlags
)
789 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
793 /* Toggle CF and return success */
794 State
->Flags
.Cf
= !State
->Flags
.Cf
;
798 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearInt
)
800 /* Make sure this is the right instruction */
801 ASSERT(Opcode
== 0xFA);
803 /* No prefixes allowed */
804 if (State
->PrefixFlags
)
806 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
810 /* Check for protected mode */
811 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
814 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
)
816 /* Clear the interrupt flag */
817 State
->Flags
.If
= FALSE
;
821 /* General Protection Fault */
822 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
828 /* Just clear the interrupt flag */
829 State
->Flags
.If
= FALSE
;
836 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetInt
)
838 /* Make sure this is the right instruction */
839 ASSERT(Opcode
== 0xFB);
841 /* No prefixes allowed */
842 if (State
->PrefixFlags
)
844 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
848 /* Check for protected mode */
849 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
852 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
)
854 /* Set the interrupt flag */
855 State
->Flags
.If
= TRUE
;
859 /* General Protection Fault */
860 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
866 /* Just set the interrupt flag */
867 State
->Flags
.If
= TRUE
;
874 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearDir
)
876 /* Make sure this is the right instruction */
877 ASSERT(Opcode
== 0xFC);
879 /* No prefixes allowed */
880 if (State
->PrefixFlags
)
882 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
886 /* Clear DF and return success */
887 State
->Flags
.Df
= FALSE
;
891 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetDir
)
893 /* Make sure this is the right instruction */
894 ASSERT(Opcode
== 0xFD);
896 /* No prefixes allowed */
897 if (State
->PrefixFlags
)
899 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
903 /* Set DF and return success*/
904 State
->Flags
.Df
= TRUE
;
908 SOFT386_OPCODE_HANDLER(Soft386OpcodeHalt
)
910 /* Make sure this is the right instruction */
911 ASSERT(Opcode
== 0xF4);
913 /* No prefixes allowed */
914 if (State
->PrefixFlags
)
916 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
920 /* Privileged instructions can only be executed under CPL = 0 */
921 if (State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
!= 0)
923 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
928 while (!State
->HardwareInt
) State
->IdleCallback(State
);
934 SOFT386_OPCODE_HANDLER(Soft386OpcodeInByte
)
939 /* Make sure this is the right instruction */
940 ASSERT((Opcode
& 0xF7) == 0xE4);
944 /* Fetch the parameter */
945 if (!Soft386FetchByte(State
, &Data
))
947 /* Exception occurred */
951 /* Set the port number to the parameter */
956 /* The port number is in DX */
957 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
960 /* Read a byte from the I/O port */
961 State
->IoReadCallback(State
, Port
, &Data
, sizeof(UCHAR
));
963 /* Store the result in AL */
964 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Data
;
969 SOFT386_OPCODE_HANDLER(Soft386OpcodeIn
)
972 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
974 /* Make sure this is the right instruction */
975 ASSERT((Opcode
& 0xF7) == 0xE5);
977 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
979 /* The OPSIZE prefix toggles the size */
982 else if (State
->PrefixFlags
!= 0)
985 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
993 /* Fetch the parameter */
994 if (!Soft386FetchByte(State
, &Data
))
996 /* Exception occurred */
1000 /* Set the port number to the parameter */
1005 /* The port number is in DX */
1006 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1013 /* Read a dword from the I/O port */
1014 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1016 /* Store the value in EAX */
1017 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Data
;
1023 /* Read a word from the I/O port */
1024 State
->IoReadCallback(State
, Port
, &Data
, sizeof(USHORT
));
1026 /* Store the value in AX */
1027 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Data
;
1033 SOFT386_OPCODE_HANDLER(Soft386OpcodeOutByte
)
1038 /* Make sure this is the right instruction */
1039 ASSERT((Opcode
& 0xF7) == 0xE6);
1043 /* Fetch the parameter */
1044 if (!Soft386FetchByte(State
, &Data
))
1046 /* Exception occurred */
1050 /* Set the port number to the parameter */
1055 /* The port number is in DX */
1056 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1059 /* Read the value from AL */
1060 Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1062 /* Write the byte to the I/O port */
1063 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(UCHAR
));
1068 SOFT386_OPCODE_HANDLER(Soft386OpcodeOut
)
1071 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1073 /* Make sure this is the right instruction */
1074 ASSERT((Opcode
& 0xF7) == 0xE7);
1076 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
1078 /* The OPSIZE prefix toggles the size */
1081 else if (State
->PrefixFlags
!= 0)
1083 /* Invalid prefix */
1084 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1092 /* Fetch the parameter */
1093 if (!Soft386FetchByte(State
, &Data
))
1095 /* Exception occurred */
1099 /* Set the port number to the parameter */
1104 /* The port number is in DX */
1105 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1110 /* Get the value from EAX */
1111 ULONG Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1113 /* Write a dword to the I/O port */
1114 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1118 /* Get the value from AX */
1119 USHORT Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1121 /* Write a word to the I/O port */
1122 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(USHORT
));
1128 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortJump
)
1132 /* Make sure this is the right instruction */
1133 ASSERT(Opcode
== 0xEB);
1135 /* Fetch the offset */
1136 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
1138 /* An exception occurred */
1142 /* Move the instruction pointer */
1143 State
->InstPtr
.Long
+= Offset
;
1148 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovRegImm
)
1150 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1152 /* Make sure this is the right instruction */
1153 ASSERT((Opcode
& 0xF8) == 0xB8);
1155 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1157 /* The OPSIZE prefix toggles the size */
1161 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1163 /* Invalid prefix */
1164 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1172 /* Fetch the dword */
1173 if (!Soft386FetchDword(State
, &Value
))
1175 /* Exception occurred */
1179 /* Store the value in the register */
1180 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1186 /* Fetch the word */
1187 if (!Soft386FetchWord(State
, &Value
))
1189 /* Exception occurred */
1193 /* Store the value in the register */
1194 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1200 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteRegImm
)
1204 /* Make sure this is the right instruction */
1205 ASSERT((Opcode
& 0xF8) == 0xB0);
1207 if (State
->PrefixFlags
!= 0)
1209 /* Invalid prefix */
1210 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1214 /* Fetch the byte */
1215 if (!Soft386FetchByte(State
, &Value
))
1217 /* Exception occurred */
1223 /* AH, CH, DH or BH */
1224 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1228 /* AL, CL, DL or BL */
1229 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1235 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddByteModrm
)
1237 UCHAR FirstValue
, SecondValue
, Result
;
1238 SOFT386_MOD_REG_RM ModRegRm
;
1239 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1241 /* Make sure this is the right instruction */
1242 ASSERT((Opcode
& 0xFD) == 0x00);
1244 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1246 /* The ADSIZE prefix toggles the size */
1247 AddressSize
= !AddressSize
;
1249 else if (State
->PrefixFlags
1250 & ~(SOFT386_PREFIX_ADSIZE
1251 | SOFT386_PREFIX_SEG
1252 | SOFT386_PREFIX_LOCK
))
1254 /* Invalid prefix */
1255 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1259 /* Get the operands */
1260 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1262 /* Exception occurred */
1266 if (!Soft386ReadModrmByteOperands(State
,
1271 /* Exception occurred */
1275 /* Calculate the result */
1276 Result
= FirstValue
+ SecondValue
;
1278 /* Update the flags */
1279 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1280 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1281 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1282 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1283 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1284 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1285 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1287 /* Write back the result */
1288 return Soft386WriteModrmByteOperands(State
,
1290 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1294 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddModrm
)
1296 SOFT386_MOD_REG_RM ModRegRm
;
1297 BOOLEAN OperandSize
, AddressSize
;
1299 /* Make sure this is the right instruction */
1300 ASSERT((Opcode
& 0xFD) == 0x01);
1302 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1304 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1306 /* The ADSIZE prefix toggles the address size */
1307 AddressSize
= !AddressSize
;
1310 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1312 /* The OPSIZE prefix toggles the operand size */
1313 OperandSize
= !OperandSize
;
1316 if (State
->PrefixFlags
1317 & ~(SOFT386_PREFIX_ADSIZE
1318 | SOFT386_PREFIX_OPSIZE
1319 | SOFT386_PREFIX_SEG
1320 | SOFT386_PREFIX_LOCK
))
1322 /* Invalid prefix */
1323 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1327 /* Get the operands */
1328 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1330 /* Exception occurred */
1334 /* Check the operand size */
1337 ULONG FirstValue
, SecondValue
, Result
;
1339 if (!Soft386ReadModrmDwordOperands(State
,
1344 /* Exception occurred */
1348 /* Calculate the result */
1349 Result
= FirstValue
+ SecondValue
;
1351 /* Update the flags */
1352 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1353 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1354 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1355 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1356 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1357 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1358 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1360 /* Write back the result */
1361 return Soft386WriteModrmDwordOperands(State
,
1363 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1368 USHORT FirstValue
, SecondValue
, Result
;
1370 if (!Soft386ReadModrmWordOperands(State
,
1375 /* Exception occurred */
1379 /* Calculate the result */
1380 Result
= FirstValue
+ SecondValue
;
1382 /* Update the flags */
1383 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1384 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1385 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1386 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1387 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1388 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1389 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1391 /* Write back the result */
1392 return Soft386WriteModrmWordOperands(State
,
1394 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1399 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddAl
)
1401 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1402 UCHAR SecondValue
, Result
;
1404 /* Make sure this is the right instruction */
1405 ASSERT(Opcode
== 0x04);
1407 if (State
->PrefixFlags
)
1409 /* This opcode doesn't take any prefixes */
1410 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1414 if (!Soft386FetchByte(State
, &SecondValue
))
1416 /* Exception occurred */
1420 /* Calculate the result */
1421 Result
= FirstValue
+ SecondValue
;
1423 /* Update the flags */
1424 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1425 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1426 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1427 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1428 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1429 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1430 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1432 /* Write back the result */
1433 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1438 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddEax
)
1440 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1442 /* Make sure this is the right instruction */
1443 ASSERT(Opcode
== 0x05);
1445 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1447 /* Invalid prefix */
1448 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1452 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1454 /* The OPSIZE prefix toggles the size */
1460 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1461 ULONG SecondValue
, Result
;
1463 if (!Soft386FetchDword(State
, &SecondValue
))
1465 /* Exception occurred */
1469 /* Calculate the result */
1470 Result
= FirstValue
+ SecondValue
;
1472 /* Update the flags */
1473 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1474 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1475 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1476 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1477 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1478 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1479 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1481 /* Write back the result */
1482 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
1486 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1487 USHORT SecondValue
, Result
;
1489 if (!Soft386FetchWord(State
, &SecondValue
))
1491 /* Exception occurred */
1495 /* Calculate the result */
1496 Result
= FirstValue
+ SecondValue
;
1498 /* Update the flags */
1499 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1500 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1501 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1502 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1503 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1504 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1505 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1507 /* Write back the result */
1508 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
1514 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrByteModrm
)
1516 UCHAR FirstValue
, SecondValue
, Result
;
1517 SOFT386_MOD_REG_RM ModRegRm
;
1518 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1520 /* Make sure this is the right instruction */
1521 ASSERT((Opcode
& 0xFD) == 0x08);
1523 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1525 /* The ADSIZE prefix toggles the size */
1526 AddressSize
= !AddressSize
;
1528 else if (State
->PrefixFlags
1529 & ~(SOFT386_PREFIX_ADSIZE
1530 | SOFT386_PREFIX_SEG
1531 | SOFT386_PREFIX_LOCK
))
1533 /* Invalid prefix */
1534 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1538 /* Get the operands */
1539 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1541 /* Exception occurred */
1545 if (!Soft386ReadModrmByteOperands(State
,
1550 /* Exception occurred */
1554 /* Calculate the result */
1555 Result
= FirstValue
| SecondValue
;
1557 /* Update the flags */
1558 State
->Flags
.Cf
= FALSE
;
1559 State
->Flags
.Of
= FALSE
;
1560 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1561 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1562 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1564 /* Write back the result */
1565 return Soft386WriteModrmByteOperands(State
,
1567 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1571 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrModrm
)
1573 SOFT386_MOD_REG_RM ModRegRm
;
1574 BOOLEAN OperandSize
, AddressSize
;
1576 /* Make sure this is the right instruction */
1577 ASSERT((Opcode
& 0xFD) == 0x09);
1579 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1581 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1583 /* The ADSIZE prefix toggles the address size */
1584 AddressSize
= !AddressSize
;
1587 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1589 /* The OPSIZE prefix toggles the operand size */
1590 OperandSize
= !OperandSize
;
1593 if (State
->PrefixFlags
1594 & ~(SOFT386_PREFIX_ADSIZE
1595 | SOFT386_PREFIX_OPSIZE
1596 | SOFT386_PREFIX_SEG
1597 | SOFT386_PREFIX_LOCK
))
1599 /* Invalid prefix */
1600 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1604 /* Get the operands */
1605 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1607 /* Exception occurred */
1611 /* Check the operand size */
1614 ULONG FirstValue
, SecondValue
, Result
;
1616 if (!Soft386ReadModrmDwordOperands(State
,
1621 /* Exception occurred */
1625 /* Calculate the result */
1626 Result
= FirstValue
| SecondValue
;
1628 /* Update the flags */
1629 State
->Flags
.Cf
= FALSE
;
1630 State
->Flags
.Of
= FALSE
;
1631 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1632 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1633 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1635 /* Write back the result */
1636 return Soft386WriteModrmDwordOperands(State
,
1638 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1643 USHORT FirstValue
, SecondValue
, Result
;
1645 if (!Soft386ReadModrmWordOperands(State
,
1650 /* Exception occurred */
1654 /* Calculate the result */
1655 Result
= FirstValue
| SecondValue
;
1657 /* Update the flags */
1658 State
->Flags
.Cf
= FALSE
;
1659 State
->Flags
.Of
= FALSE
;
1660 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1661 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1662 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1664 /* Write back the result */
1665 return Soft386WriteModrmWordOperands(State
,
1667 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1672 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrAl
)
1674 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1675 UCHAR SecondValue
, Result
;
1677 /* Make sure this is the right instruction */
1678 ASSERT(Opcode
== 0x0C);
1680 if (State
->PrefixFlags
)
1682 /* This opcode doesn't take any prefixes */
1683 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1687 if (!Soft386FetchByte(State
, &SecondValue
))
1689 /* Exception occurred */
1693 /* Calculate the result */
1694 Result
= FirstValue
| SecondValue
;
1696 /* Update the flags */
1697 State
->Flags
.Cf
= FALSE
;
1698 State
->Flags
.Of
= FALSE
;
1699 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1700 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1701 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1703 /* Write back the result */
1704 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1709 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrEax
)
1711 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1713 /* Make sure this is the right instruction */
1714 ASSERT(Opcode
== 0x0D);
1716 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1718 /* Invalid prefix */
1719 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1723 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1725 /* The OPSIZE prefix toggles the size */
1731 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1732 ULONG SecondValue
, Result
;
1734 if (!Soft386FetchDword(State
, &SecondValue
))
1736 /* Exception occurred */
1740 /* Calculate the result */
1741 Result
= FirstValue
| SecondValue
;
1743 /* Update the flags */
1744 State
->Flags
.Cf
= FALSE
;
1745 State
->Flags
.Of
= FALSE
;
1746 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1747 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1748 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1750 /* Write back the result */
1751 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
1755 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1756 USHORT SecondValue
, Result
;
1758 if (!Soft386FetchWord(State
, &SecondValue
))
1760 /* Exception occurred */
1764 /* Calculate the result */
1765 Result
= FirstValue
| SecondValue
;
1767 /* Update the flags */
1768 State
->Flags
.Cf
= FALSE
;
1769 State
->Flags
.Of
= FALSE
;
1770 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1771 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1772 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1774 /* Write back the result */
1775 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
1781 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndByteModrm
)
1783 UCHAR FirstValue
, SecondValue
, Result
;
1784 SOFT386_MOD_REG_RM ModRegRm
;
1785 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1787 /* Make sure this is the right instruction */
1788 ASSERT((Opcode
& 0xFD) == 0x20);
1790 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1792 /* The ADSIZE prefix toggles the size */
1793 AddressSize
= !AddressSize
;
1795 else if (State
->PrefixFlags
1796 & ~(SOFT386_PREFIX_ADSIZE
1797 | SOFT386_PREFIX_SEG
1798 | SOFT386_PREFIX_LOCK
))
1800 /* Invalid prefix */
1801 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1805 /* Get the operands */
1806 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1808 /* Exception occurred */
1812 if (!Soft386ReadModrmByteOperands(State
,
1817 /* Exception occurred */
1821 /* Calculate the result */
1822 Result
= FirstValue
& SecondValue
;
1824 /* Update the flags */
1825 State
->Flags
.Cf
= FALSE
;
1826 State
->Flags
.Of
= FALSE
;
1827 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1828 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1829 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1831 /* Write back the result */
1832 return Soft386WriteModrmByteOperands(State
,
1834 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1838 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndModrm
)
1840 SOFT386_MOD_REG_RM ModRegRm
;
1841 BOOLEAN OperandSize
, AddressSize
;
1843 /* Make sure this is the right instruction */
1844 ASSERT((Opcode
& 0xFD) == 0x21);
1846 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1848 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1850 /* The ADSIZE prefix toggles the address size */
1851 AddressSize
= !AddressSize
;
1854 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1856 /* The OPSIZE prefix toggles the operand size */
1857 OperandSize
= !OperandSize
;
1860 if (State
->PrefixFlags
1861 & ~(SOFT386_PREFIX_ADSIZE
1862 | SOFT386_PREFIX_OPSIZE
1863 | SOFT386_PREFIX_SEG
1864 | SOFT386_PREFIX_LOCK
))
1866 /* Invalid prefix */
1867 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1871 /* Get the operands */
1872 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1874 /* Exception occurred */
1878 /* Check the operand size */
1881 ULONG FirstValue
, SecondValue
, Result
;
1883 if (!Soft386ReadModrmDwordOperands(State
,
1888 /* Exception occurred */
1892 /* Calculate the result */
1893 Result
= FirstValue
& SecondValue
;
1895 /* Update the flags */
1896 State
->Flags
.Cf
= FALSE
;
1897 State
->Flags
.Of
= FALSE
;
1898 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1899 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1900 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1902 /* Write back the result */
1903 return Soft386WriteModrmDwordOperands(State
,
1905 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1910 USHORT FirstValue
, SecondValue
, Result
;
1912 if (!Soft386ReadModrmWordOperands(State
,
1917 /* Exception occurred */
1921 /* Calculate the result */
1922 Result
= FirstValue
& SecondValue
;
1924 /* Update the flags */
1925 State
->Flags
.Cf
= FALSE
;
1926 State
->Flags
.Of
= FALSE
;
1927 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1928 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1929 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1931 /* Write back the result */
1932 return Soft386WriteModrmWordOperands(State
,
1934 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1939 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndAl
)
1941 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1942 UCHAR SecondValue
, Result
;
1944 /* Make sure this is the right instruction */
1945 ASSERT(Opcode
== 0x24);
1947 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1949 /* Invalid prefix */
1950 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1954 if (!Soft386FetchByte(State
, &SecondValue
))
1956 /* Exception occurred */
1960 /* Calculate the result */
1961 Result
= FirstValue
& SecondValue
;
1963 /* Update the flags */
1964 State
->Flags
.Cf
= FALSE
;
1965 State
->Flags
.Of
= FALSE
;
1966 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1967 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1968 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1970 /* Write back the result */
1971 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1976 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndEax
)
1978 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1980 /* Make sure this is the right instruction */
1981 ASSERT(Opcode
== 0x25);
1983 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1985 /* Invalid prefix */
1986 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1990 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1992 /* The OPSIZE prefix toggles the size */
1998 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1999 ULONG SecondValue
, Result
;
2001 if (!Soft386FetchDword(State
, &SecondValue
))
2003 /* Exception occurred */
2007 /* Calculate the result */
2008 Result
= FirstValue
& SecondValue
;
2010 /* Update the flags */
2011 State
->Flags
.Cf
= FALSE
;
2012 State
->Flags
.Of
= FALSE
;
2013 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2014 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2015 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2017 /* Write back the result */
2018 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
2022 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2023 USHORT SecondValue
, Result
;
2025 if (!Soft386FetchWord(State
, &SecondValue
))
2027 /* Exception occurred */
2031 /* Calculate the result */
2032 Result
= FirstValue
& SecondValue
;
2034 /* Update the flags */
2035 State
->Flags
.Cf
= FALSE
;
2036 State
->Flags
.Of
= FALSE
;
2037 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2038 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2039 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2041 /* Write back the result */
2042 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
2048 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorByteModrm
)
2050 UCHAR FirstValue
, SecondValue
, Result
;
2051 SOFT386_MOD_REG_RM ModRegRm
;
2052 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2054 /* Make sure this is the right instruction */
2055 ASSERT((Opcode
& 0xFD) == 0x30);
2057 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2059 /* The ADSIZE prefix toggles the size */
2060 AddressSize
= !AddressSize
;
2062 else if (State
->PrefixFlags
2063 & ~(SOFT386_PREFIX_ADSIZE
2064 | SOFT386_PREFIX_SEG
2065 | SOFT386_PREFIX_LOCK
))
2067 /* Invalid prefix */
2068 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2072 /* Get the operands */
2073 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2075 /* Exception occurred */
2079 if (!Soft386ReadModrmByteOperands(State
,
2084 /* Exception occurred */
2088 /* Calculate the result */
2089 Result
= FirstValue
^ SecondValue
;
2091 /* Update the flags */
2092 State
->Flags
.Cf
= FALSE
;
2093 State
->Flags
.Of
= FALSE
;
2094 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2095 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2096 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2098 /* Write back the result */
2099 return Soft386WriteModrmByteOperands(State
,
2101 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2105 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorModrm
)
2107 SOFT386_MOD_REG_RM ModRegRm
;
2108 BOOLEAN OperandSize
, AddressSize
;
2110 /* Make sure this is the right instruction */
2111 ASSERT((Opcode
& 0xFD) == 0x31);
2113 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2115 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2117 /* The ADSIZE prefix toggles the address size */
2118 AddressSize
= !AddressSize
;
2121 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2123 /* The OPSIZE prefix toggles the operand size */
2124 OperandSize
= !OperandSize
;
2127 if (State
->PrefixFlags
2128 & ~(SOFT386_PREFIX_ADSIZE
2129 | SOFT386_PREFIX_OPSIZE
2130 | SOFT386_PREFIX_SEG
2131 | SOFT386_PREFIX_LOCK
))
2133 /* Invalid prefix */
2134 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2138 /* Get the operands */
2139 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2141 /* Exception occurred */
2145 /* Check the operand size */
2148 ULONG FirstValue
, SecondValue
, Result
;
2150 if (!Soft386ReadModrmDwordOperands(State
,
2155 /* Exception occurred */
2159 /* Calculate the result */
2160 Result
= FirstValue
^ SecondValue
;
2162 /* Update the flags */
2163 State
->Flags
.Cf
= FALSE
;
2164 State
->Flags
.Of
= FALSE
;
2165 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2166 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2167 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2169 /* Write back the result */
2170 return Soft386WriteModrmDwordOperands(State
,
2172 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2177 USHORT FirstValue
, SecondValue
, Result
;
2179 if (!Soft386ReadModrmWordOperands(State
,
2184 /* Exception occurred */
2188 /* Calculate the result */
2189 Result
= FirstValue
^ SecondValue
;
2191 /* Update the flags */
2192 State
->Flags
.Cf
= FALSE
;
2193 State
->Flags
.Of
= FALSE
;
2194 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2195 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2196 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2198 /* Write back the result */
2199 return Soft386WriteModrmWordOperands(State
,
2201 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2206 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorAl
)
2208 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2209 UCHAR SecondValue
, Result
;
2211 /* Make sure this is the right instruction */
2212 ASSERT(Opcode
== 0x34);
2214 if (State
->PrefixFlags
)
2216 /* This opcode doesn't take any prefixes */
2217 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2221 if (!Soft386FetchByte(State
, &SecondValue
))
2223 /* Exception occurred */
2227 /* Calculate the result */
2228 Result
= FirstValue
^ SecondValue
;
2230 /* Update the flags */
2231 State
->Flags
.Cf
= FALSE
;
2232 State
->Flags
.Of
= FALSE
;
2233 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2234 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2235 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2237 /* Write back the result */
2238 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
2243 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax
)
2245 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2247 /* Make sure this is the right instruction */
2248 ASSERT(Opcode
== 0x35);
2250 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2252 /* Invalid prefix */
2253 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2257 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2259 /* The OPSIZE prefix toggles the size */
2265 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2266 ULONG SecondValue
, Result
;
2268 if (!Soft386FetchDword(State
, &SecondValue
))
2270 /* Exception occurred */
2274 /* Calculate the result */
2275 Result
= FirstValue
^ SecondValue
;
2277 /* Update the flags */
2278 State
->Flags
.Cf
= FALSE
;
2279 State
->Flags
.Of
= FALSE
;
2280 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2281 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2282 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2284 /* Write back the result */
2285 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
2289 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2290 USHORT SecondValue
, Result
;
2292 if (!Soft386FetchWord(State
, &SecondValue
))
2294 /* Exception occurred */
2298 /* Calculate the result */
2299 Result
= FirstValue
^ SecondValue
;
2301 /* Update the flags */
2302 State
->Flags
.Cf
= FALSE
;
2303 State
->Flags
.Of
= FALSE
;
2304 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2305 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2306 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2308 /* Write back the result */
2309 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
2315 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm
)
2317 UCHAR FirstValue
, SecondValue
, Result
;
2318 SOFT386_MOD_REG_RM ModRegRm
;
2319 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2321 /* Make sure this is the right instruction */
2322 ASSERT(Opcode
== 0x84);
2324 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2326 /* The ADSIZE prefix toggles the size */
2327 AddressSize
= !AddressSize
;
2329 else if (State
->PrefixFlags
2330 & ~(SOFT386_PREFIX_ADSIZE
2331 | SOFT386_PREFIX_SEG
2332 | SOFT386_PREFIX_LOCK
))
2334 /* Invalid prefix */
2335 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2339 /* Get the operands */
2340 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2342 /* Exception occurred */
2346 if (!Soft386ReadModrmByteOperands(State
,
2351 /* Exception occurred */
2354 /* Calculate the result */
2355 Result
= FirstValue
& SecondValue
;
2357 /* Update the flags */
2358 State
->Flags
.Cf
= FALSE
;
2359 State
->Flags
.Of
= FALSE
;
2360 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2361 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2362 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2364 /* The result is discarded */
2368 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm
)
2370 SOFT386_MOD_REG_RM ModRegRm
;
2371 BOOLEAN OperandSize
, AddressSize
;
2373 /* Make sure this is the right instruction */
2374 ASSERT(Opcode
== 0x85);
2376 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2378 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2380 /* The ADSIZE prefix toggles the address size */
2381 AddressSize
= !AddressSize
;
2384 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2386 /* The OPSIZE prefix toggles the operand size */
2387 OperandSize
= !OperandSize
;
2390 if (State
->PrefixFlags
2391 & ~(SOFT386_PREFIX_ADSIZE
2392 | SOFT386_PREFIX_OPSIZE
2393 | SOFT386_PREFIX_SEG
2394 | SOFT386_PREFIX_LOCK
))
2396 /* Invalid prefix */
2397 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2401 /* Get the operands */
2402 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2404 /* Exception occurred */
2408 /* Check the operand size */
2411 ULONG FirstValue
, SecondValue
, Result
;
2413 if (!Soft386ReadModrmDwordOperands(State
,
2418 /* Exception occurred */
2422 /* Calculate the result */
2423 Result
= FirstValue
& SecondValue
;
2425 /* Update the flags */
2426 State
->Flags
.Cf
= FALSE
;
2427 State
->Flags
.Of
= FALSE
;
2428 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2429 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2430 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2434 USHORT FirstValue
, SecondValue
, Result
;
2436 if (!Soft386ReadModrmWordOperands(State
,
2441 /* Exception occurred */
2445 /* Calculate the result */
2446 Result
= FirstValue
& SecondValue
;
2448 /* Update the flags */
2449 State
->Flags
.Cf
= FALSE
;
2450 State
->Flags
.Of
= FALSE
;
2451 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2452 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2453 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2456 /* The result is discarded */
2460 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestAl
)
2462 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2463 UCHAR SecondValue
, Result
;
2465 /* Make sure this is the right instruction */
2466 ASSERT(Opcode
== 0xA8);
2468 if (State
->PrefixFlags
)
2470 /* This opcode doesn't take any prefixes */
2471 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2475 if (!Soft386FetchByte(State
, &SecondValue
))
2477 /* Exception occurred */
2481 /* Calculate the result */
2482 Result
= FirstValue
& SecondValue
;
2484 /* Update the flags */
2485 State
->Flags
.Cf
= FALSE
;
2486 State
->Flags
.Of
= FALSE
;
2487 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2488 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2489 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2491 /* The result is discarded */
2495 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestEax
)
2497 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2499 /* Make sure this is the right instruction */
2500 ASSERT(Opcode
== 0xA9);
2502 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2504 /* Invalid prefix */
2505 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2509 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2511 /* The OPSIZE prefix toggles the size */
2517 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2518 ULONG SecondValue
, Result
;
2520 if (!Soft386FetchDword(State
, &SecondValue
))
2522 /* Exception occurred */
2526 /* Calculate the result */
2527 Result
= FirstValue
& SecondValue
;
2529 /* Update the flags */
2530 State
->Flags
.Cf
= FALSE
;
2531 State
->Flags
.Of
= FALSE
;
2532 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2533 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2534 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2538 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2539 USHORT SecondValue
, Result
;
2541 if (!Soft386FetchWord(State
, &SecondValue
))
2543 /* Exception occurred */
2547 /* Calculate the result */
2548 Result
= FirstValue
& SecondValue
;
2550 /* Update the flags */
2551 State
->Flags
.Cf
= FALSE
;
2552 State
->Flags
.Of
= FALSE
;
2553 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2554 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2555 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2558 /* The result is discarded */
2562 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm
)
2564 UCHAR FirstValue
, SecondValue
;
2565 SOFT386_MOD_REG_RM ModRegRm
;
2566 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2568 /* Make sure this is the right instruction */
2569 ASSERT(Opcode
== 0x86);
2571 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2573 /* The ADSIZE prefix toggles the size */
2574 AddressSize
= !AddressSize
;
2576 else if (State
->PrefixFlags
2577 & ~(SOFT386_PREFIX_ADSIZE
2578 | SOFT386_PREFIX_SEG
2579 | SOFT386_PREFIX_LOCK
))
2581 /* Invalid prefix */
2582 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2586 /* Get the operands */
2587 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2589 /* Exception occurred */
2593 if (!Soft386ReadModrmByteOperands(State
,
2598 /* Exception occurred */
2602 /* Write the value from the register to the R/M */
2603 if (!Soft386WriteModrmByteOperands(State
,
2608 /* Exception occurred */
2612 /* Write the value from the R/M to the register */
2613 if (!Soft386WriteModrmByteOperands(State
,
2618 /* Exception occurred */
2625 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm
)
2627 SOFT386_MOD_REG_RM ModRegRm
;
2628 BOOLEAN OperandSize
, AddressSize
;
2630 /* Make sure this is the right instruction */
2631 ASSERT(Opcode
== 0x87);
2633 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2635 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2637 /* The ADSIZE prefix toggles the address size */
2638 AddressSize
= !AddressSize
;
2641 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2643 /* The OPSIZE prefix toggles the operand size */
2644 OperandSize
= !OperandSize
;
2647 if (State
->PrefixFlags
2648 & ~(SOFT386_PREFIX_ADSIZE
2649 | SOFT386_PREFIX_OPSIZE
2650 | SOFT386_PREFIX_SEG
2651 | SOFT386_PREFIX_LOCK
))
2653 /* Invalid prefix */
2654 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2658 /* Get the operands */
2659 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2661 /* Exception occurred */
2665 /* Check the operand size */
2668 ULONG FirstValue
, SecondValue
;
2670 if (!Soft386ReadModrmDwordOperands(State
,
2675 /* Exception occurred */
2679 /* Write the value from the register to the R/M */
2680 if (!Soft386WriteModrmDwordOperands(State
,
2685 /* Exception occurred */
2689 /* Write the value from the R/M to the register */
2690 if (!Soft386WriteModrmDwordOperands(State
,
2695 /* Exception occurred */
2701 USHORT FirstValue
, SecondValue
;
2703 if (!Soft386ReadModrmWordOperands(State
,
2708 /* Exception occurred */
2712 /* Write the value from the register to the R/M */
2713 if (!Soft386WriteModrmWordOperands(State
,
2718 /* Exception occurred */
2722 /* Write the value from the R/M to the register */
2723 if (!Soft386WriteModrmWordOperands(State
,
2728 /* Exception occurred */
2733 /* The result is discarded */
2737 SOFT386_OPCODE_HANDLER(Soft386OpcodePushEs
)
2739 /* Call the internal API */
2740 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_ES
].Selector
);
2743 SOFT386_OPCODE_HANDLER(Soft386OpcodePopEs
)
2747 if (!Soft386StackPop(State
, &NewSelector
))
2749 /* Exception occurred */
2753 /* Call the internal API */
2754 return Soft386LoadSegment(State
, SOFT386_REG_ES
, LOWORD(NewSelector
));
2757 SOFT386_OPCODE_HANDLER(Soft386OpcodePushCs
)
2759 /* Call the internal API */
2760 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_CS
].Selector
);
2763 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcByteModrm
)
2765 UCHAR FirstValue
, SecondValue
, Result
;
2766 SOFT386_MOD_REG_RM ModRegRm
;
2767 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2769 /* Make sure this is the right instruction */
2770 ASSERT((Opcode
& 0xFD) == 0x10);
2772 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2774 /* The ADSIZE prefix toggles the size */
2775 AddressSize
= !AddressSize
;
2777 else if (State
->PrefixFlags
2778 & ~(SOFT386_PREFIX_ADSIZE
2779 | SOFT386_PREFIX_SEG
2780 | SOFT386_PREFIX_LOCK
))
2782 /* Invalid prefix */
2783 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2787 /* Get the operands */
2788 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2790 /* Exception occurred */
2794 if (!Soft386ReadModrmByteOperands(State
,
2799 /* Exception occurred */
2803 /* Calculate the result */
2804 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2806 /* Special exception for CF */
2807 State
->Flags
.Cf
= State
->Flags
.Cf
2808 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2810 /* Update the flags */
2811 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2812 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2813 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2814 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2815 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2816 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2817 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2819 /* Write back the result */
2820 return Soft386WriteModrmByteOperands(State
,
2822 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2826 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcModrm
)
2828 SOFT386_MOD_REG_RM ModRegRm
;
2829 BOOLEAN OperandSize
, AddressSize
;
2831 /* Make sure this is the right instruction */
2832 ASSERT((Opcode
& 0xFD) == 0x11);
2834 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2836 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2838 /* The ADSIZE prefix toggles the address size */
2839 AddressSize
= !AddressSize
;
2842 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2844 /* The OPSIZE prefix toggles the operand size */
2845 OperandSize
= !OperandSize
;
2848 if (State
->PrefixFlags
2849 & ~(SOFT386_PREFIX_ADSIZE
2850 | SOFT386_PREFIX_OPSIZE
2851 | SOFT386_PREFIX_SEG
2852 | SOFT386_PREFIX_LOCK
))
2854 /* Invalid prefix */
2855 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2859 /* Get the operands */
2860 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2862 /* Exception occurred */
2866 /* Check the operand size */
2869 ULONG FirstValue
, SecondValue
, Result
;
2871 if (!Soft386ReadModrmDwordOperands(State
,
2876 /* Exception occurred */
2880 /* Calculate the result */
2881 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2883 /* Special exception for CF */
2884 State
->Flags
.Cf
= State
->Flags
.Cf
2885 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2887 /* Update the flags */
2888 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2889 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2890 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2891 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2892 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2893 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2894 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2896 /* Write back the result */
2897 return Soft386WriteModrmDwordOperands(State
,
2899 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2904 USHORT FirstValue
, SecondValue
, Result
;
2906 if (!Soft386ReadModrmWordOperands(State
,
2911 /* Exception occurred */
2915 /* Calculate the result */
2916 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2918 /* Special exception for CF */
2919 State
->Flags
.Cf
= State
->Flags
.Cf
2920 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2922 /* Update the flags */
2923 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2924 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2925 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2926 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2927 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2928 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2929 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2931 /* Write back the result */
2932 return Soft386WriteModrmWordOperands(State
,
2934 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2940 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcAl
)
2942 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2943 UCHAR SecondValue
, Result
;
2945 /* Make sure this is the right instruction */
2946 ASSERT(Opcode
== 0x14);
2948 if (State
->PrefixFlags
)
2950 /* This opcode doesn't take any prefixes */
2951 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2955 if (!Soft386FetchByte(State
, &SecondValue
))
2957 /* Exception occurred */
2961 /* Calculate the result */
2962 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2964 /* Special exception for CF */
2965 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2966 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2968 /* Update the flags */
2969 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2970 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2971 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2972 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2973 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2974 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2975 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2977 /* Write back the result */
2978 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
2983 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcEax
)
2985 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2987 /* Make sure this is the right instruction */
2988 ASSERT(Opcode
== 0x15);
2990 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2992 /* Invalid prefix */
2993 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2997 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2999 /* The OPSIZE prefix toggles the size */
3005 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
3006 ULONG SecondValue
, Result
;
3008 if (!Soft386FetchDword(State
, &SecondValue
))
3010 /* Exception occurred */
3014 /* Calculate the result */
3015 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3017 /* Special exception for CF */
3018 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3019 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
3021 /* Update the flags */
3022 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3023 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
3024 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3025 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3026 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3027 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3028 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3030 /* Write back the result */
3031 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3035 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3036 USHORT SecondValue
, Result
;
3038 if (!Soft386FetchWord(State
, &SecondValue
))
3040 /* Exception occurred */
3044 /* Calculate the result */
3045 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3047 /* Special exception for CF */
3048 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3049 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
3051 /* Update the flags */
3052 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3053 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
3054 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3055 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3056 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3057 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3058 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3060 /* Write back the result */
3061 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3067 SOFT386_OPCODE_HANDLER(Soft386OpcodePushSs
)
3069 /* Call the internal API */
3070 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_SS
].Selector
);
3073 SOFT386_OPCODE_HANDLER(Soft386OpcodePopSs
)
3077 if (!Soft386StackPop(State
, &NewSelector
))
3079 /* Exception occurred */
3083 /* Call the internal API */
3084 return Soft386LoadSegment(State
, SOFT386_REG_SS
, LOWORD(NewSelector
));
3087 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm
)
3089 UCHAR FirstValue
, SecondValue
, Result
;
3090 SOFT386_MOD_REG_RM ModRegRm
;
3091 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3092 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3094 /* Make sure this is the right instruction */
3095 ASSERT((Opcode
& 0xFD) == 0x18);
3097 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3099 /* The ADSIZE prefix toggles the size */
3100 AddressSize
= !AddressSize
;
3103 /* Get the operands */
3104 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3106 /* Exception occurred */
3110 if (!Soft386ReadModrmByteOperands(State
,
3115 /* Exception occurred */
3119 /* Check if this is the instruction that writes to R/M */
3120 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3122 /* Swap the order */
3123 FirstValue
^= SecondValue
;
3124 SecondValue
^= FirstValue
;
3125 FirstValue
^= SecondValue
;
3128 /* Calculate the result */
3129 Result
= FirstValue
- SecondValue
- Carry
;
3131 /* Update the flags */
3132 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ 1);
3133 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3134 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3135 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3136 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3137 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3138 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3140 /* Write back the result */
3141 return Soft386WriteModrmByteOperands(State
,
3143 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3147 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm
)
3149 SOFT386_MOD_REG_RM ModRegRm
;
3150 BOOLEAN OperandSize
, AddressSize
;
3151 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3153 /* Make sure this is the right instruction */
3154 ASSERT((Opcode
& 0xFD) == 0x19);
3156 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3158 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3160 /* The ADSIZE prefix toggles the address size */
3161 AddressSize
= !AddressSize
;
3164 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3166 /* The OPSIZE prefix toggles the operand size */
3167 OperandSize
= !OperandSize
;
3170 /* Get the operands */
3171 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3173 /* Exception occurred */
3177 /* Check the operand size */
3180 ULONG FirstValue
, SecondValue
, Result
;
3182 if (!Soft386ReadModrmDwordOperands(State
,
3187 /* Exception occurred */
3191 /* Check if this is the instruction that writes to R/M */
3192 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3194 /* Swap the order */
3195 FirstValue
^= SecondValue
;
3196 SecondValue
^= FirstValue
;
3197 FirstValue
^= SecondValue
;
3200 /* Calculate the result */
3201 Result
= FirstValue
- SecondValue
- Carry
;
3203 /* Update the flags */
3204 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3205 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3206 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3207 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3208 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3209 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3210 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3212 /* Write back the result */
3213 return Soft386WriteModrmDwordOperands(State
,
3215 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3220 USHORT FirstValue
, SecondValue
, Result
;
3222 if (!Soft386ReadModrmWordOperands(State
,
3227 /* Exception occurred */
3231 /* Check if this is the instruction that writes to R/M */
3232 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3234 /* Swap the order */
3235 FirstValue
^= SecondValue
;
3236 SecondValue
^= FirstValue
;
3237 FirstValue
^= SecondValue
;
3240 /* Calculate the result */
3241 Result
= FirstValue
- SecondValue
- Carry
;
3243 /* Update the flags */
3244 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3245 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3246 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3247 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3248 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3249 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3250 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3252 /* Write back the result */
3253 return Soft386WriteModrmWordOperands(State
,
3255 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3260 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl
)
3262 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3263 UCHAR SecondValue
, Result
;
3264 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3266 /* Make sure this is the right instruction */
3267 ASSERT(Opcode
== 0x1C);
3269 if (State
->PrefixFlags
)
3271 /* This opcode doesn't take any prefixes */
3272 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3276 if (!Soft386FetchByte(State
, &SecondValue
))
3278 /* Exception occurred */
3282 /* Calculate the result */
3283 Result
= FirstValue
- SecondValue
- Carry
;
3285 /* Update the flags */
3286 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3287 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3288 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3289 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ 1) & 0x0F);
3290 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3291 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3292 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3294 /* Write back the result */
3295 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
3301 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax
)
3303 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3304 INT Carry
= State
->Flags
.Cf
? 1 : 0;
3306 /* Make sure this is the right instruction */
3307 ASSERT(Opcode
== 0x1D);
3309 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3311 /* Invalid prefix */
3312 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3316 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3318 /* The OPSIZE prefix toggles the size */
3324 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
3325 ULONG SecondValue
, Result
;
3327 if (!Soft386FetchDword(State
, &SecondValue
))
3329 /* Exception occurred */
3333 /* Calculate the result */
3334 Result
= FirstValue
- SecondValue
- Carry
;
3336 /* Update the flags */
3337 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3338 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3339 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3340 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
3341 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3342 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3343 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3345 /* Write back the result */
3346 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3350 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3351 USHORT SecondValue
, Result
;
3353 if (!Soft386FetchWord(State
, &SecondValue
))
3355 /* Exception occurred */
3359 /* Calculate the result */
3360 Result
= FirstValue
- SecondValue
- Carry
;
3362 /* Update the flags */
3363 State
->Flags
.Cf
= FirstValue
< (SecondValue
+ Carry
);
3364 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3365 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3366 State
->Flags
.Af
= (FirstValue
& 0x0F) < ((SecondValue
+ Carry
) & 0x0F);
3367 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3368 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3369 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3371 /* Write back the result */
3372 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3379 SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs
)
3381 /* Call the internal API */
3382 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_DS
].Selector
);
3385 SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs
)
3389 if (!Soft386StackPop(State
, &NewSelector
))
3391 /* Exception occurred */
3395 /* Call the internal API */
3396 return Soft386LoadSegment(State
, SOFT386_REG_DS
, LOWORD(NewSelector
));
3399 SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa
)
3401 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3402 BOOLEAN Carry
= State
->Flags
.Cf
;
3404 /* Clear the carry flag */
3405 State
->Flags
.Cf
= FALSE
;
3407 /* Check if the first BCD digit is invalid or there was a carry from it */
3408 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3411 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x06;
3412 if (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
< 0x06)
3414 /* A carry occurred */
3415 State
->Flags
.Cf
= TRUE
;
3418 /* Set the adjust flag */
3419 State
->Flags
.Af
= TRUE
;
3422 /* Check if the second BCD digit is invalid or there was a carry from it */
3423 if ((Value
> 0x99) || Carry
)
3426 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x60;
3428 /* There was a carry */
3429 State
->Flags
.Cf
= TRUE
;
3435 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm
)
3437 UCHAR FirstValue
, SecondValue
, Result
;
3438 SOFT386_MOD_REG_RM ModRegRm
;
3439 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3441 /* Make sure this is the right instruction */
3442 ASSERT((Opcode
& 0xED) == 0x28);
3444 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3446 /* The ADSIZE prefix toggles the size */
3447 AddressSize
= !AddressSize
;
3449 else if (State
->PrefixFlags
3450 & ~(SOFT386_PREFIX_ADSIZE
3451 | SOFT386_PREFIX_SEG
3452 | SOFT386_PREFIX_LOCK
))
3454 /* Invalid prefix */
3455 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3459 /* Get the operands */
3460 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3462 /* Exception occurred */
3466 if (!Soft386ReadModrmByteOperands(State
,
3471 /* Exception occurred */
3475 /* Check if this is the instruction that writes to R/M */
3476 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3478 /* Swap the order */
3479 FirstValue
^= SecondValue
;
3480 SecondValue
^= FirstValue
;
3481 FirstValue
^= SecondValue
;
3484 /* Calculate the result */
3485 Result
= FirstValue
- SecondValue
;
3487 /* Update the flags */
3488 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3489 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3490 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3491 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3492 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3493 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3494 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3496 /* Check if this is not a CMP */
3497 if (!(Opcode
& 0x10))
3499 /* Write back the result */
3500 return Soft386WriteModrmByteOperands(State
,
3502 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3507 /* Discard the result */
3512 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm
)
3514 SOFT386_MOD_REG_RM ModRegRm
;
3515 BOOLEAN OperandSize
, AddressSize
;
3517 /* Make sure this is the right instruction */
3518 ASSERT((Opcode
& 0xED) == 0x29);
3520 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3522 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3524 /* The ADSIZE prefix toggles the address size */
3525 AddressSize
= !AddressSize
;
3528 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3530 /* The OPSIZE prefix toggles the operand size */
3531 OperandSize
= !OperandSize
;
3534 if (State
->PrefixFlags
3535 & ~(SOFT386_PREFIX_ADSIZE
3536 | SOFT386_PREFIX_OPSIZE
3537 | SOFT386_PREFIX_SEG
3538 | SOFT386_PREFIX_LOCK
))
3540 /* Invalid prefix */
3541 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3545 /* Get the operands */
3546 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3548 /* Exception occurred */
3552 /* Check the operand size */
3555 ULONG FirstValue
, SecondValue
, Result
;
3557 if (!Soft386ReadModrmDwordOperands(State
,
3562 /* Exception occurred */
3566 /* Check if this is the instruction that writes to R/M */
3567 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3569 /* Swap the order */
3570 FirstValue
^= SecondValue
;
3571 SecondValue
^= FirstValue
;
3572 FirstValue
^= SecondValue
;
3575 /* Calculate the result */
3576 Result
= FirstValue
- SecondValue
;
3578 /* Update the flags */
3579 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3580 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3581 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3582 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3583 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3584 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3585 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3587 /* Check if this is not a CMP */
3588 if (!(Opcode
& 0x10))
3590 /* Write back the result */
3591 return Soft386WriteModrmDwordOperands(State
,
3593 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3598 /* Discard the result */
3604 USHORT FirstValue
, SecondValue
, Result
;
3606 if (!Soft386ReadModrmWordOperands(State
,
3611 /* Exception occurred */
3615 /* Check if this is the instruction that writes to R/M */
3616 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3618 /* Swap the order */
3619 FirstValue
^= SecondValue
;
3620 SecondValue
^= FirstValue
;
3621 FirstValue
^= SecondValue
;
3624 /* Calculate the result */
3625 Result
= FirstValue
- SecondValue
;
3627 /* Update the flags */
3628 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3629 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3630 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3631 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3632 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3633 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3634 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3636 /* Check if this is not a CMP */
3637 if (!(Opcode
& 0x10))
3639 /* Write back the result */
3640 return Soft386WriteModrmWordOperands(State
,
3642 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3647 /* Discard the result */
3653 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl
)
3655 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3656 UCHAR SecondValue
, Result
;
3658 /* Make sure this is the right instruction */
3659 ASSERT((Opcode
& 0xEF) == 0x2C);
3661 if (State
->PrefixFlags
)
3663 /* This opcode doesn't take any prefixes */
3664 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3668 if (!Soft386FetchByte(State
, &SecondValue
))
3670 /* Exception occurred */
3674 /* Calculate the result */
3675 Result
= FirstValue
- SecondValue
;
3677 /* Update the flags */
3678 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3679 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3680 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3681 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3682 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3683 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3684 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3686 /* Check if this is not a CMP */
3687 if (!(Opcode
& 0x10))
3689 /* Write back the result */
3690 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
3696 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax
)
3698 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3700 /* Make sure this is the right instruction */
3701 ASSERT((Opcode
& 0xEF) == 0x2D);
3703 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3705 /* Invalid prefix */
3706 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3710 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3712 /* The OPSIZE prefix toggles the size */
3718 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
3719 ULONG SecondValue
, Result
;
3721 if (!Soft386FetchDword(State
, &SecondValue
))
3723 /* Exception occurred */
3727 /* Calculate the result */
3728 Result
= FirstValue
- SecondValue
;
3730 /* Update the flags */
3731 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3732 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3733 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3734 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3735 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3736 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3737 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3739 /* Check if this is not a CMP */
3740 if (!(Opcode
& 0x10))
3742 /* Write back the result */
3743 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3748 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3749 USHORT SecondValue
, Result
;
3751 if (!Soft386FetchWord(State
, &SecondValue
))
3753 /* Exception occurred */
3757 /* Calculate the result */
3758 Result
= FirstValue
- SecondValue
;
3760 /* Update the flags */
3761 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3762 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3763 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3764 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3765 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3766 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3767 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3769 /* Check if this is not a CMP */
3770 if (!(Opcode
& 0x10))
3772 /* Write back the result */
3773 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3780 SOFT386_OPCODE_HANDLER(Soft386OpcodeDas
)
3782 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3783 BOOLEAN Carry
= State
->Flags
.Cf
;
3785 /* Clear the carry flag */
3786 State
->Flags
.Cf
= FALSE
;
3788 /* Check if the first BCD digit is invalid or there was a borrow */
3789 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3792 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x06;
3793 if (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
> 0xFB)
3795 /* A borrow occurred */
3796 State
->Flags
.Cf
= TRUE
;
3799 /* Set the adjust flag */
3800 State
->Flags
.Af
= TRUE
;
3803 /* Check if the second BCD digit is invalid or there was a borrow */
3804 if ((Value
> 0x99) || Carry
)
3807 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x60;
3809 /* There was a borrow */
3810 State
->Flags
.Cf
= TRUE
;
3816 SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa
)
3818 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3821 * Check if the value in AL is not a valid BCD digit,
3822 * or there was a carry from the lowest 4 bits of AL
3824 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3827 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x06;
3828 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
++;
3831 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3835 /* Clear CF and AF */
3836 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3839 /* Keep only the lowest 4 bits of AL */
3840 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
&= 0x0F;
3845 SOFT386_OPCODE_HANDLER(Soft386OpcodeAas
)
3847 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3850 * Check if the value in AL is not a valid BCD digit,
3851 * or there was a borrow from the lowest 4 bits of AL
3853 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3856 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x06;
3857 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
--;
3860 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3864 /* Clear CF and AF */
3865 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3868 /* Keep only the lowest 4 bits of AL */
3869 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
&= 0x0F;
3874 SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll
)
3877 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3878 SOFT386_REG SavedEsp
= State
->GeneralRegs
[SOFT386_REG_ESP
];
3880 /* Make sure this is the right instruction */
3881 ASSERT(Opcode
== 0x60);
3883 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3885 /* The OPSIZE prefix toggles the size */
3889 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3891 /* Invalid prefix */
3892 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3896 /* Push all the registers in order */
3897 for (i
= 0; i
< SOFT386_NUM_GEN_REGS
; i
++)
3899 if (i
== SOFT386_REG_ESP
)
3901 /* Use the saved ESP instead */
3902 if (!Soft386StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3904 /* Exception occurred */
3910 /* Push the register */
3911 if (!Soft386StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3912 : State
->GeneralRegs
[i
].LowWord
))
3914 /* Exception occurred */
3923 SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll
)
3926 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3929 /* Make sure this is the right instruction */
3930 ASSERT(Opcode
== 0x61);
3932 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3934 /* The OPSIZE prefix toggles the size */
3938 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3940 /* Invalid prefix */
3941 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3945 /* Pop all the registers in reverse order */
3946 for (i
= SOFT386_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3949 if (!Soft386StackPop(State
, &Value
))
3951 /* Exception occurred */
3955 /* Don't modify ESP */
3956 if (i
!= SOFT386_REG_ESP
)
3958 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3959 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3966 SOFT386_OPCODE_HANDLER(Soft386OpcodeBound
)
3968 // TODO: NOT IMPLEMENTED
3974 SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl
)
3976 USHORT FirstValue
, SecondValue
;
3977 SOFT386_MOD_REG_RM ModRegRm
;
3978 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3980 if (!(State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
3982 || (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
))
3984 /* Cannot be used in real mode or with a LOCK prefix */
3985 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3989 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3991 /* The ADSIZE prefix toggles the size */
3992 AddressSize
= !AddressSize
;
3995 /* Get the operands */
3996 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3998 /* Exception occurred */
4002 /* Read the operands */
4003 if (!Soft386ReadModrmWordOperands(State
,
4008 /* Exception occurred */
4012 /* Check if the RPL needs adjusting */
4013 if ((SecondValue
& 3) < (FirstValue
& 3))
4015 /* Adjust the RPL */
4017 SecondValue
|= FirstValue
& 3;
4020 State
->Flags
.Zf
= TRUE
;
4022 /* Write back the result */
4023 return Soft386WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
4028 State
->Flags
.Zf
= FALSE
;
4033 SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm
)
4035 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4037 /* Make sure this is the right instruction */
4038 ASSERT(Opcode
== 0x68);
4040 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4042 /* Invalid prefix */
4043 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4047 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4049 /* The OPSIZE prefix toggles the size */
4057 if (!Soft386FetchDword(State
, &Data
))
4059 /* Exception occurred */
4063 /* Call the internal API */
4064 return Soft386StackPush(State
, Data
);
4070 if (!Soft386FetchWord(State
, &Data
))
4072 /* Exception occurred */
4076 /* Call the internal API */
4077 return Soft386StackPush(State
, Data
);
4081 SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm
)
4083 BOOLEAN OperandSize
, AddressSize
;
4084 SOFT386_MOD_REG_RM ModRegRm
;
4088 /* Make sure this is the right instruction */
4089 ASSERT((Opcode
& 0xFD) == 0x69);
4091 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4093 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4095 /* The ADSIZE prefix toggles the address size */
4096 AddressSize
= !AddressSize
;
4099 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4101 /* The OPSIZE prefix toggles the operand size */
4102 OperandSize
= !OperandSize
;
4105 /* Fetch the parameters */
4106 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4108 /* Exception occurred */
4116 /* Fetch the immediate operand */
4117 if (!Soft386FetchByte(State
, (PUCHAR
)&Byte
))
4119 /* Exception occurred */
4123 Multiplier
= (LONG
)Byte
;
4131 /* Fetch the immediate operand */
4132 if (!Soft386FetchDword(State
, (PULONG
)&Dword
))
4134 /* Exception occurred */
4144 /* Fetch the immediate operand */
4145 if (!Soft386FetchWord(State
, (PUSHORT
)&Word
))
4147 /* Exception occurred */
4151 Multiplier
= (LONG
)Word
;
4157 LONG RegValue
, Multiplicand
;
4159 /* Read the operands */
4160 if (!Soft386ReadModrmDwordOperands(State
,
4163 (PULONG
)&Multiplicand
))
4165 /* Exception occurred */
4170 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
4174 SHORT RegValue
, Multiplicand
;
4176 /* Read the operands */
4177 if (!Soft386ReadModrmWordOperands(State
,
4180 (PUSHORT
)&Multiplicand
))
4182 /* Exception occurred */
4187 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
4190 /* Check for carry/overflow */
4191 if ((Product
< LONG_MIN
) || (Product
> LONG_MAX
))
4193 State
->Flags
.Cf
= State
->Flags
.Of
= TRUE
;
4195 else State
->Flags
.Cf
= State
->Flags
.Of
= FALSE
;
4197 /* Write-back the result */
4198 return Soft386WriteModrmDwordOperands(State
,
4201 (ULONG
)((LONG
)Product
));
4204 SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm
)
4208 /* Make sure this is the right instruction */
4209 ASSERT(Opcode
== 0x6A);
4211 if (!Soft386FetchByte(State
, &Data
))
4213 /* Exception occurred */
4217 /* Call the internal API */
4218 return Soft386StackPush(State
, Data
);
4221 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm
)
4223 UCHAR FirstValue
, SecondValue
, Result
;
4224 SOFT386_MOD_REG_RM ModRegRm
;
4225 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4227 /* Make sure this is the right instruction */
4228 ASSERT((Opcode
& 0xFD) == 0x88);
4230 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4232 /* The ADSIZE prefix toggles the size */
4233 AddressSize
= !AddressSize
;
4235 else if (State
->PrefixFlags
4236 & ~(SOFT386_PREFIX_ADSIZE
4237 | SOFT386_PREFIX_SEG
4238 | SOFT386_PREFIX_LOCK
))
4240 /* Invalid prefix */
4241 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4245 /* Get the operands */
4246 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4248 /* Exception occurred */
4252 if (!Soft386ReadModrmByteOperands(State
,
4257 /* Exception occurred */
4261 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4262 else Result
= FirstValue
;
4264 /* Write back the result */
4265 return Soft386WriteModrmByteOperands(State
,
4267 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4272 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm
)
4274 SOFT386_MOD_REG_RM ModRegRm
;
4275 BOOLEAN OperandSize
, AddressSize
;
4277 /* Make sure this is the right instruction */
4278 ASSERT((Opcode
& 0xFD) == 0x89);
4280 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4282 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4284 /* The ADSIZE prefix toggles the address size */
4285 AddressSize
= !AddressSize
;
4288 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4290 /* The OPSIZE prefix toggles the operand size */
4291 OperandSize
= !OperandSize
;
4294 if (State
->PrefixFlags
4295 & ~(SOFT386_PREFIX_ADSIZE
4296 | SOFT386_PREFIX_OPSIZE
4297 | SOFT386_PREFIX_SEG
4298 | SOFT386_PREFIX_LOCK
))
4300 /* Invalid prefix */
4301 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4305 /* Get the operands */
4306 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4308 /* Exception occurred */
4312 /* Check the operand size */
4315 ULONG FirstValue
, SecondValue
, Result
;
4317 if (!Soft386ReadModrmDwordOperands(State
,
4322 /* Exception occurred */
4326 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4327 else Result
= FirstValue
;
4329 /* Write back the result */
4330 return Soft386WriteModrmDwordOperands(State
,
4332 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4337 USHORT FirstValue
, SecondValue
, Result
;
4339 if (!Soft386ReadModrmWordOperands(State
,
4344 /* Exception occurred */
4348 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4349 else Result
= FirstValue
;
4351 /* Write back the result */
4352 return Soft386WriteModrmWordOperands(State
,
4354 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4359 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg
)
4361 BOOLEAN OperandSize
, AddressSize
;
4362 SOFT386_MOD_REG_RM ModRegRm
;
4364 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4366 /* Make sure this is the right instruction */
4367 ASSERT(Opcode
== 0x8C);
4369 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4371 /* The ADSIZE prefix toggles the address size */
4372 AddressSize
= !AddressSize
;
4375 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4377 /* The OPSIZE prefix toggles the operand size */
4378 OperandSize
= !OperandSize
;
4381 /* Get the operands */
4382 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4384 /* Exception occurred */
4388 if (ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4391 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4397 return Soft386WriteModrmDwordOperands(State
,
4400 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4404 return Soft386WriteModrmWordOperands(State
,
4407 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4411 SOFT386_OPCODE_HANDLER(Soft386OpcodeLea
)
4413 SOFT386_MOD_REG_RM ModRegRm
;
4414 BOOLEAN OperandSize
, AddressSize
;
4416 /* Make sure this is the right instruction */
4417 ASSERT(Opcode
== 0x8D);
4419 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4421 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4423 /* The ADSIZE prefix toggles the address size */
4424 AddressSize
= !AddressSize
;
4427 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4429 /* The OPSIZE prefix toggles the operand size */
4430 OperandSize
= !OperandSize
;
4433 /* Get the operands */
4434 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4436 /* Exception occurred */
4440 /* The second operand must be memory */
4441 if (!ModRegRm
.Memory
)
4444 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4448 /* Write the address to the register */
4451 return Soft386WriteModrmDwordOperands(State
,
4454 ModRegRm
.MemoryAddress
);
4458 return Soft386WriteModrmWordOperands(State
,
4461 ModRegRm
.MemoryAddress
);
4466 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg
)
4468 BOOLEAN OperandSize
, AddressSize
;
4469 SOFT386_MOD_REG_RM ModRegRm
;
4471 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4473 /* Make sure this is the right instruction */
4474 ASSERT(Opcode
== 0x8E);
4476 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4478 /* The ADSIZE prefix toggles the address size */
4479 AddressSize
= !AddressSize
;
4482 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4484 /* The OPSIZE prefix toggles the operand size */
4485 OperandSize
= !OperandSize
;
4488 /* Get the operands */
4489 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4491 /* Exception occurred */
4495 if ((ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4496 || ((SOFT386_SEG_REGS
)ModRegRm
.Register
== SOFT386_REG_CS
))
4499 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4505 ULONG Dummy
, Selector
;
4507 if (!Soft386ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4509 /* Exception occurred */
4513 return Soft386LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4517 USHORT Dummy
, Selector
;
4519 if (!Soft386ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4521 /* Exception occurred */
4525 return Soft386LoadSegment(State
, ModRegRm
.Register
, Selector
);
4529 SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde
)
4531 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4533 /* Make sure this is the right instruction */
4534 ASSERT(Opcode
== 0x98);
4536 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4538 /* The OPSIZE prefix toggles the size */
4541 else if (State
->PrefixFlags
!= 0)
4543 /* Invalid prefix */
4544 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4550 /* Sign extend AX to EAX */
4551 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= MAKELONG
4553 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
4554 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4560 /* Sign extend AL to AX */
4561 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
=
4562 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4569 SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq
)
4571 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4573 /* Make sure this is the right instruction */
4574 ASSERT(Opcode
== 0x99);
4576 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4578 /* The OPSIZE prefix toggles the size */
4581 else if (State
->PrefixFlags
!= 0)
4583 /* Invalid prefix */
4584 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4590 /* Sign extend EAX to EDX:EAX */
4591 State
->GeneralRegs
[SOFT386_REG_EDX
].Long
=
4592 (State
->GeneralRegs
[SOFT386_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4593 ? 0xFFFFFFFF : 0x00000000;
4597 /* Sign extend AX to DX:AX */
4598 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
=
4599 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4606 SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs
)
4608 // TODO: NOT IMPLEMENTED
4614 SOFT386_OPCODE_HANDLER(Soft386OpcodeWait
)
4616 // TODO: NOT IMPLEMENTED
4622 SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags
)
4624 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4626 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4628 /* Invalid prefix */
4629 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4633 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4635 /* This OPSIZE prefix toggles the size */
4639 /* Check for VM86 mode when IOPL is not 3 */
4640 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4642 /* Call the VM86 monitor */
4643 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4647 /* Push the flags */
4648 if (Size
) return Soft386StackPush(State
, State
->Flags
.Long
);
4649 else return Soft386StackPush(State
, LOWORD(State
->Flags
.Long
));
4652 SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags
)
4654 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4655 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4658 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4660 /* Invalid prefix */
4661 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4665 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4667 /* This OPSIZE prefix toggles the size */
4671 /* Pop the new flags */
4672 if (!Soft386StackPop(State
, &NewFlags
))
4674 /* Exception occurred */
4678 if (!State
->Flags
.Vm
)
4680 /* Check the current privilege level */
4688 /* Memorize the old state of RF */
4689 BOOLEAN OldRf
= State
->Flags
.Rf
;
4691 State
->Flags
.Long
= NewFlags
;
4693 /* Restore VM and RF */
4694 State
->Flags
.Vm
= FALSE
;
4695 State
->Flags
.Rf
= OldRf
;
4697 /* Clear VIF and VIP */
4698 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4700 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4702 /* Restore the reserved bits */
4703 State
->Flags
.AlwaysSet
= TRUE
;
4704 State
->Flags
.Reserved0
= FALSE
;
4705 State
->Flags
.Reserved1
= FALSE
;
4711 /* Memorize the old state of IF and IOPL */
4712 BOOLEAN OldIf
= State
->Flags
.If
;
4713 UINT OldIopl
= State
->Flags
.Iopl
;
4718 /* Memorize the old state of RF */
4719 BOOLEAN OldRf
= State
->Flags
.Rf
;
4721 State
->Flags
.Long
= NewFlags
;
4723 /* Restore VM and RF */
4724 State
->Flags
.Vm
= FALSE
;
4725 State
->Flags
.Rf
= OldRf
;
4727 /* Clear VIF and VIP */
4728 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4730 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4732 /* Restore the reserved bits and IOPL */
4733 State
->Flags
.AlwaysSet
= TRUE
;
4734 State
->Flags
.Reserved0
= FALSE
;
4735 State
->Flags
.Reserved1
= FALSE
;
4736 State
->Flags
.Iopl
= OldIopl
;
4738 /* Check if the user doesn't have the privilege to change IF */
4739 if (Cpl
> State
->Flags
.Iopl
)
4742 State
->Flags
.If
= OldIf
;
4748 /* Check the IOPL */
4749 if (State
->Flags
.Iopl
== 3)
4753 /* Memorize the old state of RF, VIF and VIP */
4754 BOOLEAN OldRf
= State
->Flags
.Rf
;
4755 BOOLEAN OldVif
= State
->Flags
.Vif
;
4756 BOOLEAN OldVip
= State
->Flags
.Vip
;
4758 State
->Flags
.Long
= NewFlags
;
4760 /* Restore VM, RF, VIF and VIP */
4761 State
->Flags
.Vm
= TRUE
;
4762 State
->Flags
.Rf
= OldRf
;
4763 State
->Flags
.Vif
= OldVif
;
4764 State
->Flags
.Vip
= OldVip
;
4766 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4768 /* Restore the reserved bits and IOPL */
4769 State
->Flags
.AlwaysSet
= TRUE
;
4770 State
->Flags
.Reserved0
= FALSE
;
4771 State
->Flags
.Reserved1
= FALSE
;
4772 State
->Flags
.Iopl
= 3;
4776 /* Call the VM86 monitor */
4777 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4785 SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf
)
4787 /* Make sure this is the right instruction */
4788 ASSERT(Opcode
== 0x9E);
4790 /* Set the low-order byte of FLAGS to AH */
4791 State
->Flags
.Long
&= 0xFFFFFF00;
4792 State
->Flags
.Long
|= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
;
4794 /* Restore the reserved bits of FLAGS */
4795 State
->Flags
.AlwaysSet
= TRUE
;
4796 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4801 SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf
)
4803 /* Make sure this is the right instruction */
4804 ASSERT(Opcode
== 0x9F);
4806 /* Set AH to the low-order byte of FLAGS */
4807 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4812 SOFT386_OPCODE_HANDLER(Soft386OpcodeRet
)
4814 ULONG ReturnAddress
;
4815 USHORT BytesToPop
= 0;
4816 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4818 /* Make sure this is the right instruction */
4819 ASSERT((Opcode
& 0xFE) == 0xC2);
4821 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4823 /* Invalid prefix */
4824 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4828 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4830 /* The OPSIZE prefix toggles the size */
4836 /* Fetch the number of bytes to pop after the return */
4837 if (!Soft386FetchWord(State
, &BytesToPop
)) return FALSE
;
4840 /* Pop the return address */
4841 if (!Soft386StackPop(State
, &ReturnAddress
)) return FALSE
;
4843 /* Return to the calling procedure, and if necessary, pop the parameters */
4846 State
->InstPtr
.Long
= ReturnAddress
;
4847 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
+= BytesToPop
;
4851 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4852 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
+= BytesToPop
;
4858 SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes
)
4860 UCHAR FarPointer
[6];
4861 BOOLEAN OperandSize
, AddressSize
;
4862 SOFT386_MOD_REG_RM ModRegRm
;
4864 /* Make sure this is the right instruction */
4865 ASSERT((Opcode
& 0xFE) == 0xC4);
4867 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4869 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4871 /* The ADSIZE prefix toggles the size */
4872 AddressSize
= !AddressSize
;
4875 /* Get the operands */
4876 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4878 /* Exception occurred */
4882 if (!ModRegRm
.Memory
)
4884 /* Check if this is a BOP and the host supports BOPs */
4885 if ((Opcode
== 0xC4)
4886 && (ModRegRm
.Register
== SOFT386_REG_EAX
)
4887 && (ModRegRm
.SecondRegister
== SOFT386_REG_ESP
)
4888 && (State
->BopCallback
!= NULL
))
4892 /* Fetch the BOP code */
4893 if (!Soft386FetchWord(State
, &BopCode
))
4895 /* Exception occurred */
4899 /* Call the BOP handler */
4900 State
->BopCallback(State
, BopCode
);
4902 /* Return success */
4907 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4911 if (!Soft386ReadMemory(State
,
4912 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
)
4913 ? State
->SegmentOverride
: SOFT386_REG_DS
,
4914 ModRegRm
.MemoryAddress
,
4917 OperandSize
? 6 : 4))
4919 /* Exception occurred */
4925 ULONG Offset
= *((PULONG
)FarPointer
);
4926 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4928 /* Set the register to the offset */
4929 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4931 /* Load the segment */
4932 return Soft386LoadSegment(State
,
4934 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4939 USHORT Offset
= *((PUSHORT
)FarPointer
);
4940 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4942 /* Set the register to the offset */
4943 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4945 /* Load the segment */
4946 return Soft386LoadSegment(State
,
4948 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4953 SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter
)
4956 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4959 SOFT386_REG FramePointer
;
4961 /* Make sure this is the right instruction */
4962 ASSERT(Opcode
== 0xC8);
4964 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4966 /* Invalid prefix */
4967 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4971 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4973 /* The OPSIZE prefix toggles the size */
4977 if (!Soft386FetchWord(State
, &FrameSize
))
4979 /* Exception occurred */
4983 if (!Soft386FetchByte(State
, &NestingLevel
))
4985 /* Exception occurred */
4990 if (!Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
))
4992 /* Exception occurred */
4997 FramePointer
= State
->GeneralRegs
[SOFT386_REG_ESP
];
4999 /* Set up the nested procedure stacks */
5000 for (i
= 1; i
< NestingLevel
; i
++)
5004 State
->GeneralRegs
[SOFT386_REG_EBP
].Long
-= 4;
5005 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
5009 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
-= 2;
5010 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
);
5014 if (NestingLevel
> 0) Soft386StackPush(State
, FramePointer
.Long
);
5016 /* Set EBP to the frame pointer */
5017 State
->GeneralRegs
[SOFT386_REG_EBP
] = FramePointer
;
5019 /* Reserve space for the frame */
5020 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
-= (ULONG
)FrameSize
;
5021 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
-= FrameSize
;
5026 SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave
)
5028 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5030 /* Make sure this is the right instruction */
5031 ASSERT(Opcode
== 0xC9);
5033 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5035 /* Invalid prefix */
5036 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5040 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5042 /* The OPSIZE prefix toggles the size */
5048 /* Set the stack pointer (ESP) to the base pointer (EBP) */
5049 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= State
->GeneralRegs
[SOFT386_REG_EBP
].Long
;
5051 /* Pop the saved base pointer from the stack */
5052 return Soft386StackPop(State
, &State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
5058 /* Set the stack pointer (SP) to the base pointer (BP) */
5059 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
;
5061 /* Pop the saved base pointer from the stack */
5062 if (Soft386StackPop(State
, &Value
))
5064 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
= LOWORD(Value
);
5071 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm
)
5073 // TODO: NOT IMPLEMENTED
5079 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar
)
5081 // TODO: NOT IMPLEMENTED
5087 SOFT386_OPCODE_HANDLER(Soft386OpcodeInt
)
5090 SOFT386_IDT_ENTRY IdtEntry
;
5096 /* This is the INT3 instruction */
5103 /* Fetch the interrupt number */
5104 if (!Soft386FetchByte(State
, &IntNum
))
5106 /* Exception occurred */
5115 /* Don't do anything if OF is cleared */
5116 if (!State
->Flags
.Of
) return TRUE
;
5119 IntNum
= SOFT386_EXCEPTION_OF
;
5126 /* Should not happen */
5131 /* Get the interrupt vector */
5132 if (!Soft386GetIntVector(State
, IntNum
, &IdtEntry
))
5134 /* Exception occurred */
5138 /* Perform the interrupt */
5139 if (!Soft386InterruptInternal(State
,
5141 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
5144 /* Exception occurred */
5151 SOFT386_OPCODE_HANDLER(Soft386OpcodeIret
)
5154 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
5155 SOFT386_FLAGS_REG NewFlags
;
5156 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5158 /* Make sure this is the right instruction */
5159 ASSERT(Opcode
== 0xCF);
5161 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5163 /* Invalid prefix */
5164 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5168 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5170 /* The OPSIZE prefix toggles the size */
5175 if (!Soft386StackPop(State
, &InstPtr
))
5177 /* Exception occurred */
5182 if (!Soft386StackPop(State
, &CodeSel
))
5184 /* Exception occurred */
5189 if (!Soft386StackPop(State
, &NewFlags
.Long
))
5191 /* Exception occurred */
5195 /* Check for protected mode */
5196 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
5198 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
5200 if (State
->Flags
.Vm
)
5202 /* Return from VM86 mode */
5204 /* Check the IOPL */
5205 if (State
->Flags
.Iopl
== 3)
5208 State
->InstPtr
.Long
= LOWORD(InstPtr
);
5211 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5213 /* Exception occurred */
5217 /* Set the new flags */
5218 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5219 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5220 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
5221 State
->Flags
.Iopl
= 3;
5225 /* Call the VM86 monitor */
5226 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
5233 if (State
->Flags
.Nt
)
5235 /* Nested task return */
5243 /* Return to VM86 mode */
5244 ULONG Es
, Ds
, Fs
, Gs
;
5246 /* Pop ESP, SS, ES, FS, GS */
5247 if (!Soft386StackPop(State
, &StackPtr
)) return FALSE
;
5248 if (!Soft386StackPop(State
, &StackSel
)) return FALSE
;
5249 if (!Soft386StackPop(State
, &Es
)) return FALSE
;
5250 if (!Soft386StackPop(State
, &Ds
)) return FALSE
;
5251 if (!Soft386StackPop(State
, &Fs
)) return FALSE
;
5252 if (!Soft386StackPop(State
, &Gs
)) return FALSE
;
5254 /* Set the new IP */
5255 State
->InstPtr
.Long
= LOWORD(InstPtr
);
5257 /* Set the new flags */
5258 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5259 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5260 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
5262 /* Load the new segments */
5263 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
)) return FALSE
;
5264 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
)) return FALSE
;
5265 if (!Soft386LoadSegment(State
, SOFT386_REG_ES
, Es
)) return FALSE
;
5266 if (!Soft386LoadSegment(State
, SOFT386_REG_DS
, Ds
)) return FALSE
;
5267 if (!Soft386LoadSegment(State
, SOFT386_REG_FS
, Fs
)) return FALSE
;
5268 if (!Soft386LoadSegment(State
, SOFT386_REG_GS
, Gs
)) return FALSE
;
5273 /* Load the new CS */
5274 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5276 /* Exception occurred */
5281 if (Size
) State
->InstPtr
.Long
= InstPtr
;
5282 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
5284 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5287 if (!Soft386StackPop(State
, &StackPtr
))
5294 if (!Soft386StackPop(State
, &StackSel
))
5301 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
))
5308 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= StackPtr
;
5309 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= LOWORD(StackPtr
);
5312 /* Set the new flags */
5313 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
5314 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
5315 State
->Flags
.AlwaysSet
= TRUE
;
5317 /* Set additional flags */
5318 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
5319 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
5321 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5323 /* Update the CPL */
5324 Cpl
= Soft386GetCurrentPrivLevel(State
);
5326 /* Check segment security */
5327 for (i
= 0; i
<= SOFT386_NUM_SEG_REGS
; i
++)
5329 /* Don't check CS or SS */
5330 if ((i
== SOFT386_REG_CS
) || (i
== SOFT386_REG_SS
)) continue;
5332 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
5333 && (!State
->SegmentRegs
[i
].Executable
5334 || !State
->SegmentRegs
[i
].DirConf
))
5336 /* Load the NULL descriptor in the segment */
5337 if (!Soft386LoadSegment(State
, i
, 0)) return FALSE
;
5344 if (Size
&& (InstPtr
& 0xFFFF0000))
5347 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
5352 State
->InstPtr
.Long
= InstPtr
;
5355 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5357 /* Exception occurred */
5361 /* Set the new flags */
5362 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5363 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5364 State
->Flags
.AlwaysSet
= TRUE
;
5370 SOFT386_OPCODE_HANDLER(Soft386OpcodeAam
)
5373 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5375 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5377 /* Invalid prefix */
5378 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5382 /* Fetch the base */
5383 if (!Soft386FetchByte(State
, &Base
))
5385 /* Exception occurred */
5389 /* Check if the base is zero */
5393 Soft386Exception(State
, SOFT386_EXCEPTION_DE
);
5398 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= Value
/ Base
;
5399 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
%= Base
;
5402 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5403 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5404 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5409 SOFT386_OPCODE_HANDLER(Soft386OpcodeAad
)
5412 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5414 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5416 /* Invalid prefix */
5417 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5421 /* Fetch the base */
5422 if (!Soft386FetchByte(State
, &Base
))
5424 /* Exception occurred */
5429 Value
+= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
* Base
;
5430 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
;
5433 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5434 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5435 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5440 SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat
)
5443 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5445 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
5447 /* The ADSIZE prefix toggles the size */
5448 AddressSize
= !AddressSize
;
5451 /* Read a byte from DS:[(E)BX + AL] */
5452 if (!Soft386ReadMemory(State
,
5454 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EBX
].Long
5455 : State
->GeneralRegs
[SOFT386_REG_EBX
].LowWord
5456 + State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5461 /* Exception occurred */
5465 /* Set AL to the result */
5466 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
;
5468 /* Return success */
5472 SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop
)
5475 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5478 /* Make sure this is the right instruction */
5479 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
5481 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5483 /* Invalid prefix */
5484 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5488 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5490 /* The OPSIZE prefix toggles the size */
5494 if (Size
) Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].Long
) != 0);
5495 else Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
) != 0);
5499 /* Additional rule for LOOPNZ */
5500 if (State
->Flags
.Zf
) Condition
= FALSE
;
5505 /* Additional rule for LOOPZ */
5506 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5509 /* Fetch the offset */
5510 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5512 /* An exception occurred */
5518 /* Move the instruction pointer */
5519 State
->InstPtr
.Long
+= Offset
;
5525 SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz
)
5528 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5531 /* Make sure this is the right instruction */
5532 ASSERT(Opcode
== 0xE3);
5534 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5536 /* Invalid prefix */
5537 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5541 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5543 /* The OPSIZE prefix toggles the size */
5547 if (Size
) Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].Long
== 0);
5548 else Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
== 0);
5550 /* Fetch the offset */
5551 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5553 /* An exception occurred */
5559 /* Move the instruction pointer */
5560 State
->InstPtr
.Long
+= Offset
;
5566 SOFT386_OPCODE_HANDLER(Soft386OpcodeCall
)
5568 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5570 /* Make sure this is the right instruction */
5571 ASSERT(Opcode
== 0xE8);
5573 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5575 /* The OPSIZE prefix toggles the size */
5578 else if (State
->PrefixFlags
!= 0)
5580 /* Invalid prefix */
5581 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5589 /* Fetch the offset */
5590 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5592 /* An exception occurred */
5596 /* Push the current value of the instruction pointer */
5597 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5599 /* Exception occurred */
5603 /* Move the instruction pointer */
5604 State
->InstPtr
.Long
+= Offset
;
5610 /* Fetch the offset */
5611 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5613 /* An exception occurred */
5617 /* Push the current value of the instruction pointer */
5618 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5620 /* Exception occurred */
5624 /* Move the instruction pointer */
5625 State
->InstPtr
.LowWord
+= Offset
;
5631 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp
)
5633 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5635 /* Make sure this is the right instruction */
5636 ASSERT(Opcode
== 0xE9);
5638 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5640 /* The OPSIZE prefix toggles the size */
5643 else if (State
->PrefixFlags
!= 0)
5645 /* Invalid prefix */
5646 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5654 /* Fetch the offset */
5655 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5657 /* An exception occurred */
5661 /* Move the instruction pointer */
5662 State
->InstPtr
.Long
+= Offset
;
5668 /* Fetch the offset */
5669 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5671 /* An exception occurred */
5675 /* Move the instruction pointer */
5676 State
->InstPtr
.LowWord
+= Offset
;
5682 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs
)
5684 // TODO: NOT IMPLEMENTED
5690 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset
)
5692 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5695 /* Make sure this is the right instruction */
5696 ASSERT(Opcode
== 0xA0);
5698 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5700 /* The OPSIZE prefix toggles the size */
5706 if (!Soft386FetchDword(State
, &Offset
))
5708 /* Exception occurred */
5716 if (!Soft386FetchWord(State
, &WordOffset
))
5718 /* Exception occurred */
5722 Offset
= (ULONG
)WordOffset
;
5725 /* Read from memory */
5726 return Soft386ReadMemory(State
,
5727 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5728 State
->SegmentOverride
: SOFT386_REG_DS
,
5731 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5735 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset
)
5737 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5739 /* Make sure this is the right instruction */
5740 ASSERT(Opcode
== 0xA1);
5742 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5744 /* The OPSIZE prefix toggles the size */
5752 if (!Soft386FetchDword(State
, &Offset
))
5754 /* Exception occurred */
5758 /* Read from memory */
5759 return Soft386ReadMemory(State
,
5760 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5761 State
->SegmentOverride
: SOFT386_REG_DS
,
5764 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5771 if (!Soft386FetchWord(State
, &Offset
))
5773 /* Exception occurred */
5777 /* Read from memory */
5778 return Soft386ReadMemory(State
,
5779 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5780 State
->SegmentOverride
: SOFT386_REG_DS
,
5783 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
5788 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl
)
5790 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5793 /* Make sure this is the right instruction */
5794 ASSERT(Opcode
== 0xA2);
5796 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5798 /* The OPSIZE prefix toggles the size */
5804 if (!Soft386FetchDword(State
, &Offset
))
5806 /* Exception occurred */
5814 if (!Soft386FetchWord(State
, &WordOffset
))
5816 /* Exception occurred */
5820 Offset
= (ULONG
)WordOffset
;
5823 /* Write to memory */
5824 return Soft386WriteMemory(State
,
5825 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5826 State
->SegmentOverride
: SOFT386_REG_DS
,
5828 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5832 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax
)
5834 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5836 /* Make sure this is the right instruction */
5837 ASSERT(Opcode
== 0xA3);
5839 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5841 /* The OPSIZE prefix toggles the size */
5849 if (!Soft386FetchDword(State
, &Offset
))
5851 /* Exception occurred */
5855 /* Write to memory */
5856 return Soft386WriteMemory(State
,
5857 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5858 State
->SegmentOverride
: SOFT386_REG_DS
,
5860 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5867 if (!Soft386FetchWord(State
, &Offset
))
5869 /* Exception occurred */
5873 /* Write to memory */
5874 return Soft386WriteMemory(State
,
5875 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5876 State
->SegmentOverride
: SOFT386_REG_DS
,
5878 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
5883 SOFT386_OPCODE_HANDLER(Soft386OpcodeSalc
)
5885 /* Make sure this is the right instruction */
5886 ASSERT(Opcode
== 0xD6);
5888 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5890 /* Invalid prefix */
5891 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5895 /* Set all the bits of AL to CF */
5896 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= State
->Flags
.Cf
? 0xFF : 0x00;
5901 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovs
)
5903 ULONG Data
, DataSize
;
5904 BOOLEAN OperandSize
, AddressSize
;
5906 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5908 /* Make sure this is the right instruction */
5909 ASSERT((Opcode
& 0xFE) == 0xA4);
5911 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5913 /* The OPSIZE prefix toggles the size */
5914 OperandSize
= !OperandSize
;
5917 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
5919 /* The ADSIZE prefix toggles the size */
5920 AddressSize
= !AddressSize
;
5923 if ((State
->PrefixFlags
& SOFT386_PREFIX_REP
)
5924 || (State
->PrefixFlags
& SOFT386_PREFIX_REPNZ
))
5926 // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
5927 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5931 /* Calculate the size */
5932 if (Opcode
== 0xA4) DataSize
= sizeof(UCHAR
);
5933 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
5935 /* Read from the source operand */
5936 if (!Soft386ReadMemory(State
,
5938 AddressSize
? State
->GeneralRegs
[SOFT386_REG_ESI
].Long
5939 : State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
,
5944 /* Exception occurred */
5948 /* Write to the destination operand */
5949 if (!Soft386WriteMemory(State
,
5951 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
5952 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
5956 /* Exception occurred */
5960 /* Increment/decrement ESI and EDI */
5963 if (!State
->Flags
.Df
)
5965 State
->GeneralRegs
[SOFT386_REG_ESI
].Long
+= DataSize
;
5966 State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= DataSize
;
5970 State
->GeneralRegs
[SOFT386_REG_ESI
].Long
-= DataSize
;
5971 State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= DataSize
;
5976 if (!State
->Flags
.Df
)
5978 State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
+= DataSize
;
5979 State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= DataSize
;
5983 State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
-= DataSize
;
5984 State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= DataSize
;
5988 /* Return success */
5992 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmps
)
5994 ULONG FirstValue
= 0, SecondValue
= 0, Result
;
5995 ULONG DataSize
, DataMask
, SignFlag
;
5996 BOOLEAN OperandSize
, AddressSize
;
5998 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
6000 /* Make sure this is the right instruction */
6001 ASSERT((Opcode
& 0xFE) == 0xA6);
6003 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
6005 /* The OPSIZE prefix toggles the size */
6006 OperandSize
= !OperandSize
;
6009 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
6011 /* The ADSIZE prefix toggles the size */
6012 AddressSize
= !AddressSize
;
6015 if ((State
->PrefixFlags
& SOFT386_PREFIX_REP
)
6016 || (State
->PrefixFlags
& SOFT386_PREFIX_REPNZ
))
6018 // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
6019 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
6023 /* Calculate the size */
6024 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
6025 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6027 /* Calculate the mask and sign flag */
6028 DataMask
= (1 << (DataSize
* 8)) - 1;
6029 SignFlag
= 1 << ((DataSize
* 8) - 1);
6031 /* Read from the first source operand */
6032 if (!Soft386ReadMemory(State
,
6034 AddressSize
? State
->GeneralRegs
[SOFT386_REG_ESI
].Long
6035 : State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
,
6040 /* Exception occurred */
6044 /* Read from the second source operand */
6045 if (!Soft386ReadMemory(State
,
6047 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6048 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6053 /* Exception occurred */
6057 /* Calculate the result */
6058 FirstValue
&= DataMask
;
6059 SecondValue
&= DataMask
;
6060 Result
= (FirstValue
- SecondValue
) & DataMask
;
6062 /* Update the flags */
6063 State
->Flags
.Cf
= FirstValue
< SecondValue
;
6064 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
6065 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
6066 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
6067 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
6068 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
6069 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
6071 /* Increment/decrement ESI and EDI */
6074 if (!State
->Flags
.Df
)
6076 State
->GeneralRegs
[SOFT386_REG_ESI
].Long
+= DataSize
;
6077 State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= DataSize
;
6081 State
->GeneralRegs
[SOFT386_REG_ESI
].Long
-= DataSize
;
6082 State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= DataSize
;
6087 if (!State
->Flags
.Df
)
6089 State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
+= DataSize
;
6090 State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= DataSize
;
6094 State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
-= DataSize
;
6095 State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= DataSize
;
6099 /* Return success */
6103 SOFT386_OPCODE_HANDLER(Soft386OpcodeStos
)
6106 BOOLEAN OperandSize
, AddressSize
;
6108 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
6110 /* Make sure this is the right instruction */
6111 ASSERT((Opcode
& 0xFE) == 0xAA);
6113 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
6115 /* The OPSIZE prefix toggles the size */
6116 OperandSize
= !OperandSize
;
6119 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
6121 /* The ADSIZE prefix toggles the size */
6122 AddressSize
= !AddressSize
;
6125 /* Calculate the size */
6126 if (Opcode
== 0xAA) DataSize
= sizeof(UCHAR
);
6127 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6129 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
6131 UCHAR Block
[STRING_BLOCK_SIZE
];
6132 ULONG Count
= OperandSize
? State
->GeneralRegs
[SOFT386_REG_ECX
].Long
6133 : State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
;
6135 /* Fill the memory block with the data */
6136 if (DataSize
== sizeof(UCHAR
))
6138 RtlFillMemory(Block
, State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
, sizeof(Block
));
6144 for (i
= 0; i
< STRING_BLOCK_SIZE
/ DataSize
; i
++)
6146 if (DataSize
== sizeof(USHORT
))
6148 ((PUSHORT
)Block
)[i
] = State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
6152 ((PULONG
)Block
)[i
] = State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
6157 /* Transfer until finished */
6160 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6162 if (State
->Flags
.Df
)
6164 /* Reduce EDI by the number of bytes to transfer */
6165 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= Processed
* DataSize
;
6166 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= Processed
* DataSize
;
6169 /* Write to memory */
6170 if (!Soft386WriteMemory(State
,
6172 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6173 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6175 Processed
* DataSize
))
6178 if (OperandSize
) State
->GeneralRegs
[SOFT386_REG_ECX
].Long
= Count
;
6179 else State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
= LOWORD(Count
);
6181 /* Exception occurred */
6185 if (!State
->Flags
.Df
)
6187 /* Increase EDI by the number of bytes transfered */
6188 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= Processed
* DataSize
;
6189 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= Processed
* DataSize
;
6192 /* Reduce the total count by the number processed in this run */
6197 if (OperandSize
) State
->GeneralRegs
[SOFT386_REG_ECX
].Long
= 0;
6198 else State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
= 0;
6202 /* Write to the destination operand */
6203 if (!Soft386WriteMemory(State
,
6205 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6206 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6207 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
6210 /* Exception occurred */
6214 /* Increment/decrement EDI */
6217 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= DataSize
;
6218 else State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= DataSize
;
6222 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= DataSize
;
6223 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= DataSize
;
6227 /* Return success */
6231 SOFT386_OPCODE_HANDLER(Soft386OpcodeLods
)
6234 BOOLEAN OperandSize
, AddressSize
;
6236 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
6238 /* Make sure this is the right instruction */
6239 ASSERT((Opcode
& 0xFE) == 0xAC);
6241 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
6243 /* The OPSIZE prefix toggles the size */
6244 OperandSize
= !OperandSize
;
6247 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
6249 /* The ADSIZE prefix toggles the size */
6250 AddressSize
= !AddressSize
;
6253 /* Calculate the size */
6254 if (Opcode
== 0xAC) DataSize
= sizeof(UCHAR
);
6255 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6257 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
6259 ULONG Count
= OperandSize
? State
->GeneralRegs
[SOFT386_REG_ECX
].Long
6260 : State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
;
6262 /* If the count is 0, do nothing */
6263 if (Count
== 0) return TRUE
;
6265 /* Only the last entry will be loaded */
6266 if (!State
->Flags
.Df
)
6268 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_ESI
].Long
+= (Count
- 1) * DataSize
;
6269 else State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
+= (Count
- 1) * DataSize
;
6273 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_ESI
].Long
-= (Count
- 1) * DataSize
;
6274 else State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
-= (Count
- 1) * DataSize
;
6278 /* Read from the source operand */
6279 if (!Soft386ReadMemory(State
,
6281 AddressSize
? State
->GeneralRegs
[SOFT386_REG_ESI
].Long
6282 : State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
,
6284 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
6287 /* Exception occurred */
6291 /* Increment/decrement ESI */
6294 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_ESI
].Long
+= DataSize
;
6295 else State
->GeneralRegs
[SOFT386_REG_ESI
].Long
-= DataSize
;
6299 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
+= DataSize
;
6300 else State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
-= DataSize
;
6303 /* Return success */
6307 SOFT386_OPCODE_HANDLER(Soft386OpcodeScas
)
6309 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
6310 ULONG SecondValue
= 0;
6312 ULONG DataSize
, DataMask
, SignFlag
;
6313 BOOLEAN OperandSize
, AddressSize
;
6315 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
6317 /* Make sure this is the right instruction */
6318 ASSERT((Opcode
& 0xFE) == 0xAE);
6320 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
6322 /* The OPSIZE prefix toggles the size */
6323 OperandSize
= !OperandSize
;
6326 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
6328 /* The ADSIZE prefix toggles the size */
6329 AddressSize
= !AddressSize
;
6332 if ((State
->PrefixFlags
& SOFT386_PREFIX_REP
)
6333 || (State
->PrefixFlags
& SOFT386_PREFIX_REPNZ
))
6335 // TODO: The REP/REPZ/REPNZ prefixes need to be implemented!
6336 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
6340 /* Calculate the size */
6341 if (Opcode
== 0xA6) DataSize
= sizeof(UCHAR
);
6342 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6344 /* Calculate the mask and sign flag */
6345 DataMask
= (1 << (DataSize
* 8)) - 1;
6346 SignFlag
= 1 << ((DataSize
* 8) - 1);
6348 /* Read from the source operand */
6349 if (!Soft386ReadMemory(State
,
6351 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6352 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6357 /* Exception occurred */
6361 /* Calculate the result */
6362 FirstValue
&= DataMask
;
6363 SecondValue
&= DataMask
;
6364 Result
= (FirstValue
- SecondValue
) & DataMask
;
6366 /* Update the flags */
6367 State
->Flags
.Cf
= FirstValue
< SecondValue
;
6368 State
->Flags
.Of
= ((FirstValue
& SignFlag
) != (SecondValue
& SignFlag
))
6369 && ((FirstValue
& SignFlag
) != (Result
& SignFlag
));
6370 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
6371 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
6372 State
->Flags
.Sf
= (Result
& SignFlag
) ? TRUE
: FALSE
;
6373 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
6375 /* Increment/decrement EDI */
6378 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= DataSize
;
6379 else State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= DataSize
;
6383 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= DataSize
;
6384 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= DataSize
;
6387 /* Return success */
6391 SOFT386_OPCODE_HANDLER(Soft386OpcodeIns
)
6394 BOOLEAN OperandSize
, AddressSize
;
6396 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
6398 /* Make sure this is the right instruction */
6399 ASSERT((Opcode
& 0xFE) == 0x6C);
6401 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
6403 /* The OPSIZE prefix toggles the size */
6404 OperandSize
= !OperandSize
;
6407 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
6409 /* The ADSIZE prefix toggles the size */
6410 AddressSize
= !AddressSize
;
6413 /* Calculate the size */
6414 if (Opcode
== 0x6C) DataSize
= sizeof(UCHAR
);
6415 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6417 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
6419 UCHAR Block
[STRING_BLOCK_SIZE
];
6420 ULONG Count
= OperandSize
? State
->GeneralRegs
[SOFT386_REG_ECX
].Long
6421 : State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
;
6423 /* Clear the memory block */
6424 RtlZeroMemory(Block
, sizeof(Block
));
6426 /* Transfer until finished */
6429 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6431 /* Read from the I/O port */
6432 State
->IoReadCallback(State
,
6433 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
,
6435 Processed
* DataSize
);
6437 if (State
->Flags
.Df
)
6441 /* Reduce EDI by the number of bytes to transfer */
6442 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= Processed
* DataSize
;
6443 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= Processed
* DataSize
;
6445 /* Reverse the block data */
6446 for (i
= 0; i
< Processed
/ 2; i
++)
6448 /* Swap the values */
6449 for (j
= 0; j
< DataSize
; j
++)
6451 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6452 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6453 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6458 /* Write to memory */
6459 if (!Soft386WriteMemory(State
,
6461 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6462 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6464 Processed
* DataSize
))
6467 if (OperandSize
) State
->GeneralRegs
[SOFT386_REG_ECX
].Long
= Count
;
6468 else State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
= LOWORD(Count
);
6470 /* Exception occurred */
6474 if (!State
->Flags
.Df
)
6476 /* Increase EDI by the number of bytes transfered */
6477 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= Processed
* DataSize
;
6478 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= Processed
* DataSize
;
6481 /* Reduce the total count by the number processed in this run */
6486 if (OperandSize
) State
->GeneralRegs
[SOFT386_REG_ECX
].Long
= 0;
6487 else State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
= 0;
6493 /* Read from the I/O port */
6494 State
->IoReadCallback(State
,
6495 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
,
6499 /* Write to the destination operand */
6500 if (!Soft386WriteMemory(State
,
6502 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6503 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6507 /* Exception occurred */
6511 /* Increment/decrement EDI */
6514 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= DataSize
;
6515 else State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= DataSize
;
6519 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= DataSize
;
6520 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= DataSize
;
6524 /* Return success */
6528 SOFT386_OPCODE_HANDLER(Soft386OpcodeOuts
)
6531 BOOLEAN OperandSize
, AddressSize
;
6533 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
6535 /* Make sure this is the right instruction */
6536 ASSERT((Opcode
& 0xFE) == 0x6E);
6538 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
6540 /* The OPSIZE prefix toggles the size */
6541 OperandSize
= !OperandSize
;
6544 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
6546 /* The ADSIZE prefix toggles the size */
6547 AddressSize
= !AddressSize
;
6550 /* Calculate the size */
6551 if (Opcode
== 0x6E) DataSize
= sizeof(UCHAR
);
6552 else DataSize
= OperandSize
? sizeof(ULONG
) : sizeof(USHORT
);
6554 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
6556 UCHAR Block
[STRING_BLOCK_SIZE
];
6557 ULONG Count
= OperandSize
? State
->GeneralRegs
[SOFT386_REG_ECX
].Long
6558 : State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
;
6560 /* Clear the memory block */
6561 RtlZeroMemory(Block
, sizeof(Block
));
6563 /* Transfer until finished */
6566 ULONG Processed
= min(Count
, STRING_BLOCK_SIZE
/ DataSize
);
6568 /* Read from memory */
6569 if (!Soft386ReadMemory(State
,
6571 AddressSize
? State
->GeneralRegs
[SOFT386_REG_EDI
].Long
6572 : State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
,
6575 Processed
* DataSize
))
6578 if (OperandSize
) State
->GeneralRegs
[SOFT386_REG_ECX
].Long
= Count
;
6579 else State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
= LOWORD(Count
);
6581 /* Exception occurred */
6585 if (State
->Flags
.Df
)
6589 /* Reduce EDI by the number of bytes to transfer */
6590 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
-= Processed
* DataSize
;
6591 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
-= Processed
* DataSize
;
6593 /* Reverse the block data */
6594 for (i
= 0; i
< Processed
/ 2; i
++)
6596 /* Swap the values */
6597 for (j
= 0; j
< DataSize
; j
++)
6599 UCHAR Temp
= Block
[i
* DataSize
+ j
];
6600 Block
[i
* DataSize
+ j
] = Block
[(Processed
- i
- 1) * DataSize
+ j
];
6601 Block
[(Processed
- i
- 1) * DataSize
+ j
] = Temp
;
6606 /* Write to the I/O port */
6607 State
->IoWriteCallback(State
,
6608 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
,
6610 Processed
* DataSize
);
6612 if (!State
->Flags
.Df
)
6614 /* Increase EDI by the number of bytes transfered */
6615 if (AddressSize
) State
->GeneralRegs
[SOFT386_REG_EDI
].Long
+= Processed
* DataSize
;
6616 else State
->GeneralRegs
[SOFT386_REG_EDI
].LowWord
+= Processed
* DataSize
;
6619 /* Reduce the total count by the number processed in this run */
6624 if (OperandSize
) State
->GeneralRegs
[SOFT386_REG_ECX
].Long
= 0;
6625 else State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
= 0;
6631 /* Read from the source operand */
6632 if (!Soft386ReadMemory(State
,
6634 AddressSize
? State
->GeneralRegs
[SOFT386_REG_ESI
].Long
6635 : State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
,
6640 /* Exception occurred */
6644 /* Write to the I/O port */
6645 State
->IoWriteCallback(State
,
6646 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
,
6650 /* Increment/decrement ESI */
6653 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_ESI
].Long
+= DataSize
;
6654 else State
->GeneralRegs
[SOFT386_REG_ESI
].Long
-= DataSize
;
6658 if (!State
->Flags
.Df
) State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
+= DataSize
;
6659 else State
->GeneralRegs
[SOFT386_REG_ESI
].LowWord
-= DataSize
;
6663 /* Return success */