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