xref: /reactos/sdk/lib/fast486/opgroups.c (revision c2c66aff)
1 /*
2  * Fast486 386/486 CPU Emulation Library
3  * opgroups.c
4  *
5  * Copyright (C) 2015 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 static
36 inline
37 ULONG
Fast486ArithmeticOperation(PFAST486_STATE State,INT Operation,ULONG FirstValue,ULONG SecondValue,UCHAR Bits)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             State->Flags.Cf = State->Flags.Of = FALSE;
74             break;
75         }
76 
77         /* ADC */
78         case 2:
79         {
80             INT Carry = State->Flags.Cf ? 1 : 0;
81 
82             Result = (FirstValue + SecondValue + Carry) & MaxValue;
83 
84             /* Update CF, OF and AF */
85             State->Flags.Cf = ((SecondValue == MaxValue) && (Carry == 1))
86                               || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
87             State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
88                               && ((FirstValue & SignFlag) != (Result & SignFlag));
89             State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
90 
91             break;
92         }
93 
94         /* SBB */
95         case 3:
96         {
97             INT Carry = State->Flags.Cf ? 1 : 0;
98 
99             Result = (FirstValue - SecondValue - Carry) & MaxValue;
100 
101             /* Update CF, OF and AF */
102             State->Flags.Cf = Carry
103                               ? (FirstValue <= SecondValue)
104                               : (FirstValue < SecondValue);
105             State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
106                               && ((FirstValue & SignFlag) != (Result & SignFlag));
107             State->Flags.Af = ((FirstValue ^ SecondValue ^ Result) & 0x10) != 0;
108 
109             break;
110         }
111 
112         /* AND */
113         case 4:
114         {
115             Result = FirstValue & SecondValue;
116             State->Flags.Cf = State->Flags.Of = FALSE;
117             break;
118         }
119 
120         /* SUB or CMP */
121         case 5:
122         case 7:
123         {
124             Result = (FirstValue - SecondValue) & MaxValue;
125 
126             /* Update CF, OF and AF */
127             State->Flags.Cf = (FirstValue < SecondValue);
128             State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
129                               && ((FirstValue & SignFlag) != (Result & SignFlag));
130             State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
131 
132             break;
133         }
134 
135         /* XOR */
136         case 6:
137         {
138             Result = FirstValue ^ SecondValue;
139             State->Flags.Cf = State->Flags.Of = FALSE;
140             break;
141         }
142 
143         default:
144         {
145             /* Shouldn't happen */
146             ASSERT(FALSE);
147         }
148     }
149 
150     /* Update ZF, SF and PF */
151     State->Flags.Zf = (Result == 0);
152     State->Flags.Sf = ((Result & SignFlag) != 0);
153     State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
154 
155     /* Return the result */
156     return Result;
157 }
158 
159 static
160 inline
161 ULONG
Fast486RotateOperation(PFAST486_STATE State,INT Operation,ULONG Value,UCHAR Bits,UCHAR Count)162 Fast486RotateOperation(PFAST486_STATE State,
163                        INT Operation,
164                        ULONG Value,
165                        UCHAR Bits,
166                        UCHAR Count)
167 {
168     ULONG HighestBit = 1 << (Bits - 1);
169     ULONG MaxValue = HighestBit | (HighestBit - 1);
170     ULONG Result;
171 
172     /* Normalize the count */
173     Count &= 0x1F;
174 
175     if ((Operation == 2) || (Operation == 3)) Count %= Bits + 1;
176 
177     /* If the count is zero, do nothing */
178     if (Count == 0) return Value;
179 
180     /* Check which operation is this */
181     switch (Operation)
182     {
183         /* ROL */
184         case 0:
185         {
186             Count %= Bits;
187             Result = (Value << Count) | (Value >> (Bits - Count));
188 
189             /* Update CF and OF */
190             State->Flags.Cf = Result & 1;
191             if (Count == 1) State->Flags.Of = State->Flags.Cf
192                                               ^ ((Result & HighestBit) != 0);
193 
194             break;
195         }
196 
197         /* ROR */
198         case 1:
199         {
200             Count %= Bits;
201             Result = (Value >> Count) | (Value << (Bits - Count));
202 
203             /* Update CF and OF */
204             State->Flags.Cf = ((Result & HighestBit) != 0);
205             if (Count == 1) State->Flags.Of = State->Flags.Cf
206                                               ^ ((Result & (HighestBit >> 1)) != 0);
207 
208             break;
209         }
210 
211         /* RCL */
212         case 2:
213         {
214             Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
215 
216             /* Complete the calculation, but make sure we don't shift by too much */
217             if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
218 
219             /* Update CF and OF */
220             State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
221             if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Result & HighestBit) != 0);
222 
223             break;
224         }
225 
226         /* RCR */
227         case 3:
228         {
229             /* Update OF */
230             if (Count == 1) State->Flags.Of = State->Flags.Cf ^ ((Value & HighestBit) != 0);
231 
232             Result = (Value >> Count) | (State->Flags.Cf << (Bits - Count));
233 
234             /* Complete the calculation, but make sure we don't shift by too much */
235             if ((Bits - Count) < 31) Result |= Value << (Bits - Count + 1);
236 
237             /* Update CF */
238             State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
239 
240             break;
241         }
242 
243         /* SHL/SAL */
244         case 4:
245         case 6:
246         {
247             Result = Value << Count;
248 
249             /* Update CF and OF */
250             State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
251             if (Count == 1) State->Flags.Of = State->Flags.Cf
252                                               ^ ((Result & HighestBit) != 0);
253 
254             break;
255         }
256 
257         /* SHR */
258         case 5:
259         {
260             Result = Value >> Count;
261 
262             /* Update CF and OF */
263             State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
264             if (Count == 1) State->Flags.Of = ((Value & HighestBit) != 0);
265 
266             break;
267         }
268 
269         /* SAR */
270         case 7:
271         {
272             Result = Value >> Count;
273 
274             /* Fill the top Count bits with the sign bit */
275             if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
276 
277             /* Update CF and OF */
278             State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
279             if (Count == 1) State->Flags.Of = FALSE;
280 
281             break;
282         }
283     }
284 
285     if (Operation >= 4)
286     {
287         /* Update ZF, SF and PF */
288         State->Flags.Zf = ((Result & MaxValue) == 0);
289         State->Flags.Sf = ((Result & HighestBit) != 0);
290         State->Flags.Pf = Fast486CalculateParity(Result);
291     }
292 
293     /* Return the result */
294     return Result;
295 }
296 
297 /* PUBLIC FUNCTIONS ***********************************************************/
298 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)299 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8082)
300 {
301     UCHAR Immediate, Value;
302     FAST486_MOD_REG_RM ModRegRm;
303     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
304 
305     TOGGLE_ADSIZE(AddressSize);
306 
307     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
308     {
309         /* Exception occurred */
310         return;
311     }
312 
313     /* Fetch the immediate operand */
314     if (!Fast486FetchByte(State, &Immediate))
315     {
316         /* Exception occurred */
317         return;
318     }
319 
320     /* Read the operands */
321     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
322     {
323         /* Exception occurred */
324         return;
325     }
326 
327     /* Calculate the result */
328     Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 8);
329 
330     /* Unless this is CMP, write back the result */
331     if (ModRegRm.Register != 7)
332     {
333         Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
334     }
335 }
336 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)337 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup81)
338 {
339     FAST486_MOD_REG_RM ModRegRm;
340     BOOLEAN OperandSize, AddressSize;
341 
342     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
343 
344     TOGGLE_OPSIZE(OperandSize);
345     TOGGLE_ADSIZE(AddressSize);
346 
347     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
348     {
349         /* Exception occurred */
350         return;
351     }
352 
353     if (OperandSize)
354     {
355         ULONG Immediate, Value;
356 
357         /* Fetch the immediate operand */
358         if (!Fast486FetchDword(State, &Immediate))
359         {
360             /* Exception occurred */
361             return;
362         }
363 
364         /* Read the operands */
365         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
366         {
367             /* Exception occurred */
368             return;
369         }
370 
371         /* Calculate the result */
372         Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
373 
374         /* Unless this is CMP, write back the result */
375         if (ModRegRm.Register != 7)
376         {
377             Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
378         }
379     }
380     else
381     {
382         USHORT Immediate, Value;
383 
384         /* Fetch the immediate operand */
385         if (!Fast486FetchWord(State, &Immediate))
386         {
387             /* Exception occurred */
388             return;
389         }
390 
391         /* Read the operands */
392         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
393         {
394             /* Exception occurred */
395             return;
396         }
397 
398         /* Calculate the result */
399         Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
400 
401         /* Unless this is CMP, write back the result */
402         if (ModRegRm.Register != 7)
403         {
404             Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
405         }
406     }
407 }
408 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)409 FAST486_OPCODE_HANDLER(Fast486OpcodeGroup83)
410 {
411     CHAR ImmByte;
412     FAST486_MOD_REG_RM ModRegRm;
413     BOOLEAN OperandSize, AddressSize;
414 
415     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
416 
417     TOGGLE_OPSIZE(OperandSize);
418     TOGGLE_ADSIZE(AddressSize);
419 
420     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
421     {
422         /* Exception occurred */
423         return;
424     }
425 
426     /* Fetch the immediate operand */
427     if (!Fast486FetchByte(State, (PUCHAR)&ImmByte))
428     {
429         /* Exception occurred */
430         return;
431     }
432 
433     if (OperandSize)
434     {
435         ULONG Immediate = (ULONG)((LONG)ImmByte); // Sign extend
436         ULONG Value;
437 
438         /* Read the operands */
439         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
440         {
441             /* Exception occurred */
442             return;
443         }
444 
445         /* Calculate the result */
446         Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 32);
447 
448         /* Unless this is CMP, write back the result */
449         if (ModRegRm.Register != 7)
450         {
451             Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
452         }
453     }
454     else
455     {
456         USHORT Immediate = (USHORT)((SHORT)ImmByte); // Sign extend
457         USHORT Value;
458 
459         /* Read the operands */
460         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
461         {
462             /* Exception occurred */
463             return;
464         }
465 
466         /* Calculate the result */
467         Value = Fast486ArithmeticOperation(State, ModRegRm.Register, Value, Immediate, 16);
468 
469         /* Unless this is CMP, write back the result */
470         if (ModRegRm.Register != 7)
471         {
472             Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
473         }
474     }
475 }
476 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)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     /* Pop a value from the stack - this must be done first */
489     if (!Fast486StackPop(State, &Value))
490     {
491         /* Exception occurred */
492         return;
493     }
494 
495     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
496     {
497         /* Exception occurred */
498         return;
499     }
500 
501     if (ModRegRm.Register != 0)
502     {
503         /* Invalid */
504         Fast486Exception(State, FAST486_EXCEPTION_UD);
505         return;
506     }
507 
508     if (OperandSize) Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
509     else Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Value));
510 }
511 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)512 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC0)
513 {
514     UCHAR Value, Count;
515     FAST486_MOD_REG_RM ModRegRm;
516     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
517 
518     TOGGLE_ADSIZE(AddressSize);
519 
520     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
521     {
522         /* Exception occurred */
523         return;
524     }
525 
526     /* Fetch the count */
527     if (!Fast486FetchByte(State, &Count))
528     {
529         /* Exception occurred */
530         return;
531     }
532 
533     /* Read the operands */
534     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
535     {
536         /* Exception occurred */
537         return;
538     }
539 
540     /* Calculate the result */
541     Value = LOBYTE(Fast486RotateOperation(State,
542                                           ModRegRm.Register,
543                                           Value,
544                                           8,
545                                           Count));
546 
547     /* Write back the result */
548     Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
549 }
550 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)551 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC1)
552 {
553     UCHAR Count;
554     FAST486_MOD_REG_RM ModRegRm;
555     BOOLEAN OperandSize, AddressSize;
556 
557     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
558 
559     TOGGLE_OPSIZE(OperandSize);
560     TOGGLE_ADSIZE(AddressSize);
561 
562     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
563     {
564         /* Exception occurred */
565         return;
566     }
567 
568     /* Fetch the count */
569     if (!Fast486FetchByte(State, &Count))
570     {
571         /* Exception occurred */
572         return;
573     }
574 
575     if (OperandSize)
576     {
577         ULONG Value;
578 
579         /* Read the operands */
580         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
581         {
582             /* Exception occurred */
583             return;
584         }
585 
586         /* Calculate the result */
587         Value = Fast486RotateOperation(State,
588                                        ModRegRm.Register,
589                                        Value,
590                                        32,
591                                        Count);
592 
593         /* Write back the result */
594         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
595     }
596     else
597     {
598         USHORT Value;
599 
600         /* Read the operands */
601         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
602         {
603             /* Exception occurred */
604             return;
605         }
606 
607         /* Calculate the result */
608         Value = LOWORD(Fast486RotateOperation(State,
609                                               ModRegRm.Register,
610                                               Value,
611                                               16,
612                                               Count));
613 
614         /* Write back the result */
615         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
616     }
617 }
618 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)619 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC6)
620 {
621     UCHAR Immediate;
622     FAST486_MOD_REG_RM ModRegRm;
623     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
624 
625     TOGGLE_ADSIZE(AddressSize);
626 
627     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
628     {
629         /* Exception occurred */
630         return;
631     }
632 
633     if (ModRegRm.Register != 0)
634     {
635         /* Invalid */
636         Fast486Exception(State, FAST486_EXCEPTION_UD);
637         return;
638     }
639 
640     /* Get the immediate operand */
641     if (!Fast486FetchByte(State, &Immediate))
642     {
643         /* Exception occurred */
644         return;
645     }
646 
647     Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Immediate);
648 }
649 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)650 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupC7)
651 {
652     FAST486_MOD_REG_RM ModRegRm;
653     BOOLEAN OperandSize, AddressSize;
654 
655     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
656 
657     TOGGLE_OPSIZE(OperandSize);
658     TOGGLE_ADSIZE(AddressSize);
659 
660     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
661     {
662         /* Exception occurred */
663         return;
664     }
665 
666     if (ModRegRm.Register != 0)
667     {
668         /* Invalid */
669         Fast486Exception(State, FAST486_EXCEPTION_UD);
670         return;
671     }
672 
673     if (OperandSize)
674     {
675         ULONG Immediate;
676 
677         /* Get the immediate operand */
678         if (!Fast486FetchDword(State, &Immediate))
679         {
680             /* Exception occurred */
681             return;
682         }
683 
684         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Immediate);
685     }
686     else
687     {
688         USHORT Immediate;
689 
690         /* Get the immediate operand */
691         if (!Fast486FetchWord(State, &Immediate))
692         {
693             /* Exception occurred */
694             return;
695         }
696 
697         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Immediate);
698     }
699 }
700 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)701 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD0)
702 {
703     UCHAR Value;
704     FAST486_MOD_REG_RM ModRegRm;
705     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
706 
707     TOGGLE_ADSIZE(AddressSize);
708 
709     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
710     {
711         /* Exception occurred */
712         return;
713     }
714 
715     /* Read the operands */
716     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
717     {
718         /* Exception occurred */
719         return;
720     }
721 
722     /* Calculate the result */
723     Value = LOBYTE(Fast486RotateOperation(State, ModRegRm.Register, Value, 8, 1));
724 
725     /* Write back the result */
726     Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
727 
728 }
729 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)730 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD1)
731 {
732     FAST486_MOD_REG_RM ModRegRm;
733     BOOLEAN OperandSize, AddressSize;
734 
735     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
736 
737     TOGGLE_OPSIZE(OperandSize);
738     TOGGLE_ADSIZE(AddressSize);
739 
740     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
741     {
742         /* Exception occurred */
743         return;
744     }
745 
746     if (OperandSize)
747     {
748         ULONG Value;
749 
750         /* Read the operands */
751         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
752         {
753             /* Exception occurred */
754             return;
755         }
756 
757         /* Calculate the result */
758         Value = Fast486RotateOperation(State, ModRegRm.Register, Value, 32, 1);
759 
760         /* Write back the result */
761         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
762     }
763     else
764     {
765         USHORT Value;
766 
767         /* Read the operands */
768         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
769         {
770             /* Exception occurred */
771             return;
772         }
773 
774         /* Calculate the result */
775         Value = LOWORD(Fast486RotateOperation(State, ModRegRm.Register, Value, 16, 1));
776 
777         /* Write back the result */
778         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
779     }
780 }
781 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)782 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD2)
783 {
784     UCHAR Value;
785     FAST486_MOD_REG_RM ModRegRm;
786     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
787 
788     TOGGLE_ADSIZE(AddressSize);
789 
790     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
791     {
792         /* Exception occurred */
793         return;
794     }
795 
796     /* Read the operands */
797     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
798     {
799         /* Exception occurred */
800         return;
801     }
802 
803     /* Calculate the result */
804     Value = LOBYTE(Fast486RotateOperation(State,
805                                           ModRegRm.Register,
806                                           Value,
807                                           8,
808                                           State->GeneralRegs[FAST486_REG_ECX].LowByte));
809 
810     /* Write back the result */
811     Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
812 }
813 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)814 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupD3)
815 {
816     FAST486_MOD_REG_RM ModRegRm;
817     BOOLEAN OperandSize, AddressSize;
818 
819     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
820 
821     TOGGLE_OPSIZE(OperandSize);
822     TOGGLE_ADSIZE(AddressSize);
823 
824     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
825     {
826         /* Exception occurred */
827         return;
828     }
829 
830     if (OperandSize)
831     {
832         ULONG Value;
833 
834         /* Read the operands */
835         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
836         {
837             /* Exception occurred */
838             return;
839         }
840 
841         /* Calculate the result */
842         Value = Fast486RotateOperation(State,
843                                        ModRegRm.Register,
844                                        Value,
845                                        32,
846                                        State->GeneralRegs[FAST486_REG_ECX].LowByte);
847 
848         /* Write back the result */
849         Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
850     }
851     else
852     {
853         USHORT Value;
854 
855         /* Read the operands */
856         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
857         {
858             /* Exception occurred */
859             return;
860         }
861 
862         /* Calculate the result */
863         Value = LOWORD(Fast486RotateOperation(State,
864                                               ModRegRm.Register,
865                                               Value,
866                                               16,
867                                               State->GeneralRegs[FAST486_REG_ECX].LowByte));
868 
869         /* Write back the result */
870         Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
871     }
872 }
873 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)874 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
875 {
876     UCHAR Value = 0;
877     FAST486_MOD_REG_RM ModRegRm;
878     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
879 
880     TOGGLE_ADSIZE(AddressSize);
881 
882     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
883     {
884         /* Exception occurred */
885         return;
886     }
887 
888     /* Read the operands */
889     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
890     {
891         /* Exception occurred */
892         return;
893     }
894 
895     switch (ModRegRm.Register)
896     {
897         /* TEST */
898         case 0:
899         case 1:
900         {
901             UCHAR Immediate, Result;
902 
903             /* Fetch the immediate byte */
904             if (!Fast486FetchByte(State, &Immediate))
905             {
906                 /* Exception occurred */
907                 return;
908             }
909 
910             /* Calculate the result */
911             Result = Value & Immediate;
912 
913             /* Update the flags */
914             State->Flags.Cf = FALSE;
915             State->Flags.Of = FALSE;
916             State->Flags.Zf = (Result == 0);
917             State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
918             State->Flags.Pf = Fast486CalculateParity(Result);
919 
920             break;
921         }
922 
923         /* NOT */
924         case 2:
925         {
926             /* Write back the result */
927             Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, ~Value);
928 
929             break;
930         }
931 
932         /* NEG */
933         case 3:
934         {
935             /* Calculate the result */
936             UCHAR Result = -Value;
937 
938             /* Update the flags */
939             State->Flags.Cf = (Value != 0);
940             State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
941             State->Flags.Af = ((Value & 0x0F) != 0);
942             State->Flags.Zf = (Result == 0);
943             State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
944             State->Flags.Pf = Fast486CalculateParity(Result);
945 
946             /* Write back the result */
947             Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Result);
948 
949             break;
950         }
951 
952         /* MUL */
953         case 4:
954         {
955             USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
956 
957             /* Update the flags */
958             State->Flags.Cf = State->Flags.Of = (HIBYTE(Result) != 0);
959 
960             /* Write back the result */
961             State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
962 
963             break;
964         }
965 
966         /* IMUL */
967         case 5:
968         {
969             SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
970 
971             /* Update the flags */
972             State->Flags.Cf = State->Flags.Of = ((Result < FAST486_CHAR_MIN) || (Result > FAST486_CHAR_MAX));
973 
974             /* Write back the result */
975             State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
976 
977             break;
978         }
979 
980         /* DIV */
981         case 6:
982         {
983             USHORT Quotient;
984             UCHAR Remainder;
985 
986             if (Value == 0)
987             {
988                 /* Divide error */
989                 Fast486Exception(State, FAST486_EXCEPTION_DE);
990                 return;
991             }
992 
993             Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
994             Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
995 
996             if (Quotient > 0xFF)
997             {
998                 /* Divide error */
999                 Fast486Exception(State, FAST486_EXCEPTION_DE);
1000                 return;
1001             }
1002 
1003             /* Write back the results */
1004             State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)Quotient;
1005             State->GeneralRegs[FAST486_REG_EAX].HighByte = Remainder;
1006 
1007             break;
1008         }
1009 
1010         /* IDIV */
1011         case 7:
1012         {
1013             SHORT Quotient;
1014             CHAR Remainder;
1015 
1016             if (Value == 0)
1017             {
1018                 /* Divide error */
1019                 Fast486Exception(State, FAST486_EXCEPTION_DE);
1020                 return;
1021             }
1022 
1023             Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
1024             Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
1025 
1026             if (Quotient > FAST486_CHAR_MAX || Quotient < FAST486_CHAR_MIN)
1027             {
1028                 /* Divide error */
1029                 Fast486Exception(State, FAST486_EXCEPTION_DE);
1030                 return;
1031             }
1032 
1033             /* Write back the results */
1034             State->GeneralRegs[FAST486_REG_EAX].LowByte = (UCHAR)((CHAR)Quotient);
1035             State->GeneralRegs[FAST486_REG_EAX].HighByte = (UCHAR)Remainder;
1036 
1037             break;
1038         }
1039     }
1040 }
1041 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)1042 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
1043 {
1044     ULONG Value = 0, SignFlag;
1045     FAST486_MOD_REG_RM ModRegRm;
1046     BOOLEAN OperandSize, AddressSize;
1047 
1048     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1049 
1050     TOGGLE_OPSIZE(OperandSize);
1051     TOGGLE_ADSIZE(AddressSize);
1052 
1053     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1054     {
1055         /* Exception occurred */
1056         return;
1057     }
1058 
1059     /* Set the sign flag */
1060     if (OperandSize) SignFlag = SIGN_FLAG_LONG;
1061     else SignFlag = SIGN_FLAG_WORD;
1062 
1063     /* Read the operand */
1064     if (OperandSize)
1065     {
1066         /* 32-bit */
1067         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1068         {
1069             /* Exception occurred */
1070             return;
1071         }
1072     }
1073     else
1074     {
1075         /* 16-bit */
1076         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, (PUSHORT)&Value))
1077         {
1078             /* Exception occurred */
1079             return;
1080         }
1081     }
1082 
1083     switch (ModRegRm.Register)
1084     {
1085         /* TEST */
1086         case 0:
1087         case 1:
1088         {
1089             ULONG Immediate = 0, Result = 0;
1090 
1091             if (OperandSize)
1092             {
1093                 /* Fetch the immediate dword */
1094                 if (!Fast486FetchDword(State, &Immediate))
1095                 {
1096                     /* Exception occurred */
1097                     return;
1098                 }
1099             }
1100             else
1101             {
1102                 /* Fetch the immediate word */
1103                 if (!Fast486FetchWord(State, (PUSHORT)&Immediate))
1104                 {
1105                     /* Exception occurred */
1106                     return;
1107                 }
1108             }
1109 
1110             /* Calculate the result */
1111             Result = Value & Immediate;
1112 
1113             /* Update the flags */
1114             State->Flags.Cf = FALSE;
1115             State->Flags.Of = FALSE;
1116             State->Flags.Zf = (Result == 0);
1117             State->Flags.Sf = ((Result & SignFlag) != 0);
1118             State->Flags.Pf = Fast486CalculateParity(Result);
1119 
1120             break;
1121         }
1122 
1123         /* NOT */
1124         case 2:
1125         {
1126             /* Write back the result */
1127             if (OperandSize)
1128             {
1129                 /* 32-bit */
1130                 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, ~Value);
1131             }
1132             else
1133             {
1134                 /* 16-bit */
1135                 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(~Value));
1136             }
1137 
1138             break;
1139         }
1140 
1141         /* NEG */
1142         case 3:
1143         {
1144             /* Calculate the result */
1145             ULONG Result = -(LONG)Value;
1146             if (!OperandSize) Result &= 0xFFFF;
1147 
1148             /* Update the flags */
1149             State->Flags.Cf = (Value != 0);
1150             State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
1151             State->Flags.Af = ((Value & 0x0F) != 0);
1152             State->Flags.Zf = (Result == 0);
1153             State->Flags.Sf = ((Result & SignFlag) != 0);
1154             State->Flags.Pf = Fast486CalculateParity(Result);
1155 
1156             /* Write back the result */
1157             if (OperandSize)
1158             {
1159                 /* 32-bit */
1160                 Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Result);
1161             }
1162             else
1163             {
1164                 /* 16-bit */
1165                 Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, LOWORD(Result));
1166             }
1167 
1168             break;
1169         }
1170 
1171         /* MUL */
1172         case 4:
1173         {
1174             if (OperandSize)
1175             {
1176                 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
1177 
1178                 /* Update the flags */
1179                 State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
1180 
1181                 /* Write back the result */
1182                 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1183                 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1184             }
1185             else
1186             {
1187                 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
1188 
1189                 /* Update the flags */
1190                 State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
1191 
1192                 /* Write back the result */
1193                 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1194                 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1195             }
1196 
1197             break;
1198         }
1199 
1200         /* IMUL */
1201         case 5:
1202         {
1203             if (OperandSize)
1204             {
1205                 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
1206 
1207                 /* Update the flags */
1208                 State->Flags.Cf = State->Flags.Of = ((Result < FAST486_LONG_MIN) || (Result > FAST486_LONG_MAX));
1209 
1210                 /* Write back the result */
1211                 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
1212                 State->GeneralRegs[FAST486_REG_EDX].Long = Result >> 32;
1213             }
1214             else
1215             {
1216                 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
1217 
1218                 /* Update the flags */
1219                 State->Flags.Cf = State->Flags.Of = ((Result < FAST486_SHORT_MIN) || (Result > FAST486_SHORT_MAX));
1220 
1221                 /* Write back the result */
1222                 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
1223                 State->GeneralRegs[FAST486_REG_EDX].LowWord = HIWORD(Result);
1224             }
1225 
1226             break;
1227         }
1228 
1229         /* DIV */
1230         case 6:
1231         {
1232             if (Value == 0)
1233             {
1234                 /* Divide error */
1235                 Fast486Exception(State, FAST486_EXCEPTION_DE);
1236                 return;
1237             }
1238 
1239             if (OperandSize)
1240             {
1241                 ULONGLONG Dividend = (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1242                                      | ((ULONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1243                 ULONGLONG Quotient = Dividend / Value;
1244                 ULONG Remainder = Dividend % Value;
1245 
1246                 if (Quotient > 0xFFFFFFFFULL)
1247                 {
1248                     /* Divide error */
1249                     Fast486Exception(State, FAST486_EXCEPTION_DE);
1250                     return;
1251                 }
1252 
1253                 /* Write back the results */
1254                 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)Quotient;
1255                 State->GeneralRegs[FAST486_REG_EDX].Long = Remainder;
1256             }
1257             else
1258             {
1259                 ULONG Dividend = (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1260                                  | ((ULONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1261                 ULONG Quotient = Dividend / Value;
1262                 USHORT Remainder = Dividend % Value;
1263 
1264                 if (Quotient > 0xFFFF)
1265                 {
1266                     /* Divide error */
1267                     Fast486Exception(State, FAST486_EXCEPTION_DE);
1268                     return;
1269                 }
1270 
1271                 /* Write back the results */
1272                 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Quotient;
1273                 State->GeneralRegs[FAST486_REG_EDX].LowWord = Remainder;
1274             }
1275 
1276             break;
1277         }
1278 
1279         /* IDIV */
1280         case 7:
1281         {
1282             if (Value == 0)
1283             {
1284                 /* Divide error */
1285                 Fast486Exception(State, FAST486_EXCEPTION_DE);
1286                 return;
1287             }
1288 
1289             if (OperandSize)
1290             {
1291                 LONGLONG Dividend = (LONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long
1292                                      | ((LONGLONG)State->GeneralRegs[FAST486_REG_EDX].Long << 32);
1293                 LONGLONG Quotient = Dividend / (LONG)Value;
1294                 LONG Remainder = Dividend % (LONG)Value;
1295 
1296                 if (Quotient > FAST486_LONG_MAX || Quotient < FAST486_LONG_MIN)
1297                 {
1298                     /* Divide error */
1299                     Fast486Exception(State, FAST486_EXCEPTION_DE);
1300                     return;
1301                 }
1302 
1303                 /* Write back the results */
1304                 State->GeneralRegs[FAST486_REG_EAX].Long = (ULONG)((LONG)Quotient);
1305                 State->GeneralRegs[FAST486_REG_EDX].Long = (ULONG)Remainder;
1306             }
1307             else
1308             {
1309                 LONG Dividend = (LONG)State->GeneralRegs[FAST486_REG_EAX].LowWord
1310                                  | ((LONG)State->GeneralRegs[FAST486_REG_EDX].LowWord << 16);
1311                 LONG Quotient = Dividend / (SHORT)LOWORD(Value);
1312                 SHORT Remainder = Dividend % (SHORT)LOWORD(Value);
1313 
1314                 if (Quotient > FAST486_SHORT_MAX || Quotient < FAST486_SHORT_MIN)
1315                 {
1316                     /* Divide error */
1317                     Fast486Exception(State, FAST486_EXCEPTION_DE);
1318                     return;
1319                 }
1320 
1321                 /* Write back the results */
1322                 State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)((SHORT)Quotient);
1323                 State->GeneralRegs[FAST486_REG_EDX].LowWord = (USHORT)Remainder;
1324             }
1325 
1326             break;
1327         }
1328     }
1329 }
1330 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)1331 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
1332 {
1333     UCHAR Value;
1334     FAST486_MOD_REG_RM ModRegRm;
1335     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1336 
1337     TOGGLE_ADSIZE(AddressSize);
1338 
1339     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1340     {
1341         /* Exception occurred */
1342         return;
1343     }
1344 
1345     if (ModRegRm.Register > 1)
1346     {
1347         /* Invalid */
1348         Fast486Exception(State, FAST486_EXCEPTION_UD);
1349         return;
1350     }
1351 
1352     /* Read the operands */
1353     if (!Fast486ReadModrmByteOperands(State, &ModRegRm, NULL, &Value))
1354     {
1355         /* Exception occurred */
1356         return;
1357     }
1358 
1359     if (ModRegRm.Register == 0)
1360     {
1361         /* Increment and update OF and AF */
1362         Value++;
1363         State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1364         State->Flags.Af = ((Value & 0x0F) == 0);
1365     }
1366     else
1367     {
1368         /* Decrement and update OF and AF */
1369         State->Flags.Of = (Value == SIGN_FLAG_BYTE);
1370         Value--;
1371         State->Flags.Af = ((Value & 0x0F) == 0x0F);
1372     }
1373 
1374     /* Update flags */
1375     State->Flags.Zf = (Value == 0);
1376     State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
1377     State->Flags.Pf = Fast486CalculateParity(Value);
1378 
1379     /* Write back the result */
1380     Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
1381 }
1382 
FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)1383 FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
1384 {
1385     FAST486_MOD_REG_RM ModRegRm;
1386     BOOLEAN OperandSize, AddressSize;
1387 
1388     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1389 
1390     TOGGLE_OPSIZE(OperandSize);
1391     TOGGLE_ADSIZE(AddressSize);
1392 
1393     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1394     {
1395         /* Exception occurred */
1396         return;
1397     }
1398 
1399     if (ModRegRm.Register == 7)
1400     {
1401         /* Invalid */
1402         Fast486Exception(State, FAST486_EXCEPTION_UD);
1403         return;
1404     }
1405 
1406     /* Read the operands */
1407     if (OperandSize)
1408     {
1409         ULONG Value;
1410 
1411         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
1412         {
1413             /* Exception occurred */
1414             return;
1415         }
1416 
1417         if (ModRegRm.Register == 0)
1418         {
1419             /* Increment and update OF and AF */
1420             Value++;
1421             State->Flags.Of = (Value == SIGN_FLAG_LONG);
1422             State->Flags.Af = ((Value & 0x0F) == 0);
1423         }
1424         else if (ModRegRm.Register == 1)
1425         {
1426             /* Decrement and update OF and AF */
1427             State->Flags.Of = (Value == SIGN_FLAG_LONG);
1428             Value--;
1429             State->Flags.Af = ((Value & 0x0F) == 0x0F);
1430         }
1431         else if (ModRegRm.Register == 2)
1432         {
1433             /* Push the current value of EIP */
1434             if (!Fast486StackPush(State, State->InstPtr.Long))
1435             {
1436                 /* Exception occurred */
1437                 return;
1438             }
1439 
1440             /* Set the EIP to the address */
1441             State->InstPtr.Long = Value;
1442         }
1443         else if (ModRegRm.Register == 3)
1444         {
1445             USHORT Selector;
1446             FAST486_SEG_REGS Segment = FAST486_REG_DS;
1447 
1448             /* Check for the segment override */
1449             if (State->PrefixFlags & FAST486_PREFIX_SEG)
1450             {
1451                 /* Use the override segment instead */
1452                 Segment = State->SegmentOverride;
1453             }
1454 
1455             /* Read the selector */
1456             if (!Fast486ReadMemory(State,
1457                                    Segment,
1458                                    ModRegRm.MemoryAddress + sizeof(ULONG),
1459                                    FALSE,
1460                                    &Selector,
1461                                    sizeof(USHORT)))
1462             {
1463                 /* Exception occurred */
1464                 return;
1465             }
1466 
1467             if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1468                 && !State->Flags.Vm)
1469             {
1470                 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1471                 {
1472                     /* Gate processed or exception occurred */
1473                     return;
1474                 }
1475             }
1476 
1477             /* Push the current value of CS */
1478             if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1479             {
1480                 /* Exception occurred */
1481                 return;
1482             }
1483 
1484             /* Push the current value of EIP */
1485             if (!Fast486StackPush(State, State->InstPtr.Long))
1486             {
1487                 /* Exception occurred */
1488                 return;
1489             }
1490 
1491             /* Load the new code segment */
1492             if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1493             {
1494                 /* Exception occurred */
1495                 return;
1496             }
1497 
1498             /* Set the EIP to the address */
1499             State->InstPtr.Long = Value;
1500         }
1501         else if (ModRegRm.Register == 4)
1502         {
1503             /* Set the EIP to the address */
1504             State->InstPtr.Long = Value;
1505         }
1506         else if (ModRegRm.Register == 5)
1507         {
1508             USHORT Selector;
1509             FAST486_SEG_REGS Segment = FAST486_REG_DS;
1510 
1511             /* Check for the segment override */
1512             if (State->PrefixFlags & FAST486_PREFIX_SEG)
1513             {
1514                 /* Use the override segment instead */
1515                 Segment = State->SegmentOverride;
1516             }
1517 
1518             /* Read the selector */
1519             if (!Fast486ReadMemory(State,
1520                                    Segment,
1521                                    ModRegRm.MemoryAddress + sizeof(ULONG),
1522                                    FALSE,
1523                                    &Selector,
1524                                    sizeof(USHORT)))
1525             {
1526                 /* Exception occurred */
1527                 return;
1528             }
1529 
1530             if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1531                 && !State->Flags.Vm)
1532             {
1533                 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1534                 {
1535                     /* Gate processed or exception occurred */
1536                     return;
1537                 }
1538             }
1539 
1540             /* Load the new code segment */
1541             if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1542             {
1543                 /* Exception occurred */
1544                 return;
1545             }
1546 
1547             /* Set the EIP to the address */
1548             State->InstPtr.Long = Value;
1549         }
1550         else if (ModRegRm.Register == 6)
1551         {
1552             /* Push the value on to the stack */
1553             Fast486StackPush(State, Value);
1554             return;
1555         }
1556 
1557         if (ModRegRm.Register <= 1)
1558         {
1559             /* Update flags */
1560             State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
1561             State->Flags.Zf = (Value == 0);
1562             State->Flags.Pf = Fast486CalculateParity(Value);
1563 
1564             /* Write back the result */
1565             Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value);
1566         }
1567     }
1568     else
1569     {
1570         USHORT Value;
1571 
1572         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
1573         {
1574             /* Exception occurred */
1575             return;
1576         }
1577 
1578         if (ModRegRm.Register == 0)
1579         {
1580             /* Increment and update OF */
1581             Value++;
1582             State->Flags.Of = (Value == SIGN_FLAG_WORD);
1583             State->Flags.Af = ((Value & 0x0F) == 0);
1584         }
1585         else if (ModRegRm.Register == 1)
1586         {
1587             /* Decrement and update OF */
1588             State->Flags.Of = (Value == SIGN_FLAG_WORD);
1589             Value--;
1590             State->Flags.Af = ((Value & 0x0F) == 0x0F);
1591         }
1592         else if (ModRegRm.Register == 2)
1593         {
1594             /* Push the current value of IP */
1595             if (!Fast486StackPush(State, State->InstPtr.LowWord))
1596             {
1597                 /* Exception occurred */
1598                 return;
1599             }
1600 
1601             /* Set the IP to the address */
1602             State->InstPtr.LowWord = Value;
1603 
1604             /* Clear the top half of EIP */
1605             State->InstPtr.Long &= 0xFFFF;
1606         }
1607         else if (ModRegRm.Register == 3)
1608         {
1609             USHORT Selector;
1610             FAST486_SEG_REGS Segment = FAST486_REG_DS;
1611 
1612             /* Check for the segment override */
1613             if (State->PrefixFlags & FAST486_PREFIX_SEG)
1614             {
1615                 /* Use the override segment instead */
1616                 Segment = State->SegmentOverride;
1617             }
1618 
1619             /* Read the selector */
1620             if (!Fast486ReadMemory(State,
1621                                    Segment,
1622                                    ModRegRm.MemoryAddress + sizeof(USHORT),
1623                                    FALSE,
1624                                    &Selector,
1625                                    sizeof(USHORT)))
1626             {
1627                 /* Exception occurred */
1628                 return;
1629             }
1630 
1631             if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1632                 && !State->Flags.Vm)
1633             {
1634                 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
1635                 {
1636                     /* Gate processed or exception occurred */
1637                     return;
1638                 }
1639             }
1640 
1641             /* Push the current value of CS */
1642             if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
1643             {
1644                 /* Exception occurred */
1645                 return;
1646             }
1647 
1648             /* Push the current value of IP */
1649             if (!Fast486StackPush(State, State->InstPtr.LowWord))
1650             {
1651                 /* Exception occurred */
1652                 return;
1653             }
1654 
1655             /* Load the new code segment */
1656             if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1657             {
1658                 /* Exception occurred */
1659                 return;
1660             }
1661 
1662             /* Set the IP to the address */
1663             State->InstPtr.LowWord = Value;
1664 
1665             /* Clear the top half of EIP */
1666             State->InstPtr.Long &= 0xFFFF;
1667         }
1668         else if (ModRegRm.Register == 4)
1669         {
1670             /* Set the IP to the address */
1671             State->InstPtr.LowWord = Value;
1672 
1673             /* Clear the top half of EIP */
1674             State->InstPtr.Long &= 0xFFFF;
1675         }
1676         else if (ModRegRm.Register == 5)
1677         {
1678             USHORT Selector;
1679             FAST486_SEG_REGS Segment = FAST486_REG_DS;
1680 
1681             /* Check for the segment override */
1682             if (State->PrefixFlags & FAST486_PREFIX_SEG)
1683             {
1684                 /* Use the override segment instead */
1685                 Segment = State->SegmentOverride;
1686             }
1687 
1688             /* Read the selector */
1689             if (!Fast486ReadMemory(State,
1690                                    Segment,
1691                                    ModRegRm.MemoryAddress + sizeof(USHORT),
1692                                    FALSE,
1693                                    &Selector,
1694                                    sizeof(USHORT)))
1695             {
1696                 /* Exception occurred */
1697                 return;
1698             }
1699 
1700             if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1701                 && !State->Flags.Vm)
1702             {
1703                 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
1704                 {
1705                     /* Gate processed or exception occurred */
1706                     return;
1707                 }
1708             }
1709 
1710             /* Load the new code segment */
1711             if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
1712             {
1713                 /* Exception occurred */
1714                 return;
1715             }
1716 
1717             /* Set the IP to the address */
1718             State->InstPtr.LowWord = Value;
1719 
1720             /* Clear the top half of EIP */
1721             State->InstPtr.Long &= 0xFFFF;
1722         }
1723         else if (ModRegRm.Register == 6)
1724         {
1725             /* Push the value on to the stack */
1726             Fast486StackPush(State, Value);
1727             return;
1728         }
1729         else
1730         {
1731             /* Invalid */
1732             Fast486Exception(State, FAST486_EXCEPTION_UD);
1733             return;
1734         }
1735 
1736         if (ModRegRm.Register <= 1)
1737         {
1738             /* Update flags */
1739             State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
1740             State->Flags.Zf = (Value == 0);
1741             State->Flags.Pf = Fast486CalculateParity(Value);
1742 
1743             /* Write back the result */
1744             Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value);
1745         }
1746     }
1747 }
1748 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)1749 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
1750 {
1751     FAST486_MOD_REG_RM ModRegRm;
1752     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
1753 
1754     NO_LOCK_PREFIX();
1755     TOGGLE_ADSIZE(AddressSize);
1756 
1757     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
1758     {
1759         /* Exception occurred */
1760         return;
1761     }
1762 
1763     /* Check which operation this is */
1764     switch (ModRegRm.Register)
1765     {
1766         /* SLDT */
1767         case 0:
1768         {
1769             /* Not recognized in real mode or virtual 8086 mode */
1770             if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1771                 || State->Flags.Vm)
1772             {
1773                 Fast486Exception(State, FAST486_EXCEPTION_UD);
1774                 return;
1775             }
1776 
1777             Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->Ldtr.Selector);
1778             break;
1779         }
1780 
1781         /* STR */
1782         case 1:
1783         {
1784             /* Not recognized in real mode or virtual 8086 mode */
1785             if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1786                 || State->Flags.Vm)
1787             {
1788                 Fast486Exception(State, FAST486_EXCEPTION_UD);
1789                 return;
1790             }
1791 
1792             Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, State->TaskReg.Selector);
1793             break;
1794         }
1795 
1796         /* LLDT */
1797         case 2:
1798         {
1799             BOOLEAN Valid;
1800             USHORT Selector;
1801             FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1802 
1803             /* Not recognized in real mode or virtual 8086 mode */
1804             if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1805                 || State->Flags.Vm)
1806             {
1807                 Fast486Exception(State, FAST486_EXCEPTION_UD);
1808                 return;
1809             }
1810 
1811             /* This is a privileged instruction */
1812             if (Fast486GetCurrentPrivLevel(State) != 0)
1813             {
1814                 Fast486Exception(State, FAST486_EXCEPTION_GP);
1815                 return;
1816             }
1817 
1818             if (!Fast486ReadModrmWordOperands(State,
1819                                               &ModRegRm,
1820                                               NULL,
1821                                               &Selector))
1822             {
1823                 /* Exception occurred */
1824                 return;
1825             }
1826 
1827             if (Selector & SEGMENT_TABLE_INDICATOR)
1828             {
1829                 /* This selector doesn't point to the GDT */
1830                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1831                 return;
1832             }
1833 
1834             if (!Fast486ReadDescriptorEntry(State,
1835                                             Selector,
1836                                             &Valid,
1837                                             (PFAST486_GDT_ENTRY)&GdtEntry))
1838             {
1839                 /* Exception occurred */
1840                 return;
1841             }
1842 
1843             if (!Valid)
1844             {
1845                 /* Invalid selector */
1846                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1847                 return;
1848             }
1849 
1850             if (GET_SEGMENT_INDEX(Selector) == 0)
1851             {
1852                 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
1853                 return;
1854             }
1855 
1856             if (!GdtEntry.Present)
1857             {
1858                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1859                 return;
1860             }
1861 
1862             if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
1863             {
1864                 /* This is not a LDT descriptor */
1865                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1866                 return;
1867             }
1868 
1869             /* Update the LDTR */
1870             State->Ldtr.Selector = Selector;
1871             State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1872             State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1873 
1874             if (GdtEntry.Granularity)
1875             {
1876                 State->Ldtr.Limit <<= 12;
1877                 State->Ldtr.Limit |= 0x00000FFF;
1878             }
1879 
1880             break;
1881         }
1882 
1883         /* LTR */
1884         case 3:
1885         {
1886             BOOLEAN Valid;
1887             USHORT Selector;
1888             FAST486_SYSTEM_DESCRIPTOR GdtEntry;
1889 
1890             /* Not recognized in real mode or virtual 8086 mode */
1891             if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1892                 || State->Flags.Vm)
1893             {
1894                 Fast486Exception(State, FAST486_EXCEPTION_UD);
1895                 return;
1896             }
1897 
1898             /* This is a privileged instruction */
1899             if (Fast486GetCurrentPrivLevel(State) != 0)
1900             {
1901                 Fast486Exception(State, FAST486_EXCEPTION_GP);
1902                 return;
1903             }
1904 
1905             if (!Fast486ReadModrmWordOperands(State,
1906                                               &ModRegRm,
1907                                               NULL,
1908                                               &Selector))
1909             {
1910                 /* Exception occurred */
1911                 return;
1912             }
1913 
1914             if (Selector & SEGMENT_TABLE_INDICATOR)
1915             {
1916                 /* This selector doesn't point to the GDT */
1917                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1918                 return;
1919             }
1920 
1921             if (!Fast486ReadDescriptorEntry(State,
1922                                             Selector,
1923                                             &Valid,
1924                                             (PFAST486_GDT_ENTRY)&GdtEntry))
1925             {
1926                 /* Exception occurred */
1927                 return;
1928             }
1929 
1930             if (!Valid)
1931             {
1932                 /* Invalid selector */
1933                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1934                 return;
1935             }
1936 
1937             if (GET_SEGMENT_INDEX(Selector) == 0)
1938             {
1939                 Fast486Exception(State, FAST486_EXCEPTION_GP);
1940                 return;
1941             }
1942 
1943             if (!GdtEntry.Present)
1944             {
1945                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
1946                 return;
1947             }
1948 
1949             if (GdtEntry.Signature != FAST486_TSS_SIGNATURE
1950                 && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1951                 && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE
1952                 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1953             {
1954                 /* This is not a TSS descriptor */
1955                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
1956                 return;
1957             }
1958 
1959             /* Update the TR */
1960             State->TaskReg.Selector = Selector;
1961             State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
1962             State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
1963             State->TaskReg.Modern = GdtEntry.Signature == FAST486_TSS_SIGNATURE
1964                                     || GdtEntry.Signature == FAST486_BUSY_TSS_SIGNATURE;
1965 
1966             if (GdtEntry.Granularity)
1967             {
1968                 State->TaskReg.Limit <<= 12;
1969                 State->TaskReg.Limit |= 0x00000FFF;
1970             }
1971 
1972             if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
1973                 && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
1974             {
1975                 /* Set the busy bit of this TSS descriptor and write it back */
1976                 GdtEntry.Signature |= 2;
1977 
1978                 Fast486WriteLinearMemory(State,
1979                                          State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
1980                                          &GdtEntry,
1981                                          sizeof(GdtEntry),
1982                                          FALSE /* We already made sure CPL is 0 */);
1983             }
1984 
1985             break;
1986         }
1987 
1988         /* VERR/VERW */
1989         case 4:
1990         case 5:
1991         {
1992             USHORT Selector;
1993             BOOLEAN Valid;
1994             FAST486_GDT_ENTRY GdtEntry;
1995 
1996             /* Not recognized in real mode or virtual 8086 mode */
1997             if (!(State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
1998                 || State->Flags.Vm)
1999             {
2000                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2001                 return;
2002             }
2003 
2004             if (!Fast486ReadModrmWordOperands(State,
2005                                               &ModRegRm,
2006                                               NULL,
2007                                               &Selector))
2008             {
2009                 /* Exception occurred */
2010                 return;
2011             }
2012 
2013             if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry))
2014             {
2015                 /* Exception occurred */
2016                 return;
2017             }
2018 
2019             if (!Valid)
2020             {
2021                 /* Clear ZF */
2022                 State->Flags.Zf = FALSE;
2023                 return;
2024             }
2025 
2026             /* Set ZF if it is valid and accessible */
2027             State->Flags.Zf = GdtEntry.Present // must be present
2028                               && GdtEntry.SystemType // must be a segment
2029                               && (((ModRegRm.Register == 4)
2030                               /* code segments are only readable if the RW bit is set */
2031                               && (!GdtEntry.Executable || GdtEntry.ReadWrite))
2032                               || ((ModRegRm.Register == 5)
2033                               /* code segments are never writable, data segments are writable when RW is set */
2034                               && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
2035                               /*
2036                                * for segments other than conforming code segments,
2037                                * both RPL and CPL must be less than or equal to DPL
2038                                */
2039                               && (((!GdtEntry.Executable || !GdtEntry.DirConf)
2040                               && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
2041                               && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl))
2042                               /* for conforming code segments, DPL must be less than or equal to CPL */
2043                               || ((GdtEntry.Executable && GdtEntry.DirConf)
2044                               && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
2045 
2046 
2047             break;
2048         }
2049 
2050         /* Invalid */
2051         default:
2052         {
2053             Fast486Exception(State, FAST486_EXCEPTION_UD);
2054         }
2055     }
2056 }
2057 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)2058 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
2059 {
2060     // FAST486_TABLE_REG TableReg;
2061     UCHAR TableReg[6];
2062     FAST486_MOD_REG_RM ModRegRm;
2063     BOOLEAN OperandSize, AddressSize;
2064     FAST486_SEG_REGS Segment = FAST486_REG_DS;
2065 
2066     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2067 
2068     NO_LOCK_PREFIX();
2069     TOGGLE_OPSIZE(OperandSize);
2070     TOGGLE_ADSIZE(AddressSize);
2071 
2072     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2073     {
2074         /* Exception occurred */
2075         return;
2076     }
2077 
2078     /* Check for the segment override */
2079     if (State->PrefixFlags & FAST486_PREFIX_SEG)
2080     {
2081         /* Use the override segment instead */
2082         Segment = State->SegmentOverride;
2083     }
2084 
2085     /* Check which operation this is */
2086     switch (ModRegRm.Register)
2087     {
2088         /* SGDT */
2089         case 0:
2090         {
2091             if (!ModRegRm.Memory)
2092             {
2093                 /* The second operand must be a memory location */
2094                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2095                 return;
2096             }
2097 
2098             /* Fill the 6-byte table register */
2099             // TableReg = State->Gdtr;
2100             *((PUSHORT)&TableReg) = State->Gdtr.Size;
2101             *((PULONG)&TableReg[sizeof(USHORT)]) = State->Gdtr.Address;
2102 
2103             /* Store the GDTR */
2104             Fast486WriteMemory(State,
2105                                Segment,
2106                                ModRegRm.MemoryAddress,
2107                                TableReg,
2108                                sizeof(TableReg));
2109 
2110             break;
2111         }
2112 
2113         /* SIDT */
2114         case 1:
2115         {
2116             if (!ModRegRm.Memory)
2117             {
2118                 /* The second operand must be a memory location */
2119                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2120                 return;
2121             }
2122 
2123             /* Fill the 6-byte table register */
2124             // TableReg = State->Idtr;
2125             *((PUSHORT)&TableReg) = State->Idtr.Size;
2126             *((PULONG)&TableReg[sizeof(USHORT)]) = State->Idtr.Address;
2127 
2128             /* Store the IDTR */
2129             Fast486WriteMemory(State,
2130                                Segment,
2131                                ModRegRm.MemoryAddress,
2132                                TableReg,
2133                                sizeof(TableReg));
2134 
2135             break;
2136         }
2137 
2138         /* LGDT */
2139         case 2:
2140         {
2141             /* This is a privileged instruction */
2142             if (Fast486GetCurrentPrivLevel(State) != 0)
2143             {
2144                 Fast486Exception(State, FAST486_EXCEPTION_GP);
2145                 return;
2146             }
2147 
2148             if (!ModRegRm.Memory)
2149             {
2150                 /* The second operand must be a memory location */
2151                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2152                 return;
2153             }
2154 
2155             /* Read the new GDTR */
2156             if (!Fast486ReadMemory(State,
2157                                    Segment,
2158                                    ModRegRm.MemoryAddress,
2159                                    FALSE,
2160                                    TableReg,
2161                                    sizeof(TableReg)))
2162             {
2163                 /* Exception occurred */
2164                 return;
2165             }
2166 
2167             /* Load the new GDT */
2168             // State->Gdtr = TableReg;
2169             State->Gdtr.Size = *((PUSHORT)&TableReg);
2170             State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2171 
2172             /* In 16-bit mode the highest byte is masked out */
2173             if (!OperandSize) State->Gdtr.Address &= 0x00FFFFFF;
2174 
2175             break;
2176         }
2177 
2178         /* LIDT */
2179         case 3:
2180         {
2181             /* This is a privileged instruction */
2182             if (Fast486GetCurrentPrivLevel(State) != 0)
2183             {
2184                 Fast486Exception(State, FAST486_EXCEPTION_GP);
2185                 return;
2186             }
2187 
2188             if (!ModRegRm.Memory)
2189             {
2190                 /* The second operand must be a memory location */
2191                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2192                 return;
2193             }
2194 
2195             /* Read the new IDTR */
2196             if (!Fast486ReadMemory(State,
2197                                    Segment,
2198                                    ModRegRm.MemoryAddress,
2199                                    FALSE,
2200                                    TableReg,
2201                                    sizeof(TableReg)))
2202             {
2203                 /* Exception occurred */
2204                 return;
2205             }
2206 
2207             /* Load the new IDT */
2208             // State->Idtr = TableReg;
2209             State->Idtr.Size = *((PUSHORT)&TableReg);
2210             State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
2211 
2212             /* In 16-bit mode the highest byte is masked out */
2213             if (!OperandSize) State->Idtr.Address &= 0x00FFFFFF;
2214 
2215             break;
2216         }
2217 
2218         /* SMSW */
2219         case 4:
2220         {
2221             /* Store the lower 16 bits (Machine Status Word) of CR0 */
2222             Fast486WriteModrmWordOperands(State,
2223                                           &ModRegRm,
2224                                           FALSE,
2225                                           LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
2226 
2227             break;
2228         }
2229 
2230         /* LMSW */
2231         case 6:
2232         {
2233             USHORT MachineStatusWord;
2234 
2235             if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
2236             {
2237                 /* This is a privileged instruction */
2238                 if (Fast486GetCurrentPrivLevel(State) != 0)
2239                 {
2240                     Fast486Exception(State, FAST486_EXCEPTION_GP);
2241                     return;
2242                 }
2243             }
2244 
2245             /* Read the new Machine Status Word */
2246             if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &MachineStatusWord))
2247             {
2248                 /* Exception occurred */
2249                 return;
2250             }
2251 
2252             /* Set the lowest 4 bits, but never clear bit 0 */
2253             State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1;
2254             State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
2255 
2256             break;
2257         }
2258 
2259         /* INVLPG */
2260         case 7:
2261         {
2262 #ifndef FAST486_NO_PREFETCH
2263             /* Invalidate the prefetch */
2264             State->PrefetchValid = FALSE;
2265 #endif
2266 
2267             /* This is a privileged instruction */
2268             if (Fast486GetCurrentPrivLevel(State) != 0)
2269             {
2270                 Fast486Exception(State, FAST486_EXCEPTION_GP);
2271                 return;
2272             }
2273 
2274             if (!ModRegRm.Memory)
2275             {
2276                 /* The second operand must be a memory location */
2277                 Fast486Exception(State, FAST486_EXCEPTION_UD);
2278                 return;
2279             }
2280 
2281             if (State->Tlb != NULL)
2282             {
2283                 /* Clear the TLB entry */
2284                 State->Tlb[ModRegRm.MemoryAddress >> 12] = INVALID_TLB_FIELD;
2285             }
2286 
2287             break;
2288         }
2289 
2290         /* Invalid */
2291         default:
2292         {
2293             Fast486Exception(State, FAST486_EXCEPTION_UD);
2294         }
2295     }
2296 }
2297 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)2298 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FB9)
2299 {
2300     FAST486_MOD_REG_RM ModRegRm;
2301     BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2302 
2303     TOGGLE_ADSIZE(AddressSize);
2304 
2305     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2306     {
2307         /* Exception occurred */
2308         return;
2309     }
2310 
2311     /* All of them are reserved (UD2) */
2312     Fast486Exception(State, FAST486_EXCEPTION_UD);
2313     return;
2314 }
2315 
FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)2316 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0FBA)
2317 {
2318     FAST486_MOD_REG_RM ModRegRm;
2319     BOOLEAN OperandSize, AddressSize;
2320     UINT DataSize;
2321     UCHAR BitNumber;
2322 
2323     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
2324 
2325     TOGGLE_OPSIZE(OperandSize);
2326     TOGGLE_ADSIZE(AddressSize);
2327 
2328     /* Get the number of bits */
2329     if (OperandSize) DataSize = 32;
2330     else DataSize = 16;
2331 
2332     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
2333     {
2334         /* Exception occurred */
2335         return;
2336     }
2337 
2338     if (ModRegRm.Register < 4)
2339     {
2340         /* Invalid */
2341         Fast486Exception(State, FAST486_EXCEPTION_UD);
2342         return;
2343     }
2344 
2345     /* Get the bit number */
2346     if (!Fast486FetchByte(State, &BitNumber))
2347     {
2348         /* Exception occurred */
2349         return;
2350     }
2351 
2352     if (ModRegRm.Memory)
2353     {
2354         /*
2355          * For memory operands, add the bit offset divided by
2356          * the data size to the address
2357          */
2358         ModRegRm.MemoryAddress += BitNumber / DataSize;
2359     }
2360 
2361     /* Normalize the bit number */
2362     BitNumber %= DataSize;
2363 
2364     if (OperandSize)
2365     {
2366         ULONG Value;
2367 
2368         /* Read the value */
2369         if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Value))
2370         {
2371             /* Exception occurred */
2372             return;
2373         }
2374 
2375         /* Set CF to the bit value */
2376         State->Flags.Cf = (Value >> BitNumber) & 1;
2377 
2378         if (ModRegRm.Register == 5)
2379         {
2380             /* BTS */
2381             Value |= 1 << BitNumber;
2382         }
2383         else if (ModRegRm.Register == 6)
2384         {
2385             /* BTR */
2386             Value &= ~(1 << BitNumber);
2387         }
2388         else if (ModRegRm.Register == 7)
2389         {
2390             /* BTC */
2391             Value ^= 1 << BitNumber;
2392         }
2393 
2394         if (ModRegRm.Register >= 5)
2395         {
2396             /* Write back the result */
2397             if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
2398             {
2399                 /* Exception occurred */
2400                 return;
2401             }
2402         }
2403     }
2404     else
2405     {
2406         USHORT Value;
2407 
2408         /* Read the value */
2409         if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Value))
2410         {
2411             /* Exception occurred */
2412             return;
2413         }
2414 
2415         /* Set CF to the bit value */
2416         State->Flags.Cf = (Value >> BitNumber) & 1;
2417 
2418         if (ModRegRm.Register == 5)
2419         {
2420             /* BTS */
2421             Value |= 1 << BitNumber;
2422         }
2423         else if (ModRegRm.Register == 6)
2424         {
2425             /* BTR */
2426             Value &= ~(1 << BitNumber);
2427         }
2428         else if (ModRegRm.Register == 7)
2429         {
2430             /* BTC */
2431             Value ^= 1 << BitNumber;
2432         }
2433 
2434         if (ModRegRm.Register >= 5)
2435         {
2436             /* Write back the result */
2437             if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
2438             {
2439                 /* Exception occurred */
2440                 return;
2441             }
2442         }
2443     }
2444 }
2445 
2446 /* EOF */
2447