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