[SOFT386]
[reactos.git] / lib / soft386 / opcodes.c
1 /*
2 * Soft386 386/486 CPU Emulation Library
3 * opcodes.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
26 #include <windef.h>
27 #include <limits.h>
28
29 // #define NDEBUG
30 #include <debug.h>
31
32 #include <soft386.h>
33 #include "opcodes.h"
34 #include "opgroups.h"
35 #include "common.h"
36
37 /* PUBLIC VARIABLES ***********************************************************/
38
39 SOFT386_OPCODE_HANDLER_PROC
40 Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] =
41 {
42 Soft386OpcodeAddByteModrm,
43 Soft386OpcodeAddModrm,
44 Soft386OpcodeAddByteModrm,
45 Soft386OpcodeAddModrm,
46 Soft386OpcodeAddAl,
47 Soft386OpcodeAddEax,
48 Soft386OpcodePushEs,
49 Soft386OpcodePopEs,
50 Soft386OpcodeOrByteModrm,
51 Soft386OpcodeOrModrm,
52 Soft386OpcodeOrByteModrm,
53 Soft386OpcodeOrModrm,
54 Soft386OpcodeOrAl,
55 Soft386OpcodeOrEax,
56 Soft386OpcodePushCs,
57 NULL, // TODO: OPCODE 0x0F NOT SUPPORTED
58 Soft386OpcodeAdcByteModrm,
59 Soft386OpcodeAdcModrm,
60 Soft386OpcodeAdcByteModrm,
61 Soft386OpcodeAdcModrm,
62 Soft386OpcodeAdcAl,
63 Soft386OpcodeAdcEax,
64 Soft386OpcodePushSs,
65 Soft386OpcodePopSs,
66 Soft386OpcodeSbbByteModrm,
67 Soft386OpcodeSbbModrm,
68 Soft386OpcodeSbbByteModrm,
69 Soft386OpcodeSbbModrm,
70 Soft386OpcodeSbbAl,
71 Soft386OpcodeSbbEax,
72 Soft386OpcodePushDs,
73 Soft386OpcodePopDs,
74 Soft386OpcodeAndByteModrm,
75 Soft386OpcodeAndModrm,
76 Soft386OpcodeAndByteModrm,
77 Soft386OpcodeAndModrm,
78 Soft386OpcodeAndAl,
79 Soft386OpcodeAndEax,
80 Soft386OpcodePrefix,
81 Soft386OpcodeDaa,
82 Soft386OpcodeCmpSubByteModrm,
83 Soft386OpcodeCmpSubModrm,
84 Soft386OpcodeCmpSubByteModrm,
85 Soft386OpcodeCmpSubModrm,
86 Soft386OpcodeCmpSubAl,
87 Soft386OpcodeCmpSubEax,
88 Soft386OpcodePrefix,
89 Soft386OpcodeDas,
90 Soft386OpcodeXorByteModrm,
91 Soft386OpcodeXorModrm,
92 Soft386OpcodeXorByteModrm,
93 Soft386OpcodeXorModrm,
94 Soft386OpcodeXorAl,
95 Soft386OpcodeXorEax,
96 Soft386OpcodePrefix,
97 Soft386OpcodeAaa,
98 Soft386OpcodeCmpSubByteModrm,
99 Soft386OpcodeCmpSubModrm,
100 Soft386OpcodeCmpSubByteModrm,
101 Soft386OpcodeCmpSubModrm,
102 Soft386OpcodeCmpSubAl,
103 Soft386OpcodeCmpSubEax,
104 Soft386OpcodePrefix,
105 Soft386OpcodeAas,
106 Soft386OpcodeIncrement,
107 Soft386OpcodeIncrement,
108 Soft386OpcodeIncrement,
109 Soft386OpcodeIncrement,
110 Soft386OpcodeIncrement,
111 Soft386OpcodeIncrement,
112 Soft386OpcodeIncrement,
113 Soft386OpcodeIncrement,
114 Soft386OpcodeDecrement,
115 Soft386OpcodeDecrement,
116 Soft386OpcodeDecrement,
117 Soft386OpcodeDecrement,
118 Soft386OpcodeDecrement,
119 Soft386OpcodeDecrement,
120 Soft386OpcodeDecrement,
121 Soft386OpcodeDecrement,
122 Soft386OpcodePushReg,
123 Soft386OpcodePushReg,
124 Soft386OpcodePushReg,
125 Soft386OpcodePushReg,
126 Soft386OpcodePushReg,
127 Soft386OpcodePushReg,
128 Soft386OpcodePushReg,
129 Soft386OpcodePushReg,
130 Soft386OpcodePopReg,
131 Soft386OpcodePopReg,
132 Soft386OpcodePopReg,
133 Soft386OpcodePopReg,
134 Soft386OpcodePopReg,
135 Soft386OpcodePopReg,
136 Soft386OpcodePopReg,
137 Soft386OpcodePopReg,
138 Soft386OpcodePushAll,
139 Soft386OpcodePopAll,
140 Soft386OpcodeBound,
141 Soft386OpcodeArpl,
142 Soft386OpcodePrefix,
143 Soft386OpcodePrefix,
144 Soft386OpcodePrefix,
145 Soft386OpcodePrefix,
146 Soft386OpcodePushImm,
147 Soft386OpcodeImulModrmImm,
148 Soft386OpcodePushByteImm,
149 Soft386OpcodeImulModrmImm,
150 NULL, // TODO: OPCODE 0x6C NOT SUPPORTED
151 NULL, // TODO: OPCODE 0x6D NOT SUPPORTED
152 NULL, // TODO: OPCODE 0x6E NOT SUPPORTED
153 NULL, // TODO: OPCODE 0x6F NOT SUPPORTED
154 Soft386OpcodeShortConditionalJmp,
155 Soft386OpcodeShortConditionalJmp,
156 Soft386OpcodeShortConditionalJmp,
157 Soft386OpcodeShortConditionalJmp,
158 Soft386OpcodeShortConditionalJmp,
159 Soft386OpcodeShortConditionalJmp,
160 Soft386OpcodeShortConditionalJmp,
161 Soft386OpcodeShortConditionalJmp,
162 Soft386OpcodeShortConditionalJmp,
163 Soft386OpcodeShortConditionalJmp,
164 Soft386OpcodeShortConditionalJmp,
165 Soft386OpcodeShortConditionalJmp,
166 Soft386OpcodeShortConditionalJmp,
167 Soft386OpcodeShortConditionalJmp,
168 Soft386OpcodeShortConditionalJmp,
169 Soft386OpcodeShortConditionalJmp,
170 Soft386OpcodeGroup8082,
171 Soft386OpcodeGroup81,
172 Soft386OpcodeGroup8082,
173 Soft386OpcodeGroup83,
174 Soft386OpcodeTestByteModrm,
175 Soft386OpcodeTestModrm,
176 Soft386OpcodeXchgByteModrm,
177 Soft386OpcodeXchgModrm,
178 Soft386OpcodeMovByteModrm,
179 Soft386OpcodeMovModrm,
180 Soft386OpcodeMovByteModrm,
181 Soft386OpcodeMovModrm,
182 Soft386OpcodeMovStoreSeg,
183 Soft386OpcodeLea,
184 Soft386OpcodeMovLoadSeg,
185 Soft386OpcodeGroup8F,
186 Soft386OpcodeNop,
187 Soft386OpcodeExchangeEax,
188 Soft386OpcodeExchangeEax,
189 Soft386OpcodeExchangeEax,
190 Soft386OpcodeExchangeEax,
191 Soft386OpcodeExchangeEax,
192 Soft386OpcodeExchangeEax,
193 Soft386OpcodeExchangeEax,
194 Soft386OpcodeCwde,
195 Soft386OpcodeCdq,
196 Soft386OpcodeCallAbs,
197 Soft386OpcodeWait,
198 Soft386OpcodePushFlags,
199 Soft386OpcodePopFlags,
200 Soft386OpcodeSahf,
201 Soft386OpcodeLahf,
202 Soft386OpcodeMovAlOffset,
203 Soft386OpcodeMovEaxOffset,
204 Soft386OpcodeMovOffsetAl,
205 Soft386OpcodeMovOffsetEax,
206 NULL, // TODO: OPCODE 0xA4 NOT SUPPORTED
207 NULL, // TODO: OPCODE 0xA5 NOT SUPPORTED
208 NULL, // TODO: OPCODE 0xA6 NOT SUPPORTED
209 NULL, // TODO: OPCODE 0xA7 NOT SUPPORTED
210 Soft386OpcodeTestAl,
211 Soft386OpcodeTestEax,
212 NULL, // TODO: OPCODE 0xAA NOT SUPPORTED
213 NULL, // TODO: OPCODE 0xAB NOT SUPPORTED
214 NULL, // TODO: OPCODE 0xAC NOT SUPPORTED
215 NULL, // TODO: OPCODE 0xAD NOT SUPPORTED
216 NULL, // TODO: OPCODE 0xAE NOT SUPPORTED
217 NULL, // TODO: OPCODE 0xAF NOT SUPPORTED
218 Soft386OpcodeMovByteRegImm,
219 Soft386OpcodeMovByteRegImm,
220 Soft386OpcodeMovByteRegImm,
221 Soft386OpcodeMovByteRegImm,
222 Soft386OpcodeMovByteRegImm,
223 Soft386OpcodeMovByteRegImm,
224 Soft386OpcodeMovByteRegImm,
225 Soft386OpcodeMovByteRegImm,
226 Soft386OpcodeMovRegImm,
227 Soft386OpcodeMovRegImm,
228 Soft386OpcodeMovRegImm,
229 Soft386OpcodeMovRegImm,
230 Soft386OpcodeMovRegImm,
231 Soft386OpcodeMovRegImm,
232 Soft386OpcodeMovRegImm,
233 Soft386OpcodeMovRegImm,
234 Soft386OpcodeGroupC0,
235 Soft386OpcodeGroupC1,
236 Soft386OpcodeRet,
237 Soft386OpcodeRet,
238 Soft386OpcodeLdsLes,
239 Soft386OpcodeLdsLes,
240 Soft386OpcodeGroupC6,
241 Soft386OpcodeGroupC7,
242 Soft386OpcodeEnter,
243 Soft386OpcodeLeave,
244 Soft386OpcodeRetFarImm,
245 Soft386OpcodeRetFar,
246 Soft386OpcodeInt,
247 Soft386OpcodeInt,
248 Soft386OpcodeInt,
249 Soft386OpcodeIret,
250 Soft386OpcodeGroupD0,
251 Soft386OpcodeGroupD1,
252 Soft386OpcodeGroupD2,
253 Soft386OpcodeGroupD3,
254 Soft386OpcodeAam,
255 Soft386OpcodeAad,
256 NULL, // TODO: OPCODE 0xD6 NOT SUPPORTED
257 Soft386OpcodeXlat,
258 NULL, // TODO: OPCODE 0xD8 NOT SUPPORTED
259 NULL, // TODO: OPCODE 0xD9 NOT SUPPORTED
260 NULL, // TODO: OPCODE 0xDA NOT SUPPORTED
261 NULL, // TODO: OPCODE 0xDB NOT SUPPORTED
262 NULL, // TODO: OPCODE 0xDC NOT SUPPORTED
263 NULL, // TODO: OPCODE 0xDD NOT SUPPORTED
264 NULL, // TODO: OPCODE 0xDE NOT SUPPORTED
265 NULL, // TODO: OPCODE 0xDF NOT SUPPORTED
266 Soft386OpcodeLoop,
267 Soft386OpcodeLoop,
268 Soft386OpcodeLoop,
269 Soft386OpcodeJecxz,
270 Soft386OpcodeInByte,
271 Soft386OpcodeIn,
272 Soft386OpcodeOutByte,
273 Soft386OpcodeOut,
274 Soft386OpcodeCall,
275 Soft386OpcodeJmp,
276 Soft386OpcodeJmpAbs,
277 Soft386OpcodeShortJump,
278 Soft386OpcodeInByte,
279 Soft386OpcodeIn,
280 Soft386OpcodeOutByte,
281 Soft386OpcodeOut,
282 Soft386OpcodePrefix,
283 NULL, // Invalid
284 Soft386OpcodePrefix,
285 Soft386OpcodePrefix,
286 Soft386OpcodeHalt,
287 Soft386OpcodeComplCarry,
288 Soft386OpcodeGroupF6,
289 Soft386OpcodeGroupF7,
290 Soft386OpcodeClearCarry,
291 Soft386OpcodeSetCarry,
292 Soft386OpcodeClearInt,
293 Soft386OpcodeSetInt,
294 Soft386OpcodeClearDir,
295 Soft386OpcodeSetDir,
296 Soft386OpcodeGroupFE,
297 Soft386OpcodeGroupFF,
298 };
299
300 /* PUBLIC FUNCTIONS ***********************************************************/
301
302 SOFT386_OPCODE_HANDLER(Soft386OpcodePrefix)
303 {
304 BOOLEAN Valid = FALSE;
305
306 switch (Opcode)
307 {
308 /* ES: */
309 case 0x26:
310 {
311 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
312 {
313 State->PrefixFlags |= SOFT386_PREFIX_SEG;
314 State->SegmentOverride = SOFT386_REG_ES;
315 Valid = TRUE;
316 }
317
318 break;
319 }
320
321 /* CS: */
322 case 0x2E:
323 {
324 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
325 {
326 State->PrefixFlags |= SOFT386_PREFIX_SEG;
327 State->SegmentOverride = SOFT386_REG_CS;
328 Valid = TRUE;
329 }
330
331 break;
332 }
333
334 /* SS: */
335 case 0x36:
336 {
337 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
338 {
339 State->PrefixFlags |= SOFT386_PREFIX_SEG;
340 State->SegmentOverride = SOFT386_REG_SS;
341 Valid = TRUE;
342 }
343
344 break;
345 }
346
347 /* DS: */
348 case 0x3E:
349 {
350 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
351 {
352 State->PrefixFlags |= SOFT386_PREFIX_SEG;
353 State->SegmentOverride = SOFT386_REG_DS;
354 Valid = TRUE;
355 }
356
357 break;
358 }
359
360 /* FS: */
361 case 0x64:
362 {
363 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
364 {
365 State->PrefixFlags |= SOFT386_PREFIX_SEG;
366 State->SegmentOverride = SOFT386_REG_FS;
367 Valid = TRUE;
368 }
369
370 break;
371 }
372
373 /* GS: */
374 case 0x65:
375 {
376 if (!(State->PrefixFlags & SOFT386_PREFIX_SEG))
377 {
378 State->PrefixFlags |= SOFT386_PREFIX_SEG;
379 State->SegmentOverride = SOFT386_REG_GS;
380 Valid = TRUE;
381 }
382
383 break;
384 }
385
386 /* OPSIZE */
387 case 0x66:
388 {
389 if (!(State->PrefixFlags & SOFT386_PREFIX_OPSIZE))
390 {
391 State->PrefixFlags |= SOFT386_PREFIX_OPSIZE;
392 Valid = TRUE;
393 }
394
395 break;
396 }
397
398 /* ADSIZE */
399 case 0x67:
400 {
401 if (!(State->PrefixFlags & SOFT386_PREFIX_ADSIZE))
402 {
403 State->PrefixFlags |= SOFT386_PREFIX_ADSIZE;
404 Valid = TRUE;
405 }
406 break;
407 }
408
409 /* LOCK */
410 case 0xF0:
411 {
412 if (!(State->PrefixFlags & SOFT386_PREFIX_LOCK))
413 {
414 State->PrefixFlags |= SOFT386_PREFIX_LOCK;
415 Valid = TRUE;
416 }
417
418 break;
419 }
420
421 /* REPNZ */
422 case 0xF2:
423 {
424 /* Mutually exclusive with REP */
425 if (!(State->PrefixFlags
426 & (SOFT386_PREFIX_REPNZ | SOFT386_PREFIX_REP)))
427 {
428 State->PrefixFlags |= SOFT386_PREFIX_REPNZ;
429 Valid = TRUE;
430 }
431
432 break;
433 }
434
435 /* REP / REPZ */
436 case 0xF3:
437 {
438 /* Mutually exclusive with REPNZ */
439 if (!(State->PrefixFlags
440 & (SOFT386_PREFIX_REPNZ | SOFT386_PREFIX_REP)))
441 {
442 State->PrefixFlags |= SOFT386_PREFIX_REP;
443 Valid = TRUE;
444 }
445
446 break;
447 }
448 }
449
450 if (!Valid)
451 {
452 /* Clear all prefixes */
453 State->PrefixFlags = 0;
454
455 /* Throw an exception */
456 Soft386Exception(State, SOFT386_EXCEPTION_UD);
457 return FALSE;
458 }
459
460 return TRUE;
461 }
462
463 SOFT386_OPCODE_HANDLER(Soft386OpcodeIncrement)
464 {
465 ULONG Value;
466 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
467
468 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
469 {
470 /* The OPSIZE prefix toggles the size */
471 Size = !Size;
472 }
473 else if (State->PrefixFlags != 0)
474 {
475 /* Invalid prefix */
476 Soft386Exception(State, SOFT386_EXCEPTION_UD);
477 return FALSE;
478 }
479
480 /* Make sure this is the right instruction */
481 ASSERT((Opcode & 0xF8) == 0x40);
482
483 if (Size)
484 {
485 Value = ++State->GeneralRegs[Opcode & 0x07].Long;
486
487 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
488 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
489 }
490 else
491 {
492 Value = ++State->GeneralRegs[Opcode & 0x07].LowWord;
493
494 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
495 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
496 }
497
498 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
499 State->Flags.Af = ((Value & 0x0F) == 0) ? TRUE : FALSE;
500 State->Flags.Pf = Soft386CalculateParity(LOBYTE(Value));
501
502 /* Return success */
503 return TRUE;
504 }
505
506 SOFT386_OPCODE_HANDLER(Soft386OpcodeDecrement)
507 {
508 ULONG Value;
509 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
510
511 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
512 {
513 /* The OPSIZE prefix toggles the size */
514 Size = !Size;
515 }
516 else if (State->PrefixFlags != 0)
517 {
518 /* Invalid prefix */
519 Soft386Exception(State, SOFT386_EXCEPTION_UD);
520 return FALSE;
521 }
522
523 /* Make sure this is the right instruction */
524 ASSERT((Opcode & 0xF8) == 0x48);
525
526 if (Size)
527 {
528 Value = --State->GeneralRegs[Opcode & 0x07].Long;
529
530 State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1)) ? TRUE : FALSE;
531 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
532 }
533 else
534 {
535 Value = --State->GeneralRegs[Opcode & 0x07].LowWord;
536
537 State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1)) ? TRUE : FALSE;
538 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
539 }
540
541 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
542 State->Flags.Af = ((Value & 0x0F) == 0x0F) ? TRUE : FALSE;
543 State->Flags.Pf = Soft386CalculateParity(LOBYTE(Value));
544
545 /* Return success */
546 return TRUE;
547 }
548
549 SOFT386_OPCODE_HANDLER(Soft386OpcodePushReg)
550 {
551 if ((State->PrefixFlags != SOFT386_PREFIX_OPSIZE)
552 && (State->PrefixFlags != 0))
553 {
554 /* Invalid prefix */
555 Soft386Exception(State, SOFT386_EXCEPTION_UD);
556 return FALSE;
557 }
558
559 /* Make sure this is the right instruction */
560 ASSERT((Opcode & 0xF8) == 0x50);
561
562 /* Call the internal function */
563 return Soft386StackPush(State, State->GeneralRegs[Opcode & 0x07].Long);
564 }
565
566 SOFT386_OPCODE_HANDLER(Soft386OpcodePopReg)
567 {
568 ULONG Value;
569 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
570
571 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
572 {
573 /* The OPSIZE prefix toggles the size */
574 Size = !Size;
575 }
576 else if (State->PrefixFlags != 0)
577 {
578 /* Invalid prefix */
579 Soft386Exception(State, SOFT386_EXCEPTION_UD);
580 return FALSE;
581 }
582
583 /* Make sure this is the right instruction */
584 ASSERT((Opcode & 0xF8) == 0x58);
585
586 /* Call the internal function */
587 if (!Soft386StackPop(State, &Value)) return FALSE;
588
589 /* Store the value */
590 if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value;
591 else State->GeneralRegs[Opcode & 0x07].LowWord = Value;
592
593 /* Return success */
594 return TRUE;
595 }
596
597 SOFT386_OPCODE_HANDLER(Soft386OpcodeNop)
598 {
599 if (State->PrefixFlags & ~(SOFT386_PREFIX_OPSIZE | SOFT386_PREFIX_REP))
600 {
601 /* Allowed prefixes are REP and OPSIZE */
602 Soft386Exception(State, SOFT386_EXCEPTION_UD);
603 return FALSE;
604 }
605
606 if (State->PrefixFlags & SOFT386_PREFIX_REP)
607 {
608 /* Idle cycle */
609 State->IdleCallback(State);
610 }
611
612 return TRUE;
613 }
614
615 SOFT386_OPCODE_HANDLER(Soft386OpcodeExchangeEax)
616 {
617 INT Reg = Opcode & 0x07;
618 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
619
620 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
621 {
622 /* The OPSIZE prefix toggles the size */
623 Size = !Size;
624 }
625 else if (State->PrefixFlags != 0)
626 {
627 /* Invalid prefix */
628 Soft386Exception(State, SOFT386_EXCEPTION_UD);
629 return FALSE;
630 }
631
632 /* Make sure this is the right instruction */
633 ASSERT((Opcode & 0xF8) == 0x90);
634
635 /* Exchange the values */
636 if (Size)
637 {
638 ULONG Value;
639
640 Value = State->GeneralRegs[Reg].Long;
641 State->GeneralRegs[Reg].Long = State->GeneralRegs[SOFT386_REG_EAX].Long;
642 State->GeneralRegs[SOFT386_REG_EAX].Long = Value;
643 }
644 else
645 {
646 USHORT Value;
647
648 Value = State->GeneralRegs[Reg].LowWord;
649 State->GeneralRegs[Reg].LowWord = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
650 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Value;
651 }
652
653 return TRUE;
654 }
655
656 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortConditionalJmp)
657 {
658 BOOLEAN Jump = FALSE;
659 CHAR Offset = 0;
660
661 /* Make sure this is the right instruction */
662 ASSERT((Opcode & 0xF0) == 0x70);
663
664 /* Fetch the offset */
665 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
666 {
667 /* An exception occurred */
668 return FALSE;
669 }
670
671 switch ((Opcode & 0x0F) >> 1)
672 {
673 /* JO / JNO */
674 case 0:
675 {
676 Jump = State->Flags.Of;
677 break;
678 }
679
680 /* JC / JNC */
681 case 1:
682 {
683 Jump = State->Flags.Cf;
684 break;
685 }
686
687 /* JZ / JNZ */
688 case 2:
689 {
690 Jump = State->Flags.Zf;
691 break;
692 }
693
694 /* JBE / JNBE */
695 case 3:
696 {
697 Jump = State->Flags.Cf || State->Flags.Zf;
698 break;
699 }
700
701 /* JS / JNS */
702 case 4:
703 {
704 Jump = State->Flags.Sf;
705 break;
706 }
707
708 /* JP / JNP */
709 case 5:
710 {
711 Jump = State->Flags.Pf;
712 break;
713 }
714
715 /* JL / JNL */
716 case 6:
717 {
718 Jump = State->Flags.Sf != State->Flags.Of;
719 break;
720 }
721
722 /* JLE / JNLE */
723 case 7:
724 {
725 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
726 break;
727 }
728 }
729
730 if (Opcode & 1)
731 {
732 /* Invert the result */
733 Jump = !Jump;
734 }
735
736 if (Jump)
737 {
738 /* Move the instruction pointer */
739 State->InstPtr.Long += Offset;
740 }
741
742 /* Return success */
743 return TRUE;
744 }
745
746 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearCarry)
747 {
748 /* Make sure this is the right instruction */
749 ASSERT(Opcode == 0xF8);
750
751 /* No prefixes allowed */
752 if (State->PrefixFlags)
753 {
754 Soft386Exception(State, SOFT386_EXCEPTION_UD);
755 return FALSE;
756 }
757
758 /* Clear CF and return success */
759 State->Flags.Cf = FALSE;
760 return TRUE;
761 }
762
763 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetCarry)
764 {
765 /* Make sure this is the right instruction */
766 ASSERT(Opcode == 0xF9);
767
768 /* No prefixes allowed */
769 if (State->PrefixFlags)
770 {
771 Soft386Exception(State, SOFT386_EXCEPTION_UD);
772 return FALSE;
773 }
774
775 /* Set CF and return success*/
776 State->Flags.Cf = TRUE;
777 return TRUE;
778 }
779
780 SOFT386_OPCODE_HANDLER(Soft386OpcodeComplCarry)
781 {
782 /* Make sure this is the right instruction */
783 ASSERT(Opcode == 0xF5);
784
785 /* No prefixes allowed */
786 if (State->PrefixFlags)
787 {
788 Soft386Exception(State, SOFT386_EXCEPTION_UD);
789 return FALSE;
790 }
791
792 /* Toggle CF and return success */
793 State->Flags.Cf = !State->Flags.Cf;
794 return TRUE;
795 }
796
797 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearInt)
798 {
799 /* Make sure this is the right instruction */
800 ASSERT(Opcode == 0xFA);
801
802 /* No prefixes allowed */
803 if (State->PrefixFlags)
804 {
805 Soft386Exception(State, SOFT386_EXCEPTION_UD);
806 return FALSE;
807 }
808
809 /* Check for protected mode */
810 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
811 {
812 /* Check IOPL */
813 if (State->Flags.Iopl >= State->SegmentRegs[SOFT386_REG_CS].Dpl)
814 {
815 /* Clear the interrupt flag */
816 State->Flags.If = FALSE;
817 }
818 else
819 {
820 /* General Protection Fault */
821 Soft386Exception(State, SOFT386_EXCEPTION_GP);
822 return FALSE;
823 }
824 }
825 else
826 {
827 /* Just clear the interrupt flag */
828 State->Flags.If = FALSE;
829 }
830
831 /* Return success */
832 return TRUE;
833 }
834
835 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetInt)
836 {
837 /* Make sure this is the right instruction */
838 ASSERT(Opcode == 0xFB);
839
840 /* No prefixes allowed */
841 if (State->PrefixFlags)
842 {
843 Soft386Exception(State, SOFT386_EXCEPTION_UD);
844 return FALSE;
845 }
846
847 /* Check for protected mode */
848 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
849 {
850 /* Check IOPL */
851 if (State->Flags.Iopl >= State->SegmentRegs[SOFT386_REG_CS].Dpl)
852 {
853 /* Set the interrupt flag */
854 State->Flags.If = TRUE;
855 }
856 else
857 {
858 /* General Protection Fault */
859 Soft386Exception(State, SOFT386_EXCEPTION_GP);
860 return FALSE;
861 }
862 }
863 else
864 {
865 /* Just set the interrupt flag */
866 State->Flags.If = TRUE;
867 }
868
869 /* Return success */
870 return TRUE;
871 }
872
873 SOFT386_OPCODE_HANDLER(Soft386OpcodeClearDir)
874 {
875 /* Make sure this is the right instruction */
876 ASSERT(Opcode == 0xFC);
877
878 /* No prefixes allowed */
879 if (State->PrefixFlags)
880 {
881 Soft386Exception(State, SOFT386_EXCEPTION_UD);
882 return FALSE;
883 }
884
885 /* Clear DF and return success */
886 State->Flags.Df = FALSE;
887 return TRUE;
888 }
889
890 SOFT386_OPCODE_HANDLER(Soft386OpcodeSetDir)
891 {
892 /* Make sure this is the right instruction */
893 ASSERT(Opcode == 0xFD);
894
895 /* No prefixes allowed */
896 if (State->PrefixFlags)
897 {
898 Soft386Exception(State, SOFT386_EXCEPTION_UD);
899 return FALSE;
900 }
901
902 /* Set DF and return success*/
903 State->Flags.Df = TRUE;
904 return TRUE;
905 }
906
907 SOFT386_OPCODE_HANDLER(Soft386OpcodeHalt)
908 {
909 /* Make sure this is the right instruction */
910 ASSERT(Opcode == 0xF4);
911
912 /* No prefixes allowed */
913 if (State->PrefixFlags)
914 {
915 Soft386Exception(State, SOFT386_EXCEPTION_UD);
916 return FALSE;
917 }
918
919 /* Privileged instructions can only be executed under CPL = 0 */
920 if (State->SegmentRegs[SOFT386_REG_CS].Dpl != 0)
921 {
922 Soft386Exception(State, SOFT386_EXCEPTION_GP);
923 return FALSE;
924 }
925
926 /* Halt */
927 while (!State->HardwareInt) State->IdleCallback(State);
928
929 /* Return success */
930 return TRUE;
931 }
932
933 SOFT386_OPCODE_HANDLER(Soft386OpcodeInByte)
934 {
935 UCHAR Data;
936 ULONG Port;
937
938 /* Make sure this is the right instruction */
939 ASSERT((Opcode & 0xF7) == 0xE4);
940
941 if (Opcode == 0xE4)
942 {
943 /* Fetch the parameter */
944 if (!Soft386FetchByte(State, &Data))
945 {
946 /* Exception occurred */
947 return FALSE;
948 }
949
950 /* Set the port number to the parameter */
951 Port = Data;
952 }
953 else
954 {
955 /* The port number is in DX */
956 Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord;
957 }
958
959 /* Read a byte from the I/O port */
960 State->IoReadCallback(State, Port, &Data, sizeof(UCHAR));
961
962 /* Store the result in AL */
963 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Data;
964
965 return TRUE;
966 }
967
968 SOFT386_OPCODE_HANDLER(Soft386OpcodeIn)
969 {
970 ULONG Port;
971 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
972
973 /* Make sure this is the right instruction */
974 ASSERT((Opcode & 0xF7) == 0xE5);
975
976 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
977 {
978 /* The OPSIZE prefix toggles the size */
979 Size = !Size;
980 }
981 else if (State->PrefixFlags != 0)
982 {
983 /* Invalid prefix */
984 Soft386Exception(State, SOFT386_EXCEPTION_UD);
985 return FALSE;
986 }
987
988 if (Opcode == 0xE5)
989 {
990 UCHAR Data;
991
992 /* Fetch the parameter */
993 if (!Soft386FetchByte(State, &Data))
994 {
995 /* Exception occurred */
996 return FALSE;
997 }
998
999 /* Set the port number to the parameter */
1000 Port = Data;
1001 }
1002 else
1003 {
1004 /* The port number is in DX */
1005 Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord;
1006 }
1007
1008 if (Size)
1009 {
1010 ULONG Data;
1011
1012 /* Read a dword from the I/O port */
1013 State->IoReadCallback(State, Port, &Data, sizeof(ULONG));
1014
1015 /* Store the value in EAX */
1016 State->GeneralRegs[SOFT386_REG_EAX].Long = Data;
1017 }
1018 else
1019 {
1020 USHORT Data;
1021
1022 /* Read a word from the I/O port */
1023 State->IoReadCallback(State, Port, &Data, sizeof(USHORT));
1024
1025 /* Store the value in AX */
1026 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Data;
1027 }
1028
1029 return TRUE;
1030 }
1031
1032 SOFT386_OPCODE_HANDLER(Soft386OpcodeOutByte)
1033 {
1034 UCHAR Data;
1035 ULONG Port;
1036
1037 /* Make sure this is the right instruction */
1038 ASSERT((Opcode & 0xF7) == 0xE6);
1039
1040 if (Opcode == 0xE6)
1041 {
1042 /* Fetch the parameter */
1043 if (!Soft386FetchByte(State, &Data))
1044 {
1045 /* Exception occurred */
1046 return FALSE;
1047 }
1048
1049 /* Set the port number to the parameter */
1050 Port = Data;
1051 }
1052 else
1053 {
1054 /* The port number is in DX */
1055 Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord;
1056 }
1057
1058 /* Read the value from AL */
1059 Data = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
1060
1061 /* Write the byte to the I/O port */
1062 State->IoWriteCallback(State, Port, &Data, sizeof(UCHAR));
1063
1064 return TRUE;
1065 }
1066
1067 SOFT386_OPCODE_HANDLER(Soft386OpcodeOut)
1068 {
1069 ULONG Port;
1070 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
1071
1072 /* Make sure this is the right instruction */
1073 ASSERT((Opcode & 0xF7) == 0xE7);
1074
1075 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
1076 {
1077 /* The OPSIZE prefix toggles the size */
1078 Size = !Size;
1079 }
1080 else if (State->PrefixFlags != 0)
1081 {
1082 /* Invalid prefix */
1083 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1084 return FALSE;
1085 }
1086
1087 if (Opcode == 0xE7)
1088 {
1089 UCHAR Data;
1090
1091 /* Fetch the parameter */
1092 if (!Soft386FetchByte(State, &Data))
1093 {
1094 /* Exception occurred */
1095 return FALSE;
1096 }
1097
1098 /* Set the port number to the parameter */
1099 Port = Data;
1100 }
1101 else
1102 {
1103 /* The port number is in DX */
1104 Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord;
1105 }
1106
1107 if (Size)
1108 {
1109 /* Get the value from EAX */
1110 ULONG Data = State->GeneralRegs[SOFT386_REG_EAX].Long;
1111
1112 /* Write a dword to the I/O port */
1113 State->IoReadCallback(State, Port, &Data, sizeof(ULONG));
1114 }
1115 else
1116 {
1117 /* Get the value from AX */
1118 USHORT Data = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
1119
1120 /* Write a word to the I/O port */
1121 State->IoWriteCallback(State, Port, &Data, sizeof(USHORT));
1122 }
1123
1124 return TRUE;
1125 }
1126
1127 SOFT386_OPCODE_HANDLER(Soft386OpcodeShortJump)
1128 {
1129 CHAR Offset = 0;
1130
1131 /* Make sure this is the right instruction */
1132 ASSERT(Opcode == 0xEB);
1133
1134 /* Fetch the offset */
1135 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
1136 {
1137 /* An exception occurred */
1138 return FALSE;
1139 }
1140
1141 /* Move the instruction pointer */
1142 State->InstPtr.Long += Offset;
1143
1144 return TRUE;
1145 }
1146
1147 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovRegImm)
1148 {
1149 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
1150
1151 /* Make sure this is the right instruction */
1152 ASSERT((Opcode & 0xF8) == 0xB8);
1153
1154 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
1155 {
1156 /* The OPSIZE prefix toggles the size */
1157 Size = !Size;
1158 }
1159 else if (State->PrefixFlags != 0)
1160 {
1161 /* Invalid prefix */
1162 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1163 return FALSE;
1164 }
1165
1166 if (Size)
1167 {
1168 ULONG Value;
1169
1170 /* Fetch the dword */
1171 if (!Soft386FetchDword(State, &Value))
1172 {
1173 /* Exception occurred */
1174 return FALSE;
1175 }
1176
1177 /* Store the value in the register */
1178 State->GeneralRegs[Opcode & 0x07].Long = Value;
1179 }
1180 else
1181 {
1182 USHORT Value;
1183
1184 /* Fetch the word */
1185 if (!Soft386FetchWord(State, &Value))
1186 {
1187 /* Exception occurred */
1188 return FALSE;
1189 }
1190
1191 /* Store the value in the register */
1192 State->GeneralRegs[Opcode & 0x07].LowWord = Value;
1193 }
1194
1195 return TRUE;
1196 }
1197
1198 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteRegImm)
1199 {
1200 UCHAR Value;
1201
1202 /* Make sure this is the right instruction */
1203 ASSERT((Opcode & 0xF8) == 0xB0);
1204
1205 if (State->PrefixFlags != 0)
1206 {
1207 /* Invalid prefix */
1208 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1209 return FALSE;
1210 }
1211
1212 /* Fetch the byte */
1213 if (!Soft386FetchByte(State, &Value))
1214 {
1215 /* Exception occurred */
1216 return FALSE;
1217 }
1218
1219 if (Opcode & 0x04)
1220 {
1221 /* AH, CH, DH or BH */
1222 State->GeneralRegs[Opcode & 0x03].HighByte = Value;
1223 }
1224 else
1225 {
1226 /* AL, CL, DL or BL */
1227 State->GeneralRegs[Opcode & 0x03].LowByte = Value;
1228 }
1229
1230 return TRUE;
1231 }
1232
1233 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddByteModrm)
1234 {
1235 UCHAR FirstValue, SecondValue, Result;
1236 SOFT386_MOD_REG_RM ModRegRm;
1237 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1238
1239 /* Make sure this is the right instruction */
1240 ASSERT((Opcode & 0xFD) == 0x00);
1241
1242 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1243 {
1244 /* The ADSIZE prefix toggles the size */
1245 AddressSize = !AddressSize;
1246 }
1247 else if (State->PrefixFlags
1248 & ~(SOFT386_PREFIX_ADSIZE
1249 | SOFT386_PREFIX_SEG
1250 | SOFT386_PREFIX_LOCK))
1251 {
1252 /* Invalid prefix */
1253 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1254 return FALSE;
1255 }
1256
1257 /* Get the operands */
1258 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1259 {
1260 /* Exception occurred */
1261 return FALSE;
1262 }
1263
1264 if (!Soft386ReadModrmByteOperands(State,
1265 &ModRegRm,
1266 &FirstValue,
1267 &SecondValue))
1268 {
1269 /* Exception occurred */
1270 return FALSE;
1271 }
1272
1273 /* Calculate the result */
1274 Result = FirstValue + SecondValue;
1275
1276 /* Update the flags */
1277 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1278 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1279 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1280 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
1281 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1282 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1283 State->Flags.Pf = Soft386CalculateParity(Result);
1284
1285 /* Write back the result */
1286 return Soft386WriteModrmByteOperands(State,
1287 &ModRegRm,
1288 Opcode & SOFT386_OPCODE_WRITE_REG,
1289 Result);
1290 }
1291
1292 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddModrm)
1293 {
1294 SOFT386_MOD_REG_RM ModRegRm;
1295 BOOLEAN OperandSize, AddressSize;
1296
1297 /* Make sure this is the right instruction */
1298 ASSERT((Opcode & 0xFD) == 0x01);
1299
1300 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1301
1302 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1303 {
1304 /* The ADSIZE prefix toggles the address size */
1305 AddressSize = !AddressSize;
1306 }
1307
1308 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1309 {
1310 /* The OPSIZE prefix toggles the operand size */
1311 OperandSize = !OperandSize;
1312 }
1313
1314 if (State->PrefixFlags
1315 & ~(SOFT386_PREFIX_ADSIZE
1316 | SOFT386_PREFIX_OPSIZE
1317 | SOFT386_PREFIX_SEG
1318 | SOFT386_PREFIX_LOCK))
1319 {
1320 /* Invalid prefix */
1321 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1322 return FALSE;
1323 }
1324
1325 /* Get the operands */
1326 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1327 {
1328 /* Exception occurred */
1329 return FALSE;
1330 }
1331
1332 /* Check the operand size */
1333 if (OperandSize)
1334 {
1335 ULONG FirstValue, SecondValue, Result;
1336
1337 if (!Soft386ReadModrmDwordOperands(State,
1338 &ModRegRm,
1339 &FirstValue,
1340 &SecondValue))
1341 {
1342 /* Exception occurred */
1343 return FALSE;
1344 }
1345
1346 /* Calculate the result */
1347 Result = FirstValue + SecondValue;
1348
1349 /* Update the flags */
1350 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1351 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1352 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1353 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
1354 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1355 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1356 State->Flags.Pf = Soft386CalculateParity(Result);
1357
1358 /* Write back the result */
1359 return Soft386WriteModrmDwordOperands(State,
1360 &ModRegRm,
1361 Opcode & SOFT386_OPCODE_WRITE_REG,
1362 Result);
1363 }
1364 else
1365 {
1366 USHORT FirstValue, SecondValue, Result;
1367
1368 if (!Soft386ReadModrmWordOperands(State,
1369 &ModRegRm,
1370 &FirstValue,
1371 &SecondValue))
1372 {
1373 /* Exception occurred */
1374 return FALSE;
1375 }
1376
1377 /* Calculate the result */
1378 Result = FirstValue + SecondValue;
1379
1380 /* Update the flags */
1381 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1382 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1383 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1384 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
1385 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1386 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
1387 State->Flags.Pf = Soft386CalculateParity(Result);
1388
1389 /* Write back the result */
1390 return Soft386WriteModrmWordOperands(State,
1391 &ModRegRm,
1392 Opcode & SOFT386_OPCODE_WRITE_REG,
1393 Result);
1394 }
1395 }
1396
1397 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddAl)
1398 {
1399 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
1400 UCHAR SecondValue, Result;
1401
1402 /* Make sure this is the right instruction */
1403 ASSERT(Opcode == 0x04);
1404
1405 if (State->PrefixFlags)
1406 {
1407 /* This opcode doesn't take any prefixes */
1408 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1409 return FALSE;
1410 }
1411
1412 if (!Soft386FetchByte(State, &SecondValue))
1413 {
1414 /* Exception occurred */
1415 return FALSE;
1416 }
1417
1418 /* Calculate the result */
1419 Result = FirstValue + SecondValue;
1420
1421 /* Update the flags */
1422 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1423 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
1424 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
1425 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
1426 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1427 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1428 State->Flags.Pf = Soft386CalculateParity(Result);
1429
1430 /* Write back the result */
1431 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
1432
1433 return TRUE;
1434 }
1435
1436 SOFT386_OPCODE_HANDLER(Soft386OpcodeAddEax)
1437 {
1438 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
1439
1440 /* Make sure this is the right instruction */
1441 ASSERT(Opcode == 0x05);
1442
1443 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
1444 {
1445 /* Invalid prefix */
1446 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1447 return FALSE;
1448 }
1449
1450 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1451 {
1452 /* The OPSIZE prefix toggles the size */
1453 Size = !Size;
1454 }
1455
1456 if (Size)
1457 {
1458 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
1459 ULONG SecondValue, Result;
1460
1461 if (!Soft386FetchDword(State, &SecondValue))
1462 {
1463 /* Exception occurred */
1464 return FALSE;
1465 }
1466
1467 /* Calculate the result */
1468 Result = FirstValue + SecondValue;
1469
1470 /* Update the flags */
1471 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1472 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
1473 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
1474 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
1475 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1476 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1477 State->Flags.Pf = Soft386CalculateParity(Result);
1478
1479 /* Write back the result */
1480 State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
1481 }
1482 else
1483 {
1484 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
1485 USHORT SecondValue, Result;
1486
1487 if (!Soft386FetchWord(State, &SecondValue))
1488 {
1489 /* Exception occurred */
1490 return FALSE;
1491 }
1492
1493 /* Calculate the result */
1494 Result = FirstValue + SecondValue;
1495
1496 /* Update the flags */
1497 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
1498 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
1499 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
1500 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
1501 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1502 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
1503 State->Flags.Pf = Soft386CalculateParity(Result);
1504
1505 /* Write back the result */
1506 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
1507 }
1508
1509 return TRUE;
1510 }
1511
1512 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrByteModrm)
1513 {
1514 UCHAR FirstValue, SecondValue, Result;
1515 SOFT386_MOD_REG_RM ModRegRm;
1516 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1517
1518 /* Make sure this is the right instruction */
1519 ASSERT((Opcode & 0xFD) == 0x08);
1520
1521 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1522 {
1523 /* The ADSIZE prefix toggles the size */
1524 AddressSize = !AddressSize;
1525 }
1526 else if (State->PrefixFlags
1527 & ~(SOFT386_PREFIX_ADSIZE
1528 | SOFT386_PREFIX_SEG
1529 | SOFT386_PREFIX_LOCK))
1530 {
1531 /* Invalid prefix */
1532 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1533 return FALSE;
1534 }
1535
1536 /* Get the operands */
1537 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1538 {
1539 /* Exception occurred */
1540 return FALSE;
1541 }
1542
1543 if (!Soft386ReadModrmByteOperands(State,
1544 &ModRegRm,
1545 &FirstValue,
1546 &SecondValue))
1547 {
1548 /* Exception occurred */
1549 return FALSE;
1550 }
1551
1552 /* Calculate the result */
1553 Result = FirstValue | SecondValue;
1554
1555 /* Update the flags */
1556 State->Flags.Cf = FALSE;
1557 State->Flags.Of = FALSE;
1558 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1559 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1560 State->Flags.Pf = Soft386CalculateParity(Result);
1561
1562 /* Write back the result */
1563 return Soft386WriteModrmByteOperands(State,
1564 &ModRegRm,
1565 Opcode & SOFT386_OPCODE_WRITE_REG,
1566 Result);
1567 }
1568
1569 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrModrm)
1570 {
1571 SOFT386_MOD_REG_RM ModRegRm;
1572 BOOLEAN OperandSize, AddressSize;
1573
1574 /* Make sure this is the right instruction */
1575 ASSERT((Opcode & 0xFD) == 0x09);
1576
1577 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1578
1579 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1580 {
1581 /* The ADSIZE prefix toggles the address size */
1582 AddressSize = !AddressSize;
1583 }
1584
1585 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1586 {
1587 /* The OPSIZE prefix toggles the operand size */
1588 OperandSize = !OperandSize;
1589 }
1590
1591 if (State->PrefixFlags
1592 & ~(SOFT386_PREFIX_ADSIZE
1593 | SOFT386_PREFIX_OPSIZE
1594 | SOFT386_PREFIX_SEG
1595 | SOFT386_PREFIX_LOCK))
1596 {
1597 /* Invalid prefix */
1598 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1599 return FALSE;
1600 }
1601
1602 /* Get the operands */
1603 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1604 {
1605 /* Exception occurred */
1606 return FALSE;
1607 }
1608
1609 /* Check the operand size */
1610 if (OperandSize)
1611 {
1612 ULONG FirstValue, SecondValue, Result;
1613
1614 if (!Soft386ReadModrmDwordOperands(State,
1615 &ModRegRm,
1616 &FirstValue,
1617 &SecondValue))
1618 {
1619 /* Exception occurred */
1620 return FALSE;
1621 }
1622
1623 /* Calculate the result */
1624 Result = FirstValue | SecondValue;
1625
1626 /* Update the flags */
1627 State->Flags.Cf = FALSE;
1628 State->Flags.Of = FALSE;
1629 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1630 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1631 State->Flags.Pf = Soft386CalculateParity(Result);
1632
1633 /* Write back the result */
1634 return Soft386WriteModrmDwordOperands(State,
1635 &ModRegRm,
1636 Opcode & SOFT386_OPCODE_WRITE_REG,
1637 Result);
1638 }
1639 else
1640 {
1641 USHORT FirstValue, SecondValue, Result;
1642
1643 if (!Soft386ReadModrmWordOperands(State,
1644 &ModRegRm,
1645 &FirstValue,
1646 &SecondValue))
1647 {
1648 /* Exception occurred */
1649 return FALSE;
1650 }
1651
1652 /* Calculate the result */
1653 Result = FirstValue | SecondValue;
1654
1655 /* Update the flags */
1656 State->Flags.Cf = FALSE;
1657 State->Flags.Of = FALSE;
1658 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1659 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1660 State->Flags.Pf = Soft386CalculateParity(Result);
1661
1662 /* Write back the result */
1663 return Soft386WriteModrmWordOperands(State,
1664 &ModRegRm,
1665 Opcode & SOFT386_OPCODE_WRITE_REG,
1666 Result);
1667 }
1668 }
1669
1670 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrAl)
1671 {
1672 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
1673 UCHAR SecondValue, Result;
1674
1675 /* Make sure this is the right instruction */
1676 ASSERT(Opcode == 0x0C);
1677
1678 if (State->PrefixFlags)
1679 {
1680 /* This opcode doesn't take any prefixes */
1681 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1682 return FALSE;
1683 }
1684
1685 if (!Soft386FetchByte(State, &SecondValue))
1686 {
1687 /* Exception occurred */
1688 return FALSE;
1689 }
1690
1691 /* Calculate the result */
1692 Result = FirstValue | SecondValue;
1693
1694 /* Update the flags */
1695 State->Flags.Cf = FALSE;
1696 State->Flags.Of = FALSE;
1697 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1698 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1699 State->Flags.Pf = Soft386CalculateParity(Result);
1700
1701 /* Write back the result */
1702 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
1703
1704 return TRUE;
1705 }
1706
1707 SOFT386_OPCODE_HANDLER(Soft386OpcodeOrEax)
1708 {
1709 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
1710
1711 /* Make sure this is the right instruction */
1712 ASSERT(Opcode == 0x0D);
1713
1714 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
1715 {
1716 /* Invalid prefix */
1717 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1718 return FALSE;
1719 }
1720
1721 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1722 {
1723 /* The OPSIZE prefix toggles the size */
1724 Size = !Size;
1725 }
1726
1727 if (Size)
1728 {
1729 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
1730 ULONG SecondValue, Result;
1731
1732 if (!Soft386FetchDword(State, &SecondValue))
1733 {
1734 /* Exception occurred */
1735 return FALSE;
1736 }
1737
1738 /* Calculate the result */
1739 Result = FirstValue | SecondValue;
1740
1741 /* Update the flags */
1742 State->Flags.Cf = FALSE;
1743 State->Flags.Of = FALSE;
1744 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1745 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1746 State->Flags.Pf = Soft386CalculateParity(Result);
1747
1748 /* Write back the result */
1749 State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
1750 }
1751 else
1752 {
1753 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
1754 USHORT SecondValue, Result;
1755
1756 if (!Soft386FetchWord(State, &SecondValue))
1757 {
1758 /* Exception occurred */
1759 return FALSE;
1760 }
1761
1762 /* Calculate the result */
1763 Result = FirstValue | SecondValue;
1764
1765 /* Update the flags */
1766 State->Flags.Cf = FALSE;
1767 State->Flags.Of = FALSE;
1768 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1769 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
1770 State->Flags.Pf = Soft386CalculateParity(Result);
1771
1772 /* Write back the result */
1773 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
1774 }
1775
1776 return TRUE;
1777 }
1778
1779 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndByteModrm)
1780 {
1781 UCHAR FirstValue, SecondValue, Result;
1782 SOFT386_MOD_REG_RM ModRegRm;
1783 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1784
1785 /* Make sure this is the right instruction */
1786 ASSERT((Opcode & 0xFD) == 0x20);
1787
1788 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1789 {
1790 /* The ADSIZE prefix toggles the size */
1791 AddressSize = !AddressSize;
1792 }
1793 else if (State->PrefixFlags
1794 & ~(SOFT386_PREFIX_ADSIZE
1795 | SOFT386_PREFIX_SEG
1796 | SOFT386_PREFIX_LOCK))
1797 {
1798 /* Invalid prefix */
1799 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1800 return FALSE;
1801 }
1802
1803 /* Get the operands */
1804 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1805 {
1806 /* Exception occurred */
1807 return FALSE;
1808 }
1809
1810 if (!Soft386ReadModrmByteOperands(State,
1811 &ModRegRm,
1812 &FirstValue,
1813 &SecondValue))
1814 {
1815 /* Exception occurred */
1816 return FALSE;
1817 }
1818
1819 /* Calculate the result */
1820 Result = FirstValue & SecondValue;
1821
1822 /* Update the flags */
1823 State->Flags.Cf = FALSE;
1824 State->Flags.Of = FALSE;
1825 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1826 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1827 State->Flags.Pf = Soft386CalculateParity(Result);
1828
1829 /* Write back the result */
1830 return Soft386WriteModrmByteOperands(State,
1831 &ModRegRm,
1832 Opcode & SOFT386_OPCODE_WRITE_REG,
1833 Result);
1834 }
1835
1836 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndModrm)
1837 {
1838 SOFT386_MOD_REG_RM ModRegRm;
1839 BOOLEAN OperandSize, AddressSize;
1840
1841 /* Make sure this is the right instruction */
1842 ASSERT((Opcode & 0xFD) == 0x21);
1843
1844 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1845
1846 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1847 {
1848 /* The ADSIZE prefix toggles the address size */
1849 AddressSize = !AddressSize;
1850 }
1851
1852 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1853 {
1854 /* The OPSIZE prefix toggles the operand size */
1855 OperandSize = !OperandSize;
1856 }
1857
1858 if (State->PrefixFlags
1859 & ~(SOFT386_PREFIX_ADSIZE
1860 | SOFT386_PREFIX_OPSIZE
1861 | SOFT386_PREFIX_SEG
1862 | SOFT386_PREFIX_LOCK))
1863 {
1864 /* Invalid prefix */
1865 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1866 return FALSE;
1867 }
1868
1869 /* Get the operands */
1870 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1871 {
1872 /* Exception occurred */
1873 return FALSE;
1874 }
1875
1876 /* Check the operand size */
1877 if (OperandSize)
1878 {
1879 ULONG FirstValue, SecondValue, Result;
1880
1881 if (!Soft386ReadModrmDwordOperands(State,
1882 &ModRegRm,
1883 &FirstValue,
1884 &SecondValue))
1885 {
1886 /* Exception occurred */
1887 return FALSE;
1888 }
1889
1890 /* Calculate the result */
1891 Result = FirstValue & SecondValue;
1892
1893 /* Update the flags */
1894 State->Flags.Cf = FALSE;
1895 State->Flags.Of = FALSE;
1896 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1897 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1898 State->Flags.Pf = Soft386CalculateParity(Result);
1899
1900 /* Write back the result */
1901 return Soft386WriteModrmDwordOperands(State,
1902 &ModRegRm,
1903 Opcode & SOFT386_OPCODE_WRITE_REG,
1904 Result);
1905 }
1906 else
1907 {
1908 USHORT FirstValue, SecondValue, Result;
1909
1910 if (!Soft386ReadModrmWordOperands(State,
1911 &ModRegRm,
1912 &FirstValue,
1913 &SecondValue))
1914 {
1915 /* Exception occurred */
1916 return FALSE;
1917 }
1918
1919 /* Calculate the result */
1920 Result = FirstValue & SecondValue;
1921
1922 /* Update the flags */
1923 State->Flags.Cf = FALSE;
1924 State->Flags.Of = FALSE;
1925 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1926 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
1927 State->Flags.Pf = Soft386CalculateParity(Result);
1928
1929 /* Write back the result */
1930 return Soft386WriteModrmWordOperands(State,
1931 &ModRegRm,
1932 Opcode & SOFT386_OPCODE_WRITE_REG,
1933 Result);
1934 }
1935 }
1936
1937 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndAl)
1938 {
1939 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
1940 UCHAR SecondValue, Result;
1941
1942 /* Make sure this is the right instruction */
1943 ASSERT(Opcode == 0x24);
1944
1945 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
1946 {
1947 /* Invalid prefix */
1948 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1949 return FALSE;
1950 }
1951
1952 if (!Soft386FetchByte(State, &SecondValue))
1953 {
1954 /* Exception occurred */
1955 return FALSE;
1956 }
1957
1958 /* Calculate the result */
1959 Result = FirstValue & SecondValue;
1960
1961 /* Update the flags */
1962 State->Flags.Cf = FALSE;
1963 State->Flags.Of = FALSE;
1964 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1965 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1966 State->Flags.Pf = Soft386CalculateParity(Result);
1967
1968 /* Write back the result */
1969 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
1970
1971 return TRUE;
1972 }
1973
1974 SOFT386_OPCODE_HANDLER(Soft386OpcodeAndEax)
1975 {
1976 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
1977
1978 /* Make sure this is the right instruction */
1979 ASSERT(Opcode == 0x25);
1980
1981 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
1982 {
1983 /* Invalid prefix */
1984 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1985 return FALSE;
1986 }
1987
1988 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1989 {
1990 /* The OPSIZE prefix toggles the size */
1991 Size = !Size;
1992 }
1993
1994 if (Size)
1995 {
1996 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
1997 ULONG SecondValue, Result;
1998
1999 if (!Soft386FetchDword(State, &SecondValue))
2000 {
2001 /* Exception occurred */
2002 return FALSE;
2003 }
2004
2005 /* Calculate the result */
2006 Result = FirstValue & SecondValue;
2007
2008 /* Update the flags */
2009 State->Flags.Cf = FALSE;
2010 State->Flags.Of = FALSE;
2011 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2012 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2013 State->Flags.Pf = Soft386CalculateParity(Result);
2014
2015 /* Write back the result */
2016 State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
2017 }
2018 else
2019 {
2020 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
2021 USHORT SecondValue, Result;
2022
2023 if (!Soft386FetchWord(State, &SecondValue))
2024 {
2025 /* Exception occurred */
2026 return FALSE;
2027 }
2028
2029 /* Calculate the result */
2030 Result = FirstValue & SecondValue;
2031
2032 /* Update the flags */
2033 State->Flags.Cf = FALSE;
2034 State->Flags.Of = FALSE;
2035 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2036 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
2037 State->Flags.Pf = Soft386CalculateParity(Result);
2038
2039 /* Write back the result */
2040 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
2041 }
2042
2043 return TRUE;
2044 }
2045
2046 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorByteModrm)
2047 {
2048 UCHAR FirstValue, SecondValue, Result;
2049 SOFT386_MOD_REG_RM ModRegRm;
2050 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2051
2052 /* Make sure this is the right instruction */
2053 ASSERT((Opcode & 0xFD) == 0x30);
2054
2055 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2056 {
2057 /* The ADSIZE prefix toggles the size */
2058 AddressSize = !AddressSize;
2059 }
2060 else if (State->PrefixFlags
2061 & ~(SOFT386_PREFIX_ADSIZE
2062 | SOFT386_PREFIX_SEG
2063 | SOFT386_PREFIX_LOCK))
2064 {
2065 /* Invalid prefix */
2066 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2067 return FALSE;
2068 }
2069
2070 /* Get the operands */
2071 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2072 {
2073 /* Exception occurred */
2074 return FALSE;
2075 }
2076
2077 if (!Soft386ReadModrmByteOperands(State,
2078 &ModRegRm,
2079 &FirstValue,
2080 &SecondValue))
2081 {
2082 /* Exception occurred */
2083 return FALSE;
2084 }
2085
2086 /* Calculate the result */
2087 Result = FirstValue ^ SecondValue;
2088
2089 /* Update the flags */
2090 State->Flags.Cf = FALSE;
2091 State->Flags.Of = FALSE;
2092 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2093 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
2094 State->Flags.Pf = Soft386CalculateParity(Result);
2095
2096 /* Write back the result */
2097 return Soft386WriteModrmByteOperands(State,
2098 &ModRegRm,
2099 Opcode & SOFT386_OPCODE_WRITE_REG,
2100 Result);
2101 }
2102
2103 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorModrm)
2104 {
2105 SOFT386_MOD_REG_RM ModRegRm;
2106 BOOLEAN OperandSize, AddressSize;
2107
2108 /* Make sure this is the right instruction */
2109 ASSERT((Opcode & 0xFD) == 0x31);
2110
2111 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2112
2113 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2114 {
2115 /* The ADSIZE prefix toggles the address size */
2116 AddressSize = !AddressSize;
2117 }
2118
2119 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2120 {
2121 /* The OPSIZE prefix toggles the operand size */
2122 OperandSize = !OperandSize;
2123 }
2124
2125 if (State->PrefixFlags
2126 & ~(SOFT386_PREFIX_ADSIZE
2127 | SOFT386_PREFIX_OPSIZE
2128 | SOFT386_PREFIX_SEG
2129 | SOFT386_PREFIX_LOCK))
2130 {
2131 /* Invalid prefix */
2132 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2133 return FALSE;
2134 }
2135
2136 /* Get the operands */
2137 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2138 {
2139 /* Exception occurred */
2140 return FALSE;
2141 }
2142
2143 /* Check the operand size */
2144 if (OperandSize)
2145 {
2146 ULONG FirstValue, SecondValue, Result;
2147
2148 if (!Soft386ReadModrmDwordOperands(State,
2149 &ModRegRm,
2150 &FirstValue,
2151 &SecondValue))
2152 {
2153 /* Exception occurred */
2154 return FALSE;
2155 }
2156
2157 /* Calculate the result */
2158 Result = FirstValue ^ SecondValue;
2159
2160 /* Update the flags */
2161 State->Flags.Cf = FALSE;
2162 State->Flags.Of = FALSE;
2163 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2164 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2165 State->Flags.Pf = Soft386CalculateParity(Result);
2166
2167 /* Write back the result */
2168 return Soft386WriteModrmDwordOperands(State,
2169 &ModRegRm,
2170 Opcode & SOFT386_OPCODE_WRITE_REG,
2171 Result);
2172 }
2173 else
2174 {
2175 USHORT FirstValue, SecondValue, Result;
2176
2177 if (!Soft386ReadModrmWordOperands(State,
2178 &ModRegRm,
2179 &FirstValue,
2180 &SecondValue))
2181 {
2182 /* Exception occurred */
2183 return FALSE;
2184 }
2185
2186 /* Calculate the result */
2187 Result = FirstValue ^ SecondValue;
2188
2189 /* Update the flags */
2190 State->Flags.Cf = FALSE;
2191 State->Flags.Of = FALSE;
2192 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2193 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2194 State->Flags.Pf = Soft386CalculateParity(Result);
2195
2196 /* Write back the result */
2197 return Soft386WriteModrmWordOperands(State,
2198 &ModRegRm,
2199 Opcode & SOFT386_OPCODE_WRITE_REG,
2200 Result);
2201 }
2202 }
2203
2204 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorAl)
2205 {
2206 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
2207 UCHAR SecondValue, Result;
2208
2209 /* Make sure this is the right instruction */
2210 ASSERT(Opcode == 0x34);
2211
2212 if (State->PrefixFlags)
2213 {
2214 /* This opcode doesn't take any prefixes */
2215 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2216 return FALSE;
2217 }
2218
2219 if (!Soft386FetchByte(State, &SecondValue))
2220 {
2221 /* Exception occurred */
2222 return FALSE;
2223 }
2224
2225 /* Calculate the result */
2226 Result = FirstValue ^ SecondValue;
2227
2228 /* Update the flags */
2229 State->Flags.Cf = FALSE;
2230 State->Flags.Of = FALSE;
2231 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2232 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
2233 State->Flags.Pf = Soft386CalculateParity(Result);
2234
2235 /* Write back the result */
2236 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
2237
2238 return TRUE;
2239 }
2240
2241 SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax)
2242 {
2243 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
2244
2245 /* Make sure this is the right instruction */
2246 ASSERT(Opcode == 0x35);
2247
2248 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
2249 {
2250 /* Invalid prefix */
2251 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2252 return FALSE;
2253 }
2254
2255 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2256 {
2257 /* The OPSIZE prefix toggles the size */
2258 Size = !Size;
2259 }
2260
2261 if (Size)
2262 {
2263 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
2264 ULONG SecondValue, Result;
2265
2266 if (!Soft386FetchDword(State, &SecondValue))
2267 {
2268 /* Exception occurred */
2269 return FALSE;
2270 }
2271
2272 /* Calculate the result */
2273 Result = FirstValue ^ SecondValue;
2274
2275 /* Update the flags */
2276 State->Flags.Cf = FALSE;
2277 State->Flags.Of = FALSE;
2278 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2279 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2280 State->Flags.Pf = Soft386CalculateParity(Result);
2281
2282 /* Write back the result */
2283 State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
2284 }
2285 else
2286 {
2287 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
2288 USHORT SecondValue, Result;
2289
2290 if (!Soft386FetchWord(State, &SecondValue))
2291 {
2292 /* Exception occurred */
2293 return FALSE;
2294 }
2295
2296 /* Calculate the result */
2297 Result = FirstValue ^ SecondValue;
2298
2299 /* Update the flags */
2300 State->Flags.Cf = FALSE;
2301 State->Flags.Of = FALSE;
2302 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2303 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
2304 State->Flags.Pf = Soft386CalculateParity(Result);
2305
2306 /* Write back the result */
2307 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
2308 }
2309
2310 return TRUE;
2311 }
2312
2313 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm)
2314 {
2315 UCHAR FirstValue, SecondValue, Result;
2316 SOFT386_MOD_REG_RM ModRegRm;
2317 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2318
2319 /* Make sure this is the right instruction */
2320 ASSERT(Opcode == 0x84);
2321
2322 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2323 {
2324 /* The ADSIZE prefix toggles the size */
2325 AddressSize = !AddressSize;
2326 }
2327 else if (State->PrefixFlags
2328 & ~(SOFT386_PREFIX_ADSIZE
2329 | SOFT386_PREFIX_SEG
2330 | SOFT386_PREFIX_LOCK))
2331 {
2332 /* Invalid prefix */
2333 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2334 return FALSE;
2335 }
2336
2337 /* Get the operands */
2338 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2339 {
2340 /* Exception occurred */
2341 return FALSE;
2342 }
2343
2344 if (!Soft386ReadModrmByteOperands(State,
2345 &ModRegRm,
2346 &FirstValue,
2347 &SecondValue))
2348 {
2349 /* Exception occurred */
2350 return FALSE;
2351 }
2352 /* Calculate the result */
2353 Result = FirstValue & SecondValue;
2354
2355 /* Update the flags */
2356 State->Flags.Cf = FALSE;
2357 State->Flags.Of = FALSE;
2358 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2359 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
2360 State->Flags.Pf = Soft386CalculateParity(Result);
2361
2362 /* The result is discarded */
2363 return TRUE;
2364 }
2365
2366 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm)
2367 {
2368 SOFT386_MOD_REG_RM ModRegRm;
2369 BOOLEAN OperandSize, AddressSize;
2370
2371 /* Make sure this is the right instruction */
2372 ASSERT(Opcode == 0x85);
2373
2374 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2375
2376 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2377 {
2378 /* The ADSIZE prefix toggles the address size */
2379 AddressSize = !AddressSize;
2380 }
2381
2382 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2383 {
2384 /* The OPSIZE prefix toggles the operand size */
2385 OperandSize = !OperandSize;
2386 }
2387
2388 if (State->PrefixFlags
2389 & ~(SOFT386_PREFIX_ADSIZE
2390 | SOFT386_PREFIX_OPSIZE
2391 | SOFT386_PREFIX_SEG
2392 | SOFT386_PREFIX_LOCK))
2393 {
2394 /* Invalid prefix */
2395 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2396 return FALSE;
2397 }
2398
2399 /* Get the operands */
2400 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2401 {
2402 /* Exception occurred */
2403 return FALSE;
2404 }
2405
2406 /* Check the operand size */
2407 if (OperandSize)
2408 {
2409 ULONG FirstValue, SecondValue, Result;
2410
2411 if (!Soft386ReadModrmDwordOperands(State,
2412 &ModRegRm,
2413 &FirstValue,
2414 &SecondValue))
2415 {
2416 /* Exception occurred */
2417 return FALSE;
2418 }
2419
2420 /* Calculate the result */
2421 Result = FirstValue & SecondValue;
2422
2423 /* Update the flags */
2424 State->Flags.Cf = FALSE;
2425 State->Flags.Of = FALSE;
2426 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2427 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2428 State->Flags.Pf = Soft386CalculateParity(Result);
2429 }
2430 else
2431 {
2432 USHORT FirstValue, SecondValue, Result;
2433
2434 if (!Soft386ReadModrmWordOperands(State,
2435 &ModRegRm,
2436 &FirstValue,
2437 &SecondValue))
2438 {
2439 /* Exception occurred */
2440 return FALSE;
2441 }
2442
2443 /* Calculate the result */
2444 Result = FirstValue & SecondValue;
2445
2446 /* Update the flags */
2447 State->Flags.Cf = FALSE;
2448 State->Flags.Of = FALSE;
2449 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2450 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2451 State->Flags.Pf = Soft386CalculateParity(Result);
2452 }
2453
2454 /* The result is discarded */
2455 return TRUE;
2456 }
2457
2458 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestAl)
2459 {
2460 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
2461 UCHAR SecondValue, Result;
2462
2463 /* Make sure this is the right instruction */
2464 ASSERT(Opcode == 0xA8);
2465
2466 if (State->PrefixFlags)
2467 {
2468 /* This opcode doesn't take any prefixes */
2469 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2470 return FALSE;
2471 }
2472
2473 if (!Soft386FetchByte(State, &SecondValue))
2474 {
2475 /* Exception occurred */
2476 return FALSE;
2477 }
2478
2479 /* Calculate the result */
2480 Result = FirstValue & SecondValue;
2481
2482 /* Update the flags */
2483 State->Flags.Cf = FALSE;
2484 State->Flags.Of = FALSE;
2485 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2486 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
2487 State->Flags.Pf = Soft386CalculateParity(Result);
2488
2489 /* The result is discarded */
2490 return TRUE;
2491 }
2492
2493 SOFT386_OPCODE_HANDLER(Soft386OpcodeTestEax)
2494 {
2495 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
2496
2497 /* Make sure this is the right instruction */
2498 ASSERT(Opcode == 0xA9);
2499
2500 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
2501 {
2502 /* Invalid prefix */
2503 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2504 return FALSE;
2505 }
2506
2507 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2508 {
2509 /* The OPSIZE prefix toggles the size */
2510 Size = !Size;
2511 }
2512
2513 if (Size)
2514 {
2515 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
2516 ULONG SecondValue, Result;
2517
2518 if (!Soft386FetchDword(State, &SecondValue))
2519 {
2520 /* Exception occurred */
2521 return FALSE;
2522 }
2523
2524 /* Calculate the result */
2525 Result = FirstValue & SecondValue;
2526
2527 /* Update the flags */
2528 State->Flags.Cf = FALSE;
2529 State->Flags.Of = FALSE;
2530 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2531 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2532 State->Flags.Pf = Soft386CalculateParity(Result);
2533 }
2534 else
2535 {
2536 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
2537 USHORT SecondValue, Result;
2538
2539 if (!Soft386FetchWord(State, &SecondValue))
2540 {
2541 /* Exception occurred */
2542 return FALSE;
2543 }
2544
2545 /* Calculate the result */
2546 Result = FirstValue & SecondValue;
2547
2548 /* Update the flags */
2549 State->Flags.Cf = FALSE;
2550 State->Flags.Of = FALSE;
2551 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2552 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
2553 State->Flags.Pf = Soft386CalculateParity(Result);
2554 }
2555
2556 /* The result is discarded */
2557 return TRUE;
2558 }
2559
2560 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm)
2561 {
2562 UCHAR FirstValue, SecondValue;
2563 SOFT386_MOD_REG_RM ModRegRm;
2564 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2565
2566 /* Make sure this is the right instruction */
2567 ASSERT(Opcode == 0x86);
2568
2569 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2570 {
2571 /* The ADSIZE prefix toggles the size */
2572 AddressSize = !AddressSize;
2573 }
2574 else if (State->PrefixFlags
2575 & ~(SOFT386_PREFIX_ADSIZE
2576 | SOFT386_PREFIX_SEG
2577 | SOFT386_PREFIX_LOCK))
2578 {
2579 /* Invalid prefix */
2580 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2581 return FALSE;
2582 }
2583
2584 /* Get the operands */
2585 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2586 {
2587 /* Exception occurred */
2588 return FALSE;
2589 }
2590
2591 if (!Soft386ReadModrmByteOperands(State,
2592 &ModRegRm,
2593 &FirstValue,
2594 &SecondValue))
2595 {
2596 /* Exception occurred */
2597 return FALSE;
2598 }
2599
2600 /* Write the value from the register to the R/M */
2601 if (!Soft386WriteModrmByteOperands(State,
2602 &ModRegRm,
2603 FALSE,
2604 FirstValue))
2605 {
2606 /* Exception occurred */
2607 return FALSE;
2608 }
2609
2610 /* Write the value from the R/M to the register */
2611 if (!Soft386WriteModrmByteOperands(State,
2612 &ModRegRm,
2613 TRUE,
2614 SecondValue))
2615 {
2616 /* Exception occurred */
2617 return FALSE;
2618 }
2619
2620 return TRUE;
2621 }
2622
2623 SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm)
2624 {
2625 SOFT386_MOD_REG_RM ModRegRm;
2626 BOOLEAN OperandSize, AddressSize;
2627
2628 /* Make sure this is the right instruction */
2629 ASSERT(Opcode == 0x87);
2630
2631 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2632
2633 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2634 {
2635 /* The ADSIZE prefix toggles the address size */
2636 AddressSize = !AddressSize;
2637 }
2638
2639 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2640 {
2641 /* The OPSIZE prefix toggles the operand size */
2642 OperandSize = !OperandSize;
2643 }
2644
2645 if (State->PrefixFlags
2646 & ~(SOFT386_PREFIX_ADSIZE
2647 | SOFT386_PREFIX_OPSIZE
2648 | SOFT386_PREFIX_SEG
2649 | SOFT386_PREFIX_LOCK))
2650 {
2651 /* Invalid prefix */
2652 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2653 return FALSE;
2654 }
2655
2656 /* Get the operands */
2657 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2658 {
2659 /* Exception occurred */
2660 return FALSE;
2661 }
2662
2663 /* Check the operand size */
2664 if (OperandSize)
2665 {
2666 ULONG FirstValue, SecondValue;
2667
2668 if (!Soft386ReadModrmDwordOperands(State,
2669 &ModRegRm,
2670 &FirstValue,
2671 &SecondValue))
2672 {
2673 /* Exception occurred */
2674 return FALSE;
2675 }
2676
2677 /* Write the value from the register to the R/M */
2678 if (!Soft386WriteModrmDwordOperands(State,
2679 &ModRegRm,
2680 FALSE,
2681 FirstValue))
2682 {
2683 /* Exception occurred */
2684 return FALSE;
2685 }
2686
2687 /* Write the value from the R/M to the register */
2688 if (!Soft386WriteModrmDwordOperands(State,
2689 &ModRegRm,
2690 TRUE,
2691 SecondValue))
2692 {
2693 /* Exception occurred */
2694 return FALSE;
2695 }
2696 }
2697 else
2698 {
2699 USHORT FirstValue, SecondValue;
2700
2701 if (!Soft386ReadModrmWordOperands(State,
2702 &ModRegRm,
2703 &FirstValue,
2704 &SecondValue))
2705 {
2706 /* Exception occurred */
2707 return FALSE;
2708 }
2709
2710 /* Write the value from the register to the R/M */
2711 if (!Soft386WriteModrmWordOperands(State,
2712 &ModRegRm,
2713 FALSE,
2714 FirstValue))
2715 {
2716 /* Exception occurred */
2717 return FALSE;
2718 }
2719
2720 /* Write the value from the R/M to the register */
2721 if (!Soft386WriteModrmWordOperands(State,
2722 &ModRegRm,
2723 TRUE,
2724 SecondValue))
2725 {
2726 /* Exception occurred */
2727 return FALSE;
2728 }
2729 }
2730
2731 /* The result is discarded */
2732 return TRUE;
2733 }
2734
2735 SOFT386_OPCODE_HANDLER(Soft386OpcodePushEs)
2736 {
2737 /* Call the internal API */
2738 return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_ES].Selector);
2739 }
2740
2741 SOFT386_OPCODE_HANDLER(Soft386OpcodePopEs)
2742 {
2743 ULONG NewSelector;
2744
2745 if (!Soft386StackPop(State, &NewSelector))
2746 {
2747 /* Exception occurred */
2748 return FALSE;
2749 }
2750
2751 /* Call the internal API */
2752 return Soft386LoadSegment(State, SOFT386_REG_ES, LOWORD(NewSelector));
2753 }
2754
2755 SOFT386_OPCODE_HANDLER(Soft386OpcodePushCs)
2756 {
2757 /* Call the internal API */
2758 return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_CS].Selector);
2759 }
2760
2761 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcByteModrm)
2762 {
2763 UCHAR FirstValue, SecondValue, Result;
2764 SOFT386_MOD_REG_RM ModRegRm;
2765 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2766
2767 /* Make sure this is the right instruction */
2768 ASSERT((Opcode & 0xFD) == 0x10);
2769
2770 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2771 {
2772 /* The ADSIZE prefix toggles the size */
2773 AddressSize = !AddressSize;
2774 }
2775 else if (State->PrefixFlags
2776 & ~(SOFT386_PREFIX_ADSIZE
2777 | SOFT386_PREFIX_SEG
2778 | SOFT386_PREFIX_LOCK))
2779 {
2780 /* Invalid prefix */
2781 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2782 return FALSE;
2783 }
2784
2785 /* Get the operands */
2786 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2787 {
2788 /* Exception occurred */
2789 return FALSE;
2790 }
2791
2792 if (!Soft386ReadModrmByteOperands(State,
2793 &ModRegRm,
2794 &FirstValue,
2795 &SecondValue))
2796 {
2797 /* Exception occurred */
2798 return FALSE;
2799 }
2800
2801 /* Calculate the result */
2802 Result = FirstValue + SecondValue + State->Flags.Cf;
2803
2804 /* Special exception for CF */
2805 State->Flags.Cf = State->Flags.Cf
2806 && ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2807
2808 /* Update the flags */
2809 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2810 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2811 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2812 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
2813 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2814 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
2815 State->Flags.Pf = Soft386CalculateParity(Result);
2816
2817 /* Write back the result */
2818 return Soft386WriteModrmByteOperands(State,
2819 &ModRegRm,
2820 Opcode & SOFT386_OPCODE_WRITE_REG,
2821 Result);
2822 }
2823
2824 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcModrm)
2825 {
2826 SOFT386_MOD_REG_RM ModRegRm;
2827 BOOLEAN OperandSize, AddressSize;
2828
2829 /* Make sure this is the right instruction */
2830 ASSERT((Opcode & 0xFD) == 0x11);
2831
2832 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
2833
2834 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
2835 {
2836 /* The ADSIZE prefix toggles the address size */
2837 AddressSize = !AddressSize;
2838 }
2839
2840 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2841 {
2842 /* The OPSIZE prefix toggles the operand size */
2843 OperandSize = !OperandSize;
2844 }
2845
2846 if (State->PrefixFlags
2847 & ~(SOFT386_PREFIX_ADSIZE
2848 | SOFT386_PREFIX_OPSIZE
2849 | SOFT386_PREFIX_SEG
2850 | SOFT386_PREFIX_LOCK))
2851 {
2852 /* Invalid prefix */
2853 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2854 return FALSE;
2855 }
2856
2857 /* Get the operands */
2858 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
2859 {
2860 /* Exception occurred */
2861 return FALSE;
2862 }
2863
2864 /* Check the operand size */
2865 if (OperandSize)
2866 {
2867 ULONG FirstValue, SecondValue, Result;
2868
2869 if (!Soft386ReadModrmDwordOperands(State,
2870 &ModRegRm,
2871 &FirstValue,
2872 &SecondValue))
2873 {
2874 /* Exception occurred */
2875 return FALSE;
2876 }
2877
2878 /* Calculate the result */
2879 Result = FirstValue + SecondValue + State->Flags.Cf;
2880
2881 /* Special exception for CF */
2882 State->Flags.Cf = State->Flags.Cf
2883 && ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
2884
2885 /* Update the flags */
2886 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2887 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
2888 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
2889 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
2890 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2891 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
2892 State->Flags.Pf = Soft386CalculateParity(Result);
2893
2894 /* Write back the result */
2895 return Soft386WriteModrmDwordOperands(State,
2896 &ModRegRm,
2897 Opcode & SOFT386_OPCODE_WRITE_REG,
2898 Result);
2899 }
2900 else
2901 {
2902 USHORT FirstValue, SecondValue, Result;
2903
2904 if (!Soft386ReadModrmWordOperands(State,
2905 &ModRegRm,
2906 &FirstValue,
2907 &SecondValue))
2908 {
2909 /* Exception occurred */
2910 return FALSE;
2911 }
2912
2913 /* Calculate the result */
2914 Result = FirstValue + SecondValue + State->Flags.Cf;
2915
2916 /* Special exception for CF */
2917 State->Flags.Cf = State->Flags.Cf
2918 && ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
2919
2920 /* Update the flags */
2921 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2922 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
2923 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
2924 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
2925 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2926 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
2927 State->Flags.Pf = Soft386CalculateParity(Result);
2928
2929 /* Write back the result */
2930 return Soft386WriteModrmWordOperands(State,
2931 &ModRegRm,
2932 Opcode & SOFT386_OPCODE_WRITE_REG,
2933 Result);
2934 }
2935
2936 }
2937
2938 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcAl)
2939 {
2940 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
2941 UCHAR SecondValue, Result;
2942
2943 /* Make sure this is the right instruction */
2944 ASSERT(Opcode == 0x14);
2945
2946 if (State->PrefixFlags)
2947 {
2948 /* This opcode doesn't take any prefixes */
2949 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2950 return FALSE;
2951 }
2952
2953 if (!Soft386FetchByte(State, &SecondValue))
2954 {
2955 /* Exception occurred */
2956 return FALSE;
2957 }
2958
2959 /* Calculate the result */
2960 Result = FirstValue + SecondValue + State->Flags.Cf;
2961
2962 /* Special exception for CF */
2963 State->Flags.Cf = State->Flags.Cf &&
2964 ((FirstValue == 0xFF) || (SecondValue == 0xFF));
2965
2966 /* Update the flags */
2967 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
2968 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) == (SecondValue & SIGN_FLAG_BYTE))
2969 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
2970 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
2971 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
2972 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
2973 State->Flags.Pf = Soft386CalculateParity(Result);
2974
2975 /* Write back the result */
2976 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
2977
2978 return TRUE;
2979 }
2980
2981 SOFT386_OPCODE_HANDLER(Soft386OpcodeAdcEax)
2982 {
2983 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
2984
2985 /* Make sure this is the right instruction */
2986 ASSERT(Opcode == 0x15);
2987
2988 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
2989 {
2990 /* Invalid prefix */
2991 Soft386Exception(State, SOFT386_EXCEPTION_UD);
2992 return FALSE;
2993 }
2994
2995 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
2996 {
2997 /* The OPSIZE prefix toggles the size */
2998 Size = !Size;
2999 }
3000
3001 if (Size)
3002 {
3003 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
3004 ULONG SecondValue, Result;
3005
3006 if (!Soft386FetchDword(State, &SecondValue))
3007 {
3008 /* Exception occurred */
3009 return FALSE;
3010 }
3011
3012 /* Calculate the result */
3013 Result = FirstValue + SecondValue + State->Flags.Cf;
3014
3015 /* Special exception for CF */
3016 State->Flags.Cf = State->Flags.Cf &&
3017 ((FirstValue == 0xFFFFFFFF) || (SecondValue == 0xFFFFFFFF));
3018
3019 /* Update the flags */
3020 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
3021 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) == (SecondValue & SIGN_FLAG_LONG))
3022 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3023 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
3024 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3025 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
3026 State->Flags.Pf = Soft386CalculateParity(Result);
3027
3028 /* Write back the result */
3029 State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
3030 }
3031 else
3032 {
3033 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
3034 USHORT SecondValue, Result;
3035
3036 if (!Soft386FetchWord(State, &SecondValue))
3037 {
3038 /* Exception occurred */
3039 return FALSE;
3040 }
3041
3042 /* Calculate the result */
3043 Result = FirstValue + SecondValue + State->Flags.Cf;
3044
3045 /* Special exception for CF */
3046 State->Flags.Cf = State->Flags.Cf &&
3047 ((FirstValue == 0xFFFF) || (SecondValue == 0xFFFF));
3048
3049 /* Update the flags */
3050 State->Flags.Cf = State->Flags.Cf || ((Result < FirstValue) && (Result < SecondValue));
3051 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) == (SecondValue & SIGN_FLAG_WORD))
3052 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3053 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
3054 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3055 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
3056 State->Flags.Pf = Soft386CalculateParity(Result);
3057
3058 /* Write back the result */
3059 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
3060 }
3061
3062 return TRUE;
3063 }
3064
3065 SOFT386_OPCODE_HANDLER(Soft386OpcodePushSs)
3066 {
3067 /* Call the internal API */
3068 return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_SS].Selector);
3069 }
3070
3071 SOFT386_OPCODE_HANDLER(Soft386OpcodePopSs)
3072 {
3073 ULONG NewSelector;
3074
3075 if (!Soft386StackPop(State, &NewSelector))
3076 {
3077 /* Exception occurred */
3078 return FALSE;
3079 }
3080
3081 /* Call the internal API */
3082 return Soft386LoadSegment(State, SOFT386_REG_SS, LOWORD(NewSelector));
3083 }
3084
3085 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbByteModrm)
3086 {
3087 // TODO: NOT IMPLEMENTED
3088 UNIMPLEMENTED;
3089
3090 return FALSE;
3091 }
3092
3093 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbModrm)
3094 {
3095 // TODO: NOT IMPLEMENTED
3096 UNIMPLEMENTED;
3097
3098 return FALSE;
3099 }
3100
3101 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbAl)
3102 {
3103 // TODO: NOT IMPLEMENTED
3104 UNIMPLEMENTED;
3105
3106 return FALSE;
3107 }
3108
3109 SOFT386_OPCODE_HANDLER(Soft386OpcodeSbbEax)
3110 {
3111 // TODO: NOT IMPLEMENTED
3112 UNIMPLEMENTED;
3113
3114 return FALSE;
3115 }
3116
3117 SOFT386_OPCODE_HANDLER(Soft386OpcodePushDs)
3118 {
3119 /* Call the internal API */
3120 return Soft386StackPush(State, State->SegmentRegs[SOFT386_REG_DS].Selector);
3121 }
3122
3123 SOFT386_OPCODE_HANDLER(Soft386OpcodePopDs)
3124 {
3125 ULONG NewSelector;
3126
3127 if (!Soft386StackPop(State, &NewSelector))
3128 {
3129 /* Exception occurred */
3130 return FALSE;
3131 }
3132
3133 /* Call the internal API */
3134 return Soft386LoadSegment(State, SOFT386_REG_DS, LOWORD(NewSelector));
3135 }
3136
3137 SOFT386_OPCODE_HANDLER(Soft386OpcodeDaa)
3138 {
3139 UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
3140 BOOLEAN Carry = State->Flags.Cf;
3141
3142 /* Clear the carry flag */
3143 State->Flags.Cf = FALSE;
3144
3145 /* Check if the first BCD digit is invalid or there was a carry from it */
3146 if (((Value & 0x0F) > 9) || State->Flags.Af)
3147 {
3148 /* Correct it */
3149 State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
3150 if (State->GeneralRegs[SOFT386_REG_EAX].LowByte < 0x06)
3151 {
3152 /* A carry occurred */
3153 State->Flags.Cf = TRUE;
3154 }
3155
3156 /* Set the adjust flag */
3157 State->Flags.Af = TRUE;
3158 }
3159
3160 /* Check if the second BCD digit is invalid or there was a carry from it */
3161 if ((Value > 0x99) || Carry)
3162 {
3163 /* Correct it */
3164 State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x60;
3165
3166 /* There was a carry */
3167 State->Flags.Cf = TRUE;
3168 }
3169
3170 return TRUE;
3171 }
3172
3173 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubByteModrm)
3174 {
3175 UCHAR FirstValue, SecondValue, Result;
3176 SOFT386_MOD_REG_RM ModRegRm;
3177 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
3178
3179 /* Make sure this is the right instruction */
3180 ASSERT((Opcode & 0xED) == 0x28);
3181
3182 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
3183 {
3184 /* The ADSIZE prefix toggles the size */
3185 AddressSize = !AddressSize;
3186 }
3187 else if (State->PrefixFlags
3188 & ~(SOFT386_PREFIX_ADSIZE
3189 | SOFT386_PREFIX_SEG
3190 | SOFT386_PREFIX_LOCK))
3191 {
3192 /* Invalid prefix */
3193 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3194 return FALSE;
3195 }
3196
3197 /* Get the operands */
3198 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
3199 {
3200 /* Exception occurred */
3201 return FALSE;
3202 }
3203
3204 if (!Soft386ReadModrmByteOperands(State,
3205 &ModRegRm,
3206 &FirstValue,
3207 &SecondValue))
3208 {
3209 /* Exception occurred */
3210 return FALSE;
3211 }
3212
3213 /* Check if this is the instruction that writes to R/M */
3214 if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
3215 {
3216 /* Swap the order */
3217 FirstValue ^= SecondValue;
3218 SecondValue ^= FirstValue;
3219 FirstValue ^= SecondValue;
3220 }
3221
3222 /* Calculate the result */
3223 Result = FirstValue - SecondValue;
3224
3225 /* Update the flags */
3226 State->Flags.Cf = FirstValue < SecondValue;
3227 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3228 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3229 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3230 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3231 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
3232 State->Flags.Pf = Soft386CalculateParity(Result);
3233
3234 /* Check if this is not a CMP */
3235 if (!(Opcode & 0x10))
3236 {
3237 /* Write back the result */
3238 return Soft386WriteModrmByteOperands(State,
3239 &ModRegRm,
3240 Opcode & SOFT386_OPCODE_WRITE_REG,
3241 Result);
3242 }
3243 else
3244 {
3245 /* Discard the result */
3246 return TRUE;
3247 }
3248 }
3249
3250 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubModrm)
3251 {
3252 SOFT386_MOD_REG_RM ModRegRm;
3253 BOOLEAN OperandSize, AddressSize;
3254
3255 /* Make sure this is the right instruction */
3256 ASSERT((Opcode & 0xED) == 0x29);
3257
3258 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
3259
3260 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
3261 {
3262 /* The ADSIZE prefix toggles the address size */
3263 AddressSize = !AddressSize;
3264 }
3265
3266 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
3267 {
3268 /* The OPSIZE prefix toggles the operand size */
3269 OperandSize = !OperandSize;
3270 }
3271
3272 if (State->PrefixFlags
3273 & ~(SOFT386_PREFIX_ADSIZE
3274 | SOFT386_PREFIX_OPSIZE
3275 | SOFT386_PREFIX_SEG
3276 | SOFT386_PREFIX_LOCK))
3277 {
3278 /* Invalid prefix */
3279 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3280 return FALSE;
3281 }
3282
3283 /* Get the operands */
3284 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
3285 {
3286 /* Exception occurred */
3287 return FALSE;
3288 }
3289
3290 /* Check the operand size */
3291 if (OperandSize)
3292 {
3293 ULONG FirstValue, SecondValue, Result;
3294
3295 if (!Soft386ReadModrmDwordOperands(State,
3296 &ModRegRm,
3297 &FirstValue,
3298 &SecondValue))
3299 {
3300 /* Exception occurred */
3301 return FALSE;
3302 }
3303
3304 /* Check if this is the instruction that writes to R/M */
3305 if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
3306 {
3307 /* Swap the order */
3308 FirstValue ^= SecondValue;
3309 SecondValue ^= FirstValue;
3310 FirstValue ^= SecondValue;
3311 }
3312
3313 /* Calculate the result */
3314 Result = FirstValue - SecondValue;
3315
3316 /* Update the flags */
3317 State->Flags.Cf = FirstValue < SecondValue;
3318 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3319 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3320 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3321 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3322 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
3323 State->Flags.Pf = Soft386CalculateParity(Result);
3324
3325 /* Check if this is not a CMP */
3326 if (!(Opcode & 0x10))
3327 {
3328 /* Write back the result */
3329 return Soft386WriteModrmDwordOperands(State,
3330 &ModRegRm,
3331 Opcode & SOFT386_OPCODE_WRITE_REG,
3332 Result);
3333 }
3334 else
3335 {
3336 /* Discard the result */
3337 return TRUE;
3338 }
3339 }
3340 else
3341 {
3342 USHORT FirstValue, SecondValue, Result;
3343
3344 if (!Soft386ReadModrmWordOperands(State,
3345 &ModRegRm,
3346 &FirstValue,
3347 &SecondValue))
3348 {
3349 /* Exception occurred */
3350 return FALSE;
3351 }
3352
3353 /* Check if this is the instruction that writes to R/M */
3354 if (!(Opcode & SOFT386_OPCODE_WRITE_REG))
3355 {
3356 /* Swap the order */
3357 FirstValue ^= SecondValue;
3358 SecondValue ^= FirstValue;
3359 FirstValue ^= SecondValue;
3360 }
3361
3362 /* Calculate the result */
3363 Result = FirstValue - SecondValue;
3364
3365 /* Update the flags */
3366 State->Flags.Cf = FirstValue < SecondValue;
3367 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3368 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3369 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3370 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3371 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
3372 State->Flags.Pf = Soft386CalculateParity(Result);
3373
3374 /* Check if this is not a CMP */
3375 if (!(Opcode & 0x10))
3376 {
3377 /* Write back the result */
3378 return Soft386WriteModrmWordOperands(State,
3379 &ModRegRm,
3380 Opcode & SOFT386_OPCODE_WRITE_REG,
3381 Result);
3382 }
3383 else
3384 {
3385 /* Discard the result */
3386 return TRUE;
3387 }
3388 }
3389
3390 }
3391
3392 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubAl)
3393 {
3394 UCHAR FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
3395 UCHAR SecondValue, Result;
3396
3397 /* Make sure this is the right instruction */
3398 ASSERT((Opcode & 0xEF) == 0x2C);
3399
3400 if (State->PrefixFlags)
3401 {
3402 /* This opcode doesn't take any prefixes */
3403 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3404 return FALSE;
3405 }
3406
3407 if (!Soft386FetchByte(State, &SecondValue))
3408 {
3409 /* Exception occurred */
3410 return FALSE;
3411 }
3412
3413 /* Calculate the result */
3414 Result = FirstValue - SecondValue;
3415
3416 /* Update the flags */
3417 State->Flags.Cf = FirstValue < SecondValue;
3418 State->Flags.Of = ((FirstValue & SIGN_FLAG_BYTE) != (SecondValue & SIGN_FLAG_BYTE))
3419 && ((FirstValue & SIGN_FLAG_BYTE) != (Result & SIGN_FLAG_BYTE));
3420 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3421 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3422 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
3423 State->Flags.Pf = Soft386CalculateParity(Result);
3424
3425 /* Check if this is not a CMP */
3426 if (!(Opcode & 0x10))
3427 {
3428 /* Write back the result */
3429 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Result;
3430 }
3431
3432 return TRUE;
3433 }
3434
3435 SOFT386_OPCODE_HANDLER(Soft386OpcodeCmpSubEax)
3436 {
3437 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
3438
3439 /* Make sure this is the right instruction */
3440 ASSERT((Opcode & 0xEF) == 0x2D);
3441
3442 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
3443 {
3444 /* Invalid prefix */
3445 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3446 return FALSE;
3447 }
3448
3449 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
3450 {
3451 /* The OPSIZE prefix toggles the size */
3452 Size = !Size;
3453 }
3454
3455 if (Size)
3456 {
3457 ULONG FirstValue = State->GeneralRegs[SOFT386_REG_EAX].Long;
3458 ULONG SecondValue, Result;
3459
3460 if (!Soft386FetchDword(State, &SecondValue))
3461 {
3462 /* Exception occurred */
3463 return FALSE;
3464 }
3465
3466 /* Calculate the result */
3467 Result = FirstValue - SecondValue;
3468
3469 /* Update the flags */
3470 State->Flags.Cf = FirstValue < SecondValue;
3471 State->Flags.Of = ((FirstValue & SIGN_FLAG_LONG) != (SecondValue & SIGN_FLAG_LONG))
3472 && ((FirstValue & SIGN_FLAG_LONG) != (Result & SIGN_FLAG_LONG));
3473 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3474 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3475 State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE;
3476 State->Flags.Pf = Soft386CalculateParity(Result);
3477
3478 /* Check if this is not a CMP */
3479 if (!(Opcode & 0x10))
3480 {
3481 /* Write back the result */
3482 State->GeneralRegs[SOFT386_REG_EAX].Long = Result;
3483 }
3484 }
3485 else
3486 {
3487 USHORT FirstValue = State->GeneralRegs[SOFT386_REG_EAX].LowWord;
3488 USHORT SecondValue, Result;
3489
3490 if (!Soft386FetchWord(State, &SecondValue))
3491 {
3492 /* Exception occurred */
3493 return FALSE;
3494 }
3495
3496 /* Calculate the result */
3497 Result = FirstValue - SecondValue;
3498
3499 /* Update the flags */
3500 State->Flags.Cf = FirstValue < SecondValue;
3501 State->Flags.Of = ((FirstValue & SIGN_FLAG_WORD) != (SecondValue & SIGN_FLAG_WORD))
3502 && ((FirstValue & SIGN_FLAG_WORD) != (Result & SIGN_FLAG_WORD));
3503 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
3504 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
3505 State->Flags.Sf = (Result & SIGN_FLAG_WORD) ? TRUE : FALSE;
3506 State->Flags.Pf = Soft386CalculateParity(Result);
3507
3508 /* Write back the result */
3509 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
3510 }
3511
3512 return TRUE;
3513 }
3514
3515 SOFT386_OPCODE_HANDLER(Soft386OpcodeDas)
3516 {
3517 UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
3518 BOOLEAN Carry = State->Flags.Cf;
3519
3520 /* Clear the carry flag */
3521 State->Flags.Cf = FALSE;
3522
3523 /* Check if the first BCD digit is invalid or there was a borrow */
3524 if (((Value & 0x0F) > 9) || State->Flags.Af)
3525 {
3526 /* Correct it */
3527 State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
3528 if (State->GeneralRegs[SOFT386_REG_EAX].LowByte > 0xFB)
3529 {
3530 /* A borrow occurred */
3531 State->Flags.Cf = TRUE;
3532 }
3533
3534 /* Set the adjust flag */
3535 State->Flags.Af = TRUE;
3536 }
3537
3538 /* Check if the second BCD digit is invalid or there was a borrow */
3539 if ((Value > 0x99) || Carry)
3540 {
3541 /* Correct it */
3542 State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x60;
3543
3544 /* There was a borrow */
3545 State->Flags.Cf = TRUE;
3546 }
3547
3548 return TRUE;
3549 }
3550
3551 SOFT386_OPCODE_HANDLER(Soft386OpcodeAaa)
3552 {
3553 UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
3554
3555 /*
3556 * Check if the value in AL is not a valid BCD digit,
3557 * or there was a carry from the lowest 4 bits of AL
3558 */
3559 if (((Value & 0x0F) > 9) || State->Flags.Af)
3560 {
3561 /* Correct it */
3562 State->GeneralRegs[SOFT386_REG_EAX].LowByte += 0x06;
3563 State->GeneralRegs[SOFT386_REG_EAX].HighByte++;
3564
3565 /* Set CF and AF */
3566 State->Flags.Cf = State->Flags.Af = TRUE;
3567 }
3568 else
3569 {
3570 /* Clear CF and AF */
3571 State->Flags.Cf = State->Flags.Af = FALSE;
3572 }
3573
3574 /* Keep only the lowest 4 bits of AL */
3575 State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
3576
3577 return TRUE;
3578 }
3579
3580 SOFT386_OPCODE_HANDLER(Soft386OpcodeAas)
3581 {
3582 UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
3583
3584 /*
3585 * Check if the value in AL is not a valid BCD digit,
3586 * or there was a borrow from the lowest 4 bits of AL
3587 */
3588 if (((Value & 0x0F) > 9) || State->Flags.Af)
3589 {
3590 /* Correct it */
3591 State->GeneralRegs[SOFT386_REG_EAX].LowByte -= 0x06;
3592 State->GeneralRegs[SOFT386_REG_EAX].HighByte--;
3593
3594 /* Set CF and AF */
3595 State->Flags.Cf = State->Flags.Af = TRUE;
3596 }
3597 else
3598 {
3599 /* Clear CF and AF */
3600 State->Flags.Cf = State->Flags.Af = FALSE;
3601 }
3602
3603 /* Keep only the lowest 4 bits of AL */
3604 State->GeneralRegs[SOFT386_REG_EAX].LowByte &= 0x0F;
3605
3606 return TRUE;
3607 }
3608
3609 SOFT386_OPCODE_HANDLER(Soft386OpcodePushAll)
3610 {
3611 INT i;
3612 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
3613 SOFT386_REG SavedEsp = State->GeneralRegs[SOFT386_REG_ESP];
3614
3615 /* Make sure this is the right instruction */
3616 ASSERT(Opcode == 0x60);
3617
3618 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
3619 {
3620 /* The OPSIZE prefix toggles the size */
3621 Size = !Size;
3622 }
3623 else
3624 {
3625 /* Invalid prefix */
3626 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3627 return FALSE;
3628 }
3629
3630 /* Push all the registers in order */
3631 for (i = 0; i < SOFT386_NUM_GEN_REGS; i++)
3632 {
3633 if (i == SOFT386_REG_ESP)
3634 {
3635 /* Use the saved ESP instead */
3636 if (!Soft386StackPush(State, Size ? SavedEsp.Long : SavedEsp.LowWord))
3637 {
3638 /* Exception occurred */
3639 return FALSE;
3640 }
3641 }
3642 else
3643 {
3644 /* Push the register */
3645 if (!Soft386StackPush(State, Size ? State->GeneralRegs[i].Long
3646 : State->GeneralRegs[i].LowWord))
3647 {
3648 /* Exception occurred */
3649 return FALSE;
3650 }
3651 }
3652 }
3653
3654 return TRUE;
3655 }
3656
3657 SOFT386_OPCODE_HANDLER(Soft386OpcodePopAll)
3658 {
3659 INT i;
3660 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
3661 ULONG Value;
3662
3663 /* Make sure this is the right instruction */
3664 ASSERT(Opcode == 0x61);
3665
3666 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
3667 {
3668 /* The OPSIZE prefix toggles the size */
3669 Size = !Size;
3670 }
3671 else
3672 {
3673 /* Invalid prefix */
3674 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3675 return FALSE;
3676 }
3677
3678 /* Pop all the registers in reverse order */
3679 for (i = SOFT386_NUM_GEN_REGS - 1; i >= 0; i--)
3680 {
3681 /* Pop the value */
3682 if (!Soft386StackPop(State, &Value))
3683 {
3684 /* Exception occurred */
3685 return FALSE;
3686 }
3687
3688 /* Don't modify ESP */
3689 if (i != SOFT386_REG_ESP)
3690 {
3691 if (Size) State->GeneralRegs[i].Long = Value;
3692 else State->GeneralRegs[i].LowWord = LOWORD(Value);
3693 }
3694 }
3695
3696 return TRUE;
3697 }
3698
3699 SOFT386_OPCODE_HANDLER(Soft386OpcodeBound)
3700 {
3701 // TODO: NOT IMPLEMENTED
3702 UNIMPLEMENTED;
3703
3704 return FALSE;
3705 }
3706
3707 SOFT386_OPCODE_HANDLER(Soft386OpcodeArpl)
3708 {
3709 USHORT FirstValue, SecondValue;
3710 SOFT386_MOD_REG_RM ModRegRm;
3711 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
3712
3713 if (!(State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
3714 || State->Flags.Vm
3715 || (State->PrefixFlags & SOFT386_PREFIX_LOCK))
3716 {
3717 /* Cannot be used in real mode or with a LOCK prefix */
3718 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3719 return FALSE;
3720 }
3721
3722 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
3723 {
3724 /* The ADSIZE prefix toggles the size */
3725 AddressSize = !AddressSize;
3726 }
3727
3728 /* Get the operands */
3729 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
3730 {
3731 /* Exception occurred */
3732 return FALSE;
3733 }
3734
3735 /* Read the operands */
3736 if (!Soft386ReadModrmWordOperands(State,
3737 &ModRegRm,
3738 &FirstValue,
3739 &SecondValue))
3740 {
3741 /* Exception occurred */
3742 return FALSE;
3743 }
3744
3745 /* Check if the RPL needs adjusting */
3746 if ((SecondValue & 3) < (FirstValue & 3))
3747 {
3748 /* Adjust the RPL */
3749 SecondValue &= ~3;
3750 SecondValue |= FirstValue & 3;
3751
3752 /* Set ZF */
3753 State->Flags.Zf = TRUE;
3754
3755 /* Write back the result */
3756 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, SecondValue);
3757 }
3758 else
3759 {
3760 /* Clear ZF */
3761 State->Flags.Zf = FALSE;
3762 return TRUE;
3763 }
3764 }
3765
3766 SOFT386_OPCODE_HANDLER(Soft386OpcodePushImm)
3767 {
3768 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
3769
3770 /* Make sure this is the right instruction */
3771 ASSERT(Opcode == 0x68);
3772
3773 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
3774 {
3775 /* Invalid prefix */
3776 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3777 return FALSE;
3778 }
3779
3780 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
3781 {
3782 /* The OPSIZE prefix toggles the size */
3783 Size = !Size;
3784 }
3785
3786 if (Size)
3787 {
3788 ULONG Data;
3789
3790 if (!Soft386FetchDword(State, &Data))
3791 {
3792 /* Exception occurred */
3793 return FALSE;
3794 }
3795
3796 /* Call the internal API */
3797 return Soft386StackPush(State, Data);
3798 }
3799 else
3800 {
3801 USHORT Data;
3802
3803 if (!Soft386FetchWord(State, &Data))
3804 {
3805 /* Exception occurred */
3806 return FALSE;
3807 }
3808
3809 /* Call the internal API */
3810 return Soft386StackPush(State, Data);
3811 }
3812 }
3813
3814 SOFT386_OPCODE_HANDLER(Soft386OpcodeImulModrmImm)
3815 {
3816 BOOLEAN OperandSize, AddressSize;
3817 SOFT386_MOD_REG_RM ModRegRm;
3818 LONG Multiplier;
3819 LONGLONG Product;
3820
3821 /* Make sure this is the right instruction */
3822 ASSERT((Opcode & 0xFD) == 0x69);
3823
3824 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
3825
3826 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
3827 {
3828 /* The ADSIZE prefix toggles the address size */
3829 AddressSize = !AddressSize;
3830 }
3831
3832 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
3833 {
3834 /* The OPSIZE prefix toggles the operand size */
3835 OperandSize = !OperandSize;
3836 }
3837
3838 /* Fetch the parameters */
3839 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
3840 {
3841 /* Exception occurred */
3842 return FALSE;
3843 }
3844
3845 if (Opcode == 0x6B)
3846 {
3847 CHAR Byte;
3848
3849 /* Fetch the immediate operand */
3850 if (!Soft386FetchByte(State, (PUCHAR)&Byte))
3851 {
3852 /* Exception occurred */
3853 return FALSE;
3854 }
3855
3856 Multiplier = (LONG)Byte;
3857 }
3858 else
3859 {
3860 if (OperandSize)
3861 {
3862 LONG Dword;
3863
3864 /* Fetch the immediate operand */
3865 if (!Soft386FetchDword(State, (PULONG)&Dword))
3866 {
3867 /* Exception occurred */
3868 return FALSE;
3869 }
3870
3871 Multiplier = Dword;
3872 }
3873 else
3874 {
3875 SHORT Word;
3876
3877 /* Fetch the immediate operand */
3878 if (!Soft386FetchWord(State, (PUSHORT)&Word))
3879 {
3880 /* Exception occurred */
3881 return FALSE;
3882 }
3883
3884 Multiplier = (LONG)Word;
3885 }
3886 }
3887
3888 if (OperandSize)
3889 {
3890 LONG RegValue, Multiplicand;
3891
3892 /* Read the operands */
3893 if (!Soft386ReadModrmDwordOperands(State,
3894 &ModRegRm,
3895 (PULONG)&RegValue,
3896 (PULONG)&Multiplicand))
3897 {
3898 /* Exception occurred */
3899 return FALSE;
3900 }
3901
3902 /* Multiply */
3903 Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
3904 }
3905 else
3906 {
3907 SHORT RegValue, Multiplicand;
3908
3909 /* Read the operands */
3910 if (!Soft386ReadModrmWordOperands(State,
3911 &ModRegRm,
3912 (PUSHORT)&RegValue,
3913 (PUSHORT)&Multiplicand))
3914 {
3915 /* Exception occurred */
3916 return FALSE;
3917 }
3918
3919 /* Multiply */
3920 Product = (LONGLONG)Multiplicand * (LONGLONG)Multiplier;
3921 }
3922
3923 /* Check for carry/overflow */
3924 if ((Product < LONG_MIN) || (Product > LONG_MAX))
3925 {
3926 State->Flags.Cf = State->Flags.Of = TRUE;
3927 }
3928 else State->Flags.Cf = State->Flags.Of = FALSE;
3929
3930 /* Write-back the result */
3931 return Soft386WriteModrmDwordOperands(State,
3932 &ModRegRm,
3933 TRUE,
3934 (ULONG)((LONG)Product));
3935 }
3936
3937 SOFT386_OPCODE_HANDLER(Soft386OpcodePushByteImm)
3938 {
3939 UCHAR Data;
3940
3941 /* Make sure this is the right instruction */
3942 ASSERT(Opcode == 0x6A);
3943
3944 if (!Soft386FetchByte(State, &Data))
3945 {
3946 /* Exception occurred */
3947 return FALSE;
3948 }
3949
3950 /* Call the internal API */
3951 return Soft386StackPush(State, Data);
3952 }
3953
3954 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovByteModrm)
3955 {
3956 UCHAR FirstValue, SecondValue, Result;
3957 SOFT386_MOD_REG_RM ModRegRm;
3958 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
3959
3960 /* Make sure this is the right instruction */
3961 ASSERT((Opcode & 0xFD) == 0x88);
3962
3963 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
3964 {
3965 /* The ADSIZE prefix toggles the size */
3966 AddressSize = !AddressSize;
3967 }
3968 else if (State->PrefixFlags
3969 & ~(SOFT386_PREFIX_ADSIZE
3970 | SOFT386_PREFIX_SEG
3971 | SOFT386_PREFIX_LOCK))
3972 {
3973 /* Invalid prefix */
3974 Soft386Exception(State, SOFT386_EXCEPTION_UD);
3975 return FALSE;
3976 }
3977
3978 /* Get the operands */
3979 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
3980 {
3981 /* Exception occurred */
3982 return FALSE;
3983 }
3984
3985 if (!Soft386ReadModrmByteOperands(State,
3986 &ModRegRm,
3987 &FirstValue,
3988 &SecondValue))
3989 {
3990 /* Exception occurred */
3991 return FALSE;
3992 }
3993
3994 if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
3995 else Result = FirstValue;
3996
3997 /* Write back the result */
3998 return Soft386WriteModrmByteOperands(State,
3999 &ModRegRm,
4000 Opcode & SOFT386_OPCODE_WRITE_REG,
4001 Result);
4002
4003 }
4004
4005 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovModrm)
4006 {
4007 SOFT386_MOD_REG_RM ModRegRm;
4008 BOOLEAN OperandSize, AddressSize;
4009
4010 /* Make sure this is the right instruction */
4011 ASSERT((Opcode & 0xFD) == 0x89);
4012
4013 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
4014
4015 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
4016 {
4017 /* The ADSIZE prefix toggles the address size */
4018 AddressSize = !AddressSize;
4019 }
4020
4021 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4022 {
4023 /* The OPSIZE prefix toggles the operand size */
4024 OperandSize = !OperandSize;
4025 }
4026
4027 if (State->PrefixFlags
4028 & ~(SOFT386_PREFIX_ADSIZE
4029 | SOFT386_PREFIX_OPSIZE
4030 | SOFT386_PREFIX_SEG
4031 | SOFT386_PREFIX_LOCK))
4032 {
4033 /* Invalid prefix */
4034 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4035 return FALSE;
4036 }
4037
4038 /* Get the operands */
4039 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
4040 {
4041 /* Exception occurred */
4042 return FALSE;
4043 }
4044
4045 /* Check the operand size */
4046 if (OperandSize)
4047 {
4048 ULONG FirstValue, SecondValue, Result;
4049
4050 if (!Soft386ReadModrmDwordOperands(State,
4051 &ModRegRm,
4052 &FirstValue,
4053 &SecondValue))
4054 {
4055 /* Exception occurred */
4056 return FALSE;
4057 }
4058
4059 if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
4060 else Result = FirstValue;
4061
4062 /* Write back the result */
4063 return Soft386WriteModrmDwordOperands(State,
4064 &ModRegRm,
4065 Opcode & SOFT386_OPCODE_WRITE_REG,
4066 Result);
4067 }
4068 else
4069 {
4070 USHORT FirstValue, SecondValue, Result;
4071
4072 if (!Soft386ReadModrmWordOperands(State,
4073 &ModRegRm,
4074 &FirstValue,
4075 &SecondValue))
4076 {
4077 /* Exception occurred */
4078 return FALSE;
4079 }
4080
4081 if (Opcode & SOFT386_OPCODE_WRITE_REG) Result = SecondValue;
4082 else Result = FirstValue;
4083
4084 /* Write back the result */
4085 return Soft386WriteModrmWordOperands(State,
4086 &ModRegRm,
4087 Opcode & SOFT386_OPCODE_WRITE_REG,
4088 Result);
4089 }
4090 }
4091
4092 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovStoreSeg)
4093 {
4094 BOOLEAN OperandSize, AddressSize;
4095 SOFT386_MOD_REG_RM ModRegRm;
4096
4097 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
4098
4099 /* Make sure this is the right instruction */
4100 ASSERT(Opcode == 0x8C);
4101
4102 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
4103 {
4104 /* The ADSIZE prefix toggles the address size */
4105 AddressSize = !AddressSize;
4106 }
4107
4108 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4109 {
4110 /* The OPSIZE prefix toggles the operand size */
4111 OperandSize = !OperandSize;
4112 }
4113
4114 /* Get the operands */
4115 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
4116 {
4117 /* Exception occurred */
4118 return FALSE;
4119 }
4120
4121 if (ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
4122 {
4123 /* Invalid */
4124 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4125 return FALSE;
4126 }
4127
4128 if (OperandSize)
4129 {
4130 return Soft386WriteModrmDwordOperands(State,
4131 &ModRegRm,
4132 FALSE,
4133 State->SegmentRegs[ModRegRm.Register].Selector);
4134 }
4135 else
4136 {
4137 return Soft386WriteModrmWordOperands(State,
4138 &ModRegRm,
4139 FALSE,
4140 State->SegmentRegs[ModRegRm.Register].Selector);
4141 }
4142 }
4143
4144 SOFT386_OPCODE_HANDLER(Soft386OpcodeLea)
4145 {
4146 SOFT386_MOD_REG_RM ModRegRm;
4147 BOOLEAN OperandSize, AddressSize;
4148
4149 /* Make sure this is the right instruction */
4150 ASSERT(Opcode == 0x8D);
4151
4152 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
4153
4154 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
4155 {
4156 /* The ADSIZE prefix toggles the address size */
4157 AddressSize = !AddressSize;
4158 }
4159
4160 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4161 {
4162 /* The OPSIZE prefix toggles the operand size */
4163 OperandSize = !OperandSize;
4164 }
4165
4166 /* Get the operands */
4167 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
4168 {
4169 /* Exception occurred */
4170 return FALSE;
4171 }
4172
4173 /* The second operand must be memory */
4174 if (!ModRegRm.Memory)
4175 {
4176 /* Invalid */
4177 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4178 return FALSE;
4179 }
4180
4181 /* Write the address to the register */
4182 if (OperandSize)
4183 {
4184 return Soft386WriteModrmDwordOperands(State,
4185 &ModRegRm,
4186 TRUE,
4187 ModRegRm.MemoryAddress);
4188 }
4189 else
4190 {
4191 return Soft386WriteModrmWordOperands(State,
4192 &ModRegRm,
4193 TRUE,
4194 ModRegRm.MemoryAddress);
4195
4196 }
4197 }
4198
4199 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovLoadSeg)
4200 {
4201 BOOLEAN OperandSize, AddressSize;
4202 SOFT386_MOD_REG_RM ModRegRm;
4203
4204 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
4205
4206 /* Make sure this is the right instruction */
4207 ASSERT(Opcode == 0x8E);
4208
4209 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
4210 {
4211 /* The ADSIZE prefix toggles the address size */
4212 AddressSize = !AddressSize;
4213 }
4214
4215 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4216 {
4217 /* The OPSIZE prefix toggles the operand size */
4218 OperandSize = !OperandSize;
4219 }
4220
4221 /* Get the operands */
4222 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
4223 {
4224 /* Exception occurred */
4225 return FALSE;
4226 }
4227
4228 if ((ModRegRm.Register >= SOFT386_NUM_SEG_REGS)
4229 || ((SOFT386_SEG_REGS)ModRegRm.Register == SOFT386_REG_CS))
4230 {
4231 /* Invalid */
4232 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4233 return FALSE;
4234 }
4235
4236 if (OperandSize)
4237 {
4238 ULONG Dummy, Selector;
4239
4240 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Selector))
4241 {
4242 /* Exception occurred */
4243 return FALSE;
4244 }
4245
4246 return Soft386LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
4247 }
4248 else
4249 {
4250 USHORT Dummy, Selector;
4251
4252 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Selector))
4253 {
4254 /* Exception occurred */
4255 return FALSE;
4256 }
4257
4258 return Soft386LoadSegment(State, ModRegRm.Register, Selector);
4259 }
4260 }
4261
4262 SOFT386_OPCODE_HANDLER(Soft386OpcodeCwde)
4263 {
4264 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4265
4266 /* Make sure this is the right instruction */
4267 ASSERT(Opcode == 0x98);
4268
4269 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
4270 {
4271 /* The OPSIZE prefix toggles the size */
4272 Size = !Size;
4273 }
4274 else if (State->PrefixFlags != 0)
4275 {
4276 /* Invalid prefix */
4277 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4278 return FALSE;
4279 }
4280
4281 if (Size)
4282 {
4283 /* Sign extend AX to EAX */
4284 State->GeneralRegs[SOFT386_REG_EAX].Long = MAKELONG
4285 (
4286 State->GeneralRegs[SOFT386_REG_EAX].LowWord,
4287 (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
4288 ? 0xFFFF : 0x0000
4289 );
4290 }
4291 else
4292 {
4293 /* Sign extend AL to AX */
4294 State->GeneralRegs[SOFT386_REG_EAX].HighByte =
4295 (State->GeneralRegs[SOFT386_REG_EAX].LowByte & SIGN_FLAG_BYTE)
4296 ? 0xFF : 0x00;
4297 }
4298
4299 return TRUE;
4300 }
4301
4302 SOFT386_OPCODE_HANDLER(Soft386OpcodeCdq)
4303 {
4304 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4305
4306 /* Make sure this is the right instruction */
4307 ASSERT(Opcode == 0x99);
4308
4309 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
4310 {
4311 /* The OPSIZE prefix toggles the size */
4312 Size = !Size;
4313 }
4314 else if (State->PrefixFlags != 0)
4315 {
4316 /* Invalid prefix */
4317 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4318 return FALSE;
4319 }
4320
4321 if (Size)
4322 {
4323 /* Sign extend EAX to EDX:EAX */
4324 State->GeneralRegs[SOFT386_REG_EDX].Long =
4325 (State->GeneralRegs[SOFT386_REG_EAX].Long & SIGN_FLAG_LONG)
4326 ? 0xFFFFFFFF : 0x00000000;
4327 }
4328 else
4329 {
4330 /* Sign extend AX to DX:AX */
4331 State->GeneralRegs[SOFT386_REG_EDX].LowWord =
4332 (State->GeneralRegs[SOFT386_REG_EAX].LowWord & SIGN_FLAG_WORD)
4333 ? 0xFFFF : 0x0000;
4334 }
4335
4336 return TRUE;
4337 }
4338
4339 SOFT386_OPCODE_HANDLER(Soft386OpcodeCallAbs)
4340 {
4341 // TODO: NOT IMPLEMENTED
4342 UNIMPLEMENTED;
4343
4344 return FALSE;
4345 }
4346
4347 SOFT386_OPCODE_HANDLER(Soft386OpcodeWait)
4348 {
4349 // TODO: NOT IMPLEMENTED
4350 UNIMPLEMENTED;
4351
4352 return FALSE;
4353 }
4354
4355 SOFT386_OPCODE_HANDLER(Soft386OpcodePushFlags)
4356 {
4357 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4358
4359 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
4360 {
4361 /* Invalid prefix */
4362 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4363 return FALSE;
4364 }
4365
4366 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4367 {
4368 /* This OPSIZE prefix toggles the size */
4369 Size = !Size;
4370 }
4371
4372 /* Check for VM86 mode when IOPL is not 3 */
4373 if (State->Flags.Vm && (State->Flags.Iopl != 3))
4374 {
4375 /* Call the VM86 monitor */
4376 Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
4377 return FALSE;
4378 }
4379
4380 /* Push the flags */
4381 if (Size) return Soft386StackPush(State, State->Flags.Long);
4382 else return Soft386StackPush(State, LOWORD(State->Flags.Long));
4383 }
4384
4385 SOFT386_OPCODE_HANDLER(Soft386OpcodePopFlags)
4386 {
4387 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4388 INT Cpl = Soft386GetCurrentPrivLevel(State);
4389 ULONG NewFlags;
4390
4391 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
4392 {
4393 /* Invalid prefix */
4394 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4395 return FALSE;
4396 }
4397
4398 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4399 {
4400 /* This OPSIZE prefix toggles the size */
4401 Size = !Size;
4402 }
4403
4404 /* Pop the new flags */
4405 if (!Soft386StackPop(State, &NewFlags))
4406 {
4407 /* Exception occurred */
4408 return FALSE;
4409 }
4410
4411 if (!State->Flags.Vm)
4412 {
4413 /* Check the current privilege level */
4414 if (Cpl == 0)
4415 {
4416 /* Supervisor */
4417
4418 /* Set the flags */
4419 if (Size)
4420 {
4421 /* Memorize the old state of RF */
4422 BOOLEAN OldRf = State->Flags.Rf;
4423
4424 State->Flags.Long = NewFlags;
4425
4426 /* Restore VM and RF */
4427 State->Flags.Vm = FALSE;
4428 State->Flags.Rf = OldRf;
4429
4430 /* Clear VIF and VIP */
4431 State->Flags.Vif = State->Flags.Vip = FALSE;
4432 }
4433 else State->Flags.LowWord = LOWORD(NewFlags);
4434
4435 /* Restore the reserved bits */
4436 State->Flags.AlwaysSet = TRUE;
4437 State->Flags.Reserved0 = FALSE;
4438 State->Flags.Reserved1 = FALSE;
4439 }
4440 else
4441 {
4442 /* User */
4443
4444 /* Memorize the old state of IF and IOPL */
4445 BOOLEAN OldIf = State->Flags.If;
4446 UINT OldIopl = State->Flags.Iopl;
4447
4448 /* Set the flags */
4449 if (Size)
4450 {
4451 /* Memorize the old state of RF */
4452 BOOLEAN OldRf = State->Flags.Rf;
4453
4454 State->Flags.Long = NewFlags;
4455
4456 /* Restore VM and RF */
4457 State->Flags.Vm = FALSE;
4458 State->Flags.Rf = OldRf;
4459
4460 /* Clear VIF and VIP */
4461 State->Flags.Vif = State->Flags.Vip = FALSE;
4462 }
4463 else State->Flags.LowWord = LOWORD(NewFlags);
4464
4465 /* Restore the reserved bits and IOPL */
4466 State->Flags.AlwaysSet = TRUE;
4467 State->Flags.Reserved0 = FALSE;
4468 State->Flags.Reserved1 = FALSE;
4469 State->Flags.Iopl = OldIopl;
4470
4471 /* Check if the user doesn't have the privilege to change IF */
4472 if (Cpl > State->Flags.Iopl)
4473 {
4474 /* Restore IF */
4475 State->Flags.If = OldIf;
4476 }
4477 }
4478 }
4479 else
4480 {
4481 /* Check the IOPL */
4482 if (State->Flags.Iopl == 3)
4483 {
4484 if (Size)
4485 {
4486 /* Memorize the old state of RF, VIF and VIP */
4487 BOOLEAN OldRf = State->Flags.Rf;
4488 BOOLEAN OldVif = State->Flags.Vif;
4489 BOOLEAN OldVip = State->Flags.Vip;
4490
4491 State->Flags.Long = NewFlags;
4492
4493 /* Restore VM, RF, VIF and VIP */
4494 State->Flags.Vm = TRUE;
4495 State->Flags.Rf = OldRf;
4496 State->Flags.Vif = OldVif;
4497 State->Flags.Vip = OldVip;
4498 }
4499 else State->Flags.LowWord = LOWORD(NewFlags);
4500
4501 /* Restore the reserved bits and IOPL */
4502 State->Flags.AlwaysSet = TRUE;
4503 State->Flags.Reserved0 = FALSE;
4504 State->Flags.Reserved1 = FALSE;
4505 State->Flags.Iopl = 3;
4506 }
4507 else
4508 {
4509 /* Call the VM86 monitor */
4510 Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
4511 }
4512
4513 }
4514
4515 return TRUE;
4516 }
4517
4518 SOFT386_OPCODE_HANDLER(Soft386OpcodeSahf)
4519 {
4520 /* Make sure this is the right instruction */
4521 ASSERT(Opcode == 0x9E);
4522
4523 /* Set the low-order byte of FLAGS to AH */
4524 State->Flags.Long &= 0xFFFFFF00;
4525 State->Flags.Long |= State->GeneralRegs[SOFT386_REG_EAX].HighByte;
4526
4527 /* Restore the reserved bits of FLAGS */
4528 State->Flags.AlwaysSet = TRUE;
4529 State->Flags.Reserved0 = State->Flags.Reserved1 = FALSE;
4530
4531 return FALSE;
4532 }
4533
4534 SOFT386_OPCODE_HANDLER(Soft386OpcodeLahf)
4535 {
4536 /* Make sure this is the right instruction */
4537 ASSERT(Opcode == 0x9F);
4538
4539 /* Set AH to the low-order byte of FLAGS */
4540 State->GeneralRegs[SOFT386_REG_EAX].HighByte = LOBYTE(State->Flags.Long);
4541
4542 return FALSE;
4543 }
4544
4545 SOFT386_OPCODE_HANDLER(Soft386OpcodeRet)
4546 {
4547 ULONG ReturnAddress;
4548 USHORT BytesToPop = 0;
4549 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4550
4551 /* Make sure this is the right instruction */
4552 ASSERT((Opcode & 0xFE) == 0xC2);
4553
4554 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
4555 {
4556 /* Invalid prefix */
4557 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4558 return FALSE;
4559 }
4560
4561 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
4562 {
4563 /* The OPSIZE prefix toggles the size */
4564 Size = !Size;
4565 }
4566
4567 if (Opcode == 0xC2)
4568 {
4569 /* Fetch the number of bytes to pop after the return */
4570 if (!Soft386FetchWord(State, &BytesToPop)) return FALSE;
4571 }
4572
4573 /* Pop the return address */
4574 if (!Soft386StackPop(State, &ReturnAddress)) return FALSE;
4575
4576 /* Return to the calling procedure, and if necessary, pop the parameters */
4577 if (Size)
4578 {
4579 State->InstPtr.Long = ReturnAddress;
4580 State->GeneralRegs[SOFT386_REG_ESP].Long += BytesToPop;
4581 }
4582 else
4583 {
4584 State->InstPtr.LowWord = LOWORD(ReturnAddress);
4585 State->GeneralRegs[SOFT386_REG_ESP].LowWord += BytesToPop;
4586 }
4587
4588 return TRUE;
4589 }
4590
4591 SOFT386_OPCODE_HANDLER(Soft386OpcodeLdsLes)
4592 {
4593 UCHAR FarPointer[6];
4594 BOOLEAN OperandSize, AddressSize;
4595 SOFT386_MOD_REG_RM ModRegRm;
4596
4597 /* Make sure this is the right instruction */
4598 ASSERT((Opcode & 0xFE) == 0xC4);
4599
4600 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
4601
4602 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
4603 {
4604 /* The ADSIZE prefix toggles the size */
4605 AddressSize = !AddressSize;
4606 }
4607
4608 /* Get the operands */
4609 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
4610 {
4611 /* Exception occurred */
4612 return FALSE;
4613 }
4614
4615 if (!ModRegRm.Memory)
4616 {
4617 /* Check if this is a BOP and the host supports BOPs */
4618 if ((Opcode == 0xC4)
4619 && (ModRegRm.Register == SOFT386_REG_EAX)
4620 && (ModRegRm.SecondRegister == SOFT386_REG_ESP)
4621 && (State->BopCallback != NULL))
4622 {
4623 USHORT BopCode;
4624
4625 /* Fetch the BOP code */
4626 if (!Soft386FetchWord(State, &BopCode))
4627 {
4628 /* Exception occurred */
4629 return FALSE;
4630 }
4631
4632 /* Call the BOP handler */
4633 State->BopCallback(State, BopCode);
4634
4635 /* Return success */
4636 return TRUE;
4637 }
4638
4639 /* Invalid */
4640 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4641 return FALSE;
4642 }
4643
4644 if (!Soft386ReadMemory(State,
4645 (State->PrefixFlags & SOFT386_PREFIX_SEG)
4646 ? State->SegmentOverride : SOFT386_REG_DS,
4647 ModRegRm.MemoryAddress,
4648 FALSE,
4649 FarPointer,
4650 OperandSize ? 6 : 4))
4651 {
4652 /* Exception occurred */
4653 return FALSE;
4654 }
4655
4656 if (OperandSize)
4657 {
4658 ULONG Offset = *((PULONG)FarPointer);
4659 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(ULONG)]);
4660
4661 /* Set the register to the offset */
4662 State->GeneralRegs[ModRegRm.Register].Long = Offset;
4663
4664 /* Load the segment */
4665 return Soft386LoadSegment(State,
4666 (Opcode == 0xC4)
4667 ? SOFT386_REG_ES : SOFT386_REG_DS,
4668 Segment);
4669 }
4670 else
4671 {
4672 USHORT Offset = *((PUSHORT)FarPointer);
4673 USHORT Segment = *((PUSHORT)&FarPointer[sizeof(USHORT)]);
4674
4675 /* Set the register to the offset */
4676 State->GeneralRegs[ModRegRm.Register].LowWord = Offset;
4677
4678 /* Load the segment */
4679 return Soft386LoadSegment(State,
4680 (Opcode == 0xC4)
4681 ? SOFT386_REG_ES : SOFT386_REG_DS,
4682 Segment);
4683 }
4684 }
4685
4686 SOFT386_OPCODE_HANDLER(Soft386OpcodeEnter)
4687 {
4688 INT i;
4689 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4690 USHORT FrameSize;
4691 UCHAR NestingLevel;
4692 SOFT386_REG FramePointer;
4693
4694 /* Make sure this is the right instruction */
4695 ASSERT(Opcode == 0xC8);
4696
4697 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
4698 {
4699 /* Invalid prefix */
4700 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4701 return FALSE;
4702 }
4703
4704 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4705 {
4706 /* The OPSIZE prefix toggles the size */
4707 Size = !Size;
4708 }
4709
4710 if (!Soft386FetchWord(State, &FrameSize))
4711 {
4712 /* Exception occurred */
4713 return FALSE;
4714 }
4715
4716 if (!Soft386FetchByte(State, &NestingLevel))
4717 {
4718 /* Exception occurred */
4719 return FALSE;
4720 }
4721
4722 /* Push EBP */
4723 if (!Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].Long))
4724 {
4725 /* Exception occurred */
4726 return FALSE;
4727 }
4728
4729 /* Save ESP */
4730 FramePointer = State->GeneralRegs[SOFT386_REG_ESP];
4731
4732 /* Set up the nested procedure stacks */
4733 for (i = 1; i < NestingLevel; i++)
4734 {
4735 if (Size)
4736 {
4737 State->GeneralRegs[SOFT386_REG_EBP].Long -= 4;
4738 Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].Long);
4739 }
4740 else
4741 {
4742 State->GeneralRegs[SOFT386_REG_EBP].LowWord -= 2;
4743 Soft386StackPush(State, State->GeneralRegs[SOFT386_REG_EBP].LowWord);
4744 }
4745 }
4746
4747 if (NestingLevel > 0) Soft386StackPush(State, FramePointer.Long);
4748
4749 /* Set EBP to the frame pointer */
4750 State->GeneralRegs[SOFT386_REG_EBP] = FramePointer;
4751
4752 /* Reserve space for the frame */
4753 if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long -= (ULONG)FrameSize;
4754 else State->GeneralRegs[SOFT386_REG_ESP].LowWord -= FrameSize;
4755
4756 return TRUE;
4757 }
4758
4759 SOFT386_OPCODE_HANDLER(Soft386OpcodeLeave)
4760 {
4761 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4762
4763 /* Make sure this is the right instruction */
4764 ASSERT(Opcode == 0xC9);
4765
4766 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
4767 {
4768 /* Invalid prefix */
4769 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4770 return FALSE;
4771 }
4772
4773 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4774 {
4775 /* The OPSIZE prefix toggles the size */
4776 Size = !Size;
4777 }
4778
4779 if (Size)
4780 {
4781 /* Set the stack pointer (ESP) to the base pointer (EBP) */
4782 State->GeneralRegs[SOFT386_REG_ESP].Long = State->GeneralRegs[SOFT386_REG_EBP].Long;
4783
4784 /* Pop the saved base pointer from the stack */
4785 return Soft386StackPop(State, &State->GeneralRegs[SOFT386_REG_EBP].Long);
4786 }
4787 else
4788 {
4789 ULONG Value;
4790
4791 /* Set the stack pointer (SP) to the base pointer (BP) */
4792 State->GeneralRegs[SOFT386_REG_ESP].LowWord = State->GeneralRegs[SOFT386_REG_EBP].LowWord;
4793
4794 /* Pop the saved base pointer from the stack */
4795 if (Soft386StackPop(State, &Value))
4796 {
4797 State->GeneralRegs[SOFT386_REG_EBP].LowWord = LOWORD(Value);
4798 return TRUE;
4799 }
4800 else return FALSE;
4801 }
4802 }
4803
4804 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFarImm)
4805 {
4806 // TODO: NOT IMPLEMENTED
4807 UNIMPLEMENTED;
4808
4809 return FALSE;
4810 }
4811
4812 SOFT386_OPCODE_HANDLER(Soft386OpcodeRetFar)
4813 {
4814 // TODO: NOT IMPLEMENTED
4815 UNIMPLEMENTED;
4816
4817 return FALSE;
4818 }
4819
4820 SOFT386_OPCODE_HANDLER(Soft386OpcodeInt)
4821 {
4822 UCHAR IntNum;
4823 SOFT386_IDT_ENTRY IdtEntry;
4824
4825 switch (Opcode)
4826 {
4827 case 0xCC:
4828 {
4829 /* This is the INT3 instruction */
4830 IntNum = 3;
4831 break;
4832 }
4833
4834 case 0xCD:
4835 {
4836 /* Fetch the interrupt number */
4837 if (!Soft386FetchByte(State, &IntNum))
4838 {
4839 /* Exception occurred */
4840 return FALSE;
4841 }
4842
4843 break;
4844 }
4845
4846 case 0xCE:
4847 {
4848 /* Don't do anything if OF is cleared */
4849 if (!State->Flags.Of) return TRUE;
4850
4851 /* Exception #OF */
4852 IntNum = SOFT386_EXCEPTION_OF;
4853
4854 break;
4855 }
4856
4857 default:
4858 {
4859 /* Should not happen */
4860 ASSERT(FALSE);
4861 }
4862 }
4863
4864 /* Get the interrupt vector */
4865 if (!Soft386GetIntVector(State, IntNum, &IdtEntry))
4866 {
4867 /* Exception occurred */
4868 return FALSE;
4869 }
4870
4871 /* Perform the interrupt */
4872 if (!Soft386InterruptInternal(State,
4873 IdtEntry.Selector,
4874 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
4875 IdtEntry.Type))
4876 {
4877 /* Exception occurred */
4878 return FALSE;
4879 }
4880
4881 return TRUE;
4882 }
4883
4884 SOFT386_OPCODE_HANDLER(Soft386OpcodeIret)
4885 {
4886 INT i;
4887 ULONG InstPtr, CodeSel, StackPtr, StackSel;
4888 SOFT386_FLAGS_REG NewFlags;
4889 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
4890
4891 /* Make sure this is the right instruction */
4892 ASSERT(Opcode == 0xCF);
4893
4894 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
4895 {
4896 /* Invalid prefix */
4897 Soft386Exception(State, SOFT386_EXCEPTION_UD);
4898 return FALSE;
4899 }
4900
4901 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
4902 {
4903 /* The OPSIZE prefix toggles the size */
4904 Size = !Size;
4905 }
4906
4907 /* Pop EIP */
4908 if (!Soft386StackPop(State, &InstPtr))
4909 {
4910 /* Exception occurred */
4911 return FALSE;
4912 }
4913
4914 /* Pop CS */
4915 if (!Soft386StackPop(State, &CodeSel))
4916 {
4917 /* Exception occurred */
4918 return FALSE;
4919 }
4920
4921 /* Pop EFLAGS */
4922 if (!Soft386StackPop(State, &NewFlags.Long))
4923 {
4924 /* Exception occurred */
4925 return FALSE;
4926 }
4927
4928 /* Check for protected mode */
4929 if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE)
4930 {
4931 INT Cpl = Soft386GetCurrentPrivLevel(State);
4932
4933 if (State->Flags.Vm)
4934 {
4935 /* Return from VM86 mode */
4936
4937 /* Check the IOPL */
4938 if (State->Flags.Iopl == 3)
4939 {
4940 /* Set new EIP */
4941 State->InstPtr.Long = LOWORD(InstPtr);
4942
4943 /* Load new CS */
4944 if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
4945 {
4946 /* Exception occurred */
4947 return FALSE;
4948 }
4949
4950 /* Set the new flags */
4951 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4952 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4953 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4954 State->Flags.Iopl = 3;
4955 }
4956 else
4957 {
4958 /* Call the VM86 monitor */
4959 Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
4960 return FALSE;
4961 }
4962
4963 return TRUE;
4964 }
4965
4966 if (State->Flags.Nt)
4967 {
4968 /* Nested task return */
4969
4970 UNIMPLEMENTED;
4971 return FALSE;
4972 }
4973
4974 if (NewFlags.Vm)
4975 {
4976 /* Return to VM86 mode */
4977 ULONG Es, Ds, Fs, Gs;
4978
4979 /* Pop ESP, SS, ES, FS, GS */
4980 if (!Soft386StackPop(State, &StackPtr)) return FALSE;
4981 if (!Soft386StackPop(State, &StackSel)) return FALSE;
4982 if (!Soft386StackPop(State, &Es)) return FALSE;
4983 if (!Soft386StackPop(State, &Ds)) return FALSE;
4984 if (!Soft386StackPop(State, &Fs)) return FALSE;
4985 if (!Soft386StackPop(State, &Gs)) return FALSE;
4986
4987 /* Set the new IP */
4988 State->InstPtr.Long = LOWORD(InstPtr);
4989
4990 /* Set the new flags */
4991 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
4992 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
4993 State->Flags.AlwaysSet = State->Flags.Vm = TRUE;
4994
4995 /* Load the new segments */
4996 if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel)) return FALSE;
4997 if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel)) return FALSE;
4998 if (!Soft386LoadSegment(State, SOFT386_REG_ES, Es)) return FALSE;
4999 if (!Soft386LoadSegment(State, SOFT386_REG_DS, Ds)) return FALSE;
5000 if (!Soft386LoadSegment(State, SOFT386_REG_FS, Fs)) return FALSE;
5001 if (!Soft386LoadSegment(State, SOFT386_REG_GS, Gs)) return FALSE;
5002
5003 return TRUE;
5004 }
5005
5006 /* Load the new CS */
5007 if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
5008 {
5009 /* Exception occurred */
5010 return FALSE;
5011 }
5012
5013 /* Set EIP */
5014 if (Size) State->InstPtr.Long = InstPtr;
5015 else State->InstPtr.LowWord = LOWORD(InstPtr);
5016
5017 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
5018 {
5019 /* Pop ESP */
5020 if (!Soft386StackPop(State, &StackPtr))
5021 {
5022 /* Exception */
5023 return FALSE;
5024 }
5025
5026 /* Pop SS */
5027 if (!Soft386StackPop(State, &StackSel))
5028 {
5029 /* Exception */
5030 return FALSE;
5031 }
5032
5033 /* Load new SS */
5034 if (!Soft386LoadSegment(State, SOFT386_REG_SS, StackSel))
5035 {
5036 /* Exception */
5037 return FALSE;
5038 }
5039
5040 /* Set ESP */
5041 if (Size) State->GeneralRegs[SOFT386_REG_ESP].Long = StackPtr;
5042 else State->GeneralRegs[SOFT386_REG_ESP].LowWord = LOWORD(StackPtr);
5043 }
5044
5045 /* Set the new flags */
5046 if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
5047 else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
5048 State->Flags.AlwaysSet = TRUE;
5049
5050 /* Set additional flags */
5051 if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
5052 if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
5053
5054 if (GET_SEGMENT_RPL(CodeSel) > Cpl)
5055 {
5056 /* Update the CPL */
5057 Cpl = Soft386GetCurrentPrivLevel(State);
5058
5059 /* Check segment security */
5060 for (i = 0; i <= SOFT386_NUM_SEG_REGS; i++)
5061 {
5062 /* Don't check CS or SS */
5063 if ((i == SOFT386_REG_CS) || (i == SOFT386_REG_SS)) continue;
5064
5065 if ((Cpl > State->SegmentRegs[i].Dpl)
5066 && (!State->SegmentRegs[i].Executable
5067 || !State->SegmentRegs[i].DirConf))
5068 {
5069 /* Load the NULL descriptor in the segment */
5070 if (!Soft386LoadSegment(State, i, 0)) return FALSE;
5071 }
5072 }
5073 }
5074 }
5075 else
5076 {
5077 if (Size && (InstPtr & 0xFFFF0000))
5078 {
5079 /* Invalid */
5080 Soft386ExceptionWithErrorCode(State, SOFT386_EXCEPTION_GP, 0);
5081 return FALSE;
5082 }
5083
5084 /* Set new EIP */
5085 State->InstPtr.Long = InstPtr;
5086
5087 /* Load new CS */
5088 if (!Soft386LoadSegment(State, SOFT386_REG_CS, CodeSel))
5089 {
5090 /* Exception occurred */
5091 return FALSE;
5092 }
5093
5094 /* Set the new flags */
5095 if (Size) State->Flags.Long = NewFlags.Long & REAL_MODE_FLAGS_MASK;
5096 else State->Flags.LowWord = NewFlags.LowWord & REAL_MODE_FLAGS_MASK;
5097 State->Flags.AlwaysSet = TRUE;
5098 }
5099
5100 return TRUE;
5101 }
5102
5103 SOFT386_OPCODE_HANDLER(Soft386OpcodeAam)
5104 {
5105 UCHAR Base;
5106 UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
5107
5108 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
5109 {
5110 /* Invalid prefix */
5111 Soft386Exception(State, SOFT386_EXCEPTION_UD);
5112 return FALSE;
5113 }
5114
5115 /* Fetch the base */
5116 if (!Soft386FetchByte(State, &Base))
5117 {
5118 /* Exception occurred */
5119 return FALSE;
5120 }
5121
5122 /* Check if the base is zero */
5123 if (Base == 0)
5124 {
5125 /* Divide error */
5126 Soft386Exception(State, SOFT386_EXCEPTION_DE);
5127 return FALSE;
5128 }
5129
5130 /* Adjust */
5131 State->GeneralRegs[SOFT386_REG_EAX].HighByte = Value / Base;
5132 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value %= Base;
5133
5134 /* Update flags */
5135 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
5136 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
5137 State->Flags.Pf = Soft386CalculateParity(Value);
5138
5139 return TRUE;
5140 }
5141
5142 SOFT386_OPCODE_HANDLER(Soft386OpcodeAad)
5143 {
5144 UCHAR Base;
5145 UCHAR Value = State->GeneralRegs[SOFT386_REG_EAX].LowByte;
5146
5147 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
5148 {
5149 /* Invalid prefix */
5150 Soft386Exception(State, SOFT386_EXCEPTION_UD);
5151 return FALSE;
5152 }
5153
5154 /* Fetch the base */
5155 if (!Soft386FetchByte(State, &Base))
5156 {
5157 /* Exception occurred */
5158 return FALSE;
5159 }
5160
5161 /* Adjust */
5162 Value += State->GeneralRegs[SOFT386_REG_EAX].HighByte * Base;
5163 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Value;
5164
5165 /* Update flags */
5166 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
5167 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
5168 State->Flags.Pf = Soft386CalculateParity(Value);
5169
5170 return TRUE;
5171 }
5172
5173 SOFT386_OPCODE_HANDLER(Soft386OpcodeXlat)
5174 {
5175 // TODO: NOT IMPLEMENTED
5176 UNIMPLEMENTED;
5177
5178 return FALSE;
5179 }
5180
5181 SOFT386_OPCODE_HANDLER(Soft386OpcodeLoop)
5182 {
5183 BOOLEAN Condition;
5184 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5185 CHAR Offset = 0;
5186
5187 /* Make sure this is the right instruction */
5188 ASSERT((Opcode >= 0xE0) && (Opcode <= 0xE2));
5189
5190 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
5191 {
5192 /* Invalid prefix */
5193 Soft386Exception(State, SOFT386_EXCEPTION_UD);
5194 return FALSE;
5195 }
5196
5197 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
5198 {
5199 /* The OPSIZE prefix toggles the size */
5200 Size = !Size;
5201 }
5202
5203 if (Size) Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].Long) != 0);
5204 else Condition = ((--State->GeneralRegs[SOFT386_REG_ECX].LowWord) != 0);
5205
5206 if (Opcode == 0xE0)
5207 {
5208 /* Additional rule for LOOPNZ */
5209 if (State->Flags.Zf) Condition = FALSE;
5210 }
5211
5212 if (Opcode == 0xE1)
5213 {
5214 /* Additional rule for LOOPZ */
5215 if (!State->Flags.Zf) Condition = FALSE;
5216 }
5217
5218 /* Fetch the offset */
5219 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
5220 {
5221 /* An exception occurred */
5222 return FALSE;
5223 }
5224
5225 if (Condition)
5226 {
5227 /* Move the instruction pointer */
5228 State->InstPtr.Long += Offset;
5229 }
5230
5231 return TRUE;
5232 }
5233
5234 SOFT386_OPCODE_HANDLER(Soft386OpcodeJecxz)
5235 {
5236 BOOLEAN Condition;
5237 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5238 CHAR Offset = 0;
5239
5240 /* Make sure this is the right instruction */
5241 ASSERT(Opcode == 0xE3);
5242
5243 if (State->PrefixFlags & SOFT386_PREFIX_LOCK)
5244 {
5245 /* Invalid prefix */
5246 Soft386Exception(State, SOFT386_EXCEPTION_UD);
5247 return FALSE;
5248 }
5249
5250 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
5251 {
5252 /* The OPSIZE prefix toggles the size */
5253 Size = !Size;
5254 }
5255
5256 if (Size) Condition = (State->GeneralRegs[SOFT386_REG_ECX].Long == 0);
5257 else Condition = (State->GeneralRegs[SOFT386_REG_ECX].LowWord == 0);
5258
5259 /* Fetch the offset */
5260 if (!Soft386FetchByte(State, (PUCHAR)&Offset))
5261 {
5262 /* An exception occurred */
5263 return FALSE;
5264 }
5265
5266 if (Condition)
5267 {
5268 /* Move the instruction pointer */
5269 State->InstPtr.Long += Offset;
5270 }
5271
5272 return TRUE;
5273 }
5274
5275 SOFT386_OPCODE_HANDLER(Soft386OpcodeCall)
5276 {
5277 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5278
5279 /* Make sure this is the right instruction */
5280 ASSERT(Opcode == 0xE8);
5281
5282 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
5283 {
5284 /* The OPSIZE prefix toggles the size */
5285 Size = !Size;
5286 }
5287 else if (State->PrefixFlags != 0)
5288 {
5289 /* Invalid prefix */
5290 Soft386Exception(State, SOFT386_EXCEPTION_UD);
5291 return FALSE;
5292 }
5293
5294 if (Size)
5295 {
5296 LONG Offset = 0;
5297
5298 /* Fetch the offset */
5299 if (!Soft386FetchDword(State, (PULONG)&Offset))
5300 {
5301 /* An exception occurred */
5302 return FALSE;
5303 }
5304
5305 /* Push the current value of the instruction pointer */
5306 if (!Soft386StackPush(State, State->InstPtr.Long))
5307 {
5308 /* Exception occurred */
5309 return FALSE;
5310 }
5311
5312 /* Move the instruction pointer */
5313 State->InstPtr.Long += Offset;
5314 }
5315 else
5316 {
5317 SHORT Offset = 0;
5318
5319 /* Fetch the offset */
5320 if (!Soft386FetchWord(State, (PUSHORT)&Offset))
5321 {
5322 /* An exception occurred */
5323 return FALSE;
5324 }
5325
5326 /* Push the current value of the instruction pointer */
5327 if (!Soft386StackPush(State, State->InstPtr.Long))
5328 {
5329 /* Exception occurred */
5330 return FALSE;
5331 }
5332
5333 /* Move the instruction pointer */
5334 State->InstPtr.LowWord += Offset;
5335 }
5336
5337 return TRUE;
5338 }
5339
5340 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmp)
5341 {
5342 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5343
5344 /* Make sure this is the right instruction */
5345 ASSERT(Opcode == 0xE9);
5346
5347 if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE)
5348 {
5349 /* The OPSIZE prefix toggles the size */
5350 Size = !Size;
5351 }
5352 else if (State->PrefixFlags != 0)
5353 {
5354 /* Invalid prefix */
5355 Soft386Exception(State, SOFT386_EXCEPTION_UD);
5356 return FALSE;
5357 }
5358
5359 if (Size)
5360 {
5361 LONG Offset = 0;
5362
5363 /* Fetch the offset */
5364 if (!Soft386FetchDword(State, (PULONG)&Offset))
5365 {
5366 /* An exception occurred */
5367 return FALSE;
5368 }
5369
5370 /* Move the instruction pointer */
5371 State->InstPtr.Long += Offset;
5372 }
5373 else
5374 {
5375 SHORT Offset = 0;
5376
5377 /* Fetch the offset */
5378 if (!Soft386FetchWord(State, (PUSHORT)&Offset))
5379 {
5380 /* An exception occurred */
5381 return FALSE;
5382 }
5383
5384 /* Move the instruction pointer */
5385 State->InstPtr.LowWord += Offset;
5386 }
5387
5388 return TRUE;
5389 }
5390
5391 SOFT386_OPCODE_HANDLER(Soft386OpcodeJmpAbs)
5392 {
5393 // TODO: NOT IMPLEMENTED
5394 UNIMPLEMENTED;
5395
5396 return FALSE;
5397 }
5398
5399 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovAlOffset)
5400 {
5401 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5402 ULONG Offset;
5403
5404 /* Make sure this is the right instruction */
5405 ASSERT(Opcode == 0xA0);
5406
5407 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
5408 {
5409 /* The OPSIZE prefix toggles the size */
5410 Size = !Size;
5411 }
5412
5413 if (Size)
5414 {
5415 if (!Soft386FetchDword(State, &Offset))
5416 {
5417 /* Exception occurred */
5418 return FALSE;
5419 }
5420 }
5421 else
5422 {
5423 USHORT WordOffset;
5424
5425 if (!Soft386FetchWord(State, &WordOffset))
5426 {
5427 /* Exception occurred */
5428 return FALSE;
5429 }
5430
5431 Offset = (ULONG)WordOffset;
5432 }
5433
5434 /* Read from memory */
5435 return Soft386ReadMemory(State,
5436 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
5437 State->SegmentOverride : SOFT386_REG_DS,
5438 Offset,
5439 FALSE,
5440 &State->GeneralRegs[SOFT386_REG_EAX].LowByte,
5441 sizeof(UCHAR));
5442 }
5443
5444 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovEaxOffset)
5445 {
5446 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5447
5448 /* Make sure this is the right instruction */
5449 ASSERT(Opcode == 0xA1);
5450
5451 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
5452 {
5453 /* The OPSIZE prefix toggles the size */
5454 Size = !Size;
5455 }
5456
5457 if (Size)
5458 {
5459 ULONG Offset;
5460
5461 if (!Soft386FetchDword(State, &Offset))
5462 {
5463 /* Exception occurred */
5464 return FALSE;
5465 }
5466
5467 /* Read from memory */
5468 return Soft386ReadMemory(State,
5469 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
5470 State->SegmentOverride : SOFT386_REG_DS,
5471 Offset,
5472 FALSE,
5473 &State->GeneralRegs[SOFT386_REG_EAX].Long,
5474 sizeof(ULONG));
5475 }
5476 else
5477 {
5478 USHORT Offset;
5479
5480 if (!Soft386FetchWord(State, &Offset))
5481 {
5482 /* Exception occurred */
5483 return FALSE;
5484 }
5485
5486 /* Read from memory */
5487 return Soft386ReadMemory(State,
5488 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
5489 State->SegmentOverride : SOFT386_REG_DS,
5490 Offset,
5491 FALSE,
5492 &State->GeneralRegs[SOFT386_REG_EAX].LowWord,
5493 sizeof(USHORT));
5494 }
5495 }
5496
5497 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetAl)
5498 {
5499 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5500 ULONG Offset;
5501
5502 /* Make sure this is the right instruction */
5503 ASSERT(Opcode == 0xA2);
5504
5505 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
5506 {
5507 /* The OPSIZE prefix toggles the size */
5508 Size = !Size;
5509 }
5510
5511 if (Size)
5512 {
5513 if (!Soft386FetchDword(State, &Offset))
5514 {
5515 /* Exception occurred */
5516 return FALSE;
5517 }
5518 }
5519 else
5520 {
5521 USHORT WordOffset;
5522
5523 if (!Soft386FetchWord(State, &WordOffset))
5524 {
5525 /* Exception occurred */
5526 return FALSE;
5527 }
5528
5529 Offset = (ULONG)WordOffset;
5530 }
5531
5532 /* Write to memory */
5533 return Soft386WriteMemory(State,
5534 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
5535 State->SegmentOverride : SOFT386_REG_DS,
5536 Offset,
5537 &State->GeneralRegs[SOFT386_REG_EAX].LowByte,
5538 sizeof(UCHAR));
5539 }
5540
5541 SOFT386_OPCODE_HANDLER(Soft386OpcodeMovOffsetEax)
5542 {
5543 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size;
5544
5545 /* Make sure this is the right instruction */
5546 ASSERT(Opcode == 0xA3);
5547
5548 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
5549 {
5550 /* The OPSIZE prefix toggles the size */
5551 Size = !Size;
5552 }
5553
5554 if (Size)
5555 {
5556 ULONG Offset;
5557
5558 if (!Soft386FetchDword(State, &Offset))
5559 {
5560 /* Exception occurred */
5561 return FALSE;
5562 }
5563
5564 /* Write to memory */
5565 return Soft386WriteMemory(State,
5566 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
5567 State->SegmentOverride : SOFT386_REG_DS,
5568 Offset,
5569 &State->GeneralRegs[SOFT386_REG_EAX].Long,
5570 sizeof(ULONG));
5571 }
5572 else
5573 {
5574 USHORT Offset;
5575
5576 if (!Soft386FetchWord(State, &Offset))
5577 {
5578 /* Exception occurred */
5579 return FALSE;
5580 }
5581
5582 /* Write to memory */
5583 return Soft386WriteMemory(State,
5584 (State->PrefixFlags & SOFT386_PREFIX_SEG) ?
5585 State->SegmentOverride : SOFT386_REG_DS,
5586 Offset,
5587 &State->GeneralRegs[SOFT386_REG_EAX].LowWord,
5588 sizeof(USHORT));
5589 }
5590 }