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