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