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