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