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_LOCK
)
3762 /* Invalid prefix */
3763 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3767 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3769 /* The OPSIZE prefix toggles the size */
3777 if (!Soft386FetchDword(State
, &Data
))
3779 /* Exception occurred */
3783 /* Call the internal API */
3784 return Soft386StackPush(State
, Data
);
3790 if (!Soft386FetchWord(State
, &Data
))
3792 /* Exception occurred */
3796 /* Call the internal API */
3797 return Soft386StackPush(State
, Data
);
3801 SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm
)
3803 BOOLEAN OperandSize
, AddressSize
;
3804 SOFT386_MOD_REG_RM ModRegRm
;
3808 /* Make sure this is the right instruction */
3809 ASSERT((Opcode
& 0xFD) == 0x69);
3811 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3813 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3815 /* The ADSIZE prefix toggles the address size */
3816 AddressSize
= !AddressSize
;
3819 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
3821 /* The OPSIZE prefix toggles the operand size */
3822 OperandSize
= !OperandSize
;
3825 /* Fetch the parameters */
3826 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3828 /* Exception occurred */
3836 /* Fetch the immediate operand */
3837 if (!Soft386FetchByte(State
, (PUCHAR
)&Byte
))
3839 /* Exception occurred */
3843 Multiplier
= (LONG
)Byte
;
3851 /* Fetch the immediate operand */
3852 if (!Soft386FetchDword(State
, (PULONG
)&Dword
))
3854 /* Exception occurred */
3864 /* Fetch the immediate operand */
3865 if (!Soft386FetchWord(State
, (PUSHORT
)&Word
))
3867 /* Exception occurred */
3871 Multiplier
= (LONG
)Word
;
3877 LONG RegValue
, Multiplicand
;
3879 /* Read the operands */
3880 if (!Soft386ReadModrmDwordOperands(State
,
3883 (PULONG
)&Multiplicand
))
3885 /* Exception occurred */
3890 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3894 SHORT RegValue
, Multiplicand
;
3896 /* Read the operands */
3897 if (!Soft386ReadModrmWordOperands(State
,
3900 (PUSHORT
)&Multiplicand
))
3902 /* Exception occurred */
3907 Product
= (LONGLONG
)Multiplicand
* (LONGLONG
)Multiplier
;
3910 /* Check for carry/overflow */
3911 if ((Product
< LONG_MIN
) || (Product
> LONG_MAX
))
3913 State
->Flags
.Cf
= State
->Flags
.Of
= TRUE
;
3915 else State
->Flags
.Cf
= State
->Flags
.Of
= FALSE
;
3917 /* Write-back the result */
3918 return Soft386WriteModrmDwordOperands(State
,
3921 (ULONG
)((LONG
)Product
));
3924 SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm
)
3928 /* Make sure this is the right instruction */
3929 ASSERT(Opcode
== 0x6A);
3931 if (!Soft386FetchByte(State
, &Data
))
3933 /* Exception occurred */
3937 /* Call the internal API */
3938 return Soft386StackPush(State
, Data
);
3941 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm
)
3943 UCHAR FirstValue
, SecondValue
, Result
;
3944 SOFT386_MOD_REG_RM ModRegRm
;
3945 BOOLEAN AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
3947 /* Make sure this is the right instruction */
3948 ASSERT((Opcode
& 0xFD) == 0x88);
3950 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
3952 /* The ADSIZE prefix toggles the size */
3953 AddressSize
= !AddressSize
;
3955 else if (State
->PrefixFlags
3956 & ~(SOFT386_PREFIX_ADSIZE
3957 | SOFT386_PREFIX_SEG
3958 | SOFT386_PREFIX_LOCK
))
3960 /* Invalid prefix */
3961 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
3965 /* Get the operands */
3966 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
3968 /* Exception occurred */
3972 if (!Soft386ReadModrmByteOperands(State
,
3977 /* Exception occurred */
3981 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
3982 else Result
= FirstValue
;
3984 /* Write back the result */
3985 return Soft386WriteModrmByteOperands(State
,
3987 Opcode
& SOFT386_OPCODE_WRITE_REG
,
3992 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm
)
3994 SOFT386_MOD_REG_RM ModRegRm
;
3995 BOOLEAN OperandSize
, AddressSize
;
3997 /* Make sure this is the right instruction */
3998 ASSERT((Opcode
& 0xFD) == 0x89);
4000 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4002 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4004 /* The ADSIZE prefix toggles the address size */
4005 AddressSize
= !AddressSize
;
4008 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4010 /* The OPSIZE prefix toggles the operand size */
4011 OperandSize
= !OperandSize
;
4014 if (State
->PrefixFlags
4015 & ~(SOFT386_PREFIX_ADSIZE
4016 | SOFT386_PREFIX_OPSIZE
4017 | SOFT386_PREFIX_SEG
4018 | SOFT386_PREFIX_LOCK
))
4020 /* Invalid prefix */
4021 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4025 /* Get the operands */
4026 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4028 /* Exception occurred */
4032 /* Check the operand size */
4035 ULONG FirstValue
, SecondValue
, Result
;
4037 if (!Soft386ReadModrmDwordOperands(State
,
4042 /* Exception occurred */
4046 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4047 else Result
= FirstValue
;
4049 /* Write back the result */
4050 return Soft386WriteModrmDwordOperands(State
,
4052 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4057 USHORT FirstValue
, SecondValue
, Result
;
4059 if (!Soft386ReadModrmWordOperands(State
,
4064 /* Exception occurred */
4068 if (Opcode
& SOFT386_OPCODE_WRITE_REG
) Result
= SecondValue
;
4069 else Result
= FirstValue
;
4071 /* Write back the result */
4072 return Soft386WriteModrmWordOperands(State
,
4074 Opcode
& SOFT386_OPCODE_WRITE_REG
,
4079 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg
)
4081 BOOLEAN OperandSize
, AddressSize
;
4082 SOFT386_MOD_REG_RM ModRegRm
;
4084 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4086 /* Make sure this is the right instruction */
4087 ASSERT(Opcode
== 0x8C);
4089 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4091 /* The ADSIZE prefix toggles the address size */
4092 AddressSize
= !AddressSize
;
4095 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4097 /* The OPSIZE prefix toggles the operand size */
4098 OperandSize
= !OperandSize
;
4101 /* Get the operands */
4102 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4104 /* Exception occurred */
4108 if (ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4111 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4117 return Soft386WriteModrmDwordOperands(State
,
4120 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4124 return Soft386WriteModrmWordOperands(State
,
4127 State
->SegmentRegs
[ModRegRm
.Register
].Selector
);
4131 SOFT386_OPCODE_HANDLER(Soft386OpcodeLea
)
4133 SOFT386_MOD_REG_RM ModRegRm
;
4134 BOOLEAN OperandSize
, AddressSize
;
4136 /* Make sure this is the right instruction */
4137 ASSERT(Opcode
== 0x8D);
4139 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4141 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4143 /* The ADSIZE prefix toggles the address size */
4144 AddressSize
= !AddressSize
;
4147 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4149 /* The OPSIZE prefix toggles the operand size */
4150 OperandSize
= !OperandSize
;
4153 /* Get the operands */
4154 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4156 /* Exception occurred */
4160 /* The second operand must be memory */
4161 if (!ModRegRm
.Memory
)
4164 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4168 /* Write the address to the register */
4171 return Soft386WriteModrmDwordOperands(State
,
4174 ModRegRm
.MemoryAddress
);
4178 return Soft386WriteModrmWordOperands(State
,
4181 ModRegRm
.MemoryAddress
);
4186 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg
)
4188 BOOLEAN OperandSize
, AddressSize
;
4189 SOFT386_MOD_REG_RM ModRegRm
;
4191 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4193 /* Make sure this is the right instruction */
4194 ASSERT(Opcode
== 0x8E);
4196 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4198 /* The ADSIZE prefix toggles the address size */
4199 AddressSize
= !AddressSize
;
4202 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4204 /* The OPSIZE prefix toggles the operand size */
4205 OperandSize
= !OperandSize
;
4208 /* Get the operands */
4209 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4211 /* Exception occurred */
4215 if ((ModRegRm
.Register
>= SOFT386_NUM_SEG_REGS
)
4216 || ((SOFT386_SEG_REGS
)ModRegRm
.Register
== SOFT386_REG_CS
))
4219 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4225 ULONG Dummy
, Selector
;
4227 if (!Soft386ReadModrmDwordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4229 /* Exception occurred */
4233 return Soft386LoadSegment(State
, ModRegRm
.Register
, LOWORD(Selector
));
4237 USHORT Dummy
, Selector
;
4239 if (!Soft386ReadModrmWordOperands(State
, &ModRegRm
, &Dummy
, &Selector
))
4241 /* Exception occurred */
4245 return Soft386LoadSegment(State
, ModRegRm
.Register
, Selector
);
4249 SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde
)
4251 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4253 /* Make sure this is the right instruction */
4254 ASSERT(Opcode
== 0x98);
4256 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4258 /* The OPSIZE prefix toggles the size */
4261 else if (State
->PrefixFlags
!= 0)
4263 /* Invalid prefix */
4264 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4270 /* Sign extend AX to EAX */
4271 State
->GeneralRegs
[SOFT386_REG_EAX
].Long
= MAKELONG
4273 State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
4274 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4280 /* Sign extend AL to AX */
4281 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
=
4282 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
& SIGN_FLAG_BYTE
)
4289 SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq
)
4291 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4293 /* Make sure this is the right instruction */
4294 ASSERT(Opcode
== 0x99);
4296 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4298 /* The OPSIZE prefix toggles the size */
4301 else if (State
->PrefixFlags
!= 0)
4303 /* Invalid prefix */
4304 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4310 /* Sign extend EAX to EDX:EAX */
4311 State
->GeneralRegs
[SOFT386_REG_EDX
].Long
=
4312 (State
->GeneralRegs
[SOFT386_REG_EAX
].Long
& SIGN_FLAG_LONG
)
4313 ? 0xFFFFFFFF : 0x00000000;
4317 /* Sign extend AX to DX:AX */
4318 State
->GeneralRegs
[SOFT386_REG_EDX
].LowWord
=
4319 (State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
& SIGN_FLAG_WORD
)
4326 SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs
)
4328 // TODO: NOT IMPLEMENTED
4334 SOFT386_OPCODE_HANDLER(Soft386OpcodeWait
)
4336 // TODO: NOT IMPLEMENTED
4342 SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags
)
4344 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4346 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4348 /* Invalid prefix */
4349 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4353 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4355 /* This OPSIZE prefix toggles the size */
4359 /* Check for VM86 mode when IOPL is not 3 */
4360 if (State
->Flags
.Vm
&& (State
->Flags
.Iopl
!= 3))
4362 /* Call the VM86 monitor */
4363 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4367 /* Push the flags */
4368 if (Size
) return Soft386StackPush(State
, State
->Flags
.Long
);
4369 else return Soft386StackPush(State
, LOWORD(State
->Flags
.Long
));
4372 SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags
)
4374 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4375 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4378 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4380 /* Invalid prefix */
4381 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4385 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4387 /* This OPSIZE prefix toggles the size */
4391 /* Pop the new flags */
4392 if (!Soft386StackPop(State
, &NewFlags
))
4394 /* Exception occurred */
4398 if (!State
->Flags
.Vm
)
4400 /* Check the current privilege level */
4408 /* Memorize the old state of RF */
4409 BOOLEAN OldRf
= State
->Flags
.Rf
;
4411 State
->Flags
.Long
= NewFlags
;
4413 /* Restore VM and RF */
4414 State
->Flags
.Vm
= FALSE
;
4415 State
->Flags
.Rf
= OldRf
;
4417 /* Clear VIF and VIP */
4418 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4420 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4422 /* Restore the reserved bits */
4423 State
->Flags
.AlwaysSet
= TRUE
;
4424 State
->Flags
.Reserved0
= FALSE
;
4425 State
->Flags
.Reserved1
= FALSE
;
4431 /* Memorize the old state of IF and IOPL */
4432 BOOLEAN OldIf
= State
->Flags
.If
;
4433 UINT OldIopl
= State
->Flags
.Iopl
;
4438 /* Memorize the old state of RF */
4439 BOOLEAN OldRf
= State
->Flags
.Rf
;
4441 State
->Flags
.Long
= NewFlags
;
4443 /* Restore VM and RF */
4444 State
->Flags
.Vm
= FALSE
;
4445 State
->Flags
.Rf
= OldRf
;
4447 /* Clear VIF and VIP */
4448 State
->Flags
.Vif
= State
->Flags
.Vip
= FALSE
;
4450 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4452 /* Restore the reserved bits and IOPL */
4453 State
->Flags
.AlwaysSet
= TRUE
;
4454 State
->Flags
.Reserved0
= FALSE
;
4455 State
->Flags
.Reserved1
= FALSE
;
4456 State
->Flags
.Iopl
= OldIopl
;
4458 /* Check if the user doesn't have the privilege to change IF */
4459 if (Cpl
> State
->Flags
.Iopl
)
4462 State
->Flags
.If
= OldIf
;
4468 /* Check the IOPL */
4469 if (State
->Flags
.Iopl
== 3)
4473 /* Memorize the old state of RF, VIF and VIP */
4474 BOOLEAN OldRf
= State
->Flags
.Rf
;
4475 BOOLEAN OldVif
= State
->Flags
.Vif
;
4476 BOOLEAN OldVip
= State
->Flags
.Vip
;
4478 State
->Flags
.Long
= NewFlags
;
4480 /* Restore VM, RF, VIF and VIP */
4481 State
->Flags
.Vm
= TRUE
;
4482 State
->Flags
.Rf
= OldRf
;
4483 State
->Flags
.Vif
= OldVif
;
4484 State
->Flags
.Vip
= OldVip
;
4486 else State
->Flags
.LowWord
= LOWORD(NewFlags
);
4488 /* Restore the reserved bits and IOPL */
4489 State
->Flags
.AlwaysSet
= TRUE
;
4490 State
->Flags
.Reserved0
= FALSE
;
4491 State
->Flags
.Reserved1
= FALSE
;
4492 State
->Flags
.Iopl
= 3;
4496 /* Call the VM86 monitor */
4497 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4505 SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf
)
4507 /* Make sure this is the right instruction */
4508 ASSERT(Opcode
== 0x9E);
4510 /* Set the low-order byte of FLAGS to AH */
4511 State
->Flags
.Long
&= 0xFFFFFF00;
4512 State
->Flags
.Long
|= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
;
4514 /* Restore the reserved bits of FLAGS */
4515 State
->Flags
.AlwaysSet
= TRUE
;
4516 State
->Flags
.Reserved0
= State
->Flags
.Reserved1
= FALSE
;
4521 SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf
)
4523 /* Make sure this is the right instruction */
4524 ASSERT(Opcode
== 0x9F);
4526 /* Set AH to the low-order byte of FLAGS */
4527 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= LOBYTE(State
->Flags
.Long
);
4532 SOFT386_OPCODE_HANDLER(Soft386OpcodeRet
)
4534 ULONG ReturnAddress
;
4535 USHORT BytesToPop
= 0;
4536 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4538 /* Make sure this is the right instruction */
4539 ASSERT((Opcode
& 0xFE) == 0xC2);
4541 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4543 /* Invalid prefix */
4544 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4548 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
4550 /* The OPSIZE prefix toggles the size */
4556 /* Fetch the number of bytes to pop after the return */
4557 if (!Soft386FetchWord(State
, &BytesToPop
)) return FALSE
;
4560 /* Pop the return address */
4561 if (!Soft386StackPop(State
, &ReturnAddress
)) return FALSE
;
4563 /* Return to the calling procedure, and if necessary, pop the parameters */
4566 State
->InstPtr
.Long
= ReturnAddress
;
4567 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
+= BytesToPop
;
4571 State
->InstPtr
.LowWord
= LOWORD(ReturnAddress
);
4572 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
+= BytesToPop
;
4578 SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes
)
4580 UCHAR FarPointer
[6];
4581 BOOLEAN OperandSize
, AddressSize
;
4582 SOFT386_MOD_REG_RM ModRegRm
;
4584 /* Make sure this is the right instruction */
4585 ASSERT((Opcode
& 0xFE) == 0xC4);
4587 OperandSize
= AddressSize
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4589 if (State
->PrefixFlags
& SOFT386_PREFIX_ADSIZE
)
4591 /* The ADSIZE prefix toggles the size */
4592 AddressSize
= !AddressSize
;
4595 /* Get the operands */
4596 if (!Soft386ParseModRegRm(State
, AddressSize
, &ModRegRm
))
4598 /* Exception occurred */
4602 if (!ModRegRm
.Memory
)
4604 /* Check if this is a BOP and the host supports BOPs */
4605 if ((Opcode
== 0xC4)
4606 && (ModRegRm
.Register
== SOFT386_REG_EAX
)
4607 && (ModRegRm
.SecondRegister
== SOFT386_REG_ESP
)
4608 && (State
->BopCallback
!= NULL
))
4612 /* Fetch the BOP code */
4613 if (!Soft386FetchWord(State
, &BopCode
))
4615 /* Exception occurred */
4619 /* Call the BOP handler */
4620 State
->BopCallback(State
, BopCode
);
4622 /* Return success */
4627 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4631 if (!Soft386ReadMemory(State
,
4632 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
)
4633 ? State
->SegmentOverride
: SOFT386_REG_DS
,
4634 ModRegRm
.MemoryAddress
,
4637 OperandSize
? 6 : 4))
4639 /* Exception occurred */
4645 ULONG Offset
= *((PULONG
)FarPointer
);
4646 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(ULONG
)]);
4648 /* Set the register to the offset */
4649 State
->GeneralRegs
[ModRegRm
.Register
].Long
= Offset
;
4651 /* Load the segment */
4652 return Soft386LoadSegment(State
,
4654 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4659 USHORT Offset
= *((PUSHORT
)FarPointer
);
4660 USHORT Segment
= *((PUSHORT
)&FarPointer
[sizeof(USHORT
)]);
4662 /* Set the register to the offset */
4663 State
->GeneralRegs
[ModRegRm
.Register
].LowWord
= Offset
;
4665 /* Load the segment */
4666 return Soft386LoadSegment(State
,
4668 ? SOFT386_REG_ES
: SOFT386_REG_DS
,
4673 SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter
)
4676 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4679 SOFT386_REG FramePointer
;
4681 /* Make sure this is the right instruction */
4682 ASSERT(Opcode
== 0xC8);
4684 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4686 /* Invalid prefix */
4687 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4691 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4693 /* The OPSIZE prefix toggles the size */
4697 if (!Soft386FetchWord(State
, &FrameSize
))
4699 /* Exception occurred */
4703 if (!Soft386FetchByte(State
, &NestingLevel
))
4705 /* Exception occurred */
4710 if (!Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
))
4712 /* Exception occurred */
4717 FramePointer
= State
->GeneralRegs
[SOFT386_REG_ESP
];
4719 /* Set up the nested procedure stacks */
4720 for (i
= 1; i
< NestingLevel
; i
++)
4724 State
->GeneralRegs
[SOFT386_REG_EBP
].Long
-= 4;
4725 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
4729 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
-= 2;
4730 Soft386StackPush(State
, State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
);
4734 if (NestingLevel
> 0) Soft386StackPush(State
, FramePointer
.Long
);
4736 /* Set EBP to the frame pointer */
4737 State
->GeneralRegs
[SOFT386_REG_EBP
] = FramePointer
;
4739 /* Reserve space for the frame */
4740 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
-= (ULONG
)FrameSize
;
4741 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
-= FrameSize
;
4746 SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave
)
4748 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4750 /* Make sure this is the right instruction */
4751 ASSERT(Opcode
== 0xC9);
4753 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4755 /* Invalid prefix */
4756 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4760 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4762 /* The OPSIZE prefix toggles the size */
4768 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4769 State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= State
->GeneralRegs
[SOFT386_REG_EBP
].Long
;
4771 /* Pop the saved base pointer from the stack */
4772 return Soft386StackPop(State
, &State
->GeneralRegs
[SOFT386_REG_EBP
].Long
);
4778 /* Set the stack pointer (SP) to the base pointer (BP) */
4779 State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
;
4781 /* Pop the saved base pointer from the stack */
4782 if (Soft386StackPop(State
, &Value
))
4784 State
->GeneralRegs
[SOFT386_REG_EBP
].LowWord
= LOWORD(Value
);
4791 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm
)
4793 // TODO: NOT IMPLEMENTED
4799 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar
)
4801 // TODO: NOT IMPLEMENTED
4807 SOFT386_OPCODE_HANDLER(Soft386OpcodeInt
)
4810 SOFT386_IDT_ENTRY IdtEntry
;
4816 /* This is the INT3 instruction */
4823 /* Fetch the interrupt number */
4824 if (!Soft386FetchByte(State
, &IntNum
))
4826 /* Exception occurred */
4835 /* Don't do anything if OF is cleared */
4836 if (!State
->Flags
.Of
) return TRUE
;
4839 IntNum
= SOFT386_EXCEPTION_OF
;
4846 /* Should not happen */
4851 /* Get the interrupt vector */
4852 if (!Soft386GetIntVector(State
, IntNum
, &IdtEntry
))
4854 /* Exception occurred */
4858 /* Perform the interrupt */
4859 if (!Soft386InterruptInternal(State
,
4861 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
4864 /* Exception occurred */
4871 SOFT386_OPCODE_HANDLER(Soft386OpcodeIret
)
4874 ULONG InstPtr
, CodeSel
, StackPtr
, StackSel
;
4875 SOFT386_FLAGS_REG NewFlags
;
4876 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
4878 /* Make sure this is the right instruction */
4879 ASSERT(Opcode
== 0xCF);
4881 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
4883 /* Invalid prefix */
4884 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
4888 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
4890 /* The OPSIZE prefix toggles the size */
4895 if (!Soft386StackPop(State
, &InstPtr
))
4897 /* Exception occurred */
4902 if (!Soft386StackPop(State
, &CodeSel
))
4904 /* Exception occurred */
4909 if (!Soft386StackPop(State
, &NewFlags
.Long
))
4911 /* Exception occurred */
4915 /* Check for protected mode */
4916 if (State
->ControlRegisters
[SOFT386_REG_CR0
] & SOFT386_CR0_PE
)
4918 INT Cpl
= Soft386GetCurrentPrivLevel(State
);
4920 if (State
->Flags
.Vm
)
4922 /* Return from VM86 mode */
4924 /* Check the IOPL */
4925 if (State
->Flags
.Iopl
== 3)
4928 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4931 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
4933 /* Exception occurred */
4937 /* Set the new flags */
4938 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4939 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4940 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4941 State
->Flags
.Iopl
= 3;
4945 /* Call the VM86 monitor */
4946 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
4953 if (State
->Flags
.Nt
)
4955 /* Nested task return */
4963 /* Return to VM86 mode */
4964 ULONG Es
, Ds
, Fs
, Gs
;
4966 /* Pop ESP, SS, ES, FS, GS */
4967 if (!Soft386StackPop(State
, &StackPtr
)) return FALSE
;
4968 if (!Soft386StackPop(State
, &StackSel
)) return FALSE
;
4969 if (!Soft386StackPop(State
, &Es
)) return FALSE
;
4970 if (!Soft386StackPop(State
, &Ds
)) return FALSE
;
4971 if (!Soft386StackPop(State
, &Fs
)) return FALSE
;
4972 if (!Soft386StackPop(State
, &Gs
)) return FALSE
;
4974 /* Set the new IP */
4975 State
->InstPtr
.Long
= LOWORD(InstPtr
);
4977 /* Set the new flags */
4978 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
4979 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
4980 State
->Flags
.AlwaysSet
= State
->Flags
.Vm
= TRUE
;
4982 /* Load the new segments */
4983 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
)) return FALSE
;
4984 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
)) return FALSE
;
4985 if (!Soft386LoadSegment(State
, SOFT386_REG_ES
, Es
)) return FALSE
;
4986 if (!Soft386LoadSegment(State
, SOFT386_REG_DS
, Ds
)) return FALSE
;
4987 if (!Soft386LoadSegment(State
, SOFT386_REG_FS
, Fs
)) return FALSE
;
4988 if (!Soft386LoadSegment(State
, SOFT386_REG_GS
, Gs
)) return FALSE
;
4993 /* Load the new CS */
4994 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
4996 /* Exception occurred */
5001 if (Size
) State
->InstPtr
.Long
= InstPtr
;
5002 else State
->InstPtr
.LowWord
= LOWORD(InstPtr
);
5004 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5007 if (!Soft386StackPop(State
, &StackPtr
))
5014 if (!Soft386StackPop(State
, &StackSel
))
5021 if (!Soft386LoadSegment(State
, SOFT386_REG_SS
, StackSel
))
5028 if (Size
) State
->GeneralRegs
[SOFT386_REG_ESP
].Long
= StackPtr
;
5029 else State
->GeneralRegs
[SOFT386_REG_ESP
].LowWord
= LOWORD(StackPtr
);
5032 /* Set the new flags */
5033 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& PROT_MODE_FLAGS_MASK
;
5034 else State
->Flags
.LowWord
= NewFlags
.LowWord
& PROT_MODE_FLAGS_MASK
;
5035 State
->Flags
.AlwaysSet
= TRUE
;
5037 /* Set additional flags */
5038 if (Cpl
<= State
->Flags
.Iopl
) State
->Flags
.If
= NewFlags
.If
;
5039 if (Cpl
== 0) State
->Flags
.Iopl
= NewFlags
.Iopl
;
5041 if (GET_SEGMENT_RPL(CodeSel
) > Cpl
)
5043 /* Update the CPL */
5044 Cpl
= Soft386GetCurrentPrivLevel(State
);
5046 /* Check segment security */
5047 for (i
= 0; i
<= SOFT386_NUM_SEG_REGS
; i
++)
5049 /* Don't check CS or SS */
5050 if ((i
== SOFT386_REG_CS
) || (i
== SOFT386_REG_SS
)) continue;
5052 if ((Cpl
> State
->SegmentRegs
[i
].Dpl
)
5053 && (!State
->SegmentRegs
[i
].Executable
5054 || !State
->SegmentRegs
[i
].DirConf
))
5056 /* Load the NULL descriptor in the segment */
5057 if (!Soft386LoadSegment(State
, i
, 0)) return FALSE
;
5064 if (Size
&& (InstPtr
& 0xFFFF0000))
5067 Soft386ExceptionWithErrorCode(State
, SOFT386_EXCEPTION_GP
, 0);
5072 State
->InstPtr
.Long
= InstPtr
;
5075 if (!Soft386LoadSegment(State
, SOFT386_REG_CS
, CodeSel
))
5077 /* Exception occurred */
5081 /* Set the new flags */
5082 if (Size
) State
->Flags
.Long
= NewFlags
.Long
& REAL_MODE_FLAGS_MASK
;
5083 else State
->Flags
.LowWord
= NewFlags
.LowWord
& REAL_MODE_FLAGS_MASK
;
5084 State
->Flags
.AlwaysSet
= TRUE
;
5090 SOFT386_OPCODE_HANDLER(Soft386OpcodeAam
)
5093 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5095 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5097 /* Invalid prefix */
5098 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5102 /* Fetch the base */
5103 if (!Soft386FetchByte(State
, &Base
))
5105 /* Exception occurred */
5109 /* Check if the base is zero */
5113 Soft386Exception(State
, SOFT386_EXCEPTION_DE
);
5118 State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
= Value
/ Base
;
5119 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
%= Base
;
5122 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5123 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5124 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5129 SOFT386_OPCODE_HANDLER(Soft386OpcodeAad
)
5132 UCHAR Value
= State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
;
5134 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5136 /* Invalid prefix */
5137 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5141 /* Fetch the base */
5142 if (!Soft386FetchByte(State
, &Base
))
5144 /* Exception occurred */
5149 Value
+= State
->GeneralRegs
[SOFT386_REG_EAX
].HighByte
* Base
;
5150 State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
= Value
;
5153 State
->Flags
.Zf
= (Value
== 0) ? TRUE
: FALSE
;
5154 State
->Flags
.Sf
= (Value
& SIGN_FLAG_BYTE
) ? TRUE
: FALSE
;
5155 State
->Flags
.Pf
= Soft386CalculateParity(Value
);
5160 SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat
)
5162 // TODO: NOT IMPLEMENTED
5168 SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop
)
5171 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5174 /* Make sure this is the right instruction */
5175 ASSERT((Opcode
>= 0xE0) && (Opcode
<= 0xE2));
5177 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5179 /* Invalid prefix */
5180 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5184 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5186 /* The OPSIZE prefix toggles the size */
5190 if (Size
) Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].Long
) != 0);
5191 else Condition
= ((--State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
) != 0);
5195 /* Additional rule for LOOPNZ */
5196 if (State
->Flags
.Zf
) Condition
= FALSE
;
5201 /* Additional rule for LOOPZ */
5202 if (!State
->Flags
.Zf
) Condition
= FALSE
;
5205 /* Fetch the offset */
5206 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5208 /* An exception occurred */
5214 /* Move the instruction pointer */
5215 State
->InstPtr
.Long
+= Offset
;
5221 SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz
)
5224 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5227 /* Make sure this is the right instruction */
5228 ASSERT(Opcode
== 0xE3);
5230 if (State
->PrefixFlags
& SOFT386_PREFIX_LOCK
)
5232 /* Invalid prefix */
5233 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5237 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5239 /* The OPSIZE prefix toggles the size */
5243 if (Size
) Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].Long
== 0);
5244 else Condition
= (State
->GeneralRegs
[SOFT386_REG_ECX
].LowWord
== 0);
5246 /* Fetch the offset */
5247 if (!Soft386FetchByte(State
, (PUCHAR
)&Offset
))
5249 /* An exception occurred */
5255 /* Move the instruction pointer */
5256 State
->InstPtr
.Long
+= Offset
;
5262 SOFT386_OPCODE_HANDLER(Soft386OpcodeCall
)
5264 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5266 /* Make sure this is the right instruction */
5267 ASSERT(Opcode
== 0xE8);
5269 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5271 /* The OPSIZE prefix toggles the size */
5274 else if (State
->PrefixFlags
!= 0)
5276 /* Invalid prefix */
5277 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5285 /* Fetch the offset */
5286 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5288 /* An exception occurred */
5292 /* Push the current value of the instruction pointer */
5293 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5295 /* Exception occurred */
5299 /* Move the instruction pointer */
5300 State
->InstPtr
.Long
+= Offset
;
5306 /* Fetch the offset */
5307 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5309 /* An exception occurred */
5313 /* Push the current value of the instruction pointer */
5314 if (!Soft386StackPush(State
, State
->InstPtr
.Long
))
5316 /* Exception occurred */
5320 /* Move the instruction pointer */
5321 State
->InstPtr
.LowWord
+= Offset
;
5327 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp
)
5329 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5331 /* Make sure this is the right instruction */
5332 ASSERT(Opcode
== 0xE9);
5334 if (State
->PrefixFlags
== SOFT386_PREFIX_OPSIZE
)
5336 /* The OPSIZE prefix toggles the size */
5339 else if (State
->PrefixFlags
!= 0)
5341 /* Invalid prefix */
5342 Soft386Exception(State
, SOFT386_EXCEPTION_UD
);
5350 /* Fetch the offset */
5351 if (!Soft386FetchDword(State
, (PULONG
)&Offset
))
5353 /* An exception occurred */
5357 /* Move the instruction pointer */
5358 State
->InstPtr
.Long
+= Offset
;
5364 /* Fetch the offset */
5365 if (!Soft386FetchWord(State
, (PUSHORT
)&Offset
))
5367 /* An exception occurred */
5371 /* Move the instruction pointer */
5372 State
->InstPtr
.LowWord
+= Offset
;
5378 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs
)
5380 // TODO: NOT IMPLEMENTED
5386 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset
)
5388 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5391 /* Make sure this is the right instruction */
5392 ASSERT(Opcode
== 0xA0);
5394 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5396 /* The OPSIZE prefix toggles the size */
5402 if (!Soft386FetchDword(State
, &Offset
))
5404 /* Exception occurred */
5412 if (!Soft386FetchWord(State
, &WordOffset
))
5414 /* Exception occurred */
5418 Offset
= (ULONG
)WordOffset
;
5421 /* Read from memory */
5422 return Soft386ReadMemory(State
,
5423 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5424 State
->SegmentOverride
: SOFT386_REG_DS
,
5427 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5431 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset
)
5433 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5435 /* Make sure this is the right instruction */
5436 ASSERT(Opcode
== 0xA1);
5438 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5440 /* The OPSIZE prefix toggles the size */
5448 if (!Soft386FetchDword(State
, &Offset
))
5450 /* Exception occurred */
5454 /* Read from memory */
5455 return Soft386ReadMemory(State
,
5456 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5457 State
->SegmentOverride
: SOFT386_REG_DS
,
5460 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5467 if (!Soft386FetchWord(State
, &Offset
))
5469 /* Exception occurred */
5473 /* Read from memory */
5474 return Soft386ReadMemory(State
,
5475 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5476 State
->SegmentOverride
: SOFT386_REG_DS
,
5479 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,
5484 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl
)
5486 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5489 /* Make sure this is the right instruction */
5490 ASSERT(Opcode
== 0xA2);
5492 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5494 /* The OPSIZE prefix toggles the size */
5500 if (!Soft386FetchDword(State
, &Offset
))
5502 /* Exception occurred */
5510 if (!Soft386FetchWord(State
, &WordOffset
))
5512 /* Exception occurred */
5516 Offset
= (ULONG
)WordOffset
;
5519 /* Write to memory */
5520 return Soft386WriteMemory(State
,
5521 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5522 State
->SegmentOverride
: SOFT386_REG_DS
,
5524 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowByte
,
5528 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax
)
5530 BOOLEAN Size
= State
->SegmentRegs
[SOFT386_REG_CS
].Size
;
5532 /* Make sure this is the right instruction */
5533 ASSERT(Opcode
== 0xA3);
5535 if (State
->PrefixFlags
& SOFT386_PREFIX_OPSIZE
)
5537 /* The OPSIZE prefix toggles the size */
5545 if (!Soft386FetchDword(State
, &Offset
))
5547 /* Exception occurred */
5551 /* Write to memory */
5552 return Soft386WriteMemory(State
,
5553 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5554 State
->SegmentOverride
: SOFT386_REG_DS
,
5556 &State
->GeneralRegs
[SOFT386_REG_EAX
].Long
,
5563 if (!Soft386FetchWord(State
, &Offset
))
5565 /* Exception occurred */
5569 /* Write to memory */
5570 return Soft386WriteMemory(State
,
5571 (State
->PrefixFlags
& SOFT386_PREFIX_SEG
) ?
5572 State
->SegmentOverride
: SOFT386_REG_DS
,
5574 &State
->GeneralRegs
[SOFT386_REG_EAX
].LowWord
,