[FAST486]
[reactos.git] / lib / fast486 / opgroups.c
1 /*
2 * Fast486 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 <fast486.h>
32 #include "opcodes.h"
33 #include "common.h"
34
35 /* PRIVATE FUNCTIONS **********************************************************/
36
37 inline
38 static
39 ULONG
40 Fast486ArithmeticOperation(PFAST486_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 = Fast486CalculateParity(LOBYTE(Result));
152
153 /* Return the result */
154 return Result;
155 }
156
157 static
158 inline
159 ULONG
160 Fast486RotateOperation(PFAST486_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 << (Count - 1))) ? TRUE : FALSE;
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 = Fast486CalculateParity(Result);
287
288 /* Return the result */
289 return Result;
290 }
291
292 /* PUBLIC FUNCTIONS ***********************************************************/
293
294 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)
295 {
296 UCHAR Immediate, Dummy, Value;
297 FAST486_MOD_REG_RM ModRegRm;
298 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
299
300 TOGGLE_ADSIZE(AddressSize);
301
302 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
303 {
304 /* Exception occurred */
305 return FALSE;
306 }
307
308 /* Fetch the immediate operand */
309 if (!Fast486FetchByte(State, &Immediate))
310 {
311 /* Exception occurred */
312 return FALSE;
313 }
314
315 /* Read the operands */
316 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
317 {
318 /* Exception occurred */
319 return FALSE;
320 }
321
322 /* Calculate the result */
323 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
324
325 /* Unless this is CMP, write back the result */
326 if (ModRegRm.Register != 7)
327 {
328 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
329 }
330
331 return TRUE;
332 }
333
334 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
335 {
336 FAST486_MOD_REG_RM ModRegRm;
337 BOOLEAN OperandSize, AddressSize;
338
339 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
340
341 TOGGLE_OPSIZE(OperandSize);
342 TOGGLE_ADSIZE(AddressSize);
343
344 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
345 {
346 /* Exception occurred */
347 return FALSE;
348 }
349
350 if (OperandSize)
351 {
352 ULONG Immediate, Value, Dummy;
353
354 /* Fetch the immediate operand */
355 if (!Fast486FetchDword(State, &Immediate))
356 {
357 /* Exception occurred */
358 return FALSE;
359 }
360
361 /* Read the operands */
362 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
363 {
364 /* Exception occurred */
365 return FALSE;
366 }
367
368 /* Calculate the result */
369 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
370
371 /* Unless this is CMP, write back the result */
372 if (ModRegRm.Register != 7)
373 {
374 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
375 }
376 }
377 else
378 {
379 USHORT Immediate, Value, Dummy;
380
381 /* Fetch the immediate operand */
382 if (!Fast486FetchWord(State, &Immediate))
383 {
384 /* Exception occurred */
385 return FALSE;
386 }
387
388 /* Read the operands */
389 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
390 {
391 /* Exception occurred */
392 return FALSE;
393 }
394
395 /* Calculate the result */
396 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
397
398 /* Unless this is CMP, write back the result */
399 if (ModRegRm.Register != 7)
400 {
401 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
402 }
403 }
404
405 return TRUE;
406 }
407
408 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
409 {
410 CHAR ImmByte;
411 FAST486_MOD_REG_RM ModRegRm;
412 BOOLEAN OperandSize, AddressSize;
413
414 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
415
416 TOGGLE_OPSIZE(OperandSize);
417 TOGGLE_ADSIZE(AddressSize);
418
419 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
420 {
421 /* Exception occurred */
422 return FALSE;
423 }
424
425 /* Fetch the immediate operand */
426 if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
427 {
428 /* Exception occurred */
429 return FALSE;
430 }
431
432 if (OperandSize)
433 {
434 ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
435 ULONG Value, Dummy;
436
437 /* Read the operands */
438 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
439 {
440 /* Exception occurred */
441 return FALSE;
442 }
443
444 /* Calculate the result */
445 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
446
447 /* Unless this is CMP, write back the result */
448 if (ModRegRm.Register != 7)
449 {
450 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
451 }
452 }
453 else
454 {
455 USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
456 USHORT Value, Dummy;
457
458 /* Read the operands */
459 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
460 {
461 /* Exception occurred */
462 return FALSE;
463 }
464
465 /* Calculate the result */
466 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
467
468 /* Unless this is CMP, write back the result */
469 if (ModRegRm.Register != 7)
470 {
471 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
472 }
473 }
474
475 return TRUE;
476 }
477
478 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
479 {
480 ULONG Value;
481 FAST486_MOD_REG_RM ModRegRm;
482 BOOLEAN OperandSize, AddressSize;
483
484 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
485
486 TOGGLE_OPSIZE(OperandSize);
487 TOGGLE_ADSIZE(AddressSize);
488
489 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
490 {
491 /* Exception occurred */
492 return FALSE;
493 }
494
495 if (ModRegRm.Register != 0)
496 {
497 /* Invalid */
498 Fast486Exception(State, FAST486_EXCEPTION_UD);
499 return FALSE;
500 }
501
502 /* Pop a value from the stack */
503 if (!Fast486StackPop(State, &Value))
504 {
505 /* Exception occurred */
506 return FALSE;
507 }
508
509 if (OperandSize)
510 {
511 return Fast486WriteModrmDwordOperands(State,
512 &ModRegRm,
513 FALSE,
514 Value);
515 }
516 else
517 {
518 return Fast486WriteModrmWordOperands(State,
519 &ModRegRm,
520 FALSE,
521 LOWORD(Value));
522 }
523 }
524
525 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
526 {
527 UCHAR Dummy, Value, Count;
528 FAST486_MOD_REG_RM ModRegRm;
529 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
530
531 TOGGLE_ADSIZE(AddressSize);
532
533 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
534 {
535 /* Exception occurred */
536 return FALSE;
537 }
538
539 /* Fetch the count */
540 if (!Fast486FetchByte(State, &Count))
541 {
542 /* Exception occurred */
543 return FALSE;
544 }
545
546 /* Read the operands */
547 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
548 {
549 /* Exception occurred */
550 return FALSE;
551 }
552
553 /* Calculate the result */
554 Value = LOBYTE(Fast486RotateOperation(State,
555 ModRegRm.Register,
556 Value,
557 8,
558 Count));
559
560 /* Write back the result */
561 return Fast486WriteModrmByteOperands(State,
562 &ModRegRm,
563 FALSE,
564 Value);
565 }
566
567 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
568 {
569 UCHAR Count;
570 FAST486_MOD_REG_RM ModRegRm;
571 BOOLEAN OperandSize, AddressSize;
572
573 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
574
575 TOGGLE_OPSIZE(OperandSize);
576 TOGGLE_ADSIZE(AddressSize);
577
578 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
579 {
580 /* Exception occurred */
581 return FALSE;
582 }
583
584 /* Fetch the count */
585 if (!Fast486FetchByte(State, &Count))
586 {
587 /* Exception occurred */
588 return FALSE;
589 }
590
591 if (OperandSize)
592 {
593 ULONG Dummy, Value;
594
595 /* Read the operands */
596 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
597 {
598 /* Exception occurred */
599 return FALSE;
600 }
601
602 /* Calculate the result */
603 Value = Fast486RotateOperation(State,
604 ModRegRm.Register,
605 Value,
606 32,
607 Count);
608
609 /* Write back the result */
610 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
611 }
612 else
613 {
614 USHORT Dummy, Value;
615
616 /* Read the operands */
617 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
618 {
619 /* Exception occurred */
620 return FALSE;
621 }
622
623 /* Calculate the result */
624 Value = LOWORD(Fast486RotateOperation(State,
625 ModRegRm.Register,
626 Value,
627 16,
628 Count));
629
630 /* Write back the result */
631 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
632 }
633 }
634
635 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)
636 {
637 UCHAR Immediate;
638 FAST486_MOD_REG_RM ModRegRm;
639 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
640
641 TOGGLE_ADSIZE(AddressSize);
642
643 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
644 {
645 /* Exception occurred */
646 return FALSE;
647 }
648
649 if (ModRegRm.Register != 0)
650 {
651 /* Invalid */
652 Fast486Exception(State, FAST486_EXCEPTION_UD);
653 return FALSE;
654 }
655
656 /* Get the immediate operand */
657 if (!Fast486FetchByte(State, &Immediate))
658 {
659 /* Exception occurred */
660 return FALSE;
661 }
662
663 return Fast486WriteModrmByteOperands(State,
664 &ModRegRm,
665 FALSE,
666 Immediate);
667 }
668
669 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
670 {
671 FAST486_MOD_REG_RM ModRegRm;
672 BOOLEAN OperandSize, AddressSize;
673
674 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
675
676 TOGGLE_OPSIZE(OperandSize);
677 TOGGLE_ADSIZE(AddressSize);
678
679 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
680 {
681 /* Exception occurred */
682 return FALSE;
683 }
684
685 if (ModRegRm.Register != 0)
686 {
687 /* Invalid */
688 Fast486Exception(State, FAST486_EXCEPTION_UD);
689 return FALSE;
690 }
691
692 if (OperandSize)
693 {
694 ULONG Immediate;
695
696 /* Get the immediate operand */
697 if (!Fast486FetchDword(State, &Immediate))
698 {
699 /* Exception occurred */
700 return FALSE;
701 }
702
703 return Fast486WriteModrmDwordOperands(State,
704 &ModRegRm,
705 FALSE,
706 Immediate);
707 }
708 else
709 {
710 USHORT Immediate;
711
712 /* Get the immediate operand */
713 if (!Fast486FetchWord(State, &Immediate))
714 {
715 /* Exception occurred */
716 return FALSE;
717 }
718
719 return Fast486WriteModrmWordOperands(State,
720 &ModRegRm,
721 FALSE,
722 Immediate);
723 }
724 }
725
726 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)
727 {
728 UCHAR Dummy, Value;
729 FAST486_MOD_REG_RM ModRegRm;
730 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
731
732 TOGGLE_ADSIZE(AddressSize);
733
734 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
735 {
736 /* Exception occurred */
737 return FALSE;
738 }
739
740 /* Read the operands */
741 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
742 {
743 /* Exception occurred */
744 return FALSE;
745 }
746
747 /* Calculate the result */
748 Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
749
750 /* Write back the result */
751 return Fast486WriteModrmByteOperands(State,
752 &ModRegRm,
753 FALSE,
754 Value);
755
756 }
757
758 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)
759 {
760 FAST486_MOD_REG_RM ModRegRm;
761 BOOLEAN OperandSize, AddressSize;
762
763 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
764
765 TOGGLE_OPSIZE(OperandSize);
766 TOGGLE_ADSIZE(AddressSize);
767
768 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
769 {
770 /* Exception occurred */
771 return FALSE;
772 }
773
774 if (OperandSize)
775 {
776 ULONG Dummy, Value;
777
778 /* Read the operands */
779 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
780 {
781 /* Exception occurred */
782 return FALSE;
783 }
784
785 /* Calculate the result */
786 Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
787
788 /* Write back the result */
789 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
790 }
791 else
792 {
793 USHORT Dummy, Value;
794
795 /* Read the operands */
796 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
797 {
798 /* Exception occurred */
799 return FALSE;
800 }
801
802 /* Calculate the result */
803 Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
804
805 /* Write back the result */
806 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
807 }
808 }
809
810 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)
811 {
812 UCHAR Dummy, Value;
813 FAST486_MOD_REG_RM ModRegRm;
814 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
815
816 TOGGLE_ADSIZE(AddressSize);
817
818 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
819 {
820 /* Exception occurred */
821 return FALSE;
822 }
823
824 /* Read the operands */
825 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
826 {
827 /* Exception occurred */
828 return FALSE;
829 }
830
831 /* Calculate the result */
832 Value = LOBYTE(Fast486RotateOperation(State,
833 ModRegRm.Register,
834 Value,
835 8,
836 State->GeneralRegs[FAST486_REG_ECX].LowByte));
837
838 /* Write back the result */
839 return Fast486WriteModrmByteOperands(State,
840 &ModRegRm,
841 FALSE,
842 Value);
843 }
844
845 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
846 {
847 FAST486_MOD_REG_RM ModRegRm;
848 BOOLEAN OperandSize, AddressSize;
849
850 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
851
852 TOGGLE_OPSIZE(OperandSize);
853 TOGGLE_ADSIZE(AddressSize);
854
855 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
856 {
857 /* Exception occurred */
858 return FALSE;
859 }
860
861 if (OperandSize)
862 {
863 ULONG Dummy, Value;
864
865 /* Read the operands */
866 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
867 {
868 /* Exception occurred */
869 return FALSE;
870 }
871
872 /* Calculate the result */
873 Value = Fast486RotateOperation(State,
874 ModRegRm.Register,
875 Value,
876 32,
877 State->GeneralRegs[FAST486_REG_ECX].LowByte);
878
879 /* Write back the result */
880 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
881 }
882 else
883 {
884 USHORT Dummy, Value;
885
886 /* Read the operands */
887 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
888 {
889 /* Exception occurred */
890 return FALSE;
891 }
892
893 /* Calculate the result */
894 Value = LOWORD(Fast486RotateOperation(State,
895 ModRegRm.Register,
896 Value,
897 16,
898 State->GeneralRegs[FAST486_REG_ECX].LowByte));
899
900 /* Write back the result */
901 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
902 }
903 }
904
905 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
906 {
907 UCHAR Dummy, Value = 0;
908 FAST486_MOD_REG_RM ModRegRm;
909 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
910
911 TOGGLE_ADSIZE(AddressSize);
912
913 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
914 {
915 /* Exception occurred */
916 return FALSE;
917 }
918
919 /* Read the operands */
920 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
921 {
922 /* Exception occurred */
923 return FALSE;
924 }
925
926 switch (ModRegRm.Register)
927 {
928 /* TEST */
929 case 0:
930 case 1:
931 {
932 UCHAR Immediate, Result;
933
934 /* Fetch the immediate byte */
935 if (!Fast486FetchByte(State, &Immediate))
936 {
937 /* Exception occurred */
938 return FALSE;
939 }
940
941 /* Calculate the result */
942 Result = Value & Immediate;
943
944 /* Update the flags */
945 State->Flags.Cf = FALSE;
946 State->Flags.Of = FALSE;
947 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
948 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
949 State->Flags.Pf = Fast486CalculateParity(Result);
950
951 break;
952 }
953
954 /* NOT */
955 case 2:
956 {
957 /* Write back the result */
958 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
959 }
960
961 /* NEG */
962 case 3:
963 {
964 /* Calculate the result */
965 UCHAR Result = -Value;
966
967 /* Update the flags */
968 State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
969 State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
970 State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
971 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
972 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
973 State->Flags.Pf = Fast486CalculateParity(Result);
974
975 /* Write back the result */
976 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
977 }
978
979 /* MUL */
980 case 4:
981 {
982 USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
983
984 /* Update the flags */
985 State->Flags.Cf = State->Flags.Of = HIBYTE(Result) ? TRUE : FALSE;
986
987 /* Write back the result */
988 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
989
990 break;
991 }
992
993 /* IMUL */
994 case 5:
995 {
996 SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
997
998 /* Update the flags */
999 State->Flags.Cf = State->Flags.Of =
1000 ((Result < -128) || (Result > 127)) ? TRUE : FALSE;
1001
1002 /* Write back the result */
1003 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
1004
1005 break;
1006 }
1007
1008 /* DIV */
1009 case 6:
1010 {
1011 UCHAR Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
1012 UCHAR Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
1013
1014 /* Write back the results */
1015 State->GeneralRegs[FAST486_REG_EAX].LowByte = Quotient;
1016 State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1017
1018 break;
1019 }
1020
1021 /* IDIV */
1022 case 7:
1023 {
1024 CHAR Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1025 CHAR Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1026
1027 /* Write back the results */
1028 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1029 State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1030
1031 break;
1032 }
1033 }
1034
1035 return TRUE;
1036 }
1037
1038 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1039 {
1040 ULONG Dummy, Value = 0, SignFlag;
1041 FAST486_MOD_REG_RM ModRegRm;
1042 BOOLEAN OperandSize, AddressSize;
1043
1044 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1045
1046 TOGGLE_OPSIZE(OperandSize);
1047 TOGGLE_ADSIZE(AddressSize);
1048
1049 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1050 {
1051 /* Exception occurred */
1052 return FALSE;
1053 }
1054
1055 /* Set the sign flag */
1056 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1057 else SignFlag = SIGN_FLAG_WORD;
1058
1059 /* Read the operand */
1060 if (OperandSize)
1061 {
1062 /* 32-bit */
1063 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1064 {
1065 /* Exception occurred */
1066 return FALSE;
1067 }
1068 }
1069 else
1070 {
1071 /* 16-bit */
1072 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, (PUSHORT)&Dummy, (PUSHORT)&Value))
1073 {
1074 /* Exception occurred */
1075 return FALSE;
1076 }
1077 }
1078
1079 switch (ModRegRm.Register)
1080 {
1081 /* TEST */
1082 case 0:
1083 case 1:
1084 {
1085 ULONG Immediate = 0, Result = 0;
1086
1087 if (OperandSize)
1088 {
1089 /* Fetch the immediate dword */
1090 if (!Fast486FetchDword(State, &Immediate))
1091 {
1092 /* Exception occurred */
1093 return FALSE;
1094 }
1095 }
1096 else
1097 {
1098 /* Fetch the immediate word */
1099 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1100 {
1101 /* Exception occurred */
1102 return FALSE;
1103 }
1104 }
1105
1106 /* Calculate the result */
1107 Result = Value & Immediate;
1108
1109 /* Update the flags */
1110 State->Flags.Cf = FALSE;
1111 State->Flags.Of = FALSE;
1112 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1113 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
1114 State->Flags.Pf = Fast486CalculateParity(Result);
1115
1116 break;
1117 }
1118
1119 /* NOT */
1120 case 2:
1121 {
1122 /* Write back the result */
1123 if (OperandSize)
1124 {
1125 /* 32-bit */
1126 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1127 }
1128 else
1129 {
1130 /* 16-bit */
1131 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1132 }
1133 }
1134
1135 /* NEG */
1136 case 3:
1137 {
1138 /* Calculate the result */
1139 ULONG Result = -Value;
1140 if (!OperandSize) Result &= 0xFFFF;
1141
1142 /* Update the flags */
1143 State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
1144 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1145 State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
1146 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1147 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
1148 State->Flags.Pf = Fast486CalculateParity(Result);
1149
1150 /* Write back the result */
1151 if (OperandSize)
1152 {
1153 /* 32-bit */
1154 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1155 }
1156 else
1157 {
1158 /* 16-bit */
1159 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1160 }
1161 }
1162
1163 /* MUL */
1164 case 4:
1165 {
1166 if (OperandSize)
1167 {
1168 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1169
1170 /* Update the flags */
1171 State->Flags.Cf = State->Flags.Of =
1172 (Result & 0xFFFFFFFF00000000ULL) ? TRUE : FALSE;
1173
1174 /* Write back the result */
1175 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1176 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1177 }
1178 else
1179 {
1180 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1181
1182 /* Update the flags */
1183 State->Flags.Cf = State->Flags.Of = HIWORD(Result) ? TRUE : FALSE;
1184
1185 /* Write back the result */
1186 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1187 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1188 }
1189
1190 break;
1191 }
1192
1193 /* IMUL */
1194 case 5:
1195 {
1196 if (OperandSize)
1197 {
1198 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1199
1200 /* Update the flags */
1201 State->Flags.Cf = State->Flags.Of =
1202 ((Result < -2147483648LL) || (Result > 2147483647LL)) ? TRUE : FALSE;
1203
1204 /* Write back the result */
1205 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1206 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1207 }
1208 else
1209 {
1210 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1211
1212 /* Update the flags */
1213 State->Flags.Cf = State->Flags.Of =
1214 ((Result < -32768) || (Result > 32767)) ? TRUE : FALSE;
1215
1216 /* Write back the result */
1217 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1218 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1219 }
1220
1221 break;
1222 }
1223
1224 /* DIV */
1225 case 6:
1226 {
1227 if (OperandSize)
1228 {
1229 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1230 | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1231 ULONG Quotient = Dividend / Value;
1232 ULONG Remainder = Dividend % Value;
1233
1234 /* Write back the results */
1235 State->GeneralRegs[FAST486_REG_EAX].Long = Quotient;
1236 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1237 }
1238 else
1239 {
1240 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1241 | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1242 USHORT Quotient = Dividend / Value;
1243 USHORT Remainder = Dividend % Value;
1244
1245 /* Write back the results */
1246 State->GeneralRegs[FAST486_REG_EAX].LowWord = Quotient;
1247 State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
1248 }
1249
1250 break;
1251 }
1252
1253 /* IDIV */
1254 case 7:
1255 {
1256 if (OperandSize)
1257 {
1258 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1259 | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1260 LONG Quotient = Dividend / (LONG)Value;
1261 LONG Remainder = Dividend % (LONG)Value;
1262
1263 /* Write back the results */
1264 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1265 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1266 }
1267 else
1268 {
1269 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1270 | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1271 SHORT Quotient = Dividend / (SHORT)LOWORD(Value);
1272 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1273
1274 /* Write back the results */
1275 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
1276 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1277 }
1278
1279 break;
1280 }
1281 }
1282
1283 return TRUE;
1284 }
1285
1286 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1287 {
1288 UCHAR Dummy, Value;
1289 FAST486_MOD_REG_RM ModRegRm;
1290 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1291
1292 TOGGLE_ADSIZE(AddressSize);
1293
1294 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1295 {
1296 /* Exception occurred */
1297 return FALSE;
1298 }
1299
1300 if (ModRegRm.Register > 1)
1301 {
1302 /* Invalid */
1303 Fast486Exception(State, FAST486_EXCEPTION_UD);
1304 return FALSE;
1305 }
1306
1307 /* Read the operands */
1308 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
1309 {
1310 /* Exception occurred */
1311 return FALSE;
1312 }
1313
1314 if (ModRegRm.Register == 0)
1315 {
1316 /* Increment and update OF and AF */
1317 Value++;
1318 State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
1319 State->Flags.Af = ((Value & 0x0F) == 0);
1320 }
1321 else
1322 {
1323 /* Decrement and update OF and AF */
1324 State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
1325 Value--;
1326 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1327 }
1328
1329 /* Update flags */
1330 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1331 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1332 State->Flags.Pf = Fast486CalculateParity(Value);
1333
1334 /* Write back the result */
1335 return Fast486WriteModrmByteOperands(State,
1336 &ModRegRm,
1337 FALSE,
1338 Value);
1339 }
1340
1341 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1342 {
1343 FAST486_MOD_REG_RM ModRegRm;
1344 BOOLEAN OperandSize, AddressSize;
1345
1346 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1347
1348 TOGGLE_OPSIZE(OperandSize);
1349 TOGGLE_ADSIZE(AddressSize);
1350
1351 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1352 {
1353 /* Exception occurred */
1354 return FALSE;
1355 }
1356
1357 if (ModRegRm.Register == 7)
1358 {
1359 /* Invalid */
1360 Fast486Exception(State, FAST486_EXCEPTION_UD);
1361 return FALSE;
1362 }
1363
1364 /* Read the operands */
1365 if (OperandSize)
1366 {
1367 ULONG Dummy, Value;
1368
1369 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1370 {
1371 /* Exception occurred */
1372 return FALSE;
1373 }
1374
1375 if (ModRegRm.Register == 0)
1376 {
1377 /* Increment and update OF and AF */
1378 Value++;
1379 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
1380 State->Flags.Af = ((Value & 0x0F) == 0);
1381 }
1382 else if (ModRegRm.Register == 1)
1383 {
1384 /* Decrement and update OF and AF */
1385 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
1386 Value--;
1387 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1388 }
1389 else if (ModRegRm.Register == 2)
1390 {
1391 /* Push the current value of EIP */
1392 if (!Fast486StackPush(State, State->InstPtr.Long))
1393 {
1394 /* Exception occurred */
1395 return FALSE;
1396 }
1397
1398 /* Set the EIP to the address */
1399 State->InstPtr.Long = Value;
1400 }
1401 else if (ModRegRm.Register == 3)
1402 {
1403 USHORT Selector;
1404 INT Segment = FAST486_REG_DS;
1405
1406 /* Check for the segment override */
1407 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1408 {
1409 /* Use the override segment instead */
1410 Segment = State->SegmentOverride;
1411 }
1412
1413 /* Read the selector */
1414 if (!Fast486ReadMemory(State,
1415 Segment,
1416 ModRegRm.MemoryAddress + sizeof(ULONG),
1417 FALSE,
1418 &Selector,
1419 sizeof(USHORT)))
1420 {
1421 /* Exception occurred */
1422 return FALSE;
1423 }
1424
1425 /* Push the current value of CS */
1426 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1427 {
1428 /* Exception occurred */
1429 return FALSE;
1430 }
1431
1432 /* Push the current value of EIP */
1433 if (!Fast486StackPush(State, State->InstPtr.Long))
1434 {
1435 /* Exception occurred */
1436 return FALSE;
1437 }
1438
1439 /* Load the new code segment */
1440 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1441 {
1442 /* Exception occurred */
1443 return FALSE;
1444 }
1445
1446 /* Set the EIP to the address */
1447 State->InstPtr.Long = Value;
1448 }
1449 else if (ModRegRm.Register == 4)
1450 {
1451 /* Set the EIP to the address */
1452 State->InstPtr.Long = Value;
1453 }
1454 else if (ModRegRm.Register == 5)
1455 {
1456 USHORT Selector;
1457 INT Segment = FAST486_REG_DS;
1458
1459 /* Check for the segment override */
1460 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1461 {
1462 /* Use the override segment instead */
1463 Segment = State->SegmentOverride;
1464 }
1465
1466 /* Read the selector */
1467 if (!Fast486ReadMemory(State,
1468 Segment,
1469 ModRegRm.MemoryAddress + sizeof(ULONG),
1470 FALSE,
1471 &Selector,
1472 sizeof(USHORT)))
1473 {
1474 /* Exception occurred */
1475 return FALSE;
1476 }
1477
1478 /* Load the new code segment */
1479 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1480 {
1481 /* Exception occurred */
1482 return FALSE;
1483 }
1484
1485 /* Set the EIP to the address */
1486 State->InstPtr.Long = Value;
1487 }
1488 else if (ModRegRm.Register == 6)
1489 {
1490 /* Push the value on to the stack */
1491 return Fast486StackPush(State, Value);
1492 }
1493
1494 if (ModRegRm.Register <= 1)
1495 {
1496 /* Update flags */
1497 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
1498 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1499 State->Flags.Pf = Fast486CalculateParity(Value);
1500
1501 /* Write back the result */
1502 return Fast486WriteModrmDwordOperands(State,
1503 &ModRegRm,
1504 FALSE,
1505 Value);
1506 }
1507 }
1508 else
1509 {
1510 USHORT Dummy, Value;
1511
1512 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1513 {
1514 /* Exception occurred */
1515 return FALSE;
1516 }
1517
1518 if (ModRegRm.Register == 0)
1519 {
1520 /* Increment and update OF */
1521 Value++;
1522 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
1523 State->Flags.Af = ((Value & 0x0F) == 0);
1524 }
1525 else if (ModRegRm.Register == 1)
1526 {
1527 /* Decrement and update OF */
1528 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
1529 Value--;
1530 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1531 }
1532 else if (ModRegRm.Register == 2)
1533 {
1534 /* Push the current value of IP */
1535 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1536 {
1537 /* Exception occurred */
1538 return FALSE;
1539 }
1540
1541 /* Set the IP to the address */
1542 State->InstPtr.LowWord = Value;
1543 }
1544 else if (ModRegRm.Register == 3)
1545 {
1546 USHORT Selector;
1547 INT Segment = FAST486_REG_DS;
1548
1549 /* Check for the segment override */
1550 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1551 {
1552 /* Use the override segment instead */
1553 Segment = State->SegmentOverride;
1554 }
1555
1556 /* Read the selector */
1557 if (!Fast486ReadMemory(State,
1558 Segment,
1559 ModRegRm.MemoryAddress + sizeof(USHORT),
1560 FALSE,
1561 &Selector,
1562 sizeof(USHORT)))
1563 {
1564 /* Exception occurred */
1565 return FALSE;
1566 }
1567
1568 /* Push the current value of CS */
1569 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1570 {
1571 /* Exception occurred */
1572 return FALSE;
1573 }
1574
1575 /* Push the current value of IP */
1576 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1577 {
1578 /* Exception occurred */
1579 return FALSE;
1580 }
1581
1582 /* Load the new code segment */
1583 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1584 {
1585 /* Exception occurred */
1586 return FALSE;
1587 }
1588
1589 /* Set the IP to the address */
1590 State->InstPtr.LowWord = Value;
1591
1592 }
1593 else if (ModRegRm.Register == 4)
1594 {
1595 /* Set the IP to the address */
1596 State->InstPtr.LowWord = Value;
1597 }
1598 else if (ModRegRm.Register == 5)
1599 {
1600 USHORT Selector;
1601 INT Segment = FAST486_REG_DS;
1602
1603 /* Check for the segment override */
1604 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1605 {
1606 /* Use the override segment instead */
1607 Segment = State->SegmentOverride;
1608 }
1609
1610 /* Read the selector */
1611 if (!Fast486ReadMemory(State,
1612 Segment,
1613 ModRegRm.MemoryAddress + sizeof(USHORT),
1614 FALSE,
1615 &Selector,
1616 sizeof(USHORT)))
1617 {
1618 /* Exception occurred */
1619 return FALSE;
1620 }
1621
1622 /* Load the new code segment */
1623 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1624 {
1625 /* Exception occurred */
1626 return FALSE;
1627 }
1628
1629 /* Set the IP to the address */
1630 State->InstPtr.LowWord = Value;
1631 }
1632 else if (ModRegRm.Register == 6)
1633 {
1634 /* Push the value on to the stack */
1635 return Fast486StackPush(State, Value);
1636 }
1637 else
1638 {
1639 /* Invalid */
1640 Fast486Exception(State, FAST486_EXCEPTION_UD);
1641 return FALSE;
1642 }
1643
1644 if (ModRegRm.Register <= 1)
1645 {
1646 /* Update flags */
1647 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
1648 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1649 State->Flags.Pf = Fast486CalculateParity(Value);
1650
1651 /* Write back the result */
1652 return Fast486WriteModrmWordOperands(State,
1653 &ModRegRm,
1654 FALSE,
1655 Value);
1656 }
1657 }
1658
1659 return TRUE;
1660 }
1661
1662 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
1663 {
1664 FAST486_MOD_REG_RM ModRegRm;
1665 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1666
1667 TOGGLE_ADSIZE(AddressSize);
1668
1669 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1670 {
1671 /* Exception occurred */
1672 return FALSE;
1673 }
1674
1675 /* All of them are reserved (UD2) */
1676 Fast486Exception(State, FAST486_EXCEPTION_UD);
1677 return FALSE;
1678 }
1679
1680 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
1681 {
1682 FAST486_MOD_REG_RM ModRegRm;
1683 BOOLEAN OperandSize, AddressSize;
1684 UINT DataSize;
1685 UCHAR BitNumber;
1686
1687 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1688
1689 TOGGLE_OPSIZE(OperandSize);
1690 TOGGLE_ADSIZE(AddressSize);
1691
1692 /* Get the number of bits */
1693 if (OperandSize) DataSize = 32;
1694 else DataSize = 16;
1695
1696 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1697 {
1698 /* Exception occurred */
1699 return FALSE;
1700 }
1701
1702 if (ModRegRm.Register < 4)
1703 {
1704 /* Invalid */
1705 Fast486Exception(State, FAST486_EXCEPTION_UD);
1706 return FALSE;
1707 }
1708
1709 /* Get the bit number */
1710 if (!Fast486FetchByte(State, &BitNumber))
1711 {
1712 /* Exception occurred */
1713 return FALSE;
1714 }
1715
1716 if (ModRegRm.Memory)
1717 {
1718 /*
1719 * For memory operands, add the bit offset divided by
1720 * the data size to the address
1721 */
1722 ModRegRm.MemoryAddress += BitNumber / DataSize;
1723 }
1724
1725 /* Normalize the bit number */
1726 BitNumber &= (1 << DataSize) - 1;
1727
1728 if (OperandSize)
1729 {
1730 ULONG Dummy, Value;
1731
1732 /* Read the value */
1733 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1734 {
1735 /* Exception occurred */
1736 return FALSE;
1737 }
1738
1739 /* Set CF to the bit value */
1740 State->Flags.Cf = (Value >> BitNumber) & 1;
1741
1742 if (ModRegRm.Register == 5)
1743 {
1744 /* BTS */
1745 Value |= 1 << BitNumber;
1746 }
1747 else if (ModRegRm.Register == 6)
1748 {
1749 /* BTR */
1750 Value &= ~(1 << BitNumber);
1751 }
1752 else if (ModRegRm.Register == 7)
1753 {
1754 /* BTC */
1755 Value ^= 1 << BitNumber;
1756 }
1757
1758 if (ModRegRm.Register >= 5)
1759 {
1760 /* Write back the result */
1761 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1762 {
1763 /* Exception occurred */
1764 return FALSE;
1765 }
1766 }
1767 }
1768 else
1769 {
1770 USHORT Dummy, Value;
1771
1772 /* Read the value */
1773 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1774 {
1775 /* Exception occurred */
1776 return FALSE;
1777 }
1778
1779 /* Set CF to the bit value */
1780 State->Flags.Cf = (Value >> BitNumber) & 1;
1781
1782 if (ModRegRm.Register == 5)
1783 {
1784 /* BTS */
1785 Value |= 1 << BitNumber;
1786 }
1787 else if (ModRegRm.Register == 6)
1788 {
1789 /* BTR */
1790 Value &= ~(1 << BitNumber);
1791 }
1792 else if (ModRegRm.Register == 7)
1793 {
1794 /* BTC */
1795 Value ^= 1 << BitNumber;
1796 }
1797
1798 if (ModRegRm.Register >= 5)
1799 {
1800 /* Write back the result */
1801 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
1802 {
1803 /* Exception occurred */
1804 return FALSE;
1805 }
1806 }
1807 }
1808
1809 /* Return success */
1810 return TRUE;
1811
1812 return TRUE;
1813 }
1814
1815 /* EOF */
1816