[SOFT386]
[reactos.git] / lib / soft386 / opgroups.c
1 /*
2 * Soft386 386/486 CPU Emulation Library
3 * opgroups.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
28 // #define NDEBUG
29 #include <debug.h>
30
31 #include <soft386.h>
32 #include "opcodes.h"
33 #include "common.h"
34
35 /* PRIVATE FUNCTIONS **********************************************************/
36
37 inline
38 static
39 ULONG
40 Soft386ArithmeticOperation(PSOFT386_STATE State,
41 INT Operation,
42 ULONG FirstValue,
43 ULONG SecondValue,
44 UCHAR Bits)
45 {
46 ULONG Result;
47 ULONG SignFlag = 1 << (Bits - 1);
48 ULONG MaxValue = (1 << Bits) - 1;
49
50 /* Make sure the values don't exceed the maximum for their size */
51 FirstValue &= MaxValue;
52 SecondValue &= MaxValue;
53
54 /* Check which operation is this */
55 switch (Operation)
56 {
57 /* ADD */
58 case 0:
59 {
60 Result = (FirstValue + SecondValue) & MaxValue;
61
62 /* Update CF, OF and AF */
63 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
64 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
65 && ((FirstValue & SignFlag) != (Result & SignFlag));
66 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
67
68 break;
69 }
70
71 /* OR */
72 case 1:
73 {
74 Result = FirstValue | SecondValue;
75 break;
76 }
77
78 /* ADC */
79 case 2:
80 {
81 INT Carry = State->Flags.Cf ? 1 : 0;
82
83 Result = (FirstValue + SecondValue + Carry) & MaxValue;
84
85 /* Update CF, OF and AF */
86 State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1))
87 || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
88 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
89 && ((FirstValue & SignFlag) != (Result & SignFlag));
90 State->Flags.Af = (((FirstValue & 0x0F) + ((SecondValue + Carry) & 0x0F)) & 0x10)
91 ? TRUE : FALSE;
92
93 break;
94 }
95
96 /* SBB */
97 case 3:
98 {
99 INT Carry = State->Flags.Cf ? 1 : 0;
100
101 Result = (FirstValue - SecondValue - Carry) & MaxValue;
102
103 /* Update CF, OF and AF */
104 State->Flags.Cf = FirstValue < (SecondValue + Carry);
105 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
106 && ((FirstValue & SignFlag) != (Result & SignFlag));
107 State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + Carry) & 0x0F);
108
109 break;
110 }
111
112 /* AND */
113 case 4:
114 {
115 Result = FirstValue & SecondValue;
116 break;
117 }
118
119 /* SUB or CMP */
120 case 5:
121 case 7:
122 {
123 Result = (FirstValue - SecondValue) & MaxValue;
124
125 /* Update CF, OF and AF */
126 State->Flags.Cf = FirstValue < SecondValue;
127 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
128 && ((FirstValue & SignFlag) != (Result & SignFlag));
129 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
130
131 break;
132 }
133
134 /* XOR */
135 case 6:
136 {
137 Result = FirstValue ^ SecondValue;
138 break;
139 }
140
141 default:
142 {
143 /* Shouldn't happen */
144 ASSERT(FALSE);
145 }
146 }
147
148 /* Update ZF, SF and PF */
149 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
150 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
151 State->Flags.Pf = Soft386CalculateParity(LOBYTE(Result));
152
153 /* Return the result */
154 return Result;
155 }
156
157 static
158 inline
159 ULONG
160 Soft386RotateOperation(PSOFT386_STATE State,
161 INT Operation,
162 ULONG Value,
163 UCHAR Bits,
164 UCHAR Count)
165 {
166 ULONG HighestBit = 1 << (Bits - 1);
167 ULONG Result;
168
169 if ((Operation != 2) && (Operation != 3))
170 {
171 /* Mask the count */
172 Count &= Bits - 1;
173 }
174 else
175 {
176 /* For RCL and RCR, the CF is included in the value */
177 Count %= Bits + 1;
178 }
179
180 /* Check which operation is this */
181 switch (Operation)
182 {
183 /* ROL */
184 case 0:
185 {
186 Result = (Value << Count) | (Value >> (Bits - Count));
187
188 /* Update CF and OF */
189 State->Flags.Cf = Result & 1;
190 if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
191 ^ State->Flags.Cf;
192
193 break;
194 }
195
196 /* ROR */
197 case 1:
198 {
199 Result = (Value >> Count) | (Value << (Bits - Count));
200
201 /* Update CF and OF */
202 State->Flags.Cf = (Result & HighestBit) ? TRUE : FALSE;
203 if (Count == 1) State->Flags.Of = State->Flags.Cf
204 ^ ((Result & (HighestBit >> 1))
205 ? TRUE : FALSE);
206
207 break;
208 }
209
210 /* RCL */
211 case 2:
212 {
213 Result = (Value << Count)
214 | (State->Flags.Cf << (Count - 1))
215 | (Value >> (Bits - Count + 1));
216
217 /* Update CF and OF */
218 State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
219 if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
220 ^ State->Flags.Cf;
221
222 break;
223 }
224
225 /* RCR */
226 case 3:
227 {
228 Result = (Value >> Count)
229 | (State->Flags.Cf << (Bits - Count))
230 | (Value << (Bits - Count + 1));
231
232 /* Update CF and OF */
233 State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
234 if (Count == 1) State->Flags.Of = State->Flags.Cf
235 ^ ((Result & (HighestBit >> 1))
236 ? TRUE : FALSE);
237
238 break;
239 }
240
241 /* SHL/SAL */
242 case 4:
243 case 6:
244 {
245 Result = Value << Count;
246
247 /* Update CF and OF */
248 State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
249 if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
250 ^ (State->Flags.Cf ? TRUE : FALSE);
251
252 break;
253 }
254
255 /* SHR */
256 case 5:
257 {
258 Result = Value >> Count;
259
260 /* Update CF and OF */
261 State->Flags.Cf = (Value & (1 << (Count - 1))) ? TRUE : FALSE;
262 if (Count == 1) State->Flags.Of = (Value & HighestBit) ? TRUE : FALSE;
263
264 break;
265 }
266
267 /* SAR */
268 case 7:
269 {
270 Result = Value >> Count;
271
272 /* Fill the top Count bits with the sign bit */
273 if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
274
275 /* Update CF and OF */
276 State->Flags.Cf = Value & 1;
277 if (Count == 1) State->Flags.Of = FALSE;
278
279 break;
280 }
281 }
282
283 /* Update ZF, SF and PF */
284 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
285 State->Flags.Sf = (Result & HighestBit) ? TRUE : FALSE;
286 State->Flags.Pf = Soft386CalculateParity(Result);
287
288 /* Return the result */
289 return Result;
290 }
291
292 /* PUBLIC FUNCTIONS ***********************************************************/
293
294 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroup8082)
295 {
296 UCHAR Immediate, Dummy, Value;
297 SOFT386_MOD_REG_RM ModRegRm;
298 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
299
300 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
301 {
302 /* The ADSIZE prefix toggles the size */
303 AddressSize = !AddressSize;
304 }
305
306 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
307 {
308 /* Exception occurred */
309 return FALSE;
310 }
311
312 /* Fetch the immediate operand */
313 if (!Soft386FetchByte(State, &Immediate))
314 {
315 /* Exception occurred */
316 return FALSE;
317 }
318
319 /* Read the operands */
320 if (!Soft386ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
321 {
322 /* Exception occurred */
323 return FALSE;
324 }
325
326 /* Calculate the result */
327 Value = Soft386ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
328
329 /* Unless this is CMP, write back the result */
330 if (ModRegRm.Register != 7)
331 {
332 return Soft386WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
333 }
334
335 return TRUE;
336 }
337
338 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroup81)
339 {
340 SOFT386_MOD_REG_RM ModRegRm;
341 BOOLEAN OperandSize, AddressSize;
342
343 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
344
345 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
346 {
347 /* The OPSIZE prefix toggles the size */
348 OperandSize = !OperandSize;
349 }
350
351 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
352 {
353 /* The ADSIZE prefix toggles the size */
354 AddressSize = !AddressSize;
355 }
356
357 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
358 {
359 /* Exception occurred */
360 return FALSE;
361 }
362
363 if (OperandSize)
364 {
365 ULONG Immediate, Value, Dummy;
366
367 /* Fetch the immediate operand */
368 if (!Soft386FetchDword(State, &Immediate))
369 {
370 /* Exception occurred */
371 return FALSE;
372 }
373
374 /* Read the operands */
375 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
376 {
377 /* Exception occurred */
378 return FALSE;
379 }
380
381 /* Calculate the result */
382 Value = Soft386ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
383
384 /* Unless this is CMP, write back the result */
385 if (ModRegRm.Register != 7)
386 {
387 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
388 }
389 }
390 else
391 {
392 USHORT Immediate, Value, Dummy;
393
394 /* Fetch the immediate operand */
395 if (!Soft386FetchWord(State, &Immediate))
396 {
397 /* Exception occurred */
398 return FALSE;
399 }
400
401 /* Read the operands */
402 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
403 {
404 /* Exception occurred */
405 return FALSE;
406 }
407
408 /* Calculate the result */
409 Value = Soft386ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
410
411 /* Unless this is CMP, write back the result */
412 if (ModRegRm.Register != 7)
413 {
414 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
415 }
416 }
417
418 return TRUE;
419 }
420
421 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroup83)
422 {
423 CHAR ImmByte;
424 SOFT386_MOD_REG_RM ModRegRm;
425 BOOLEAN OperandSize, AddressSize;
426
427 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
428
429 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
430 {
431 /* The OPSIZE prefix toggles the size */
432 OperandSize = !OperandSize;
433 }
434
435 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
436 {
437 /* The ADSIZE prefix toggles the size */
438 AddressSize = !AddressSize;
439 }
440
441 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
442 {
443 /* Exception occurred */
444 return FALSE;
445 }
446
447 /* Fetch the immediate operand */
448 if (!Soft386FetchByte(State, (PUCHAR)&ImmByte))
449 {
450 /* Exception occurred */
451 return FALSE;
452 }
453
454 if (OperandSize)
455 {
456 ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
457 ULONG Value, Dummy;
458
459 /* Read the operands */
460 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
461 {
462 /* Exception occurred */
463 return FALSE;
464 }
465
466 /* Calculate the result */
467 Value = Soft386ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
468
469 /* Unless this is CMP, write back the result */
470 if (ModRegRm.Register != 7)
471 {
472 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
473 }
474 }
475 else
476 {
477 USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
478 USHORT Value, Dummy;
479
480 /* Read the operands */
481 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
482 {
483 /* Exception occurred */
484 return FALSE;
485 }
486
487 /* Calculate the result */
488 Value = Soft386ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
489
490 /* Unless this is CMP, write back the result */
491 if (ModRegRm.Register != 7)
492 {
493 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
494 }
495 }
496
497 return TRUE;
498 }
499
500 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroup8F)
501 {
502 ULONG Value;
503 SOFT386_MOD_REG_RM ModRegRm;
504 BOOLEAN OperandSize, AddressSize;
505
506 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
507
508 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
509 {
510 /* The OPSIZE prefix toggles the size */
511 OperandSize = !OperandSize;
512 }
513
514 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
515 {
516 /* The ADSIZE prefix toggles the size */
517 AddressSize = !AddressSize;
518 }
519
520 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
521 {
522 /* Exception occurred */
523 return FALSE;
524 }
525
526 if (ModRegRm.Register != 0)
527 {
528 /* Invalid */
529 Soft386Exception(State, SOFT386_EXCEPTION_UD);
530 return FALSE;
531 }
532
533 /* Pop a value from the stack */
534 if (!Soft386StackPop(State, &Value))
535 {
536 /* Exception occurred */
537 return FALSE;
538 }
539
540 if (OperandSize)
541 {
542 return Soft386WriteModrmDwordOperands(State,
543 &ModRegRm,
544 FALSE,
545 Value);
546 }
547 else
548 {
549 return Soft386WriteModrmWordOperands(State,
550 &ModRegRm,
551 FALSE,
552 LOWORD(Value));
553 }
554 }
555
556 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupC0)
557 {
558 UCHAR Dummy, Value, Count;
559 SOFT386_MOD_REG_RM ModRegRm;
560 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
561
562 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
563 {
564 /* The ADSIZE prefix toggles the size */
565 AddressSize = !AddressSize;
566 }
567
568 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
569 {
570 /* Exception occurred */
571 return FALSE;
572 }
573
574 /* Fetch the count */
575 if (!Soft386FetchByte(State, &Count))
576 {
577 /* Exception occurred */
578 return FALSE;
579 }
580
581 /* Read the operands */
582 if (!Soft386ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
583 {
584 /* Exception occurred */
585 return FALSE;
586 }
587
588 /* Calculate the result */
589 Value = LOBYTE(Soft386RotateOperation(State,
590 ModRegRm.Register,
591 Value,
592 8,
593 Count));
594
595 /* Write back the result */
596 return Soft386WriteModrmByteOperands(State,
597 &ModRegRm,
598 FALSE,
599 Value);
600 }
601
602 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupC1)
603 {
604 UCHAR Count;
605 SOFT386_MOD_REG_RM ModRegRm;
606 BOOLEAN OperandSize, AddressSize;
607
608 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
609
610 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
611 {
612 /* The OPSIZE prefix toggles the size */
613 OperandSize = !OperandSize;
614 }
615
616 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
617 {
618 /* The ADSIZE prefix toggles the size */
619 AddressSize = !AddressSize;
620 }
621
622 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
623 {
624 /* Exception occurred */
625 return FALSE;
626 }
627
628 /* Fetch the count */
629 if (!Soft386FetchByte(State, &Count))
630 {
631 /* Exception occurred */
632 return FALSE;
633 }
634
635 if (OperandSize)
636 {
637 ULONG Dummy, Value;
638
639 /* Read the operands */
640 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
641 {
642 /* Exception occurred */
643 return FALSE;
644 }
645
646 /* Calculate the result */
647 Value = Soft386RotateOperation(State,
648 ModRegRm.Register,
649 Value,
650 32,
651 Count);
652
653 /* Write back the result */
654 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
655 }
656 else
657 {
658 USHORT Dummy, Value;
659
660 /* Read the operands */
661 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
662 {
663 /* Exception occurred */
664 return FALSE;
665 }
666
667 /* Calculate the result */
668 Value = LOWORD(Soft386RotateOperation(State,
669 ModRegRm.Register,
670 Value,
671 16,
672 Count));
673
674 /* Write back the result */
675 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
676 }
677 }
678
679 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupC6)
680 {
681 UCHAR Immediate;
682 SOFT386_MOD_REG_RM ModRegRm;
683 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
684
685 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
686 {
687 /* The ADSIZE prefix toggles the size */
688 AddressSize = !AddressSize;
689 }
690
691 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
692 {
693 /* Exception occurred */
694 return FALSE;
695 }
696
697 if (ModRegRm.Register != 0)
698 {
699 /* Invalid */
700 Soft386Exception(State, SOFT386_EXCEPTION_UD);
701 return FALSE;
702 }
703
704 /* Get the immediate operand */
705 if (!Soft386FetchByte(State, &Immediate))
706 {
707 /* Exception occurred */
708 return FALSE;
709 }
710
711 return Soft386WriteModrmByteOperands(State,
712 &ModRegRm,
713 FALSE,
714 Immediate);
715 }
716
717 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupC7)
718 {
719 SOFT386_MOD_REG_RM ModRegRm;
720 BOOLEAN OperandSize, AddressSize;
721
722 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
723
724 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
725 {
726 /* The OPSIZE prefix toggles the size */
727 OperandSize = !OperandSize;
728 }
729
730 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
731 {
732 /* The ADSIZE prefix toggles the size */
733 AddressSize = !AddressSize;
734 }
735
736 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
737 {
738 /* Exception occurred */
739 return FALSE;
740 }
741
742 if (ModRegRm.Register != 0)
743 {
744 /* Invalid */
745 Soft386Exception(State, SOFT386_EXCEPTION_UD);
746 return FALSE;
747 }
748
749 if (OperandSize)
750 {
751 ULONG Immediate;
752
753 /* Get the immediate operand */
754 if (!Soft386FetchDword(State, &Immediate))
755 {
756 /* Exception occurred */
757 return FALSE;
758 }
759
760 return Soft386WriteModrmDwordOperands(State,
761 &ModRegRm,
762 FALSE,
763 Immediate);
764 }
765 else
766 {
767 USHORT Immediate;
768
769 /* Get the immediate operand */
770 if (!Soft386FetchWord(State, &Immediate))
771 {
772 /* Exception occurred */
773 return FALSE;
774 }
775
776 return Soft386WriteModrmWordOperands(State,
777 &ModRegRm,
778 FALSE,
779 Immediate);
780 }
781 }
782
783 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupD0)
784 {
785 UCHAR Dummy, Value;
786 SOFT386_MOD_REG_RM ModRegRm;
787 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
788
789 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
790 {
791 /* The ADSIZE prefix toggles the size */
792 AddressSize = !AddressSize;
793 }
794
795 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
796 {
797 /* Exception occurred */
798 return FALSE;
799 }
800
801 /* Read the operands */
802 if (!Soft386ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
803 {
804 /* Exception occurred */
805 return FALSE;
806 }
807
808 /* Calculate the result */
809 Value = LOBYTE(Soft386RotateOperation(State, ModRegRm.Register, Value, 8, 1));
810
811 /* Write back the result */
812 return Soft386WriteModrmByteOperands(State,
813 &ModRegRm,
814 FALSE,
815 Value);
816
817 }
818
819 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupD1)
820 {
821 SOFT386_MOD_REG_RM ModRegRm;
822 BOOLEAN OperandSize, AddressSize;
823
824 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
825
826 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
827 {
828 /* The OPSIZE prefix toggles the size */
829 OperandSize = !OperandSize;
830 }
831
832
833 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
834 {
835 /* The ADSIZE prefix toggles the size */
836 AddressSize = !AddressSize;
837 }
838
839 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
840 {
841 /* Exception occurred */
842 return FALSE;
843 }
844
845 if (OperandSize)
846 {
847 ULONG Dummy, Value;
848
849 /* Read the operands */
850 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
851 {
852 /* Exception occurred */
853 return FALSE;
854 }
855
856 /* Calculate the result */
857 Value = Soft386RotateOperation(State, ModRegRm.Register, Value, 32, 1);
858
859 /* Write back the result */
860 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
861 }
862 else
863 {
864 USHORT Dummy, Value;
865
866 /* Read the operands */
867 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
868 {
869 /* Exception occurred */
870 return FALSE;
871 }
872
873 /* Calculate the result */
874 Value = LOWORD(Soft386RotateOperation(State, ModRegRm.Register, Value, 16, 1));
875
876 /* Write back the result */
877 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
878 }
879 }
880
881 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupD2)
882 {
883 UCHAR Dummy, Value;
884 SOFT386_MOD_REG_RM ModRegRm;
885 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
886
887 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
888 {
889 /* The ADSIZE prefix toggles the size */
890 AddressSize = !AddressSize;
891 }
892
893 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
894 {
895 /* Exception occurred */
896 return FALSE;
897 }
898
899 /* Read the operands */
900 if (!Soft386ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
901 {
902 /* Exception occurred */
903 return FALSE;
904 }
905
906 /* Calculate the result */
907 Value = LOBYTE(Soft386RotateOperation(State,
908 ModRegRm.Register,
909 Value,
910 8,
911 State->GeneralRegs[SOFT386_REG_ECX].LowByte));
912
913 /* Write back the result */
914 return Soft386WriteModrmByteOperands(State,
915 &ModRegRm,
916 FALSE,
917 Value);
918 }
919
920 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupD3)
921 {
922 SOFT386_MOD_REG_RM ModRegRm;
923 BOOLEAN OperandSize, AddressSize;
924
925 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
926
927 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
928 {
929 /* The OPSIZE prefix toggles the size */
930 OperandSize = !OperandSize;
931 }
932
933 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
934 {
935 /* The ADSIZE prefix toggles the size */
936 AddressSize = !AddressSize;
937 }
938
939 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
940 {
941 /* Exception occurred */
942 return FALSE;
943 }
944
945 if (OperandSize)
946 {
947 ULONG Dummy, Value;
948
949 /* Read the operands */
950 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
951 {
952 /* Exception occurred */
953 return FALSE;
954 }
955
956 /* Calculate the result */
957 Value = Soft386RotateOperation(State,
958 ModRegRm.Register,
959 Value,
960 32,
961 State->GeneralRegs[SOFT386_REG_ECX].LowByte);
962
963 /* Write back the result */
964 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
965 }
966 else
967 {
968 USHORT Dummy, Value;
969
970 /* Read the operands */
971 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
972 {
973 /* Exception occurred */
974 return FALSE;
975 }
976
977 /* Calculate the result */
978 Value = LOWORD(Soft386RotateOperation(State,
979 ModRegRm.Register,
980 Value,
981 16,
982 State->GeneralRegs[SOFT386_REG_ECX].LowByte));
983
984 /* Write back the result */
985 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
986 }
987 }
988
989 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupF6)
990 {
991 UCHAR Dummy, Value;
992 SOFT386_MOD_REG_RM ModRegRm;
993 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
994
995 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
996 {
997 /* The ADSIZE prefix toggles the size */
998 AddressSize = !AddressSize;
999 }
1000
1001 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1002 {
1003 /* Exception occurred */
1004 return FALSE;
1005 }
1006
1007 /* Read the operands */
1008 if (!Soft386ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
1009 {
1010 /* Exception occurred */
1011 return FALSE;
1012 }
1013
1014 switch (ModRegRm.Register)
1015 {
1016 /* TEST */
1017 case 0:
1018 case 1:
1019 {
1020 UCHAR Immediate, Result;
1021
1022 /* Fetch the immediate byte */
1023 if (!Soft386FetchByte(State, &Immediate))
1024 {
1025 /* Exception occurred */
1026 return FALSE;
1027 }
1028
1029 /* Calculate the result */
1030 Result = Value & Immediate;
1031
1032 /* Update the flags */
1033 State->Flags.Cf = FALSE;
1034 State->Flags.Of = FALSE;
1035 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1036 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1037 State->Flags.Pf = Soft386CalculateParity(Result);
1038
1039 break;
1040 }
1041
1042 /* NOT */
1043 case 2:
1044 {
1045 /* Write back the result */
1046 return Soft386WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
1047 }
1048
1049 /* NEG */
1050 case 3:
1051 {
1052 /* Calculate the result */
1053 UCHAR Result = -Value;
1054
1055 /* Update the flags */
1056 State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
1057 State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
1058 State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
1059 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1060 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1061 State->Flags.Pf = Soft386CalculateParity(Result);
1062
1063 /* Write back the result */
1064 return Soft386WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
1065 }
1066
1067 /* MUL */
1068 case 4:
1069 {
1070 USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[SOFT386_REG_EAX].LowByte;
1071
1072 /* Update the flags */
1073 State->Flags.Cf = State->Flags.Of = HIBYTE(Result) ? TRUE : FALSE;
1074
1075 /* Write back the result */
1076 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Result;
1077
1078 break;
1079 }
1080
1081 /* IMUL */
1082 case 5:
1083 {
1084 SHORT Result = (SHORT)Value * (SHORT)State->GeneralRegs[SOFT386_REG_EAX].LowByte;
1085
1086 /* Update the flags */
1087 State->Flags.Cf = State->Flags.Of =
1088 ((Result < -128) || (Result > 127)) ? TRUE : FALSE;
1089
1090 /* Write back the result */
1091 State->GeneralRegs[SOFT386_REG_EAX].LowWord = (USHORT)Result;
1092
1093 break;
1094 }
1095
1096 /* DIV */
1097 case 6:
1098 {
1099 UCHAR Quotient = State->GeneralRegs[SOFT386_REG_EAX].LowWord / Value;
1100 UCHAR Remainder = State->GeneralRegs[SOFT386_REG_EAX].LowWord % Value;
1101
1102 /* Write back the results */
1103 State->GeneralRegs[SOFT386_REG_EAX].LowByte = Quotient;
1104 State->GeneralRegs[SOFT386_REG_EAX].HighByte = Remainder;
1105
1106 break;
1107 }
1108
1109 /* IDIV */
1110 case 7:
1111 {
1112 CHAR Quotient = (SHORT)State->GeneralRegs[SOFT386_REG_EAX].LowWord / (CHAR)Value;
1113 CHAR Remainder = (SHORT)State->GeneralRegs[SOFT386_REG_EAX].LowWord % (CHAR)Value;
1114
1115 /* Write back the results */
1116 State->GeneralRegs[SOFT386_REG_EAX].LowByte = (UCHAR)Quotient;
1117 State->GeneralRegs[SOFT386_REG_EAX].HighByte = (UCHAR)Remainder;
1118
1119 break;
1120 }
1121 }
1122
1123 return TRUE;
1124 }
1125
1126 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupF7)
1127 {
1128 ULONG Dummy, Value, SignFlag;
1129 SOFT386_MOD_REG_RM ModRegRm;
1130 BOOLEAN OperandSize, AddressSize;
1131
1132 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1133
1134 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1135 {
1136 /* The OPSIZE prefix toggles the size */
1137 OperandSize = !OperandSize;
1138 }
1139
1140 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1141 {
1142 /* The ADSIZE prefix toggles the size */
1143 AddressSize = !AddressSize;
1144 }
1145
1146 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1147 {
1148 /* Exception occurred */
1149 return FALSE;
1150 }
1151
1152 /* Set the sign flag */
1153 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1154 else SignFlag = SIGN_FLAG_WORD;
1155
1156 /* Read the operand */
1157 if (OperandSize)
1158 {
1159 /* 32-bit */
1160 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1161 {
1162 /* Exception occurred */
1163 return FALSE;
1164 }
1165 }
1166 else
1167 {
1168 /* 16-bit */
1169 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, (PUSHORT)&Dummy, (PUSHORT)&Value))
1170 {
1171 /* Exception occurred */
1172 return FALSE;
1173 }
1174 }
1175
1176 switch (ModRegRm.Register)
1177 {
1178 /* TEST */
1179 case 0:
1180 case 1:
1181 {
1182 ULONG Immediate = 0, Result = 0;
1183
1184 if (OperandSize)
1185 {
1186 /* Fetch the immediate dword */
1187 if (!Soft386FetchDword(State, &Immediate))
1188 {
1189 /* Exception occurred */
1190 return FALSE;
1191 }
1192 }
1193 else
1194 {
1195 /* Fetch the immediate word */
1196 if (!Soft386FetchWord(State, (PUSHORT)&Immediate))
1197 {
1198 /* Exception occurred */
1199 return FALSE;
1200 }
1201 }
1202
1203 /* Calculate the result */
1204 Result = Value & Immediate;
1205
1206 /* Update the flags */
1207 State->Flags.Cf = FALSE;
1208 State->Flags.Of = FALSE;
1209 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1210 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
1211 State->Flags.Pf = Soft386CalculateParity(Result);
1212
1213 break;
1214 }
1215
1216 /* NOT */
1217 case 2:
1218 {
1219 /* Write back the result */
1220 if (OperandSize)
1221 {
1222 /* 32-bit */
1223 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1224 }
1225 else
1226 {
1227 /* 16-bit */
1228 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1229 }
1230 }
1231
1232 /* NEG */
1233 case 3:
1234 {
1235 /* Calculate the result */
1236 ULONG Result = -Value;
1237 if (!OperandSize) Result &= 0xFFFF;
1238
1239 /* Update the flags */
1240 State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
1241 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1242 State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
1243 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1244 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
1245 State->Flags.Pf = Soft386CalculateParity(Result);
1246
1247 /* Write back the result */
1248 if (OperandSize)
1249 {
1250 /* 32-bit */
1251 return Soft386WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1252 }
1253 else
1254 {
1255 /* 16-bit */
1256 return Soft386WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1257 }
1258 }
1259
1260 /* MUL */
1261 case 4:
1262 {
1263 if (OperandSize)
1264 {
1265 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[SOFT386_REG_EAX].Long;
1266
1267 /* Update the flags */
1268 State->Flags.Cf = State->Flags.Of =
1269 (Result & 0xFFFFFFFF00000000ULL) ? TRUE : FALSE;
1270
1271 /* Write back the result */
1272 State->GeneralRegs[SOFT386_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1273 State->GeneralRegs[SOFT386_REG_EDX].Long = Result >> 32;
1274 }
1275 else
1276 {
1277 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[SOFT386_REG_EAX].LowWord;
1278
1279 /* Update the flags */
1280 State->Flags.Cf = State->Flags.Of = HIWORD(Result) ? TRUE : FALSE;
1281
1282 /* Write back the result */
1283 State->GeneralRegs[SOFT386_REG_EAX].LowWord = LOWORD(Result);
1284 State->GeneralRegs[SOFT386_REG_EDX].LowWord = HIWORD(Result);
1285 }
1286
1287 break;
1288 }
1289
1290 /* IMUL */
1291 case 5:
1292 {
1293 if (OperandSize)
1294 {
1295 LONGLONG Result = (LONGLONG)Value * (LONGLONG)State->GeneralRegs[SOFT386_REG_EAX].Long;
1296
1297 /* Update the flags */
1298 State->Flags.Cf = State->Flags.Of =
1299 ((Result < -2147483648LL) || (Result > 2147483647LL)) ? TRUE : FALSE;
1300
1301 /* Write back the result */
1302 State->GeneralRegs[SOFT386_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1303 State->GeneralRegs[SOFT386_REG_EDX].Long = Result >> 32;
1304 }
1305 else
1306 {
1307 LONG Result = (LONG)Value * (LONG)State->GeneralRegs[SOFT386_REG_EAX].LowWord;
1308
1309 /* Update the flags */
1310 State->Flags.Cf = State->Flags.Of =
1311 ((Result < -32768) || (Result > 32767)) ? TRUE : FALSE;
1312
1313 /* Write back the result */
1314 State->GeneralRegs[SOFT386_REG_EAX].LowWord = LOWORD(Result);
1315 State->GeneralRegs[SOFT386_REG_EDX].LowWord = HIWORD(Result);
1316 }
1317
1318 break;
1319 }
1320
1321 /* DIV */
1322 case 6:
1323 {
1324 if (OperandSize)
1325 {
1326 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[SOFT386_REG_EAX].Long
1327 | ((ULONGLONG)State->GeneralRegs[SOFT386_REG_EDX].Long << 32);
1328 ULONG Quotient = Dividend / Value;
1329 ULONG Remainder = Dividend % Value;
1330
1331 /* Write back the results */
1332 State->GeneralRegs[SOFT386_REG_EAX].Long = Quotient;
1333 State->GeneralRegs[SOFT386_REG_EDX].Long = Remainder;
1334 }
1335 else
1336 {
1337 ULONG Dividend = (ULONG)State->GeneralRegs[SOFT386_REG_EAX].LowWord
1338 | ((ULONG)State->GeneralRegs[SOFT386_REG_EDX].LowWord << 16);
1339 USHORT Quotient = Dividend / Value;
1340 USHORT Remainder = Dividend % Value;
1341
1342 /* Write back the results */
1343 State->GeneralRegs[SOFT386_REG_EAX].LowWord = Quotient;
1344 State->GeneralRegs[SOFT386_REG_EDX].LowWord = Remainder;
1345 }
1346
1347 break;
1348 }
1349
1350 /* IDIV */
1351 case 7:
1352 {
1353 if (OperandSize)
1354 {
1355 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[SOFT386_REG_EAX].Long
1356 | ((LONGLONG)State->GeneralRegs[SOFT386_REG_EDX].Long << 32);
1357 LONG Quotient = Dividend / (LONG)Value;
1358 LONG Remainder = Dividend % (LONG)Value;
1359
1360 /* Write back the results */
1361 State->GeneralRegs[SOFT386_REG_EAX].Long = (ULONG)Quotient;
1362 State->GeneralRegs[SOFT386_REG_EDX].Long = (ULONG)Remainder;
1363 }
1364 else
1365 {
1366 LONG Dividend = (LONG)State->GeneralRegs[SOFT386_REG_EAX].LowWord
1367 | ((LONG)State->GeneralRegs[SOFT386_REG_EDX].LowWord << 16);
1368 SHORT Quotient = Dividend / (SHORT)Value;
1369 SHORT Remainder = Dividend % (SHORT)Value;
1370
1371 /* Write back the results */
1372 State->GeneralRegs[SOFT386_REG_EAX].LowWord = (USHORT)Quotient;
1373 State->GeneralRegs[SOFT386_REG_EDX].LowWord = (USHORT)Remainder;
1374 }
1375
1376 break;
1377 }
1378 }
1379
1380 return TRUE;
1381 }
1382
1383 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupFE)
1384 {
1385 UCHAR Dummy, Value;
1386 SOFT386_MOD_REG_RM ModRegRm;
1387 BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1388
1389 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1390 {
1391 /* The ADSIZE prefix toggles the size */
1392 AddressSize = !AddressSize;
1393 }
1394
1395 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1396 {
1397 /* Exception occurred */
1398 return FALSE;
1399 }
1400
1401 if (ModRegRm.Register > 1)
1402 {
1403 /* Invalid */
1404 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1405 return FALSE;
1406 }
1407
1408 /* Read the operands */
1409 if (!Soft386ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
1410 {
1411 /* Exception occurred */
1412 return FALSE;
1413 }
1414
1415 if (ModRegRm.Register == 0)
1416 {
1417 /* Increment and update OF */
1418 Value++;
1419 State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
1420 }
1421 else
1422 {
1423 /* Decrement and update OF */
1424 State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
1425 Value--;
1426 }
1427
1428 /* Update flags */
1429 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1430 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1431 State->Flags.Af = ((Value & 0x0F) == 0) ? TRUE : FALSE;
1432 State->Flags.Pf = Soft386CalculateParity(Value);
1433
1434 /* Write back the result */
1435 return Soft386WriteModrmByteOperands(State,
1436 &ModRegRm,
1437 FALSE,
1438 Value);
1439 }
1440
1441 SOFT386_OPCODE_HANDLER(Soft386OpcodeGroupFF)
1442 {
1443 SOFT386_MOD_REG_RM ModRegRm;
1444 BOOLEAN OperandSize, AddressSize;
1445
1446 OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size;
1447
1448 if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE)
1449 {
1450 /* The OPSIZE prefix toggles the size */
1451 OperandSize = !OperandSize;
1452 }
1453
1454 if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE)
1455 {
1456 /* The ADSIZE prefix toggles the size */
1457 AddressSize = !AddressSize;
1458 }
1459
1460 if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm))
1461 {
1462 /* Exception occurred */
1463 return FALSE;
1464 }
1465
1466 if (ModRegRm.Register == 7)
1467 {
1468 /* Invalid */
1469 Soft386Exception(State, SOFT386_EXCEPTION_UD);
1470 return FALSE;
1471 }
1472
1473 /* Read the operands */
1474 if (OperandSize)
1475 {
1476 ULONG Dummy, Value;
1477
1478 if (!Soft386ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1479 {
1480 /* Exception occurred */
1481 return FALSE;
1482 }
1483
1484 if (ModRegRm.Register == 0)
1485 {
1486 /* Increment and update OF */
1487 Value++;
1488 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
1489 }
1490 else if (ModRegRm.Register == 1)
1491 {
1492 /* Decrement and update OF */
1493 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
1494 Value--;
1495 }
1496
1497 if (ModRegRm.Register <= 1)
1498 {
1499 /* Update flags */
1500 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
1501 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1502 State->Flags.Af = ((Value & 0x0F) == 0) ? TRUE : FALSE;
1503 State->Flags.Pf = Soft386CalculateParity(Value);
1504
1505 /* Write back the result */
1506 return Soft386WriteModrmDwordOperands(State,
1507 &ModRegRm,
1508 FALSE,
1509 Value);
1510 }
1511 }
1512 else
1513 {
1514 USHORT Dummy, Value;
1515
1516 if (!Soft386ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1517 {
1518 /* Exception occurred */
1519 return FALSE;
1520 }
1521
1522 if (ModRegRm.Register == 0)
1523 {
1524 /* Increment and update OF */
1525 Value++;
1526 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
1527 }
1528 else if (ModRegRm.Register == 1)
1529 {
1530 /* Decrement and update OF */
1531 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
1532 Value--;
1533 }
1534
1535 if (ModRegRm.Register <= 1)
1536 {
1537 /* Update flags */
1538 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
1539 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1540 State->Flags.Af = ((Value & 0x0F) == 0) ? TRUE : FALSE;
1541 State->Flags.Pf = Soft386CalculateParity(Value);
1542
1543 /* Write back the result */
1544 return Soft386WriteModrmWordOperands(State,
1545 &ModRegRm,
1546 FALSE,
1547 Value);
1548 }
1549 }
1550
1551 if (ModRegRm.Register > 1)
1552 {
1553 UNIMPLEMENTED;
1554 return FALSE; // NOT IMPLEMENTED
1555 }
1556
1557 return TRUE;
1558 }
1559
1560 /* EOF */
1561