126d4d1cc74057d61ddd0825bfad5103304a100b
[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 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "opcodes.h"
31 #include "common.h"
32
33 /* PRIVATE FUNCTIONS **********************************************************/
34
35 inline
36 static
37 ULONG
38 Fast486ArithmeticOperation(PFAST486_STATE State,
39 INT Operation,
40 ULONG FirstValue,
41 ULONG SecondValue,
42 UCHAR Bits)
43 {
44 ULONG Result;
45 ULONG SignFlag = 1 << (Bits - 1);
46 ULONG MaxValue = (1 << Bits) - 1;
47
48 /* Make sure the values don't exceed the maximum for their size */
49 FirstValue &= MaxValue;
50 SecondValue &= MaxValue;
51
52 /* Check which operation is this */
53 switch (Operation)
54 {
55 /* ADD */
56 case 0:
57 {
58 Result = (FirstValue + SecondValue) & MaxValue;
59
60 /* Update CF, OF and AF */
61 State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
62 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
63 && ((FirstValue & SignFlag) != (Result & SignFlag));
64 State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
65
66 break;
67 }
68
69 /* OR */
70 case 1:
71 {
72 Result = FirstValue | SecondValue;
73 break;
74 }
75
76 /* ADC */
77 case 2:
78 {
79 INT Carry = State->Flags.Cf ? 1 : 0;
80
81 Result = (FirstValue + SecondValue + Carry) & MaxValue;
82
83 /* Update CF, OF and AF */
84 State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1))
85 || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
86 State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
87 && ((FirstValue & SignFlag) != (Result & SignFlag));
88 State->Flags.Af = (((FirstValue & 0x0F) + ((SecondValue + Carry) & 0x0F)) & 0x10)
89 ? TRUE : FALSE;
90
91 break;
92 }
93
94 /* SBB */
95 case 3:
96 {
97 INT Carry = State->Flags.Cf ? 1 : 0;
98
99 Result = (FirstValue - SecondValue - Carry) & MaxValue;
100
101 /* Update CF, OF and AF */
102 State->Flags.Cf = FirstValue < (SecondValue + Carry);
103 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
104 && ((FirstValue & SignFlag) != (Result & SignFlag));
105 State->Flags.Af = (FirstValue & 0x0F) < ((SecondValue + Carry) & 0x0F);
106
107 break;
108 }
109
110 /* AND */
111 case 4:
112 {
113 Result = FirstValue & SecondValue;
114 break;
115 }
116
117 /* SUB or CMP */
118 case 5:
119 case 7:
120 {
121 Result = (FirstValue - SecondValue) & MaxValue;
122
123 /* Update CF, OF and AF */
124 State->Flags.Cf = FirstValue < SecondValue;
125 State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
126 && ((FirstValue & SignFlag) != (Result & SignFlag));
127 State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
128
129 break;
130 }
131
132 /* XOR */
133 case 6:
134 {
135 Result = FirstValue ^ SecondValue;
136 break;
137 }
138
139 default:
140 {
141 /* Shouldn't happen */
142 ASSERT(FALSE);
143 }
144 }
145
146 /* Update ZF, SF and PF */
147 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
148 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
149 State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
150
151 /* Return the result */
152 return Result;
153 }
154
155 static
156 inline
157 ULONG
158 Fast486RotateOperation(PFAST486_STATE State,
159 INT Operation,
160 ULONG Value,
161 UCHAR Bits,
162 UCHAR Count)
163 {
164 ULONG HighestBit = 1 << (Bits - 1);
165 ULONG Result;
166
167 if ((Operation != 2) && (Operation != 3))
168 {
169 /* Mask the count */
170 Count &= Bits - 1;
171 }
172 else
173 {
174 /* For RCL and RCR, the CF is included in the value */
175 Count %= Bits + 1;
176 }
177
178 /* Check which operation is this */
179 switch (Operation)
180 {
181 /* ROL */
182 case 0:
183 {
184 Result = (Value << Count) | (Value >> (Bits - Count));
185
186 /* Update CF and OF */
187 State->Flags.Cf = Result & 1;
188 if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
189 ^ State->Flags.Cf;
190
191 break;
192 }
193
194 /* ROR */
195 case 1:
196 {
197 Result = (Value >> Count) | (Value << (Bits - Count));
198
199 /* Update CF and OF */
200 State->Flags.Cf = (Result & HighestBit) ? TRUE : FALSE;
201 if (Count == 1) State->Flags.Of = State->Flags.Cf
202 ^ ((Result & (HighestBit >> 1))
203 ? TRUE : FALSE);
204
205 break;
206 }
207
208 /* RCL */
209 case 2:
210 {
211 Result = (Value << Count)
212 | (State->Flags.Cf << (Count - 1))
213 | (Value >> (Bits - Count + 1));
214
215 /* Update CF and OF */
216 State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
217 if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
218 ^ State->Flags.Cf;
219
220 break;
221 }
222
223 /* RCR */
224 case 3:
225 {
226 Result = (Value >> Count)
227 | (State->Flags.Cf << (Bits - Count))
228 | (Value << (Bits - Count + 1));
229
230 /* Update CF and OF */
231 State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
232 if (Count == 1) State->Flags.Of = State->Flags.Cf
233 ^ ((Result & (HighestBit >> 1))
234 ? TRUE : FALSE);
235
236 break;
237 }
238
239 /* SHL/SAL */
240 case 4:
241 case 6:
242 {
243 Result = Value << Count;
244
245 /* Update CF and OF */
246 State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
247 if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
248 ^ (State->Flags.Cf ? TRUE : FALSE);
249
250 break;
251 }
252
253 /* SHR */
254 case 5:
255 {
256 Result = Value >> Count;
257
258 /* Update CF and OF */
259 State->Flags.Cf = (Value & (1 << (Count - 1))) ? TRUE : FALSE;
260 if (Count == 1) State->Flags.Of = (Value & HighestBit) ? TRUE : FALSE;
261
262 break;
263 }
264
265 /* SAR */
266 case 7:
267 {
268 Result = Value >> Count;
269
270 /* Fill the top Count bits with the sign bit */
271 if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
272
273 /* Update CF and OF */
274 State->Flags.Cf = (Value & (1 << (Count - 1))) ? TRUE : FALSE;
275 if (Count == 1) State->Flags.Of = FALSE;
276
277 break;
278 }
279 }
280
281 if (Operation >= 4)
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
289 /* Return the result */
290 return Result;
291 }
292
293 /* PUBLIC FUNCTIONS ***********************************************************/
294
295 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)
296 {
297 UCHAR Immediate, Dummy, Value;
298 FAST486_MOD_REG_RM ModRegRm;
299 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
300
301 TOGGLE_ADSIZE(AddressSize);
302
303 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
304 {
305 /* Exception occurred */
306 return FALSE;
307 }
308
309 /* Fetch the immediate operand */
310 if (!Fast486FetchByte(State, &Immediate))
311 {
312 /* Exception occurred */
313 return FALSE;
314 }
315
316 /* Read the operands */
317 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
318 {
319 /* Exception occurred */
320 return FALSE;
321 }
322
323 /* Calculate the result */
324 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
325
326 /* Unless this is CMP, write back the result */
327 if (ModRegRm.Register != 7)
328 {
329 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
330 }
331
332 return TRUE;
333 }
334
335 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
336 {
337 FAST486_MOD_REG_RM ModRegRm;
338 BOOLEAN OperandSize, AddressSize;
339
340 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
341
342 TOGGLE_OPSIZE(OperandSize);
343 TOGGLE_ADSIZE(AddressSize);
344
345 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
346 {
347 /* Exception occurred */
348 return FALSE;
349 }
350
351 if (OperandSize)
352 {
353 ULONG Immediate, Value, Dummy;
354
355 /* Fetch the immediate operand */
356 if (!Fast486FetchDword(State, &Immediate))
357 {
358 /* Exception occurred */
359 return FALSE;
360 }
361
362 /* Read the operands */
363 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
364 {
365 /* Exception occurred */
366 return FALSE;
367 }
368
369 /* Calculate the result */
370 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
371
372 /* Unless this is CMP, write back the result */
373 if (ModRegRm.Register != 7)
374 {
375 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
376 }
377 }
378 else
379 {
380 USHORT Immediate, Value, Dummy;
381
382 /* Fetch the immediate operand */
383 if (!Fast486FetchWord(State, &Immediate))
384 {
385 /* Exception occurred */
386 return FALSE;
387 }
388
389 /* Read the operands */
390 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
391 {
392 /* Exception occurred */
393 return FALSE;
394 }
395
396 /* Calculate the result */
397 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
398
399 /* Unless this is CMP, write back the result */
400 if (ModRegRm.Register != 7)
401 {
402 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
403 }
404 }
405
406 return TRUE;
407 }
408
409 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
410 {
411 CHAR ImmByte;
412 FAST486_MOD_REG_RM ModRegRm;
413 BOOLEAN OperandSize, AddressSize;
414
415 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
416
417 TOGGLE_OPSIZE(OperandSize);
418 TOGGLE_ADSIZE(AddressSize);
419
420 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
421 {
422 /* Exception occurred */
423 return FALSE;
424 }
425
426 /* Fetch the immediate operand */
427 if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
428 {
429 /* Exception occurred */
430 return FALSE;
431 }
432
433 if (OperandSize)
434 {
435 ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
436 ULONG Value, Dummy;
437
438 /* Read the operands */
439 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
440 {
441 /* Exception occurred */
442 return FALSE;
443 }
444
445 /* Calculate the result */
446 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
447
448 /* Unless this is CMP, write back the result */
449 if (ModRegRm.Register != 7)
450 {
451 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
452 }
453 }
454 else
455 {
456 USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
457 USHORT Value, Dummy;
458
459 /* Read the operands */
460 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
461 {
462 /* Exception occurred */
463 return FALSE;
464 }
465
466 /* Calculate the result */
467 Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
468
469 /* Unless this is CMP, write back the result */
470 if (ModRegRm.Register != 7)
471 {
472 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
473 }
474 }
475
476 return TRUE;
477 }
478
479 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
480 {
481 ULONG Value;
482 FAST486_MOD_REG_RM ModRegRm;
483 BOOLEAN OperandSize, AddressSize;
484
485 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
486
487 TOGGLE_OPSIZE(OperandSize);
488 TOGGLE_ADSIZE(AddressSize);
489
490 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
491 {
492 /* Exception occurred */
493 return FALSE;
494 }
495
496 if (ModRegRm.Register != 0)
497 {
498 /* Invalid */
499 Fast486Exception(State, FAST486_EXCEPTION_UD);
500 return FALSE;
501 }
502
503 /* Pop a value from the stack */
504 if (!Fast486StackPop(State, &Value))
505 {
506 /* Exception occurred */
507 return FALSE;
508 }
509
510 if (OperandSize)
511 {
512 return Fast486WriteModrmDwordOperands(State,
513 &ModRegRm,
514 FALSE,
515 Value);
516 }
517 else
518 {
519 return Fast486WriteModrmWordOperands(State,
520 &ModRegRm,
521 FALSE,
522 LOWORD(Value));
523 }
524 }
525
526 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
527 {
528 UCHAR Dummy, Value, Count;
529 FAST486_MOD_REG_RM ModRegRm;
530 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
531
532 TOGGLE_ADSIZE(AddressSize);
533
534 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
535 {
536 /* Exception occurred */
537 return FALSE;
538 }
539
540 /* Fetch the count */
541 if (!Fast486FetchByte(State, &Count))
542 {
543 /* Exception occurred */
544 return FALSE;
545 }
546
547 /* Read the operands */
548 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
549 {
550 /* Exception occurred */
551 return FALSE;
552 }
553
554 /* Calculate the result */
555 Value = LOBYTE(Fast486RotateOperation(State,
556 ModRegRm.Register,
557 Value,
558 8,
559 Count));
560
561 /* Write back the result */
562 return Fast486WriteModrmByteOperands(State,
563 &ModRegRm,
564 FALSE,
565 Value);
566 }
567
568 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
569 {
570 UCHAR Count;
571 FAST486_MOD_REG_RM ModRegRm;
572 BOOLEAN OperandSize, AddressSize;
573
574 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
575
576 TOGGLE_OPSIZE(OperandSize);
577 TOGGLE_ADSIZE(AddressSize);
578
579 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
580 {
581 /* Exception occurred */
582 return FALSE;
583 }
584
585 /* Fetch the count */
586 if (!Fast486FetchByte(State, &Count))
587 {
588 /* Exception occurred */
589 return FALSE;
590 }
591
592 if (OperandSize)
593 {
594 ULONG Dummy, Value;
595
596 /* Read the operands */
597 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
598 {
599 /* Exception occurred */
600 return FALSE;
601 }
602
603 /* Calculate the result */
604 Value = Fast486RotateOperation(State,
605 ModRegRm.Register,
606 Value,
607 32,
608 Count);
609
610 /* Write back the result */
611 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
612 }
613 else
614 {
615 USHORT Dummy, Value;
616
617 /* Read the operands */
618 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
619 {
620 /* Exception occurred */
621 return FALSE;
622 }
623
624 /* Calculate the result */
625 Value = LOWORD(Fast486RotateOperation(State,
626 ModRegRm.Register,
627 Value,
628 16,
629 Count));
630
631 /* Write back the result */
632 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
633 }
634 }
635
636 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)
637 {
638 UCHAR Immediate;
639 FAST486_MOD_REG_RM ModRegRm;
640 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
641
642 TOGGLE_ADSIZE(AddressSize);
643
644 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
645 {
646 /* Exception occurred */
647 return FALSE;
648 }
649
650 if (ModRegRm.Register != 0)
651 {
652 /* Invalid */
653 Fast486Exception(State, FAST486_EXCEPTION_UD);
654 return FALSE;
655 }
656
657 /* Get the immediate operand */
658 if (!Fast486FetchByte(State, &Immediate))
659 {
660 /* Exception occurred */
661 return FALSE;
662 }
663
664 return Fast486WriteModrmByteOperands(State,
665 &ModRegRm,
666 FALSE,
667 Immediate);
668 }
669
670 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
671 {
672 FAST486_MOD_REG_RM ModRegRm;
673 BOOLEAN OperandSize, AddressSize;
674
675 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
676
677 TOGGLE_OPSIZE(OperandSize);
678 TOGGLE_ADSIZE(AddressSize);
679
680 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
681 {
682 /* Exception occurred */
683 return FALSE;
684 }
685
686 if (ModRegRm.Register != 0)
687 {
688 /* Invalid */
689 Fast486Exception(State, FAST486_EXCEPTION_UD);
690 return FALSE;
691 }
692
693 if (OperandSize)
694 {
695 ULONG Immediate;
696
697 /* Get the immediate operand */
698 if (!Fast486FetchDword(State, &Immediate))
699 {
700 /* Exception occurred */
701 return FALSE;
702 }
703
704 return Fast486WriteModrmDwordOperands(State,
705 &ModRegRm,
706 FALSE,
707 Immediate);
708 }
709 else
710 {
711 USHORT Immediate;
712
713 /* Get the immediate operand */
714 if (!Fast486FetchWord(State, &Immediate))
715 {
716 /* Exception occurred */
717 return FALSE;
718 }
719
720 return Fast486WriteModrmWordOperands(State,
721 &ModRegRm,
722 FALSE,
723 Immediate);
724 }
725 }
726
727 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)
728 {
729 UCHAR Dummy, Value;
730 FAST486_MOD_REG_RM ModRegRm;
731 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
732
733 TOGGLE_ADSIZE(AddressSize);
734
735 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
736 {
737 /* Exception occurred */
738 return FALSE;
739 }
740
741 /* Read the operands */
742 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
743 {
744 /* Exception occurred */
745 return FALSE;
746 }
747
748 /* Calculate the result */
749 Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
750
751 /* Write back the result */
752 return Fast486WriteModrmByteOperands(State,
753 &ModRegRm,
754 FALSE,
755 Value);
756
757 }
758
759 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)
760 {
761 FAST486_MOD_REG_RM ModRegRm;
762 BOOLEAN OperandSize, AddressSize;
763
764 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
765
766 TOGGLE_OPSIZE(OperandSize);
767 TOGGLE_ADSIZE(AddressSize);
768
769 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
770 {
771 /* Exception occurred */
772 return FALSE;
773 }
774
775 if (OperandSize)
776 {
777 ULONG Dummy, Value;
778
779 /* Read the operands */
780 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
781 {
782 /* Exception occurred */
783 return FALSE;
784 }
785
786 /* Calculate the result */
787 Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
788
789 /* Write back the result */
790 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
791 }
792 else
793 {
794 USHORT Dummy, Value;
795
796 /* Read the operands */
797 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
798 {
799 /* Exception occurred */
800 return FALSE;
801 }
802
803 /* Calculate the result */
804 Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
805
806 /* Write back the result */
807 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
808 }
809 }
810
811 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)
812 {
813 UCHAR Dummy, Value;
814 FAST486_MOD_REG_RM ModRegRm;
815 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
816
817 TOGGLE_ADSIZE(AddressSize);
818
819 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
820 {
821 /* Exception occurred */
822 return FALSE;
823 }
824
825 /* Read the operands */
826 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
827 {
828 /* Exception occurred */
829 return FALSE;
830 }
831
832 /* Calculate the result */
833 Value = LOBYTE(Fast486RotateOperation(State,
834 ModRegRm.Register,
835 Value,
836 8,
837 State->GeneralRegs[FAST486_REG_ECX].LowByte));
838
839 /* Write back the result */
840 return Fast486WriteModrmByteOperands(State,
841 &ModRegRm,
842 FALSE,
843 Value);
844 }
845
846 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
847 {
848 FAST486_MOD_REG_RM ModRegRm;
849 BOOLEAN OperandSize, AddressSize;
850
851 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
852
853 TOGGLE_OPSIZE(OperandSize);
854 TOGGLE_ADSIZE(AddressSize);
855
856 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
857 {
858 /* Exception occurred */
859 return FALSE;
860 }
861
862 if (OperandSize)
863 {
864 ULONG Dummy, Value;
865
866 /* Read the operands */
867 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
868 {
869 /* Exception occurred */
870 return FALSE;
871 }
872
873 /* Calculate the result */
874 Value = Fast486RotateOperation(State,
875 ModRegRm.Register,
876 Value,
877 32,
878 State->GeneralRegs[FAST486_REG_ECX].LowByte);
879
880 /* Write back the result */
881 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
882 }
883 else
884 {
885 USHORT Dummy, Value;
886
887 /* Read the operands */
888 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
889 {
890 /* Exception occurred */
891 return FALSE;
892 }
893
894 /* Calculate the result */
895 Value = LOWORD(Fast486RotateOperation(State,
896 ModRegRm.Register,
897 Value,
898 16,
899 State->GeneralRegs[FAST486_REG_ECX].LowByte));
900
901 /* Write back the result */
902 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
903 }
904 }
905
906 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
907 {
908 UCHAR Dummy, Value = 0;
909 FAST486_MOD_REG_RM ModRegRm;
910 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
911
912 TOGGLE_ADSIZE(AddressSize);
913
914 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
915 {
916 /* Exception occurred */
917 return FALSE;
918 }
919
920 /* Read the operands */
921 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
922 {
923 /* Exception occurred */
924 return FALSE;
925 }
926
927 switch (ModRegRm.Register)
928 {
929 /* TEST */
930 case 0:
931 case 1:
932 {
933 UCHAR Immediate, Result;
934
935 /* Fetch the immediate byte */
936 if (!Fast486FetchByte(State, &Immediate))
937 {
938 /* Exception occurred */
939 return FALSE;
940 }
941
942 /* Calculate the result */
943 Result = Value & Immediate;
944
945 /* Update the flags */
946 State->Flags.Cf = FALSE;
947 State->Flags.Of = FALSE;
948 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
949 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
950 State->Flags.Pf = Fast486CalculateParity(Result);
951
952 break;
953 }
954
955 /* NOT */
956 case 2:
957 {
958 /* Write back the result */
959 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
960 }
961
962 /* NEG */
963 case 3:
964 {
965 /* Calculate the result */
966 UCHAR Result = -Value;
967
968 /* Update the flags */
969 State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
970 State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
971 State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
972 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
973 State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
974 State->Flags.Pf = Fast486CalculateParity(Result);
975
976 /* Write back the result */
977 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
978 }
979
980 /* MUL */
981 case 4:
982 {
983 USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
984
985 /* Update the flags */
986 State->Flags.Cf = State->Flags.Of = HIBYTE(Result) ? TRUE : FALSE;
987
988 /* Write back the result */
989 State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
990
991 break;
992 }
993
994 /* IMUL */
995 case 5:
996 {
997 SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
998
999 /* Update the flags */
1000 State->Flags.Cf = State->Flags.Of =
1001 ((Result < -128) || (Result > 127)) ? TRUE : FALSE;
1002
1003 /* Write back the result */
1004 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
1005
1006 break;
1007 }
1008
1009 /* DIV */
1010 case 6:
1011 {
1012 UCHAR Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
1013 UCHAR Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
1014
1015 /* Write back the results */
1016 State->GeneralRegs[FAST486_REG_EAX].LowByte = Quotient;
1017 State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1018
1019 break;
1020 }
1021
1022 /* IDIV */
1023 case 7:
1024 {
1025 CHAR Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1026 CHAR Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1027
1028 /* Write back the results */
1029 State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1030 State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1031
1032 break;
1033 }
1034 }
1035
1036 return TRUE;
1037 }
1038
1039 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1040 {
1041 ULONG Dummy, Value = 0, SignFlag;
1042 FAST486_MOD_REG_RM ModRegRm;
1043 BOOLEAN OperandSize, AddressSize;
1044
1045 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1046
1047 TOGGLE_OPSIZE(OperandSize);
1048 TOGGLE_ADSIZE(AddressSize);
1049
1050 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1051 {
1052 /* Exception occurred */
1053 return FALSE;
1054 }
1055
1056 /* Set the sign flag */
1057 if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1058 else SignFlag = SIGN_FLAG_WORD;
1059
1060 /* Read the operand */
1061 if (OperandSize)
1062 {
1063 /* 32-bit */
1064 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1065 {
1066 /* Exception occurred */
1067 return FALSE;
1068 }
1069 }
1070 else
1071 {
1072 /* 16-bit */
1073 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, (PUSHORT)&Dummy, (PUSHORT)&Value))
1074 {
1075 /* Exception occurred */
1076 return FALSE;
1077 }
1078 }
1079
1080 switch (ModRegRm.Register)
1081 {
1082 /* TEST */
1083 case 0:
1084 case 1:
1085 {
1086 ULONG Immediate = 0, Result = 0;
1087
1088 if (OperandSize)
1089 {
1090 /* Fetch the immediate dword */
1091 if (!Fast486FetchDword(State, &Immediate))
1092 {
1093 /* Exception occurred */
1094 return FALSE;
1095 }
1096 }
1097 else
1098 {
1099 /* Fetch the immediate word */
1100 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1101 {
1102 /* Exception occurred */
1103 return FALSE;
1104 }
1105 }
1106
1107 /* Calculate the result */
1108 Result = Value & Immediate;
1109
1110 /* Update the flags */
1111 State->Flags.Cf = FALSE;
1112 State->Flags.Of = FALSE;
1113 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1114 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
1115 State->Flags.Pf = Fast486CalculateParity(Result);
1116
1117 break;
1118 }
1119
1120 /* NOT */
1121 case 2:
1122 {
1123 /* Write back the result */
1124 if (OperandSize)
1125 {
1126 /* 32-bit */
1127 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1128 }
1129 else
1130 {
1131 /* 16-bit */
1132 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1133 }
1134 }
1135
1136 /* NEG */
1137 case 3:
1138 {
1139 /* Calculate the result */
1140 ULONG Result = -Value;
1141 if (!OperandSize) Result &= 0xFFFF;
1142
1143 /* Update the flags */
1144 State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
1145 State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1146 State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
1147 State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
1148 State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
1149 State->Flags.Pf = Fast486CalculateParity(Result);
1150
1151 /* Write back the result */
1152 if (OperandSize)
1153 {
1154 /* 32-bit */
1155 return Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1156 }
1157 else
1158 {
1159 /* 16-bit */
1160 return Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1161 }
1162 }
1163
1164 /* MUL */
1165 case 4:
1166 {
1167 if (OperandSize)
1168 {
1169 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1170
1171 /* Update the flags */
1172 State->Flags.Cf = State->Flags.Of =
1173 (Result & 0xFFFFFFFF00000000ULL) ? TRUE : FALSE;
1174
1175 /* Write back the result */
1176 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1177 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1178 }
1179 else
1180 {
1181 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1182
1183 /* Update the flags */
1184 State->Flags.Cf = State->Flags.Of = HIWORD(Result) ? TRUE : FALSE;
1185
1186 /* Write back the result */
1187 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1188 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1189 }
1190
1191 break;
1192 }
1193
1194 /* IMUL */
1195 case 5:
1196 {
1197 if (OperandSize)
1198 {
1199 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1200
1201 /* Update the flags */
1202 State->Flags.Cf = State->Flags.Of =
1203 ((Result < -2147483648LL) || (Result > 2147483647LL)) ? TRUE : FALSE;
1204
1205 /* Write back the result */
1206 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1207 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1208 }
1209 else
1210 {
1211 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1212
1213 /* Update the flags */
1214 State->Flags.Cf = State->Flags.Of =
1215 ((Result < -32768) || (Result > 32767)) ? TRUE : FALSE;
1216
1217 /* Write back the result */
1218 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1219 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1220 }
1221
1222 break;
1223 }
1224
1225 /* DIV */
1226 case 6:
1227 {
1228 if (OperandSize)
1229 {
1230 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1231 | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1232 ULONG Quotient = Dividend / Value;
1233 ULONG Remainder = Dividend % Value;
1234
1235 /* Write back the results */
1236 State->GeneralRegs[FAST486_REG_EAX].Long = Quotient;
1237 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1238 }
1239 else
1240 {
1241 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1242 | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1243 USHORT Quotient = Dividend / Value;
1244 USHORT Remainder = Dividend % Value;
1245
1246 /* Write back the results */
1247 State->GeneralRegs[FAST486_REG_EAX].LowWord = Quotient;
1248 State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
1249 }
1250
1251 break;
1252 }
1253
1254 /* IDIV */
1255 case 7:
1256 {
1257 if (OperandSize)
1258 {
1259 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1260 | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1261 LONG Quotient = Dividend / (LONG)Value;
1262 LONG Remainder = Dividend % (LONG)Value;
1263
1264 /* Write back the results */
1265 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1266 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1267 }
1268 else
1269 {
1270 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1271 | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1272 SHORT Quotient = Dividend / (SHORT)LOWORD(Value);
1273 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1274
1275 /* Write back the results */
1276 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
1277 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1278 }
1279
1280 break;
1281 }
1282 }
1283
1284 return TRUE;
1285 }
1286
1287 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1288 {
1289 UCHAR Dummy, Value;
1290 FAST486_MOD_REG_RM ModRegRm;
1291 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1292
1293 TOGGLE_ADSIZE(AddressSize);
1294
1295 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1296 {
1297 /* Exception occurred */
1298 return FALSE;
1299 }
1300
1301 if (ModRegRm.Register > 1)
1302 {
1303 /* Invalid */
1304 Fast486Exception(State, FAST486_EXCEPTION_UD);
1305 return FALSE;
1306 }
1307
1308 /* Read the operands */
1309 if (!Fast486ReadModrmByteOperands(State, &ModRegRm, &Dummy, &Value))
1310 {
1311 /* Exception occurred */
1312 return FALSE;
1313 }
1314
1315 if (ModRegRm.Register == 0)
1316 {
1317 /* Increment and update OF and AF */
1318 Value++;
1319 State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
1320 State->Flags.Af = ((Value & 0x0F) == 0);
1321 }
1322 else
1323 {
1324 /* Decrement and update OF and AF */
1325 State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
1326 Value--;
1327 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1328 }
1329
1330 /* Update flags */
1331 State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
1332 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1333 State->Flags.Pf = Fast486CalculateParity(Value);
1334
1335 /* Write back the result */
1336 return Fast486WriteModrmByteOperands(State,
1337 &ModRegRm,
1338 FALSE,
1339 Value);
1340 }
1341
1342 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1343 {
1344 FAST486_MOD_REG_RM ModRegRm;
1345 BOOLEAN OperandSize, AddressSize;
1346
1347 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1348
1349 TOGGLE_OPSIZE(OperandSize);
1350 TOGGLE_ADSIZE(AddressSize);
1351
1352 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1353 {
1354 /* Exception occurred */
1355 return FALSE;
1356 }
1357
1358 if (ModRegRm.Register == 7)
1359 {
1360 /* Invalid */
1361 Fast486Exception(State, FAST486_EXCEPTION_UD);
1362 return FALSE;
1363 }
1364
1365 /* Read the operands */
1366 if (OperandSize)
1367 {
1368 ULONG Dummy, Value;
1369
1370 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1371 {
1372 /* Exception occurred */
1373 return FALSE;
1374 }
1375
1376 if (ModRegRm.Register == 0)
1377 {
1378 /* Increment and update OF and AF */
1379 Value++;
1380 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
1381 State->Flags.Af = ((Value & 0x0F) == 0);
1382 }
1383 else if (ModRegRm.Register == 1)
1384 {
1385 /* Decrement and update OF and AF */
1386 State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
1387 Value--;
1388 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1389 }
1390 else if (ModRegRm.Register == 2)
1391 {
1392 /* Push the current value of EIP */
1393 if (!Fast486StackPush(State, State->InstPtr.Long))
1394 {
1395 /* Exception occurred */
1396 return FALSE;
1397 }
1398
1399 /* Set the EIP to the address */
1400 State->InstPtr.Long = Value;
1401 }
1402 else if (ModRegRm.Register == 3)
1403 {
1404 USHORT Selector;
1405 INT Segment = FAST486_REG_DS;
1406
1407 /* Check for the segment override */
1408 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1409 {
1410 /* Use the override segment instead */
1411 Segment = State->SegmentOverride;
1412 }
1413
1414 /* Read the selector */
1415 if (!Fast486ReadMemory(State,
1416 Segment,
1417 ModRegRm.MemoryAddress + sizeof(ULONG),
1418 FALSE,
1419 &Selector,
1420 sizeof(USHORT)))
1421 {
1422 /* Exception occurred */
1423 return FALSE;
1424 }
1425
1426 /* Push the current value of CS */
1427 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1428 {
1429 /* Exception occurred */
1430 return FALSE;
1431 }
1432
1433 /* Push the current value of EIP */
1434 if (!Fast486StackPush(State, State->InstPtr.Long))
1435 {
1436 /* Exception occurred */
1437 return FALSE;
1438 }
1439
1440 /* Load the new code segment */
1441 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1442 {
1443 /* Exception occurred */
1444 return FALSE;
1445 }
1446
1447 /* Set the EIP to the address */
1448 State->InstPtr.Long = Value;
1449 }
1450 else if (ModRegRm.Register == 4)
1451 {
1452 /* Set the EIP to the address */
1453 State->InstPtr.Long = Value;
1454 }
1455 else if (ModRegRm.Register == 5)
1456 {
1457 USHORT Selector;
1458 INT Segment = FAST486_REG_DS;
1459
1460 /* Check for the segment override */
1461 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1462 {
1463 /* Use the override segment instead */
1464 Segment = State->SegmentOverride;
1465 }
1466
1467 /* Read the selector */
1468 if (!Fast486ReadMemory(State,
1469 Segment,
1470 ModRegRm.MemoryAddress + sizeof(ULONG),
1471 FALSE,
1472 &Selector,
1473 sizeof(USHORT)))
1474 {
1475 /* Exception occurred */
1476 return FALSE;
1477 }
1478
1479 /* Load the new code segment */
1480 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1481 {
1482 /* Exception occurred */
1483 return FALSE;
1484 }
1485
1486 /* Set the EIP to the address */
1487 State->InstPtr.Long = Value;
1488 }
1489 else if (ModRegRm.Register == 6)
1490 {
1491 /* Push the value on to the stack */
1492 return Fast486StackPush(State, Value);
1493 }
1494
1495 if (ModRegRm.Register <= 1)
1496 {
1497 /* Update flags */
1498 State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
1499 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1500 State->Flags.Pf = Fast486CalculateParity(Value);
1501
1502 /* Write back the result */
1503 return Fast486WriteModrmDwordOperands(State,
1504 &ModRegRm,
1505 FALSE,
1506 Value);
1507 }
1508 }
1509 else
1510 {
1511 USHORT Dummy, Value;
1512
1513 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1514 {
1515 /* Exception occurred */
1516 return FALSE;
1517 }
1518
1519 if (ModRegRm.Register == 0)
1520 {
1521 /* Increment and update OF */
1522 Value++;
1523 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
1524 State->Flags.Af = ((Value & 0x0F) == 0);
1525 }
1526 else if (ModRegRm.Register == 1)
1527 {
1528 /* Decrement and update OF */
1529 State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
1530 Value--;
1531 State->Flags.Af = ((Value & 0x0F) == 0x0F);
1532 }
1533 else if (ModRegRm.Register == 2)
1534 {
1535 /* Push the current value of IP */
1536 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1537 {
1538 /* Exception occurred */
1539 return FALSE;
1540 }
1541
1542 /* Set the IP to the address */
1543 State->InstPtr.LowWord = Value;
1544 }
1545 else if (ModRegRm.Register == 3)
1546 {
1547 USHORT Selector;
1548 INT Segment = FAST486_REG_DS;
1549
1550 /* Check for the segment override */
1551 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1552 {
1553 /* Use the override segment instead */
1554 Segment = State->SegmentOverride;
1555 }
1556
1557 /* Read the selector */
1558 if (!Fast486ReadMemory(State,
1559 Segment,
1560 ModRegRm.MemoryAddress + sizeof(USHORT),
1561 FALSE,
1562 &Selector,
1563 sizeof(USHORT)))
1564 {
1565 /* Exception occurred */
1566 return FALSE;
1567 }
1568
1569 /* Push the current value of CS */
1570 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1571 {
1572 /* Exception occurred */
1573 return FALSE;
1574 }
1575
1576 /* Push the current value of IP */
1577 if (!Fast486StackPush(State, State->InstPtr.LowWord))
1578 {
1579 /* Exception occurred */
1580 return FALSE;
1581 }
1582
1583 /* Load the new code segment */
1584 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1585 {
1586 /* Exception occurred */
1587 return FALSE;
1588 }
1589
1590 /* Set the IP to the address */
1591 State->InstPtr.LowWord = Value;
1592
1593 }
1594 else if (ModRegRm.Register == 4)
1595 {
1596 /* Set the IP to the address */
1597 State->InstPtr.LowWord = Value;
1598 }
1599 else if (ModRegRm.Register == 5)
1600 {
1601 USHORT Selector;
1602 INT Segment = FAST486_REG_DS;
1603
1604 /* Check for the segment override */
1605 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1606 {
1607 /* Use the override segment instead */
1608 Segment = State->SegmentOverride;
1609 }
1610
1611 /* Read the selector */
1612 if (!Fast486ReadMemory(State,
1613 Segment,
1614 ModRegRm.MemoryAddress + sizeof(USHORT),
1615 FALSE,
1616 &Selector,
1617 sizeof(USHORT)))
1618 {
1619 /* Exception occurred */
1620 return FALSE;
1621 }
1622
1623 /* Load the new code segment */
1624 if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1625 {
1626 /* Exception occurred */
1627 return FALSE;
1628 }
1629
1630 /* Set the IP to the address */
1631 State->InstPtr.LowWord = Value;
1632 }
1633 else if (ModRegRm.Register == 6)
1634 {
1635 /* Push the value on to the stack */
1636 return Fast486StackPush(State, Value);
1637 }
1638 else
1639 {
1640 /* Invalid */
1641 Fast486Exception(State, FAST486_EXCEPTION_UD);
1642 return FALSE;
1643 }
1644
1645 if (ModRegRm.Register <= 1)
1646 {
1647 /* Update flags */
1648 State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
1649 State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
1650 State->Flags.Pf = Fast486CalculateParity(Value);
1651
1652 /* Write back the result */
1653 return Fast486WriteModrmWordOperands(State,
1654 &ModRegRm,
1655 FALSE,
1656 Value);
1657 }
1658 }
1659
1660 return TRUE;
1661 }
1662
1663 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
1664 {
1665 UCHAR TableReg[6];
1666 FAST486_MOD_REG_RM ModRegRm;
1667 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1668 FAST486_SEG_REGS Segment = FAST486_REG_DS;
1669
1670 NO_LOCK_PREFIX();
1671 TOGGLE_ADSIZE(AddressSize);
1672
1673 /* Check for the segment override */
1674 if (State->PrefixFlags & FAST486_PREFIX_SEG)
1675 {
1676 /* Use the override segment instead */
1677 Segment = State->SegmentOverride;
1678 }
1679
1680 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1681 {
1682 /* Exception occurred */
1683 return FALSE;
1684 }
1685
1686 /* Check which operation this is */
1687 switch (ModRegRm.Register)
1688 {
1689 /* SGDT */
1690 case 0:
1691 {
1692 if (!ModRegRm.Memory)
1693 {
1694 /* The second operand must be a memory location */
1695 Fast486Exception(State, FAST486_EXCEPTION_UD);
1696 return FALSE;
1697 }
1698
1699 /* Fill the 6-byte table register */
1700 RtlCopyMemory(TableReg, &State->Gdtr.Size, sizeof(USHORT));
1701 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Gdtr.Address, sizeof(ULONG));
1702
1703 /* Store the GDTR */
1704 return Fast486WriteMemory(State,
1705 Segment,
1706 ModRegRm.MemoryAddress,
1707 TableReg,
1708 sizeof(TableReg));
1709 }
1710
1711 /* SIDT */
1712 case 1:
1713 {
1714 if (!ModRegRm.Memory)
1715 {
1716 /* The second operand must be a memory location */
1717 Fast486Exception(State, FAST486_EXCEPTION_UD);
1718 return FALSE;
1719 }
1720
1721 /* Fill the 6-byte table register */
1722 RtlCopyMemory(TableReg, &State->Idtr.Size, sizeof(USHORT));
1723 RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Idtr.Address, sizeof(ULONG));
1724
1725 /* Store the IDTR */
1726 return Fast486WriteMemory(State,
1727 Segment,
1728 ModRegRm.MemoryAddress,
1729 TableReg,
1730 sizeof(TableReg));
1731 }
1732
1733 /* LGDT */
1734 case 2:
1735 {
1736 /* This is a privileged instruction */
1737 if (Fast486GetCurrentPrivLevel(State) != 0)
1738 {
1739 Fast486Exception(State, FAST486_EXCEPTION_GP);
1740 return FALSE;
1741 }
1742
1743 if (!ModRegRm.Memory)
1744 {
1745 /* The second operand must be a memory location */
1746 Fast486Exception(State, FAST486_EXCEPTION_UD);
1747 return FALSE;
1748 }
1749
1750 /* Read the new GDTR */
1751 if (!Fast486ReadMemory(State,
1752 Segment,
1753 ModRegRm.MemoryAddress,
1754 FALSE,
1755 TableReg,
1756 sizeof(TableReg)))
1757 {
1758 /* Exception occurred */
1759 return FALSE;
1760 }
1761
1762 /* Load the new GDT */
1763 State->Gdtr.Size = *((PUSHORT)TableReg);
1764 State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
1765
1766 return TRUE;
1767 }
1768
1769 /* LIDT */
1770 case 3:
1771 {
1772 /* This is a privileged instruction */
1773 if (Fast486GetCurrentPrivLevel(State) != 0)
1774 {
1775 Fast486Exception(State, FAST486_EXCEPTION_GP);
1776 return FALSE;
1777 }
1778
1779 if (!ModRegRm.Memory)
1780 {
1781 /* The second operand must be a memory location */
1782 Fast486Exception(State, FAST486_EXCEPTION_UD);
1783 return FALSE;
1784 }
1785
1786 /* Read the new IDTR */
1787 if (!Fast486ReadMemory(State,
1788 Segment,
1789 ModRegRm.MemoryAddress,
1790 FALSE,
1791 TableReg,
1792 sizeof(TableReg)))
1793 {
1794 /* Exception occurred */
1795 return FALSE;
1796 }
1797
1798 /* Load the new IDT */
1799 State->Idtr.Size = *((PUSHORT)TableReg);
1800 State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
1801
1802 return TRUE;
1803 }
1804
1805 /* SMSW */
1806 case 4:
1807 {
1808 /* Store the lower 16 bits of CR0 */
1809 return Fast486WriteModrmWordOperands(State,
1810 &ModRegRm,
1811 FALSE,
1812 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
1813 }
1814
1815 /* LMSW */
1816 case 6:
1817 {
1818 USHORT MasterStatusWord, Dummy;
1819
1820 /* This is a privileged instruction */
1821 if (Fast486GetCurrentPrivLevel(State) != 0)
1822 {
1823 Fast486Exception(State, FAST486_EXCEPTION_GP);
1824 return FALSE;
1825 }
1826
1827 /* Read the new master status word */
1828 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &MasterStatusWord))
1829 {
1830 /* Exception occurred */
1831 return FALSE;
1832 }
1833
1834 /* This instruction cannot be used to return to real mode */
1835 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1836 && !(MasterStatusWord & FAST486_CR0_PE))
1837 {
1838 Fast486Exception(State, FAST486_EXCEPTION_GP);
1839 return FALSE;
1840 }
1841
1842 /* Set the lowest 4 bits */
1843 State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
1844 State->ControlRegisters[FAST486_REG_CR0] |= MasterStatusWord & 0x0F;
1845
1846 return TRUE;
1847 }
1848
1849 /* INVLPG */
1850 case 7:
1851 {
1852 UNIMPLEMENTED;
1853 return FALSE;
1854 }
1855
1856 /* Invalid */
1857 default:
1858 {
1859 Fast486Exception(State, FAST486_EXCEPTION_UD);
1860 return FALSE;
1861 }
1862 }
1863 }
1864
1865 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
1866 {
1867 FAST486_MOD_REG_RM ModRegRm;
1868 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1869
1870 TOGGLE_ADSIZE(AddressSize);
1871
1872 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1873 {
1874 /* Exception occurred */
1875 return FALSE;
1876 }
1877
1878 /* All of them are reserved (UD2) */
1879 Fast486Exception(State, FAST486_EXCEPTION_UD);
1880 return FALSE;
1881 }
1882
1883 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
1884 {
1885 FAST486_MOD_REG_RM ModRegRm;
1886 BOOLEAN OperandSize, AddressSize;
1887 UINT DataSize;
1888 UCHAR BitNumber;
1889
1890 OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1891
1892 TOGGLE_OPSIZE(OperandSize);
1893 TOGGLE_ADSIZE(AddressSize);
1894
1895 /* Get the number of bits */
1896 if (OperandSize) DataSize = 32;
1897 else DataSize = 16;
1898
1899 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1900 {
1901 /* Exception occurred */
1902 return FALSE;
1903 }
1904
1905 if (ModRegRm.Register < 4)
1906 {
1907 /* Invalid */
1908 Fast486Exception(State, FAST486_EXCEPTION_UD);
1909 return FALSE;
1910 }
1911
1912 /* Get the bit number */
1913 if (!Fast486FetchByte(State, &BitNumber))
1914 {
1915 /* Exception occurred */
1916 return FALSE;
1917 }
1918
1919 if (ModRegRm.Memory)
1920 {
1921 /*
1922 * For memory operands, add the bit offset divided by
1923 * the data size to the address
1924 */
1925 ModRegRm.MemoryAddress += BitNumber / DataSize;
1926 }
1927
1928 /* Normalize the bit number */
1929 BitNumber &= (1 << DataSize) - 1;
1930
1931 if (OperandSize)
1932 {
1933 ULONG Dummy, Value;
1934
1935 /* Read the value */
1936 if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
1937 {
1938 /* Exception occurred */
1939 return FALSE;
1940 }
1941
1942 /* Set CF to the bit value */
1943 State->Flags.Cf = (Value >> BitNumber) & 1;
1944
1945 if (ModRegRm.Register == 5)
1946 {
1947 /* BTS */
1948 Value |= 1 << BitNumber;
1949 }
1950 else if (ModRegRm.Register == 6)
1951 {
1952 /* BTR */
1953 Value &= ~(1 << BitNumber);
1954 }
1955 else if (ModRegRm.Register == 7)
1956 {
1957 /* BTC */
1958 Value ^= 1 << BitNumber;
1959 }
1960
1961 if (ModRegRm.Register >= 5)
1962 {
1963 /* Write back the result */
1964 if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
1965 {
1966 /* Exception occurred */
1967 return FALSE;
1968 }
1969 }
1970 }
1971 else
1972 {
1973 USHORT Dummy, Value;
1974
1975 /* Read the value */
1976 if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
1977 {
1978 /* Exception occurred */
1979 return FALSE;
1980 }
1981
1982 /* Set CF to the bit value */
1983 State->Flags.Cf = (Value >> BitNumber) & 1;
1984
1985 if (ModRegRm.Register == 5)
1986 {
1987 /* BTS */
1988 Value |= 1 << BitNumber;
1989 }
1990 else if (ModRegRm.Register == 6)
1991 {
1992 /* BTR */
1993 Value &= ~(1 << BitNumber);
1994 }
1995 else if (ModRegRm.Register == 7)
1996 {
1997 /* BTC */
1998 Value ^= 1 << BitNumber;
1999 }
2000
2001 if (ModRegRm.Register >= 5)
2002 {
2003 /* Write back the result */
2004 if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2005 {
2006 /* Exception occurred */
2007 return FALSE;
2008 }
2009 }
2010 }
2011
2012 /* Return success */
2013 return TRUE;
2014
2015 return TRUE;
2016 }
2017
2018 /* EOF */
2019