2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: 386/486 CPU Emulation Library
5 * PURPOSE: Opcode handlers.
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
11 // #define WIN32_NO_STATUS
12 // #define _INC_WINDOWS
24 /* PUBLIC VARIABLES ***********************************************************/
26 SOFT386_OPCODE_HANDLER_PROC
27 Soft386OpcodeHandlers
[SOFT386_NUM_OPCODE_HANDLERS
] =
29 Soft386OpcodeAddByteModrm
,
30 Soft386OpcodeAddModrm
,
31 Soft386OpcodeAddByteModrm
,
32 Soft386OpcodeAddModrm
,
37 Soft386OpcodeOrByteModrm
,
39 Soft386OpcodeOrByteModrm
,
44 NULL
, // TODO: OPCODE 0x0F NOT SUPPORTED
45 Soft386OpcodeAdcByteModrm
,
46 Soft386OpcodeAdcModrm
,
47 Soft386OpcodeAdcByteModrm
,
48 Soft386OpcodeAdcModrm
,
53 Soft386OpcodeSbbByteModrm
,
54 Soft386OpcodeSbbModrm
,
55 Soft386OpcodeSbbByteModrm
,
56 Soft386OpcodeSbbModrm
,
61 Soft386OpcodeAndByteModrm
,
62 Soft386OpcodeAndModrm
,
63 Soft386OpcodeAndByteModrm
,
64 Soft386OpcodeAndModrm
,
69 Soft386OpcodeCmpSubByteModrm
,
70 Soft386OpcodeCmpSubModrm
,
71 Soft386OpcodeCmpSubByteModrm
,
72 Soft386OpcodeCmpSubModrm
,
73 Soft386OpcodeCmpSubAl
,
74 Soft386OpcodeCmpSubEax
,
77 Soft386OpcodeXorByteModrm
,
78 Soft386OpcodeXorModrm
,
79 Soft386OpcodeXorByteModrm
,
80 Soft386OpcodeXorModrm
,
85 Soft386OpcodeCmpSubByteModrm
,
86 Soft386OpcodeCmpSubModrm
,
87 Soft386OpcodeCmpSubByteModrm
,
88 Soft386OpcodeCmpSubModrm
,
89 Soft386OpcodeCmpSubAl
,
90 Soft386OpcodeCmpSubEax
,
93 Soft386OpcodeIncrement
,
94 Soft386OpcodeIncrement
,
95 Soft386OpcodeIncrement
,
96 Soft386OpcodeIncrement
,
97 Soft386OpcodeIncrement
,
98 Soft386OpcodeIncrement
,
99 Soft386OpcodeIncrement
,
100 Soft386OpcodeIncrement
,
101 Soft386OpcodeDecrement
,
102 Soft386OpcodeDecrement
,
103 Soft386OpcodeDecrement
,
104 Soft386OpcodeDecrement
,
105 Soft386OpcodeDecrement
,
106 Soft386OpcodeDecrement
,
107 Soft386OpcodeDecrement
,
108 Soft386OpcodeDecrement
,
109 Soft386OpcodePushReg
,
110 Soft386OpcodePushReg
,
111 Soft386OpcodePushReg
,
112 Soft386OpcodePushReg
,
113 Soft386OpcodePushReg
,
114 Soft386OpcodePushReg
,
115 Soft386OpcodePushReg
,
116 Soft386OpcodePushReg
,
125 Soft386OpcodePushAll
,
133 Soft386OpcodePushImm
,
134 Soft386OpcodeImulModrmImm
,
135 Soft386OpcodePushByteImm
,
136 Soft386OpcodeImulModrmImm
,
137 NULL
, // TODO: OPCODE 0x6C NOT SUPPORTED
138 NULL
, // TODO: OPCODE 0x6D NOT SUPPORTED
139 NULL
, // TODO: OPCODE 0x6E NOT SUPPORTED
140 NULL
, // TODO: OPCODE 0x6F NOT SUPPORTED
141 Soft386OpcodeShortConditionalJmp
,
142 Soft386OpcodeShortConditionalJmp
,
143 Soft386OpcodeShortConditionalJmp
,
144 Soft386OpcodeShortConditionalJmp
,
145 Soft386OpcodeShortConditionalJmp
,
146 Soft386OpcodeShortConditionalJmp
,
147 Soft386OpcodeShortConditionalJmp
,
148 Soft386OpcodeShortConditionalJmp
,
149 Soft386OpcodeShortConditionalJmp
,
150 Soft386OpcodeShortConditionalJmp
,
151 Soft386OpcodeShortConditionalJmp
,
152 Soft386OpcodeShortConditionalJmp
,
153 Soft386OpcodeShortConditionalJmp
,
154 Soft386OpcodeShortConditionalJmp
,
155 Soft386OpcodeShortConditionalJmp
,
156 Soft386OpcodeShortConditionalJmp
,
157 Soft386OpcodeGroup8082
,
158 Soft386OpcodeGroup81
,
159 Soft386OpcodeGroup8082
,
160 Soft386OpcodeGroup83
,
161 Soft386OpcodeTestByteModrm
,
162 Soft386OpcodeTestModrm
,
163 Soft386OpcodeXchgByteModrm
,
164 Soft386OpcodeXchgModrm
,
165 Soft386OpcodeMovByteModrm
,
166 Soft386OpcodeMovModrm
,
167 Soft386OpcodeMovByteModrm
,
168 Soft386OpcodeMovModrm
,
169 Soft386OpcodeMovStoreSeg
,
171 Soft386OpcodeMovLoadSeg
,
172 Soft386OpcodeGroup8F
,
174 Soft386OpcodeExchangeEax
,
175 Soft386OpcodeExchangeEax
,
176 Soft386OpcodeExchangeEax
,
177 Soft386OpcodeExchangeEax
,
178 Soft386OpcodeExchangeEax
,
179 Soft386OpcodeExchangeEax
,
180 Soft386OpcodeExchangeEax
,
183 Soft386OpcodeCallAbs
,
185 Soft386OpcodePushFlags
,
186 Soft386OpcodePopFlags
,
189 Soft386OpcodeMovAlOffset
,
190 Soft386OpcodeMovEaxOffset
,
191 Soft386OpcodeMovOffsetAl
,
192 Soft386OpcodeMovOffsetEax
,
193 NULL
, // TODO: OPCODE 0xA4 NOT SUPPORTED
194 NULL
, // TODO: OPCODE 0xA5 NOT SUPPORTED
195 NULL
, // TODO: OPCODE 0xA6 NOT SUPPORTED
196 NULL
, // TODO: OPCODE 0xA7 NOT SUPPORTED
198 Soft386OpcodeTestEax
,
199 NULL
, // TODO: OPCODE 0xAA NOT SUPPORTED
200 NULL
, // TODO: OPCODE 0xAB NOT SUPPORTED
201 NULL
, // TODO: OPCODE 0xAC NOT SUPPORTED
202 NULL
, // TODO: OPCODE 0xAD NOT SUPPORTED
203 NULL
, // TODO: OPCODE 0xAE NOT SUPPORTED
204 NULL
, // TODO: OPCODE 0xAF NOT SUPPORTED
205 Soft386OpcodeMovByteRegImm
,
206 Soft386OpcodeMovByteRegImm
,
207 Soft386OpcodeMovByteRegImm
,
208 Soft386OpcodeMovByteRegImm
,
209 Soft386OpcodeMovByteRegImm
,
210 Soft386OpcodeMovByteRegImm
,
211 Soft386OpcodeMovByteRegImm
,
212 Soft386OpcodeMovByteRegImm
,
213 Soft386OpcodeMovRegImm
,
214 Soft386OpcodeMovRegImm
,
215 Soft386OpcodeMovRegImm
,
216 Soft386OpcodeMovRegImm
,
217 Soft386OpcodeMovRegImm
,
218 Soft386OpcodeMovRegImm
,
219 Soft386OpcodeMovRegImm
,
220 Soft386OpcodeMovRegImm
,
221 Soft386OpcodeGroupC0
,
222 Soft386OpcodeGroupC1
,
227 Soft386OpcodeGroupC6
,
228 Soft386OpcodeGroupC7
,
231 Soft386OpcodeRetFarImm
,
237 Soft386OpcodeGroupD0
,
238 Soft386OpcodeGroupD1
,
239 Soft386OpcodeGroupD2
,
240 Soft386OpcodeGroupD3
,
243 NULL
, // TODO: OPCODE 0xD6 NOT SUPPORTED
245 NULL
, // TODO: OPCODE 0xD8 NOT SUPPORTED
246 NULL
, // TODO: OPCODE 0xD9 NOT SUPPORTED
247 NULL
, // TODO: OPCODE 0xDA NOT SUPPORTED
248 NULL
, // TODO: OPCODE 0xDB NOT SUPPORTED
249 NULL
, // TODO: OPCODE 0xDC NOT SUPPORTED
250 NULL
, // TODO: OPCODE 0xDD NOT SUPPORTED
251 NULL
, // TODO: OPCODE 0xDE NOT SUPPORTED
252 NULL
, // TODO: OPCODE 0xDF NOT SUPPORTED
259 Soft386OpcodeOutByte
,
264 Soft386OpcodeShortJump
,
267 Soft386OpcodeOutByte
,
274 Soft386OpcodeComplCarry
,
275 Soft386OpcodeGroupF6
,
276 Soft386OpcodeGroupF7
,
277 Soft386OpcodeClearCarry
,
278 Soft386OpcodeSetCarry
,
279 Soft386OpcodeClearInt
,
281 Soft386OpcodeClearDir
,
283 Soft386OpcodeGroupFE
,
284 Soft386OpcodeGroupFF
,
287 /* PUBLIC FUNCTIONS ***********************************************************/
289 SOFT386_OPCODE_HANDLER(Soft386OpcodePrefix
)
291 BOOLEAN Valid
= FALSE
;
298 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
300 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
301 State
->SegmentOverride
= SOFT386_REG_ES
;
311 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
313 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
314 State
->SegmentOverride
= SOFT386_REG_CS
;
324 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
326 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
327 State
->SegmentOverride
= SOFT386_REG_SS
;
337 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
339 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
340 State
->SegmentOverride
= SOFT386_REG_DS
;
350 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
352 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
353 State
->SegmentOverride
= SOFT386_REG_FS
;
363 if (!(State
->PrefixFlags
& SOFT386_PREFIX_SEG
))
365 State
->PrefixFlags
|= SOFT386_PREFIX_SEG
;
366 State
->SegmentOverride
= SOFT386_REG_GS
;
376 if (!(State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
))
378 State
->PrefixFlags
|= SOFT386_PREFIX_OPSIZE
;
388 if (!(State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
))
390 State
->PrefixFlags
|= SOFT386_PREFIX_ADSIZE
;
399 if (!(State
->PrefixFlags
& SOFT386_PREFIX_LOCK
))
401 State
->PrefixFlags
|= SOFT386_PREFIX_LOCK
;
411 /* Mutually exclusive with REP */
412 if (!(State
->PrefixFlags
413 & (SOFT386_PREFIX_REPNZ
| SOFT386_PREFIX_REP
)))
415 State
->PrefixFlags
|= SOFT386_PREFIX_REPNZ
;
425 /* Mutually exclusive with REPNZ */
426 if (!(State
->PrefixFlags
427 & (SOFT386_PREFIX_REPNZ
| SOFT386_PREFIX_REP
)))
429 State
->PrefixFlags
|= SOFT386_PREFIX_REP
;
439 /* Clear all prefixes */
440 State
->PrefixFlags
= 0;
442 /* Throw an exception */
443 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
450 SOFT386_OPCODE_HANDLER(Soft386OpcodeIncrement
)
453 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
455 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
457 /* The OPSIZE prefix toggles the size */
460 else if (State
->PrefixFlags
!= 0)
463 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
467 /* Make sure this is the right instruction */
468 ASSERT((Opcode
& 0xF8) == 0x40);
472 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].Long
;
474 State
->Flags
.Of
= (Value
== SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
475 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
479 Value
= ++State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
481 State
->Flags
.Of
= (Value
== SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
482 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
485 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
486 State
->Flags
.Af
= ((Value
& 0x0F) == 0) ? TRUE
: FALSE
;
487 State
->Flags
.Pf
= Soft386CalculateParity(LOBYTE(Value
));
493 SOFT386_OPCODE_HANDLER(Soft386OpcodeDecrement
)
496 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
498 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
500 /* The OPSIZE prefix toggles the size */
503 else if (State
->PrefixFlags
!= 0)
506 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
510 /* Make sure this is the right instruction */
511 ASSERT((Opcode
& 0xF8) == 0x48);
515 Value
= --State
->GeneralRegs
[Opcode
& 0x07].Long
;
517 State
->Flags
.Of
= (Value
== (SIGN_FLAG_LONG
- 1)) ? TRUE
: FALSE
;
518 State
->Flags
.Sf
= (Value
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
522 Value
= --State
->GeneralRegs
[Opcode
& 0x07].LowWord
;
524 State
->Flags
.Of
= (Value
== (SIGN_FLAG_WORD
- 1)) ? TRUE
: FALSE
;
525 State
->Flags
.Sf
= (Value
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
528 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
529 State
->Flags
.Af
= ((Value
& 0x0F) == 0x0F) ? TRUE
: FALSE
;
530 State
->Flags
.Pf
= Soft386CalculateParity(LOBYTE(Value
));
536 SOFT386_OPCODE_HANDLER(Soft386OpcodePushReg
)
538 if ((State
->PrefixFlags
!= SOFT386_PREFIX_OPSIZE
)
539 && (State
->PrefixFlags
!= 0))
542 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
546 /* Make sure this is the right instruction */
547 ASSERT((Opcode
& 0xF8) == 0x50);
549 /* Call the internal function */
550 return Soft386StackPush(State
, State
->GeneralRegs
[Opcode
& 0x07].Long
);
553 SOFT386_OPCODE_HANDLER(Soft386OpcodePopReg
)
556 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_SS
].Size
;
558 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
560 /* The OPSIZE prefix toggles the size */
563 else if (State
->PrefixFlags
!= 0)
566 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
570 /* Make sure this is the right instruction */
571 ASSERT((Opcode
& 0xF8) == 0x58);
573 /* Call the internal function */
574 if (!Soft386StackPop(State
, &Value
)) return FALSE
;
576 /* Store the value */
577 if (Size
) State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
578 else State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
584 SOFT386_OPCODE_HANDLER(Soft386OpcodeNop
)
586 if (State
->PrefixFlags
& ~(SOFT386_PREFIX_OPSIZE
| SOFT386_PREFIX_REP
))
588 /* Allowed prefixes are REP and OPSIZE */
589 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
593 if (State
->PrefixFlags
& SOFT386_PREFIX_REP
)
596 State
->IdleCallback(State
);
602 SOFT386_OPCODE_HANDLER(Soft386OpcodeExchangeEax
)
604 INT Reg
= Opcode
& 0x07;
605 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
607 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
609 /* The OPSIZE prefix toggles the size */
612 else if (State
->PrefixFlags
!= 0)
615 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
619 /* Make sure this is the right instruction */
620 ASSERT((Opcode
& 0xF8) == 0x90);
622 /* Exchange the values */
627 Value
= State
->GeneralRegs
[Reg
].Long
;
628 State
->GeneralRegs
[Reg
].Long
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
629 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Value
;
635 Value
= State
->GeneralRegs
[Reg
].LowWord
;
636 State
->GeneralRegs
[Reg
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
637 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Value
;
643 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortConditionalJmp
)
645 BOOLEAN Jump
= FALSE
;
648 /* Make sure this is the right instruction */
649 ASSERT((Opcode
& 0xF0) == 0x70);
651 /* Fetch the offset */
652 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
654 /* An exception occurred */
658 switch ((Opcode
& 0x0F) >> 1)
663 Jump
= State
->Flags
.Of
;
670 Jump
= State
->Flags
.Cf
;
677 Jump
= State
->Flags
.Zf
;
684 Jump
= State
->Flags
.Cf
|| State
->Flags
.Zf
;
691 Jump
= State
->Flags
.Sf
;
698 Jump
= State
->Flags
.Pf
;
705 Jump
= State
->Flags
.Sf
!= State
->Flags
.Of
;
712 Jump
= (State
->Flags
.Sf
!= State
->Flags
.Of
) || State
->Flags
.Zf
;
719 /* Invert the result */
725 /* Move the instruction pointer */
726 State
->InstPtr
.Long
+= Offset
;
733 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearCarry
)
735 /* Make sure this is the right instruction */
736 ASSERT(Opcode
== 0xF8);
738 /* No prefixes allowed */
739 if (State
->PrefixFlags
)
741 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
745 /* Clear CF and return success */
746 State
->Flags
.Cf
= FALSE
;
750 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetCarry
)
752 /* Make sure this is the right instruction */
753 ASSERT(Opcode
== 0xF9);
755 /* No prefixes allowed */
756 if (State
->PrefixFlags
)
758 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
762 /* Set CF and return success*/
763 State
->Flags
.Cf
= TRUE
;
767 SOFT386_OPCODE_HANDLER(Soft386OpcodeComplCarry
)
769 /* Make sure this is the right instruction */
770 ASSERT(Opcode
== 0xF5);
772 /* No prefixes allowed */
773 if (State
->PrefixFlags
)
775 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
779 /* Toggle CF and return success */
780 State
->Flags
.Cf
= !State
->Flags
.Cf
;
784 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearInt
)
786 /* Make sure this is the right instruction */
787 ASSERT(Opcode
== 0xFA);
789 /* No prefixes allowed */
790 if (State
->PrefixFlags
)
792 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
796 /* Check for protected mode */
797 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
800 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
)
802 /* Clear the interrupt flag */
803 State
->Flags
.If
= FALSE
;
807 /* General Protection Fault */
808 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
814 /* Just clear the interrupt flag */
815 State
->Flags
.If
= FALSE
;
822 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetInt
)
824 /* Make sure this is the right instruction */
825 ASSERT(Opcode
== 0xFB);
827 /* No prefixes allowed */
828 if (State
->PrefixFlags
)
830 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
834 /* Check for protected mode */
835 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
838 if (State
->Flags
.Iopl
>= State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
)
840 /* Set the interrupt flag */
841 State
->Flags
.If
= TRUE
;
845 /* General Protection Fault */
846 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
852 /* Just set the interrupt flag */
853 State
->Flags
.If
= TRUE
;
860 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearDir
)
862 /* Make sure this is the right instruction */
863 ASSERT(Opcode
== 0xFC);
865 /* No prefixes allowed */
866 if (State
->PrefixFlags
)
868 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
872 /* Clear DF and return success */
873 State
->Flags
.Df
= FALSE
;
877 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetDir
)
879 /* Make sure this is the right instruction */
880 ASSERT(Opcode
== 0xFD);
882 /* No prefixes allowed */
883 if (State
->PrefixFlags
)
885 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
889 /* Set DF and return success*/
890 State
->Flags
.Df
= TRUE
;
894 SOFT386_OPCODE_HANDLER(Soft386OpcodeHalt
)
896 /* Make sure this is the right instruction */
897 ASSERT(Opcode
== 0xF4);
899 /* No prefixes allowed */
900 if (State
->PrefixFlags
)
902 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
906 /* Privileged instructions can only be executed under CPL = 0 */
907 if (State
->SegmentRegs
[SOFT386_REG_CS
].Dpl
!= 0)
909 Soft386Exception(State
, SOFT386_EXCEPTION_GP
);
914 while (!State
->HardwareInt
) State
->IdleCallback(State
);
920 SOFT386_OPCODE_HANDLER(Soft386OpcodeInByte
)
925 /* Make sure this is the right instruction */
926 ASSERT((Opcode
& 0xF7) == 0xE4);
930 /* Fetch the parameter */
931 if (!Soft386FetchByte(State
, &Data
))
933 /* Exception occurred */
937 /* Set the port number to the parameter */
942 /* The port number is in DX */
943 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
946 /* Read a byte from the I/O port */
947 State
->IoReadCallback(State
, Port
, &Data
, sizeof(UCHAR
));
949 /* Store the result in AL */
950 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Data
;
955 SOFT386_OPCODE_HANDLER(Soft386OpcodeIn
)
958 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
960 /* Make sure this is the right instruction */
961 ASSERT((Opcode
& 0xF7) == 0xE5);
963 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
965 /* The OPSIZE prefix toggles the size */
968 else if (State
->PrefixFlags
!= 0)
971 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
979 /* Fetch the parameter */
980 if (!Soft386FetchByte(State
, &Data
))
982 /* Exception occurred */
986 /* Set the port number to the parameter */
991 /* The port number is in DX */
992 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
999 /* Read a dword from the I/O port */
1000 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1002 /* Store the value in EAX */
1003 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Data
;
1009 /* Read a word from the I/O port */
1010 State
->IoReadCallback(State
, Port
, &Data
, sizeof(USHORT
));
1012 /* Store the value in AX */
1013 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Data
;
1019 SOFT386_OPCODE_HANDLER(Soft386OpcodeOutByte
)
1024 /* Make sure this is the right instruction */
1025 ASSERT((Opcode
& 0xF7) == 0xE6);
1029 /* Fetch the parameter */
1030 if (!Soft386FetchByte(State
, &Data
))
1032 /* Exception occurred */
1036 /* Set the port number to the parameter */
1041 /* The port number is in DX */
1042 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1045 /* Read the value from AL */
1046 Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1048 /* Write the byte to the I/O port */
1049 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(UCHAR
));
1054 SOFT386_OPCODE_HANDLER(Soft386OpcodeOut
)
1057 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1059 /* Make sure this is the right instruction */
1060 ASSERT((Opcode
& 0xF7) == 0xE7);
1062 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
1064 /* The OPSIZE prefix toggles the size */
1067 else if (State
->PrefixFlags
!= 0)
1069 /* Invalid prefix */
1070 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1078 /* Fetch the parameter */
1079 if (!Soft386FetchByte(State
, &Data
))
1081 /* Exception occurred */
1085 /* Set the port number to the parameter */
1090 /* The port number is in DX */
1091 Port
= State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
;
1096 /* Get the value from EAX */
1097 ULONG Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1099 /* Write a dword to the I/O port */
1100 State
->IoReadCallback(State
, Port
, &Data
, sizeof(ULONG
));
1104 /* Get the value from AX */
1105 USHORT Data
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1107 /* Write a word to the I/O port */
1108 State
->IoWriteCallback(State
, Port
, &Data
, sizeof(USHORT
));
1114 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortJump
)
1118 /* Make sure this is the right instruction */
1119 ASSERT(Opcode
== 0xEB);
1121 /* Fetch the offset */
1122 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
1124 /* An exception occurred */
1128 /* Move the instruction pointer */
1129 State
->InstPtr
.Long
+= Offset
;
1134 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovRegImm
)
1136 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1138 /* Make sure this is the right instruction */
1139 ASSERT((Opcode
& 0xF8) == 0xB8);
1141 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
1143 /* The OPSIZE prefix toggles the size */
1146 else if (State
->PrefixFlags
!= 0)
1148 /* Invalid prefix */
1149 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1157 /* Fetch the dword */
1158 if (!Soft386FetchDword(State
, &Value
))
1160 /* Exception occurred */
1164 /* Store the value in the register */
1165 State
->GeneralRegs
[Opcode
& 0x07].Long
= Value
;
1171 /* Fetch the word */
1172 if (!Soft386FetchWord(State
, &Value
))
1174 /* Exception occurred */
1178 /* Store the value in the register */
1179 State
->GeneralRegs
[Opcode
& 0x07].LowWord
= Value
;
1185 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteRegImm
)
1189 /* Make sure this is the right instruction */
1190 ASSERT((Opcode
& 0xF8) == 0xB0);
1192 if (State
->PrefixFlags
!= 0)
1194 /* Invalid prefix */
1195 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1199 /* Fetch the byte */
1200 if (!Soft386FetchByte(State
, &Value
))
1202 /* Exception occurred */
1208 /* AH, CH, DH or BH */
1209 State
->GeneralRegs
[Opcode
& 0x03].HighByte
= Value
;
1213 /* AL, CL, DL or BL */
1214 State
->GeneralRegs
[Opcode
& 0x03].LowByte
= Value
;
1220 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddByteModrm
)
1222 UCHAR FirstValue
, SecondValue
, Result
;
1223 SOFT386_MOD_REG_RM ModRegRm
;
1224 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1226 /* Make sure this is the right instruction */
1227 ASSERT((Opcode
& 0xFD) == 0x00);
1229 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1231 /* The ADSIZE prefix toggles the size */
1232 AddressSize
= !AddressSize
;
1234 else if (State
->PrefixFlags
1235 & ~(SOFT386_PREFIX_ADSIZE
1236 | SOFT386_PREFIX_SEG
1237 | SOFT386_PREFIX_LOCK
))
1239 /* Invalid prefix */
1240 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1244 /* Get the operands */
1245 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1247 /* Exception occurred */
1251 if (!Soft386ReadModrmByteOperands(State
,
1256 /* Exception occurred */
1260 /* Calculate the result */
1261 Result
= FirstValue
+ SecondValue
;
1263 /* Update the flags */
1264 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1265 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1266 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1267 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1268 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1269 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1270 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1272 /* Write back the result */
1273 return Soft386WriteModrmByteOperands(State
,
1275 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1279 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddModrm
)
1281 SOFT386_MOD_REG_RM ModRegRm
;
1282 BOOLEAN OperandSize
, AddressSize
;
1284 /* Make sure this is the right instruction */
1285 ASSERT((Opcode
& 0xFD) == 0x01);
1287 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1289 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1291 /* The ADSIZE prefix toggles the address size */
1292 AddressSize
= !AddressSize
;
1295 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1297 /* The OPSIZE prefix toggles the operand size */
1298 OperandSize
= !OperandSize
;
1301 if (State
->PrefixFlags
1302 & ~(SOFT386_PREFIX_ADSIZE
1303 | SOFT386_PREFIX_OPSIZE
1304 | SOFT386_PREFIX_SEG
1305 | SOFT386_PREFIX_LOCK
))
1307 /* Invalid prefix */
1308 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1312 /* Get the operands */
1313 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1315 /* Exception occurred */
1319 /* Check the operand size */
1322 ULONG FirstValue
, SecondValue
, Result
;
1324 if (!Soft386ReadModrmDwordOperands(State
,
1329 /* Exception occurred */
1333 /* Calculate the result */
1334 Result
= FirstValue
+ SecondValue
;
1336 /* Update the flags */
1337 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1338 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1339 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1340 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1341 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1342 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1343 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1345 /* Write back the result */
1346 return Soft386WriteModrmDwordOperands(State
,
1348 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1353 USHORT FirstValue
, SecondValue
, Result
;
1355 if (!Soft386ReadModrmWordOperands(State
,
1360 /* Exception occurred */
1364 /* Calculate the result */
1365 Result
= FirstValue
+ SecondValue
;
1367 /* Update the flags */
1368 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1369 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1370 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1371 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1372 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1373 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1374 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1376 /* Write back the result */
1377 return Soft386WriteModrmWordOperands(State
,
1379 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1384 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddAl
)
1386 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1387 UCHAR SecondValue
, Result
;
1389 /* Make sure this is the right instruction */
1390 ASSERT(Opcode
== 0x04);
1392 if (State
->PrefixFlags
)
1394 /* This opcode doesn't take any prefixes */
1395 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1399 if (!Soft386FetchByte(State
, &SecondValue
))
1401 /* Exception occurred */
1405 /* Calculate the result */
1406 Result
= FirstValue
+ SecondValue
;
1408 /* Update the flags */
1409 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1410 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
1411 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
1412 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1413 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1414 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1415 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1417 /* Write back the result */
1418 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1423 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddEax
)
1425 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1427 /* Make sure this is the right instruction */
1428 ASSERT(Opcode
== 0x05);
1430 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1432 /* Invalid prefix */
1433 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1437 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1439 /* The OPSIZE prefix toggles the size */
1445 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1446 ULONG SecondValue
, Result
;
1448 if (!Soft386FetchDword(State
, &SecondValue
))
1450 /* Exception occurred */
1454 /* Calculate the result */
1455 Result
= FirstValue
+ SecondValue
;
1457 /* Update the flags */
1458 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1459 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
1460 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
1461 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1462 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1463 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1464 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1466 /* Write back the result */
1467 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
1471 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1472 USHORT SecondValue
, Result
;
1474 if (!Soft386FetchWord(State
, &SecondValue
))
1476 /* Exception occurred */
1480 /* Calculate the result */
1481 Result
= FirstValue
+ SecondValue
;
1483 /* Update the flags */
1484 State
->Flags
.Cf
= (Result
< FirstValue
) && (Result
< SecondValue
);
1485 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
1486 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
1487 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
1488 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1489 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1490 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1492 /* Write back the result */
1493 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
1499 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrByteModrm
)
1501 UCHAR FirstValue
, SecondValue
, Result
;
1502 SOFT386_MOD_REG_RM ModRegRm
;
1503 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1505 /* Make sure this is the right instruction */
1506 ASSERT((Opcode
& 0xFD) == 0x08);
1508 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1510 /* The ADSIZE prefix toggles the size */
1511 AddressSize
= !AddressSize
;
1513 else if (State
->PrefixFlags
1514 & ~(SOFT386_PREFIX_ADSIZE
1515 | SOFT386_PREFIX_SEG
1516 | SOFT386_PREFIX_LOCK
))
1518 /* Invalid prefix */
1519 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1523 /* Get the operands */
1524 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1526 /* Exception occurred */
1530 if (!Soft386ReadModrmByteOperands(State
,
1535 /* Exception occurred */
1539 /* Calculate the result */
1540 Result
= FirstValue
| SecondValue
;
1542 /* Update the flags */
1543 State
->Flags
.Cf
= FALSE
;
1544 State
->Flags
.Of
= FALSE
;
1545 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1546 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1547 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1549 /* Write back the result */
1550 return Soft386WriteModrmByteOperands(State
,
1552 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1556 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrModrm
)
1558 SOFT386_MOD_REG_RM ModRegRm
;
1559 BOOLEAN OperandSize
, AddressSize
;
1561 /* Make sure this is the right instruction */
1562 ASSERT((Opcode
& 0xFD) == 0x09);
1564 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1566 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1568 /* The ADSIZE prefix toggles the address size */
1569 AddressSize
= !AddressSize
;
1572 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1574 /* The OPSIZE prefix toggles the operand size */
1575 OperandSize
= !OperandSize
;
1578 if (State
->PrefixFlags
1579 & ~(SOFT386_PREFIX_ADSIZE
1580 | SOFT386_PREFIX_OPSIZE
1581 | SOFT386_PREFIX_SEG
1582 | SOFT386_PREFIX_LOCK
))
1584 /* Invalid prefix */
1585 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1589 /* Get the operands */
1590 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1592 /* Exception occurred */
1596 /* Check the operand size */
1599 ULONG FirstValue
, SecondValue
, Result
;
1601 if (!Soft386ReadModrmDwordOperands(State
,
1606 /* Exception occurred */
1610 /* Calculate the result */
1611 Result
= FirstValue
| SecondValue
;
1613 /* Update the flags */
1614 State
->Flags
.Cf
= FALSE
;
1615 State
->Flags
.Of
= FALSE
;
1616 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1617 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1618 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1620 /* Write back the result */
1621 return Soft386WriteModrmDwordOperands(State
,
1623 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1628 USHORT FirstValue
, SecondValue
, Result
;
1630 if (!Soft386ReadModrmWordOperands(State
,
1635 /* Exception occurred */
1639 /* Calculate the result */
1640 Result
= FirstValue
| SecondValue
;
1642 /* Update the flags */
1643 State
->Flags
.Cf
= FALSE
;
1644 State
->Flags
.Of
= FALSE
;
1645 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1646 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1647 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1649 /* Write back the result */
1650 return Soft386WriteModrmWordOperands(State
,
1652 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1657 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrAl
)
1659 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1660 UCHAR SecondValue
, Result
;
1662 /* Make sure this is the right instruction */
1663 ASSERT(Opcode
== 0x0C);
1665 if (State
->PrefixFlags
)
1667 /* This opcode doesn't take any prefixes */
1668 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1672 if (!Soft386FetchByte(State
, &SecondValue
))
1674 /* Exception occurred */
1678 /* Calculate the result */
1679 Result
= FirstValue
| SecondValue
;
1681 /* Update the flags */
1682 State
->Flags
.Cf
= FALSE
;
1683 State
->Flags
.Of
= FALSE
;
1684 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1685 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1686 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1688 /* Write back the result */
1689 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1694 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrEax
)
1696 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1698 /* Make sure this is the right instruction */
1699 ASSERT(Opcode
== 0x0D);
1701 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1703 /* Invalid prefix */
1704 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1708 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1710 /* The OPSIZE prefix toggles the size */
1716 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1717 ULONG SecondValue
, Result
;
1719 if (!Soft386FetchDword(State
, &SecondValue
))
1721 /* Exception occurred */
1725 /* Calculate the result */
1726 Result
= FirstValue
| SecondValue
;
1728 /* Update the flags */
1729 State
->Flags
.Cf
= FALSE
;
1730 State
->Flags
.Of
= FALSE
;
1731 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1732 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1733 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1735 /* Write back the result */
1736 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
1740 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
1741 USHORT SecondValue
, Result
;
1743 if (!Soft386FetchWord(State
, &SecondValue
))
1745 /* Exception occurred */
1749 /* Calculate the result */
1750 Result
= FirstValue
| SecondValue
;
1752 /* Update the flags */
1753 State
->Flags
.Cf
= FALSE
;
1754 State
->Flags
.Of
= FALSE
;
1755 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1756 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
1757 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1759 /* Write back the result */
1760 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
1766 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndByteModrm
)
1768 UCHAR FirstValue
, SecondValue
, Result
;
1769 SOFT386_MOD_REG_RM ModRegRm
;
1770 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1772 /* Make sure this is the right instruction */
1773 ASSERT((Opcode
& 0xFD) == 0x20);
1775 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1777 /* The ADSIZE prefix toggles the size */
1778 AddressSize
= !AddressSize
;
1780 else if (State
->PrefixFlags
1781 & ~(SOFT386_PREFIX_ADSIZE
1782 | SOFT386_PREFIX_SEG
1783 | SOFT386_PREFIX_LOCK
))
1785 /* Invalid prefix */
1786 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1790 /* Get the operands */
1791 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1793 /* Exception occurred */
1797 if (!Soft386ReadModrmByteOperands(State
,
1802 /* Exception occurred */
1806 /* Calculate the result */
1807 Result
= FirstValue
& SecondValue
;
1809 /* Update the flags */
1810 State
->Flags
.Cf
= FALSE
;
1811 State
->Flags
.Of
= FALSE
;
1812 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1813 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1814 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1816 /* Write back the result */
1817 return Soft386WriteModrmByteOperands(State
,
1819 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1823 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndModrm
)
1825 SOFT386_MOD_REG_RM ModRegRm
;
1826 BOOLEAN OperandSize
, AddressSize
;
1828 /* Make sure this is the right instruction */
1829 ASSERT((Opcode
& 0xFD) == 0x21);
1831 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1833 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
1835 /* The ADSIZE prefix toggles the address size */
1836 AddressSize
= !AddressSize
;
1839 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1841 /* The OPSIZE prefix toggles the operand size */
1842 OperandSize
= !OperandSize
;
1845 if (State
->PrefixFlags
1846 & ~(SOFT386_PREFIX_ADSIZE
1847 | SOFT386_PREFIX_OPSIZE
1848 | SOFT386_PREFIX_SEG
1849 | SOFT386_PREFIX_LOCK
))
1851 /* Invalid prefix */
1852 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1856 /* Get the operands */
1857 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
1859 /* Exception occurred */
1863 /* Check the operand size */
1866 ULONG FirstValue
, SecondValue
, Result
;
1868 if (!Soft386ReadModrmDwordOperands(State
,
1873 /* Exception occurred */
1877 /* Calculate the result */
1878 Result
= FirstValue
& SecondValue
;
1880 /* Update the flags */
1881 State
->Flags
.Cf
= FALSE
;
1882 State
->Flags
.Of
= FALSE
;
1883 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1884 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1885 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1887 /* Write back the result */
1888 return Soft386WriteModrmDwordOperands(State
,
1890 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1895 USHORT FirstValue
, SecondValue
, Result
;
1897 if (!Soft386ReadModrmWordOperands(State
,
1902 /* Exception occurred */
1906 /* Calculate the result */
1907 Result
= FirstValue
& SecondValue
;
1909 /* Update the flags */
1910 State
->Flags
.Cf
= FALSE
;
1911 State
->Flags
.Of
= FALSE
;
1912 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1913 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
1914 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1916 /* Write back the result */
1917 return Soft386WriteModrmWordOperands(State
,
1919 Opcode
& SOFT386_OPCODE_WRITE_REG
,
1924 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndAl
)
1926 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
1927 UCHAR SecondValue
, Result
;
1929 /* Make sure this is the right instruction */
1930 ASSERT(Opcode
== 0x24);
1932 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1934 /* Invalid prefix */
1935 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1939 if (!Soft386FetchByte(State
, &SecondValue
))
1941 /* Exception occurred */
1945 /* Calculate the result */
1946 Result
= FirstValue
& SecondValue
;
1948 /* Update the flags */
1949 State
->Flags
.Cf
= FALSE
;
1950 State
->Flags
.Of
= FALSE
;
1951 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1952 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
1953 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
1955 /* Write back the result */
1956 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
1961 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndEax
)
1963 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
1965 /* Make sure this is the right instruction */
1966 ASSERT(Opcode
== 0x25);
1968 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
1970 /* Invalid prefix */
1971 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
1975 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
1977 /* The OPSIZE prefix toggles the size */
1983 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
1984 ULONG SecondValue
, Result
;
1986 if (!Soft386FetchDword(State
, &SecondValue
))
1988 /* Exception occurred */
1992 /* Calculate the result */
1993 Result
= FirstValue
& SecondValue
;
1995 /* Update the flags */
1996 State
->Flags
.Cf
= FALSE
;
1997 State
->Flags
.Of
= FALSE
;
1998 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
1999 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2000 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2002 /* Write back the result */
2003 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
2007 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2008 USHORT SecondValue
, Result
;
2010 if (!Soft386FetchWord(State
, &SecondValue
))
2012 /* Exception occurred */
2016 /* Calculate the result */
2017 Result
= FirstValue
& SecondValue
;
2019 /* Update the flags */
2020 State
->Flags
.Cf
= FALSE
;
2021 State
->Flags
.Of
= FALSE
;
2022 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2023 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2024 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2026 /* Write back the result */
2027 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
2033 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorByteModrm
)
2035 UCHAR FirstValue
, SecondValue
, Result
;
2036 SOFT386_MOD_REG_RM ModRegRm
;
2037 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2039 /* Make sure this is the right instruction */
2040 ASSERT((Opcode
& 0xFD) == 0x30);
2042 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2044 /* The ADSIZE prefix toggles the size */
2045 AddressSize
= !AddressSize
;
2047 else if (State
->PrefixFlags
2048 & ~(SOFT386_PREFIX_ADSIZE
2049 | SOFT386_PREFIX_SEG
2050 | SOFT386_PREFIX_LOCK
))
2052 /* Invalid prefix */
2053 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2057 /* Get the operands */
2058 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2060 /* Exception occurred */
2064 if (!Soft386ReadModrmByteOperands(State
,
2069 /* Exception occurred */
2073 /* Calculate the result */
2074 Result
= FirstValue
^ SecondValue
;
2076 /* Update the flags */
2077 State
->Flags
.Cf
= FALSE
;
2078 State
->Flags
.Of
= FALSE
;
2079 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2080 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2081 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2083 /* Write back the result */
2084 return Soft386WriteModrmByteOperands(State
,
2086 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2090 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorModrm
)
2092 SOFT386_MOD_REG_RM ModRegRm
;
2093 BOOLEAN OperandSize
, AddressSize
;
2095 /* Make sure this is the right instruction */
2096 ASSERT((Opcode
& 0xFD) == 0x31);
2098 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2100 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2102 /* The ADSIZE prefix toggles the address size */
2103 AddressSize
= !AddressSize
;
2106 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2108 /* The OPSIZE prefix toggles the operand size */
2109 OperandSize
= !OperandSize
;
2112 if (State
->PrefixFlags
2113 & ~(SOFT386_PREFIX_ADSIZE
2114 | SOFT386_PREFIX_OPSIZE
2115 | SOFT386_PREFIX_SEG
2116 | SOFT386_PREFIX_LOCK
))
2118 /* Invalid prefix */
2119 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2123 /* Get the operands */
2124 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2126 /* Exception occurred */
2130 /* Check the operand size */
2133 ULONG FirstValue
, SecondValue
, Result
;
2135 if (!Soft386ReadModrmDwordOperands(State
,
2140 /* Exception occurred */
2144 /* Calculate the result */
2145 Result
= FirstValue
^ SecondValue
;
2147 /* Update the flags */
2148 State
->Flags
.Cf
= FALSE
;
2149 State
->Flags
.Of
= FALSE
;
2150 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2151 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2152 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2154 /* Write back the result */
2155 return Soft386WriteModrmDwordOperands(State
,
2157 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2162 USHORT FirstValue
, SecondValue
, Result
;
2164 if (!Soft386ReadModrmWordOperands(State
,
2169 /* Exception occurred */
2173 /* Calculate the result */
2174 Result
= FirstValue
^ SecondValue
;
2176 /* Update the flags */
2177 State
->Flags
.Cf
= FALSE
;
2178 State
->Flags
.Of
= FALSE
;
2179 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2180 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2181 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2183 /* Write back the result */
2184 return Soft386WriteModrmWordOperands(State
,
2186 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2191 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorAl
)
2193 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2194 UCHAR SecondValue
, Result
;
2196 /* Make sure this is the right instruction */
2197 ASSERT(Opcode
== 0x34);
2199 if (State
->PrefixFlags
)
2201 /* This opcode doesn't take any prefixes */
2202 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2206 if (!Soft386FetchByte(State
, &SecondValue
))
2208 /* Exception occurred */
2212 /* Calculate the result */
2213 Result
= FirstValue
^ SecondValue
;
2215 /* Update the flags */
2216 State
->Flags
.Cf
= FALSE
;
2217 State
->Flags
.Of
= FALSE
;
2218 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2219 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2220 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2222 /* Write back the result */
2223 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
2228 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax
)
2230 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2232 /* Make sure this is the right instruction */
2233 ASSERT(Opcode
== 0x35);
2235 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2237 /* Invalid prefix */
2238 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2242 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2244 /* The OPSIZE prefix toggles the size */
2250 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2251 ULONG SecondValue
, Result
;
2253 if (!Soft386FetchDword(State
, &SecondValue
))
2255 /* Exception occurred */
2259 /* Calculate the result */
2260 Result
= FirstValue
^ SecondValue
;
2262 /* Update the flags */
2263 State
->Flags
.Cf
= FALSE
;
2264 State
->Flags
.Of
= FALSE
;
2265 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2266 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2267 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2269 /* Write back the result */
2270 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
2274 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2275 USHORT SecondValue
, Result
;
2277 if (!Soft386FetchWord(State
, &SecondValue
))
2279 /* Exception occurred */
2283 /* Calculate the result */
2284 Result
= FirstValue
^ SecondValue
;
2286 /* Update the flags */
2287 State
->Flags
.Cf
= FALSE
;
2288 State
->Flags
.Of
= FALSE
;
2289 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2290 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2291 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2293 /* Write back the result */
2294 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
2300 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm
)
2302 UCHAR FirstValue
, SecondValue
, Result
;
2303 SOFT386_MOD_REG_RM ModRegRm
;
2304 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2306 /* Make sure this is the right instruction */
2307 ASSERT(Opcode
== 0x84);
2309 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2311 /* The ADSIZE prefix toggles the size */
2312 AddressSize
= !AddressSize
;
2314 else if (State
->PrefixFlags
2315 & ~(SOFT386_PREFIX_ADSIZE
2316 | SOFT386_PREFIX_SEG
2317 | SOFT386_PREFIX_LOCK
))
2319 /* Invalid prefix */
2320 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2324 /* Get the operands */
2325 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2327 /* Exception occurred */
2331 if (!Soft386ReadModrmByteOperands(State
,
2336 /* Exception occurred */
2339 /* Calculate the result */
2340 Result
= FirstValue
& SecondValue
;
2342 /* Update the flags */
2343 State
->Flags
.Cf
= FALSE
;
2344 State
->Flags
.Of
= FALSE
;
2345 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2346 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2347 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2349 /* The result is discarded */
2353 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm
)
2355 SOFT386_MOD_REG_RM ModRegRm
;
2356 BOOLEAN OperandSize
, AddressSize
;
2358 /* Make sure this is the right instruction */
2359 ASSERT(Opcode
== 0x85);
2361 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2363 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2365 /* The ADSIZE prefix toggles the address size */
2366 AddressSize
= !AddressSize
;
2369 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2371 /* The OPSIZE prefix toggles the operand size */
2372 OperandSize
= !OperandSize
;
2375 if (State
->PrefixFlags
2376 & ~(SOFT386_PREFIX_ADSIZE
2377 | SOFT386_PREFIX_OPSIZE
2378 | SOFT386_PREFIX_SEG
2379 | SOFT386_PREFIX_LOCK
))
2381 /* Invalid prefix */
2382 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2386 /* Get the operands */
2387 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2389 /* Exception occurred */
2393 /* Check the operand size */
2396 ULONG FirstValue
, SecondValue
, Result
;
2398 if (!Soft386ReadModrmDwordOperands(State
,
2403 /* Exception occurred */
2407 /* Calculate the result */
2408 Result
= FirstValue
& SecondValue
;
2410 /* Update the flags */
2411 State
->Flags
.Cf
= FALSE
;
2412 State
->Flags
.Of
= FALSE
;
2413 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2414 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2415 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2419 USHORT FirstValue
, SecondValue
, Result
;
2421 if (!Soft386ReadModrmWordOperands(State
,
2426 /* Exception occurred */
2430 /* Calculate the result */
2431 Result
= FirstValue
& SecondValue
;
2433 /* Update the flags */
2434 State
->Flags
.Cf
= FALSE
;
2435 State
->Flags
.Of
= FALSE
;
2436 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2437 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2438 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2441 /* The result is discarded */
2445 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestAl
)
2447 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2448 UCHAR SecondValue
, Result
;
2450 /* Make sure this is the right instruction */
2451 ASSERT(Opcode
== 0xA8);
2453 if (State
->PrefixFlags
)
2455 /* This opcode doesn't take any prefixes */
2456 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2460 if (!Soft386FetchByte(State
, &SecondValue
))
2462 /* Exception occurred */
2466 /* Calculate the result */
2467 Result
= FirstValue
& SecondValue
;
2469 /* Update the flags */
2470 State
->Flags
.Cf
= FALSE
;
2471 State
->Flags
.Of
= FALSE
;
2472 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2473 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2474 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2476 /* The result is discarded */
2480 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestEax
)
2482 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2484 /* Make sure this is the right instruction */
2485 ASSERT(Opcode
== 0xA9);
2487 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2489 /* Invalid prefix */
2490 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2494 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2496 /* The OPSIZE prefix toggles the size */
2502 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2503 ULONG SecondValue
, Result
;
2505 if (!Soft386FetchDword(State
, &SecondValue
))
2507 /* Exception occurred */
2511 /* Calculate the result */
2512 Result
= FirstValue
& SecondValue
;
2514 /* Update the flags */
2515 State
->Flags
.Cf
= FALSE
;
2516 State
->Flags
.Of
= FALSE
;
2517 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2518 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2519 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2523 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
2524 USHORT SecondValue
, Result
;
2526 if (!Soft386FetchWord(State
, &SecondValue
))
2528 /* Exception occurred */
2532 /* Calculate the result */
2533 Result
= FirstValue
& SecondValue
;
2535 /* Update the flags */
2536 State
->Flags
.Cf
= FALSE
;
2537 State
->Flags
.Of
= FALSE
;
2538 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2539 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2540 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2543 /* The result is discarded */
2547 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm
)
2549 UCHAR FirstValue
, SecondValue
;
2550 SOFT386_MOD_REG_RM ModRegRm
;
2551 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2553 /* Make sure this is the right instruction */
2554 ASSERT(Opcode
== 0x86);
2556 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2558 /* The ADSIZE prefix toggles the size */
2559 AddressSize
= !AddressSize
;
2561 else if (State
->PrefixFlags
2562 & ~(SOFT386_PREFIX_ADSIZE
2563 | SOFT386_PREFIX_SEG
2564 | SOFT386_PREFIX_LOCK
))
2566 /* Invalid prefix */
2567 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2571 /* Get the operands */
2572 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2574 /* Exception occurred */
2578 if (!Soft386ReadModrmByteOperands(State
,
2583 /* Exception occurred */
2587 /* Write the value from the register to the R/M */
2588 if (!Soft386WriteModrmByteOperands(State
,
2593 /* Exception occurred */
2597 /* Write the value from the R/M to the register */
2598 if (!Soft386WriteModrmByteOperands(State
,
2603 /* Exception occurred */
2610 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm
)
2612 SOFT386_MOD_REG_RM ModRegRm
;
2613 BOOLEAN OperandSize
, AddressSize
;
2615 /* Make sure this is the right instruction */
2616 ASSERT(Opcode
== 0x87);
2618 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2620 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2622 /* The ADSIZE prefix toggles the address size */
2623 AddressSize
= !AddressSize
;
2626 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2628 /* The OPSIZE prefix toggles the operand size */
2629 OperandSize
= !OperandSize
;
2632 if (State
->PrefixFlags
2633 & ~(SOFT386_PREFIX_ADSIZE
2634 | SOFT386_PREFIX_OPSIZE
2635 | SOFT386_PREFIX_SEG
2636 | SOFT386_PREFIX_LOCK
))
2638 /* Invalid prefix */
2639 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2643 /* Get the operands */
2644 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2646 /* Exception occurred */
2650 /* Check the operand size */
2653 ULONG FirstValue
, SecondValue
;
2655 if (!Soft386ReadModrmDwordOperands(State
,
2660 /* Exception occurred */
2664 /* Write the value from the register to the R/M */
2665 if (!Soft386WriteModrmDwordOperands(State
,
2670 /* Exception occurred */
2674 /* Write the value from the R/M to the register */
2675 if (!Soft386WriteModrmDwordOperands(State
,
2680 /* Exception occurred */
2686 USHORT FirstValue
, SecondValue
;
2688 if (!Soft386ReadModrmWordOperands(State
,
2693 /* Exception occurred */
2697 /* Write the value from the register to the R/M */
2698 if (!Soft386WriteModrmWordOperands(State
,
2703 /* Exception occurred */
2707 /* Write the value from the R/M to the register */
2708 if (!Soft386WriteModrmWordOperands(State
,
2713 /* Exception occurred */
2718 /* The result is discarded */
2722 SOFT386_OPCODE_HANDLER(Soft386OpcodePushEs
)
2724 /* Call the internal API */
2725 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_ES
].Selector
);
2728 SOFT386_OPCODE_HANDLER(Soft386OpcodePopEs
)
2732 if (!Soft386StackPop(State
, &NewSelector
))
2734 /* Exception occurred */
2738 /* Call the internal API */
2739 return Soft386LoadSegment(State
, SOFT386_REG_ES
, LOWORD(NewSelector
));
2742 SOFT386_OPCODE_HANDLER(Soft386OpcodePushCs
)
2744 /* Call the internal API */
2745 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_CS
].Selector
);
2748 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcByteModrm
)
2750 UCHAR FirstValue
, SecondValue
, Result
;
2751 SOFT386_MOD_REG_RM ModRegRm
;
2752 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2754 /* Make sure this is the right instruction */
2755 ASSERT((Opcode
& 0xFD) == 0x10);
2757 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2759 /* The ADSIZE prefix toggles the size */
2760 AddressSize
= !AddressSize
;
2762 else if (State
->PrefixFlags
2763 & ~(SOFT386_PREFIX_ADSIZE
2764 | SOFT386_PREFIX_SEG
2765 | SOFT386_PREFIX_LOCK
))
2767 /* Invalid prefix */
2768 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2772 /* Get the operands */
2773 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2775 /* Exception occurred */
2779 if (!Soft386ReadModrmByteOperands(State
,
2784 /* Exception occurred */
2788 /* Calculate the result */
2789 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2791 /* Special exception for CF */
2792 State
->Flags
.Cf
= State
->Flags
.Cf
2793 && ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2795 /* Update the flags */
2796 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2797 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2798 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2799 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2800 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2801 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2802 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2804 /* Write back the result */
2805 return Soft386WriteModrmByteOperands(State
,
2807 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2811 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcModrm
)
2813 SOFT386_MOD_REG_RM ModRegRm
;
2814 BOOLEAN OperandSize
, AddressSize
;
2816 /* Make sure this is the right instruction */
2817 ASSERT((Opcode
& 0xFD) == 0x11);
2819 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2821 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
2823 /* The ADSIZE prefix toggles the address size */
2824 AddressSize
= !AddressSize
;
2827 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2829 /* The OPSIZE prefix toggles the operand size */
2830 OperandSize
= !OperandSize
;
2833 if (State
->PrefixFlags
2834 & ~(SOFT386_PREFIX_ADSIZE
2835 | SOFT386_PREFIX_OPSIZE
2836 | SOFT386_PREFIX_SEG
2837 | SOFT386_PREFIX_LOCK
))
2839 /* Invalid prefix */
2840 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2844 /* Get the operands */
2845 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
2847 /* Exception occurred */
2851 /* Check the operand size */
2854 ULONG FirstValue
, SecondValue
, Result
;
2856 if (!Soft386ReadModrmDwordOperands(State
,
2861 /* Exception occurred */
2865 /* Calculate the result */
2866 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2868 /* Special exception for CF */
2869 State
->Flags
.Cf
= State
->Flags
.Cf
2870 && ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
2872 /* Update the flags */
2873 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2874 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
2875 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
2876 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2877 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2878 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
2879 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2881 /* Write back the result */
2882 return Soft386WriteModrmDwordOperands(State
,
2884 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2889 USHORT FirstValue
, SecondValue
, Result
;
2891 if (!Soft386ReadModrmWordOperands(State
,
2896 /* Exception occurred */
2900 /* Calculate the result */
2901 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2903 /* Special exception for CF */
2904 State
->Flags
.Cf
= State
->Flags
.Cf
2905 && ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
2907 /* Update the flags */
2908 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2909 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
2910 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
2911 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2912 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2913 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
2914 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2916 /* Write back the result */
2917 return Soft386WriteModrmWordOperands(State
,
2919 Opcode
& SOFT386_OPCODE_WRITE_REG
,
2925 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcAl
)
2927 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
2928 UCHAR SecondValue
, Result
;
2930 /* Make sure this is the right instruction */
2931 ASSERT(Opcode
== 0x14);
2933 if (State
->PrefixFlags
)
2935 /* This opcode doesn't take any prefixes */
2936 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2940 if (!Soft386FetchByte(State
, &SecondValue
))
2942 /* Exception occurred */
2946 /* Calculate the result */
2947 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
2949 /* Special exception for CF */
2950 State
->Flags
.Cf
= State
->Flags
.Cf
&&
2951 ((FirstValue
== 0xFF) || (SecondValue
== 0xFF));
2953 /* Update the flags */
2954 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
2955 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) == (SecondValue
& SIGN_FLAG_BYTE
))
2956 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
2957 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
2958 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
2959 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
2960 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
2962 /* Write back the result */
2963 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
2968 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcEax
)
2970 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
2972 /* Make sure this is the right instruction */
2973 ASSERT(Opcode
== 0x15);
2975 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
2977 /* Invalid prefix */
2978 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
2982 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
2984 /* The OPSIZE prefix toggles the size */
2990 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
2991 ULONG SecondValue
, Result
;
2993 if (!Soft386FetchDword(State
, &SecondValue
))
2995 /* Exception occurred */
2999 /* Calculate the result */
3000 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3002 /* Special exception for CF */
3003 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3004 ((FirstValue
== 0xFFFFFFFF) || (SecondValue
== 0xFFFFFFFF));
3006 /* Update the flags */
3007 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3008 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) == (SecondValue
& SIGN_FLAG_LONG
))
3009 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3010 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3011 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3012 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3013 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3015 /* Write back the result */
3016 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3020 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3021 USHORT SecondValue
, Result
;
3023 if (!Soft386FetchWord(State
, &SecondValue
))
3025 /* Exception occurred */
3029 /* Calculate the result */
3030 Result
= FirstValue
+ SecondValue
+ State
->Flags
.Cf
;
3032 /* Special exception for CF */
3033 State
->Flags
.Cf
= State
->Flags
.Cf
&&
3034 ((FirstValue
== 0xFFFF) || (SecondValue
== 0xFFFF));
3036 /* Update the flags */
3037 State
->Flags
.Cf
= State
->Flags
.Cf
|| ((Result
< FirstValue
) && (Result
< SecondValue
));
3038 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) == (SecondValue
& SIGN_FLAG_WORD
))
3039 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3040 State
->Flags
.Af
= (((FirstValue
& 0x0F) + (SecondValue
& 0x0F)) & 0x10) ? TRUE
: FALSE
;
3041 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3042 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3043 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3045 /* Write back the result */
3046 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3052 SOFT386_OPCODE_HANDLER(Soft386OpcodePushSs
)
3054 /* Call the internal API */
3055 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_SS
].Selector
);
3058 SOFT386_OPCODE_HANDLER(Soft386OpcodePopSs
)
3062 if (!Soft386StackPop(State
, &NewSelector
))
3064 /* Exception occurred */
3068 /* Call the internal API */
3069 return Soft386LoadSegment(State
, SOFT386_REG_SS
, LOWORD(NewSelector
));
3072 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm
)
3074 // TODO: NOT IMPLEMENTED
3080 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm
)
3082 // TODO: NOT IMPLEMENTED
3088 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl
)
3090 // TODO: NOT IMPLEMENTED
3096 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax
)
3098 // TODO: NOT IMPLEMENTED
3104 SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs
)
3106 /* Call the internal API */
3107 return Soft386StackPush(State
, State
->SegmentRegs
[SOFT386_REG_DS
].Selector
);
3110 SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs
)
3114 if (!Soft386StackPop(State
, &NewSelector
))
3116 /* Exception occurred */
3120 /* Call the internal API */
3121 return Soft386LoadSegment(State
, SOFT386_REG_DS
, LOWORD(NewSelector
));
3124 SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa
)
3126 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3127 BOOLEAN Carry
= State
->Flags
.Cf
;
3129 /* Clear the carry flag */
3130 State
->Flags
.Cf
= FALSE
;
3132 /* Check if the first BCD digit is invalid or there was a carry from it */
3133 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3136 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x06;
3137 if (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
< 0x06)
3139 /* A carry occurred */
3140 State
->Flags
.Cf
= TRUE
;
3143 /* Set the adjust flag */
3144 State
->Flags
.Af
= TRUE
;
3147 /* Check if the second BCD digit is invalid or there was a carry from it */
3148 if ((Value
> 0x99) || Carry
)
3151 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x60;
3153 /* There was a carry */
3154 State
->Flags
.Cf
= TRUE
;
3160 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm
)
3162 UCHAR FirstValue
, SecondValue
, Result
;
3163 SOFT386_MOD_REG_RM ModRegRm
;
3164 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3166 /* Make sure this is the right instruction */
3167 ASSERT((Opcode
& 0xED) == 0x28);
3169 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3171 /* The ADSIZE prefix toggles the size */
3172 AddressSize
= !AddressSize
;
3174 else if (State
->PrefixFlags
3175 & ~(SOFT386_PREFIX_ADSIZE
3176 | SOFT386_PREFIX_SEG
3177 | SOFT386_PREFIX_LOCK
))
3179 /* Invalid prefix */
3180 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3184 /* Get the operands */
3185 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3187 /* Exception occurred */
3191 if (!Soft386ReadModrmByteOperands(State
,
3196 /* Exception occurred */
3200 /* Check if this is the instruction that writes to R/M */
3201 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3203 /* Swap the order */
3204 FirstValue
^= SecondValue
;
3205 SecondValue
^= FirstValue
;
3206 FirstValue
^= SecondValue
;
3209 /* Calculate the result */
3210 Result
= FirstValue
- SecondValue
;
3212 /* Update the flags */
3213 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3214 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3215 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3216 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3217 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3218 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3219 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3221 /* Check if this is not a CMP */
3222 if (!(Opcode
& 0x10))
3224 /* Write back the result */
3225 return Soft386WriteModrmByteOperands(State
,
3227 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3232 /* Discard the result */
3237 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm
)
3239 SOFT386_MOD_REG_RM ModRegRm
;
3240 BOOLEAN OperandSize
, AddressSize
;
3242 /* Make sure this is the right instruction */
3243 ASSERT((Opcode
& 0xED) == 0x29);
3245 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3247 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3249 /* The ADSIZE prefix toggles the address size */
3250 AddressSize
= !AddressSize
;
3253 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3255 /* The OPSIZE prefix toggles the operand size */
3256 OperandSize
= !OperandSize
;
3259 if (State
->PrefixFlags
3260 & ~(SOFT386_PREFIX_ADSIZE
3261 | SOFT386_PREFIX_OPSIZE
3262 | SOFT386_PREFIX_SEG
3263 | SOFT386_PREFIX_LOCK
))
3265 /* Invalid prefix */
3266 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3270 /* Get the operands */
3271 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3273 /* Exception occurred */
3277 /* Check the operand size */
3280 ULONG FirstValue
, SecondValue
, Result
;
3282 if (!Soft386ReadModrmDwordOperands(State
,
3287 /* Exception occurred */
3291 /* Check if this is the instruction that writes to R/M */
3292 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3294 /* Swap the order */
3295 FirstValue
^= SecondValue
;
3296 SecondValue
^= FirstValue
;
3297 FirstValue
^= SecondValue
;
3300 /* Calculate the result */
3301 Result
= FirstValue
- SecondValue
;
3303 /* Update the flags */
3304 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3305 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3306 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3307 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3308 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3309 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3310 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3312 /* Check if this is not a CMP */
3313 if (!(Opcode
& 0x10))
3315 /* Write back the result */
3316 return Soft386WriteModrmDwordOperands(State
,
3318 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3323 /* Discard the result */
3329 USHORT FirstValue
, SecondValue
, Result
;
3331 if (!Soft386ReadModrmWordOperands(State
,
3336 /* Exception occurred */
3340 /* Check if this is the instruction that writes to R/M */
3341 if (!(Opcode
& SOFT386_OPCODE_WRITE_REG
))
3343 /* Swap the order */
3344 FirstValue
^= SecondValue
;
3345 SecondValue
^= FirstValue
;
3346 FirstValue
^= SecondValue
;
3349 /* Calculate the result */
3350 Result
= FirstValue
- SecondValue
;
3352 /* Update the flags */
3353 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3354 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3355 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3356 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3357 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3358 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3359 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3361 /* Check if this is not a CMP */
3362 if (!(Opcode
& 0x10))
3364 /* Write back the result */
3365 return Soft386WriteModrmWordOperands(State
,
3367 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3372 /* Discard the result */
3379 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl
)
3381 UCHAR FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3382 UCHAR SecondValue
, Result
;
3384 /* Make sure this is the right instruction */
3385 ASSERT((Opcode
& 0xEF) == 0x2C);
3387 if (State
->PrefixFlags
)
3389 /* This opcode doesn't take any prefixes */
3390 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3394 if (!Soft386FetchByte(State
, &SecondValue
))
3396 /* Exception occurred */
3400 /* Calculate the result */
3401 Result
= FirstValue
- SecondValue
;
3403 /* Update the flags */
3404 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3405 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_BYTE
) != (SecondValue
& SIGN_FLAG_BYTE
))
3406 && ((FirstValue
& SIGN_FLAG_BYTE
) != (Result
& SIGN_FLAG_BYTE
));
3407 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3408 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3409 State
->Flags
.Sf
= (Result
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
3410 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3412 /* Check if this is not a CMP */
3413 if (!(Opcode
& 0x10))
3415 /* Write back the result */
3416 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Result
;
3422 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax
)
3424 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3426 /* Make sure this is the right instruction */
3427 ASSERT((Opcode
& 0xEF) == 0x2D);
3429 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
3431 /* Invalid prefix */
3432 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3436 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3438 /* The OPSIZE prefix toggles the size */
3444 ULONG FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].Long
;
3445 ULONG SecondValue
, Result
;
3447 if (!Soft386FetchDword(State
, &SecondValue
))
3449 /* Exception occurred */
3453 /* Calculate the result */
3454 Result
= FirstValue
- SecondValue
;
3456 /* Update the flags */
3457 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3458 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_LONG
) != (SecondValue
& SIGN_FLAG_LONG
))
3459 && ((FirstValue
& SIGN_FLAG_LONG
) != (Result
& SIGN_FLAG_LONG
));
3460 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3461 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3462 State
->Flags
.Sf
= (Result
& SIGN_FLAG_LONG
) ? TRUE
: FALSE
;
3463 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3465 /* Check if this is not a CMP */
3466 if (!(Opcode
& 0x10))
3468 /* Write back the result */
3469 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= Result
;
3474 USHORT FirstValue
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
;
3475 USHORT SecondValue
, Result
;
3477 if (!Soft386FetchWord(State
, &SecondValue
))
3479 /* Exception occurred */
3483 /* Calculate the result */
3484 Result
= FirstValue
- SecondValue
;
3486 /* Update the flags */
3487 State
->Flags
.Cf
= FirstValue
< SecondValue
;
3488 State
->Flags
.Of
= ((FirstValue
& SIGN_FLAG_WORD
) != (SecondValue
& SIGN_FLAG_WORD
))
3489 && ((FirstValue
& SIGN_FLAG_WORD
) != (Result
& SIGN_FLAG_WORD
));
3490 State
->Flags
.Af
= (FirstValue
& 0x0F) < (SecondValue
& 0x0F);
3491 State
->Flags
.Zf
= (Result
== 0) ? TRUE
: FALSE
;
3492 State
->Flags
.Sf
= (Result
& SIGN_FLAG_WORD
) ? TRUE
: FALSE
;
3493 State
->Flags
.Pf
= Soft386CalculateParity(Result
);
3495 /* Write back the result */
3496 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
= Result
;
3502 SOFT386_OPCODE_HANDLER(Soft386OpcodeDas
)
3504 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3505 BOOLEAN Carry
= State
->Flags
.Cf
;
3507 /* Clear the carry flag */
3508 State
->Flags
.Cf
= FALSE
;
3510 /* Check if the first BCD digit is invalid or there was a borrow */
3511 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3514 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x06;
3515 if (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
> 0xFB)
3517 /* A borrow occurred */
3518 State
->Flags
.Cf
= TRUE
;
3521 /* Set the adjust flag */
3522 State
->Flags
.Af
= TRUE
;
3525 /* Check if the second BCD digit is invalid or there was a borrow */
3526 if ((Value
> 0x99) || Carry
)
3529 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x60;
3531 /* There was a borrow */
3532 State
->Flags
.Cf
= TRUE
;
3538 SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa
)
3540 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3543 * Check if the value in AL is not a valid BCD digit,
3544 * or there was a carry from the lowest 4 bits of AL
3546 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3549 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
+= 0x06;
3550 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
++;
3553 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3557 /* Clear CF and AF */
3558 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3561 /* Keep only the lowest 4 bits of AL */
3562 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
&= 0x0F;
3567 SOFT386_OPCODE_HANDLER(Soft386OpcodeAas
)
3569 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
3572 * Check if the value in AL is not a valid BCD digit,
3573 * or there was a borrow from the lowest 4 bits of AL
3575 if (((Value
& 0x0F) > 9) || State
->Flags
.Af
)
3578 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
-= 0x06;
3579 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
--;
3582 State
->Flags
.Cf
= State
->Flags
.Af
= TRUE
;
3586 /* Clear CF and AF */
3587 State
->Flags
.Cf
= State
->Flags
.Af
= FALSE
;
3590 /* Keep only the lowest 4 bits of AL */
3591 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
&= 0x0F;
3596 SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll
)
3599 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3600 SOFT386_REG SavedEsp
= State
->GeneralRegs
[SOFT386_REG_ESP
];
3602 /* Make sure this is the right instruction */
3603 ASSERT(Opcode
== 0x60);
3605 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
3607 /* The OPSIZE prefix toggles the size */
3612 /* Invalid prefix */
3613 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3617 /* Push all the registers in order */
3618 for (i
= 0; i
< SOFT386_NUM_GEN_REGS
; i
++)
3620 if (i
== SOFT386_REG_ESP
)
3622 /* Use the saved ESP instead */
3623 if (!Soft386StackPush(State
, Size
? SavedEsp
.Long
: SavedEsp
.LowWord
))
3625 /* Exception occurred */
3631 /* Push the register */
3632 if (!Soft386StackPush(State
, Size
? State
->GeneralRegs
[i
].Long
3633 : State
->GeneralRegs
[i
].LowWord
))
3635 /* Exception occurred */
3644 SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll
)
3647 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3650 /* Make sure this is the right instruction */
3651 ASSERT(Opcode
== 0x61);
3653 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
3655 /* The OPSIZE prefix toggles the size */
3660 /* Invalid prefix */
3661 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3665 /* Pop all the registers in reverse order */
3666 for (i
= SOFT386_NUM_GEN_REGS
- 1; i
>= 0; i
--)
3669 if (!Soft386StackPop(State
, &Value
))
3671 /* Exception occurred */
3675 /* Don't modify ESP */
3676 if (i
!= SOFT386_REG_ESP
)
3678 if (Size
) State
->GeneralRegs
[i
].Long
= Value
;
3679 else State
->GeneralRegs
[i
].LowWord
= LOWORD(Value
);
3686 SOFT386_OPCODE_HANDLER(Soft386OpcodeBound
)
3688 // TODO: NOT IMPLEMENTED
3694 SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl
)
3696 USHORT FirstValue
, SecondValue
;
3697 SOFT386_MOD_REG_RM ModRegRm
;
3698 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3700 if (!(State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
3702 || (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
))
3704 /* Cannot be used in real mode or with a LOCK prefix */
3705 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3709 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3711 /* The ADSIZE prefix toggles the size */
3712 AddressSize
= !AddressSize
;
3715 /* Get the operands */
3716 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3718 /* Exception occurred */
3722 /* Read the operands */
3723 if (!Soft386ReadModrmWordOperands(State
,
3728 /* Exception occurred */
3732 /* Check if the RPL needs adjusting */
3733 if ((SecondValue
& 3) < (FirstValue
& 3))
3735 /* Adjust the RPL */
3737 SecondValue
|= FirstValue
& 3;
3740 State
->Flags
.Zf
= TRUE
;
3742 /* Write back the result */
3743 return Soft386WriteModrmWordOperands(State
, &ModRegRm
, FALSE
, SecondValue
);
3748 State
->Flags
.Zf
= FALSE
;
3753 SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm
)
3755 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3757 /* Make sure this is the right instruction */
3758 ASSERT(Opcode
== 0x68);
3760 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
3762 /* The OPSIZE prefix toggles the size */
3767 /* Invalid prefix */
3768 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3776 if (!Soft386FetchDword(State
, &Data
))
3778 /* Exception occurred */
3782 /* Call the internal API */
3783 return Soft386StackPush(State
, Data
);
3789 if (!Soft386FetchWord(State
, &Data
))
3791 /* Exception occurred */
3795 /* Call the internal API */
3796 return Soft386StackPush(State
, Data
);
3800 SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm
)
3802 BOOLEAN OperandSize
, AddressSize
;
3803 SOFT386_MOD_REG_RM ModRegRm
;
3807 /* Make sure this is the right instruction */
3808 ASSERT((Opcode
& 0xFD) == 0x69);
3810 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3812 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3814 /* The ADSIZE prefix toggles the address size */
3815 AddressSize
= !AddressSize
;
3818 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3820 /* The OPSIZE prefix toggles the operand size */
3821 OperandSize
= !OperandSize
;
3824 /* Fetch the parameters */
3825 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3827 /* Exception occurred */
3835 /* Fetch the immediate operand */
3836 if (!Soft386FetchByte(State
, (PUCHAR
)&Byte
))
3838 /* Exception occurred */
3842 Multiplier
= (LONG
)Byte
;
3850 /* Fetch the immediate operand */
3851 if (!Soft386FetchDword(State
, (PULONG
)&Dword
))
3853 /* Exception occurred */
3863 /* Fetch the immediate operand */
3864 if (!Soft386FetchWord(State
, (PUSHORT
)&Word
))
3866 /* Exception occurred */
3870 Multiplier
= (LONG
)Word
;
3876 LONG RegValue
, Multiplicand
;
3878 /* Read the operands */
3879 if (!Soft386ReadModrmDwordOperands(State
,
3882 (PULONG
)&Multiplicand
))
3884 /* Exception occurred */
3889 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3893 SHORT RegValue
, Multiplicand
;
3895 /* Read the operands */
3896 if (!Soft386ReadModrmWordOperands(State
,
3899 (PUSHORT
)&Multiplicand
))
3901 /* Exception occurred */
3906 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3909 /* Check for carry/overflow */
3910 if ((Product
< LONG_MIN
) || (Product
> LONG_MAX
))
3912 State
->Flags
.Cf
= State
->Flags
.Of
= TRUE
;
3914 else State
->Flags
.Cf
= State
->Flags
.Of
= FALSE
;
3916 /* Write-back the result */
3917 return Soft386WriteModrmDwordOperands(State
,
3920 (ULONG
)((LONG
)Product
));
3923 SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm
)
3927 /* Make sure this is the right instruction */
3928 ASSERT(Opcode
== 0x6A);
3930 if (!Soft386FetchByte(State
, &Data
))
3932 /* Exception occurred */
3936 /* Call the internal API */
3937 return Soft386StackPush(State
, Data
);
3940 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm
)
3942 UCHAR FirstValue
, SecondValue
, Result
;
3943 SOFT386_MOD_REG_RM ModRegRm
;
3944 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3946 /* Make sure this is the right instruction */
3947 ASSERT((Opcode
& 0xFD) == 0x88);
3949 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3951 /* The ADSIZE prefix toggles the size */
3952 AddressSize
= !AddressSize
;
3954 else if (State
->PrefixFlags
3955 & ~(SOFT386_PREFIX_ADSIZE
3956 | SOFT386_PREFIX_SEG
3957 | SOFT386_PREFIX_LOCK
))
3959 /* Invalid prefix */
3960 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3964 /* Get the operands */
3965 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3967 /* Exception occurred */
3971 if (!Soft386ReadModrmByteOperands(State
,
3976 /* Exception occurred */
3980 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
3981 else Result
= FirstValue
;
3983 /* Write back the result */
3984 return Soft386WriteModrmByteOperands(State
,
3986 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3991 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm
)
3993 SOFT386_MOD_REG_RM ModRegRm
;
3994 BOOLEAN OperandSize
, AddressSize
;
3996 /* Make sure this is the right instruction */
3997 ASSERT((Opcode
& 0xFD) == 0x89);
3999 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4001 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4003 /* The ADSIZE prefix toggles the address size */
4004 AddressSize
= !AddressSize
;
4007 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4009 /* The OPSIZE prefix toggles the operand size */
4010 OperandSize
= !OperandSize
;
4013 if (State
->PrefixFlags
4014 & ~(SOFT386_PREFIX_ADSIZE
4015 | SOFT386_PREFIX_OPSIZE
4016 | SOFT386_PREFIX_SEG
4017 | SOFT386_PREFIX_LOCK
))
4019 /* Invalid prefix */
4020 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4024 /* Get the operands */
4025 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4027 /* Exception occurred */
4031 /* Check the operand size */
4034 ULONG FirstValue
, SecondValue
, Result
;
4036 if (!Soft386ReadModrmDwordOperands(State
,
4041 /* Exception occurred */
4045 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4046 else Result
= FirstValue
;
4048 /* Write back the result */
4049 return Soft386WriteModrmDwordOperands(State
,
4051 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4056 USHORT FirstValue
, SecondValue
, Result
;
4058 if (!Soft386ReadModrmWordOperands(State
,
4063 /* Exception occurred */
4067 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4068 else Result
= FirstValue
;
4070 /* Write back the result */
4071 return Soft386WriteModrmWordOperands(State
,
4073 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4078 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg
)
4080 BOOLEAN OperandSize
, AddressSize
;
4081 SOFT386_MOD_REG_RM ModRegRm
;
4083 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4085 /* Make sure this is the right instruction */
4086 ASSERT(Opcode
== 0x8C);
4088 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4090 /* The ADSIZE prefix toggles the address size */
4091 AddressSize
= !AddressSize
;
4094 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4096 /* The OPSIZE prefix toggles the operand size */
4097 OperandSize
= !OperandSize
;
4100 /* Get the operands */
4101 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4103 /* Exception occurred */
4107 if (ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4110 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4116 return Soft386WriteModrmDwordOperands(State
,
4119 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4123 return Soft386WriteModrmWordOperands(State
,
4126 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4130 SOFT386_OPCODE_HANDLER(Soft386OpcodeLea
)
4132 SOFT386_MOD_REG_RM ModRegRm
;
4133 BOOLEAN OperandSize
, AddressSize
;
4135 /* Make sure this is the right instruction */
4136 ASSERT(Opcode
== 0x8D);
4138 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4140 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4142 /* The ADSIZE prefix toggles the address size */
4143 AddressSize
= !AddressSize
;
4146 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4148 /* The OPSIZE prefix toggles the operand size */
4149 OperandSize
= !OperandSize
;
4152 /* Get the operands */
4153 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4155 /* Exception occurred */
4159 /* The second operand must be memory */
4160 if (!ModRegRm
.Memory
)
4163 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4167 /* Write the address to the register */
4170 return Soft386WriteModrmDwordOperands(State
,
4173 ModRegRm
.MemoryAddress
);
4177 return Soft386WriteModrmWordOperands(State
,
4180 ModRegRm
.MemoryAddress
);
4185 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg
)
4187 BOOLEAN OperandSize
, AddressSize
;
4188 SOFT386_MOD_REG_RM ModRegRm
;
4190 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4192 /* Make sure this is the right instruction */
4193 ASSERT(Opcode
== 0x8E);
4195 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4197 /* The ADSIZE prefix toggles the address size */
4198 AddressSize
= !AddressSize
;
4201 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4203 /* The OPSIZE prefix toggles the operand size */
4204 OperandSize
= !OperandSize
;
4207 /* Get the operands */
4208 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4210 /* Exception occurred */
4214 if ((ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4215 || ((SOFT386_SEG_REGS
)ModRegRm
.Register
== SOFT386_REG_CS
))
4218 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4224 ULONG Dummy
, Selector
;
4226 if (!Soft386ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4228 /* Exception occurred */
4232 return Soft386LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4236 USHORT Dummy
, Selector
;
4238 if (!Soft386ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4240 /* Exception occurred */
4244 return Soft386LoadSegment(State
, ModRegRm
.Register
, Selector
);
4248 SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde
)
4250 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4252 /* Make sure this is the right instruction */
4253 ASSERT(Opcode
== 0x98);
4255 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4257 /* The OPSIZE prefix toggles the size */
4260 else if (State
->PrefixFlags
!= 0)
4262 /* Invalid prefix */
4263 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4269 /* Sign extend AX to EAX */
4270 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= MAKELONG
4272 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
4273 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4279 /* Sign extend AL to AX */
4280 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
=
4281 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4288 SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq
)
4290 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4292 /* Make sure this is the right instruction */
4293 ASSERT(Opcode
== 0x99);
4295 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4297 /* The OPSIZE prefix toggles the size */
4300 else if (State
->PrefixFlags
!= 0)
4302 /* Invalid prefix */
4303 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4309 /* Sign extend EAX to EDX:EAX */
4310 State
->GeneralRegs
[SOFT386_REG_EDX
].Long
=
4311 (State
->GeneralRegs
[SOFT386_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4312 ? 0xFFFFFFFF : 0x00000000;
4316 /* Sign extend AX to DX:AX */
4317 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
=
4318 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4325 SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs
)
4327 // TODO: NOT IMPLEMENTED
4333 SOFT386_OPCODE_HANDLER(Soft386OpcodeWait
)
4335 // TODO: NOT IMPLEMENTED
4341 SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags
)
4343 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4345 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4347 /* Invalid prefix */
4348 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4352 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4354 /* This OPSIZE prefix toggles the size */
4358 /* Check for VM86 mode when IOPL is not 3 */
4359 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4361 /* Call the VM86 monitor */
4362 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4366 /* Push the flags */
4367 if (Size
) return Soft386StackPush(State
, State
->Flags
.Long
);
4368 else return Soft386StackPush(State
, LOWORD(State
->Flags
.Long
));
4371 SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags
)
4373 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4374 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4377 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4379 /* Invalid prefix */
4380 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4384 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4386 /* This OPSIZE prefix toggles the size */
4390 /* Pop the new flags */
4391 if (!Soft386StackPop(State
, &NewFlags
))
4393 /* Exception occurred */
4397 if (!State
->Flags
.Vm
)
4399 /* Check the current privilege level */
4407 /* Memorize the old state of RF */
4408 BOOLEAN OldRf
= State
->Flags
.Rf
;
4410 State
->Flags
.Long
= NewFlags
;
4412 /* Restore VM and RF */
4413 State
->Flags
.Vm
= FALSE
;
4414 State
->Flags
.Rf
= OldRf
;
4416 /* Clear VIF and VIP */
4417 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4419 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4421 /* Restore the reserved bits */
4422 State
->Flags
.AlwaysSet
= TRUE
;
4423 State
->Flags
.Reserved0
= FALSE
;
4424 State
->Flags
.Reserved1
= FALSE
;
4430 /* Memorize the old state of IF and IOPL */
4431 BOOLEAN OldIf
= State
->Flags
.If
;
4432 UINT OldIopl
= State
->Flags
.Iopl
;
4437 /* Memorize the old state of RF */
4438 BOOLEAN OldRf
= State
->Flags
.Rf
;
4440 State
->Flags
.Long
= NewFlags
;
4442 /* Restore VM and RF */
4443 State
->Flags
.Vm
= FALSE
;
4444 State
->Flags
.Rf
= OldRf
;
4446 /* Clear VIF and VIP */
4447 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4449 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4451 /* Restore the reserved bits and IOPL */
4452 State
->Flags
.AlwaysSet
= TRUE
;
4453 State
->Flags
.Reserved0
= FALSE
;
4454 State
->Flags
.Reserved1
= FALSE
;
4455 State
->Flags
.Iopl
= OldIopl
;
4457 /* Check if the user doesn't have the privilege to change IF */
4458 if (Cpl
> State
->Flags
.Iopl
)
4461 State
->Flags
.If
= OldIf
;
4467 /* Check the IOPL */
4468 if (State
->Flags
.Iopl
== 3)
4472 /* Memorize the old state of RF, VIF and VIP */
4473 BOOLEAN OldRf
= State
->Flags
.Rf
;
4474 BOOLEAN OldVif
= State
->Flags
.Vif
;
4475 BOOLEAN OldVip
= State
->Flags
.Vip
;
4477 State
->Flags
.Long
= NewFlags
;
4479 /* Restore VM, RF, VIF and VIP */
4480 State
->Flags
.Vm
= TRUE
;
4481 State
->Flags
.Rf
= OldRf
;
4482 State
->Flags
.Vif
= OldVif
;
4483 State
->Flags
.Vip
= OldVip
;
4485 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4487 /* Restore the reserved bits and IOPL */
4488 State
->Flags
.AlwaysSet
= TRUE
;
4489 State
->Flags
.Reserved0
= FALSE
;
4490 State
->Flags
.Reserved1
= FALSE
;
4491 State
->Flags
.Iopl
= 3;
4495 /* Call the VM86 monitor */
4496 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4504 SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf
)
4506 /* Make sure this is the right instruction */
4507 ASSERT(Opcode
== 0x9E);
4509 /* Set the low-order byte of FLAGS to AH */
4510 State
->Flags
.Long
&= 0xFFFFFF00;
4511 State
->Flags
.Long
|= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
;
4513 /* Restore the reserved bits of FLAGS */
4514 State
->Flags
.AlwaysSet
= TRUE
;
4515 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4520 SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf
)
4522 /* Make sure this is the right instruction */
4523 ASSERT(Opcode
== 0x9F);
4525 /* Set AH to the low-order byte of FLAGS */
4526 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4531 SOFT386_OPCODE_HANDLER(Soft386OpcodeRet
)
4533 ULONG ReturnAddress
;
4534 USHORT BytesToPop
= 0;
4535 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4537 /* Make sure this is the right instruction */
4538 ASSERT((Opcode
& 0xFE) == 0xC2);
4540 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4542 /* Invalid prefix */
4543 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4547 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4549 /* The OPSIZE prefix toggles the size */
4555 /* Fetch the number of bytes to pop after the return */
4556 if (!Soft386FetchWord(State
, &BytesToPop
)) return FALSE
;
4559 /* Pop the return address */
4560 if (!Soft386StackPop(State
, &ReturnAddress
)) return FALSE
;
4562 /* Return to the calling procedure, and if necessary, pop the parameters */
4565 State
->InstPtr
.Long
= ReturnAddress
;
4566 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
+= BytesToPop
;
4570 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4571 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
+= BytesToPop
;
4577 SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes
)
4579 UCHAR FarPointer
[6];
4580 BOOLEAN OperandSize
, AddressSize
;
4581 SOFT386_MOD_REG_RM ModRegRm
;
4583 /* Make sure this is the right instruction */
4584 ASSERT((Opcode
& 0xFE) == 0xC4);
4586 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4588 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4590 /* The ADSIZE prefix toggles the size */
4591 AddressSize
= !AddressSize
;
4594 /* Get the operands */
4595 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4597 /* Exception occurred */
4601 if (!ModRegRm
.Memory
)
4603 /* Check if this is a BOP and the host supports BOPs */
4604 if ((Opcode
== 0xC4)
4605 && (ModRegRm
.Register
== SOFT386_REG_EAX
)
4606 && (ModRegRm
.SecondRegister
== SOFT386_REG_ESP
)
4607 && (State
->BopCallback
!= NULL
))
4611 /* Fetch the BOP code */
4612 if (!Soft386FetchWord(State
, &BopCode
))
4614 /* Exception occurred */
4618 /* Call the BOP handler */
4619 State
->BopCallback(State
, BopCode
);
4621 /* Return success */
4626 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4630 if (!Soft386ReadMemory(State
,
4631 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
)
4632 ? State
->SegmentOverride
: SOFT386_REG_DS
,
4633 ModRegRm
.MemoryAddress
,
4636 OperandSize
? 6 : 4))
4638 /* Exception occurred */
4644 ULONG Offset
= *((PULONG
)FarPointer
);
4645 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4647 /* Set the register to the offset */
4648 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4650 /* Load the segment */
4651 return Soft386LoadSegment(State
,
4653 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4658 USHORT Offset
= *((PUSHORT
)FarPointer
);
4659 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4661 /* Set the register to the offset */
4662 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4664 /* Load the segment */
4665 return Soft386LoadSegment(State
,
4667 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4672 SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter
)
4675 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4678 SOFT386_REG FramePointer
;
4680 /* Make sure this is the right instruction */
4681 ASSERT(Opcode
== 0xC8);
4683 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4685 /* Invalid prefix */
4686 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4690 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4692 /* The OPSIZE prefix toggles the size */
4696 if (!Soft386FetchWord(State
, &FrameSize
))
4698 /* Exception occurred */
4702 if (!Soft386FetchByte(State
, &NestingLevel
))
4704 /* Exception occurred */
4709 if (!Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
))
4711 /* Exception occurred */
4716 FramePointer
= State
->GeneralRegs
[SOFT386_REG_ESP
];
4718 /* Set up the nested procedure stacks */
4719 for (i
= 1; i
< NestingLevel
; i
++)
4723 State
->GeneralRegs
[SOFT386_REG_EBP
].Long
-= 4;
4724 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
4728 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
-= 2;
4729 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
);
4733 if (NestingLevel
> 0) Soft386StackPush(State
, FramePointer
.Long
);
4735 /* Set EBP to the frame pointer */
4736 State
->GeneralRegs
[SOFT386_REG_EBP
] = FramePointer
;
4738 /* Reserve space for the frame */
4739 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4740 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
-= FrameSize
;
4745 SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave
)
4747 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4749 /* Make sure this is the right instruction */
4750 ASSERT(Opcode
== 0xC9);
4752 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4754 /* Invalid prefix */
4755 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4759 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4761 /* The OPSIZE prefix toggles the size */
4767 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4768 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= State
->GeneralRegs
[SOFT386_REG_EBP
].Long
;
4770 /* Pop the saved base pointer from the stack */
4771 return Soft386StackPop(State
, &State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
4777 /* Set the stack pointer (SP) to the base pointer (BP) */
4778 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
;
4780 /* Pop the saved base pointer from the stack */
4781 if (Soft386StackPop(State
, &Value
))
4783 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
= LOWORD(Value
);
4790 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm
)
4792 // TODO: NOT IMPLEMENTED
4798 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar
)
4800 // TODO: NOT IMPLEMENTED
4806 SOFT386_OPCODE_HANDLER(Soft386OpcodeInt
)
4809 SOFT386_IDT_ENTRY IdtEntry
;
4815 /* This is the INT3 instruction */
4822 /* Fetch the interrupt number */
4823 if (!Soft386FetchByte(State
, &IntNum
))
4825 /* Exception occurred */
4834 /* Don't do anything if OF is cleared */
4835 if (!State
->Flags
.Of
) return TRUE
;
4838 IntNum
= SOFT386_EXCEPTION_OF
;
4845 /* Should not happen */
4850 /* Get the interrupt vector */
4851 if (!Soft386GetIntVector(State
, IntNum
, &IdtEntry
))
4853 /* Exception occurred */
4857 /* Perform the interrupt */
4858 if (!Soft386InterruptInternal(State
,
4860 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4863 /* Exception occurred */
4870 SOFT386_OPCODE_HANDLER(Soft386OpcodeIret
)
4873 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4874 SOFT386_FLAGS_REG NewFlags
;
4875 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4877 /* Make sure this is the right instruction */
4878 ASSERT(Opcode
== 0xCF);
4880 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4882 /* Invalid prefix */
4883 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4887 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4889 /* The OPSIZE prefix toggles the size */
4894 if (!Soft386StackPop(State
, &InstPtr
))
4896 /* Exception occurred */
4901 if (!Soft386StackPop(State
, &CodeSel
))
4903 /* Exception occurred */
4908 if (!Soft386StackPop(State
, &NewFlags
.Long
))
4910 /* Exception occurred */
4914 /* Check for protected mode */
4915 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
4917 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4919 if (State
->Flags
.Vm
)
4921 /* Return from VM86 mode */
4923 /* Check the IOPL */
4924 if (State
->Flags
.Iopl
== 3)
4927 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4930 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
4932 /* Exception occurred */
4936 /* Set the new flags */
4937 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4938 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4939 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4940 State
->Flags
.Iopl
= 3;
4944 /* Call the VM86 monitor */
4945 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4952 if (State
->Flags
.Nt
)
4954 /* Nested task return */
4962 /* Return to VM86 mode */
4963 ULONG Es
, Ds
, Fs
, Gs
;
4965 /* Pop ESP, SS, ES, FS, GS */
4966 if (!Soft386StackPop(State
, &StackPtr
)) return FALSE
;
4967 if (!Soft386StackPop(State
, &StackSel
)) return FALSE
;
4968 if (!Soft386StackPop(State
, &Es
)) return FALSE
;
4969 if (!Soft386StackPop(State
, &Ds
)) return FALSE
;
4970 if (!Soft386StackPop(State
, &Fs
)) return FALSE
;
4971 if (!Soft386StackPop(State
, &Gs
)) return FALSE
;
4973 /* Set the new IP */
4974 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4976 /* Set the new flags */
4977 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4978 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4979 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4981 /* Load the new segments */
4982 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
)) return FALSE
;
4983 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
)) return FALSE
;
4984 if (!Soft386LoadSegment(State
, SOFT386_REG_ES
, Es
)) return FALSE
;
4985 if (!Soft386LoadSegment(State
, SOFT386_REG_DS
, Ds
)) return FALSE
;
4986 if (!Soft386LoadSegment(State
, SOFT386_REG_FS
, Fs
)) return FALSE
;
4987 if (!Soft386LoadSegment(State
, SOFT386_REG_GS
, Gs
)) return FALSE
;
4992 /* Load the new CS */
4993 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
4995 /* Exception occurred */
5000 if (Size
) State
->InstPtr
.Long
= InstPtr
;
5001 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
5003 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5006 if (!Soft386StackPop(State
, &StackPtr
))
5013 if (!Soft386StackPop(State
, &StackSel
))
5020 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
))
5027 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= StackPtr
;
5028 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= LOWORD(StackPtr
);
5031 /* Set the new flags */
5032 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
5033 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
5034 State
->Flags
.AlwaysSet
= TRUE
;
5036 /* Set additional flags */
5037 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
5038 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
5040 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5042 /* Update the CPL */
5043 Cpl
= Soft386GetCurrentPrivLevel(State
);
5045 /* Check segment security */
5046 for (i
= 0; i
<= SOFT386_NUM_SEG_REGS
; i
++)
5048 /* Don't check CS or SS */
5049 if ((i
== SOFT386_REG_CS
) || (i
== SOFT386_REG_SS
)) continue;
5051 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
5052 && (!State
->SegmentRegs
[i
].Executable
5053 || !State
->SegmentRegs
[i
].DirConf
))
5055 /* Load the NULL descriptor in the segment */
5056 if (!Soft386LoadSegment(State
, i
, 0)) return FALSE
;
5063 if (Size
&& (InstPtr
& 0xFFFF0000))
5066 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
5071 State
->InstPtr
.Long
= InstPtr
;
5074 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5076 /* Exception occurred */
5080 /* Set the new flags */
5081 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5082 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5083 State
->Flags
.AlwaysSet
= TRUE
;
5089 SOFT386_OPCODE_HANDLER(Soft386OpcodeAam
)
5092 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5094 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5096 /* Invalid prefix */
5097 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5101 /* Fetch the base */
5102 if (!Soft386FetchByte(State
, &Base
))
5104 /* Exception occurred */
5108 /* Check if the base is zero */
5112 Soft386Exception(State
, SOFT386_EXCEPTION_DE
);
5117 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= Value
/ Base
;
5118 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
%= Base
;
5121 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5122 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5123 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5128 SOFT386_OPCODE_HANDLER(Soft386OpcodeAad
)
5131 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5133 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5135 /* Invalid prefix */
5136 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5140 /* Fetch the base */
5141 if (!Soft386FetchByte(State
, &Base
))
5143 /* Exception occurred */
5148 Value
+= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
* Base
;
5149 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
;
5152 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5153 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5154 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5159 SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat
)
5161 // TODO: NOT IMPLEMENTED
5167 SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop
)
5170 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5173 /* Make sure this is the right instruction */
5174 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
5176 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5178 /* Invalid prefix */
5179 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5183 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5185 /* The OPSIZE prefix toggles the size */
5189 if (Size
) Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].Long
) == 0);
5190 else Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
) == 0);
5194 /* Additional rule for LOOPNZ */
5195 if (State
->Flags
.Zf
) Condition
= FALSE
;
5200 /* Additional rule for LOOPZ */
5201 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5204 /* Fetch the offset */
5205 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5207 /* An exception occurred */
5213 /* Move the instruction pointer */
5214 State
->InstPtr
.Long
+= Offset
;
5220 SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz
)
5223 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5226 /* Make sure this is the right instruction */
5227 ASSERT(Opcode
== 0xE3);
5229 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5231 /* Invalid prefix */
5232 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5236 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5238 /* The OPSIZE prefix toggles the size */
5242 if (Size
) Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].Long
== 0);
5243 else Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
== 0);
5245 /* Fetch the offset */
5246 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5248 /* An exception occurred */
5254 /* Move the instruction pointer */
5255 State
->InstPtr
.Long
+= Offset
;
5261 SOFT386_OPCODE_HANDLER(Soft386OpcodeCall
)
5263 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5265 /* Make sure this is the right instruction */
5266 ASSERT(Opcode
== 0xE8);
5268 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5270 /* The OPSIZE prefix toggles the size */
5273 else if (State
->PrefixFlags
!= 0)
5275 /* Invalid prefix */
5276 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5284 /* Fetch the offset */
5285 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5287 /* An exception occurred */
5291 /* Push the current value of the instruction pointer */
5292 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5294 /* Exception occurred */
5298 /* Move the instruction pointer */
5299 State
->InstPtr
.Long
+= Offset
;
5305 /* Fetch the offset */
5306 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5308 /* An exception occurred */
5312 /* Push the current value of the instruction pointer */
5313 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5315 /* Exception occurred */
5319 /* Move the instruction pointer */
5320 State
->InstPtr
.LowWord
+= Offset
;
5326 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp
)
5328 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5330 /* Make sure this is the right instruction */
5331 ASSERT(Opcode
== 0xE9);
5333 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5335 /* The OPSIZE prefix toggles the size */
5338 else if (State
->PrefixFlags
!= 0)
5340 /* Invalid prefix */
5341 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5349 /* Fetch the offset */
5350 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5352 /* An exception occurred */
5356 /* Move the instruction pointer */
5357 State
->InstPtr
.Long
+= Offset
;
5363 /* Fetch the offset */
5364 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5366 /* An exception occurred */
5370 /* Move the instruction pointer */
5371 State
->InstPtr
.LowWord
+= Offset
;
5377 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs
)
5379 // TODO: NOT IMPLEMENTED
5385 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset
)
5387 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5390 /* Make sure this is the right instruction */
5391 ASSERT(Opcode
== 0xA0);
5393 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5395 /* The OPSIZE prefix toggles the size */
5401 if (!Soft386FetchDword(State
, &Offset
))
5403 /* Exception occurred */
5411 if (!Soft386FetchWord(State
, &WordOffset
))
5413 /* Exception occurred */
5417 Offset
= (ULONG
)WordOffset
;
5420 /* Read from memory */
5421 return Soft386ReadMemory(State
,
5422 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5423 State
->SegmentOverride
: SOFT386_REG_DS
,
5426 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5430 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset
)
5432 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5434 /* Make sure this is the right instruction */
5435 ASSERT(Opcode
== 0xA1);
5437 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5439 /* The OPSIZE prefix toggles the size */
5447 if (!Soft386FetchDword(State
, &Offset
))
5449 /* Exception occurred */
5453 /* Read from memory */
5454 return Soft386ReadMemory(State
,
5455 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5456 State
->SegmentOverride
: SOFT386_REG_DS
,
5459 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5466 if (!Soft386FetchWord(State
, &Offset
))
5468 /* Exception occurred */
5472 /* Read from memory */
5473 return Soft386ReadMemory(State
,
5474 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5475 State
->SegmentOverride
: SOFT386_REG_DS
,
5478 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
5483 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl
)
5485 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5488 /* Make sure this is the right instruction */
5489 ASSERT(Opcode
== 0xA2);
5491 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5493 /* The OPSIZE prefix toggles the size */
5499 if (!Soft386FetchDword(State
, &Offset
))
5501 /* Exception occurred */
5509 if (!Soft386FetchWord(State
, &WordOffset
))
5511 /* Exception occurred */
5515 Offset
= (ULONG
)WordOffset
;
5518 /* Write to memory */
5519 return Soft386WriteMemory(State
,
5520 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5521 State
->SegmentOverride
: SOFT386_REG_DS
,
5523 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5527 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax
)
5529 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5531 /* Make sure this is the right instruction */
5532 ASSERT(Opcode
== 0xA3);
5534 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5536 /* The OPSIZE prefix toggles the size */
5544 if (!Soft386FetchDword(State
, &Offset
))
5546 /* Exception occurred */
5550 /* Write to memory */
5551 return Soft386WriteMemory(State
,
5552 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5553 State
->SegmentOverride
: SOFT386_REG_DS
,
5555 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5562 if (!Soft386FetchWord(State
, &Offset
))
5564 /* Exception occurred */
5568 /* Write to memory */
5569 return Soft386WriteMemory(State
,
5570 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5571 State
->SegmentOverride
: SOFT386_REG_DS
,
5573 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,