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