[FAST486]: Code formatting only.
[reactos.git] / lib / fast486 / opgroups.c
index 86ff1a4..61c42a8 100644 (file)
@@ -21,8 +21,6 @@
 
 /* INCLUDES *******************************************************************/
 
-// #define WIN32_NO_STATUS
-// #define _INC_WINDOWS
 #include <windef.h>
 
 // #define NDEBUG
@@ -63,7 +61,7 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
             State->Flags.Cf = (Result < FirstValue) && (Result < SecondValue);
             State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
                               && ((FirstValue & SignFlag) != (Result & SignFlag));
-            State->Flags.Af = (((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) ? TRUE : FALSE;
+            State->Flags.Af = ((((FirstValue & 0x0F) + (SecondValue & 0x0F)) & 0x10) != 0);
 
             break;
         }
@@ -87,8 +85,7 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
                               || ((Result < FirstValue) && (Result < (SecondValue + Carry)));
             State->Flags.Of = ((FirstValue & SignFlag) == (SecondValue & SignFlag))
                               && ((FirstValue & SignFlag) != (Result & SignFlag));
-            State->Flags.Af = (((FirstValue & 0x0F) + ((SecondValue + Carry) & 0x0F)) & 0x10)
-                              ? TRUE : FALSE;
+            State->Flags.Af = ((((FirstValue & 0x0F) + ((SecondValue + Carry) & 0x0F)) & 0x10) != 0);
 
             break;
         }
@@ -123,7 +120,7 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
             Result = (FirstValue - SecondValue) & MaxValue;
 
             /* Update CF, OF and AF */
-            State->Flags.Cf = FirstValue < SecondValue;
+            State->Flags.Cf = (FirstValue < SecondValue);
             State->Flags.Of = ((FirstValue & SignFlag) != (SecondValue & SignFlag))
                               && ((FirstValue & SignFlag) != (Result & SignFlag));
             State->Flags.Af = (FirstValue & 0x0F) < (SecondValue & 0x0F);
@@ -146,8 +143,8 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
     }
 
     /* Update ZF, SF and PF */
-    State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
-    State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
+    State->Flags.Zf = (Result == 0);
+    State->Flags.Sf = ((Result & SignFlag) != 0);
     State->Flags.Pf = Fast486CalculateParity(LOBYTE(Result));
 
     /* Return the result */
@@ -187,8 +184,8 @@ Fast486RotateOperation(PFAST486_STATE State,
 
             /* Update CF and OF */
             State->Flags.Cf = Result & 1;
-            if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
-                                              ^ State->Flags.Cf;
+            if (Count == 1) State->Flags.Of = State->Flags.Cf
+                                              ^ ((Result & HighestBit) != 0);
 
             break;
         }
@@ -199,10 +196,9 @@ Fast486RotateOperation(PFAST486_STATE State,
             Result = (Value >> Count) | (Value << (Bits - Count));
 
             /* Update CF and OF */
-            State->Flags.Cf = (Result & HighestBit) ? TRUE : FALSE;
+            State->Flags.Cf = ((Result & HighestBit) != 0);
             if (Count == 1) State->Flags.Of = State->Flags.Cf
-                                              ^ ((Result & (HighestBit >> 1))
-                                              ? TRUE : FALSE);
+                                              ^ ((Result & (HighestBit >> 1)) != 0);
 
             break;
         }
@@ -215,9 +211,9 @@ Fast486RotateOperation(PFAST486_STATE State,
                      | (Value >> (Bits - Count + 1));
 
             /* Update CF and OF */
-            State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
-            if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
-                                              ^ State->Flags.Cf;
+            State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
+            if (Count == 1) State->Flags.Of = State->Flags.Cf
+                                              ^ ((Result & HighestBit) != 0);
 
             break;
         }
@@ -230,10 +226,9 @@ Fast486RotateOperation(PFAST486_STATE State,
                      | (Value << (Bits - Count + 1));
 
             /* Update CF and OF */
-            State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
+            State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
             if (Count == 1) State->Flags.Of = State->Flags.Cf
-                                              ^ ((Result & (HighestBit >> 1))
-                                              ? TRUE : FALSE);
+                                              ^ ((Result & (HighestBit >> 1)) != 0);
 
             break;
         }
@@ -245,9 +240,9 @@ Fast486RotateOperation(PFAST486_STATE State,
             Result = Value << Count;
 
             /* Update CF and OF */
-            State->Flags.Cf = (Value & (1 << (Bits - Count))) ? TRUE : FALSE;
-            if (Count == 1) State->Flags.Of = ((Result & HighestBit) ? TRUE : FALSE)
-                                              ^ (State->Flags.Cf ? TRUE : FALSE);
+            State->Flags.Cf = ((Value & (1 << (Bits - Count))) != 0);
+            if (Count == 1) State->Flags.Of = State->Flags.Cf
+                                              ^ ((Result & HighestBit) != 0);
 
             break;
         }
@@ -258,8 +253,8 @@ Fast486RotateOperation(PFAST486_STATE State,
             Result = Value >> Count;
 
             /* Update CF and OF */
-            State->Flags.Cf = (Value & (1 << (Count - 1))) ? TRUE : FALSE;
-            if (Count == 1) State->Flags.Of = (Value & HighestBit) ? TRUE : FALSE;
+            State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
+            if (Count == 1) State->Flags.Of = ((Value & HighestBit) != 0);
 
             break;
         }
@@ -273,17 +268,20 @@ Fast486RotateOperation(PFAST486_STATE State,
             if (Value & HighestBit) Result |= ((1 << Count) - 1) << (Bits - Count);
 
             /* Update CF and OF */
-            State->Flags.Cf = (Value & (1 << (Count - 1))) ? TRUE : FALSE;
+            State->Flags.Cf = ((Value & (1 << (Count - 1))) != 0);
             if (Count == 1) State->Flags.Of = FALSE;
 
             break;
         }
     }
 
-    /* Update ZF, SF and PF */
-    State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
-    State->Flags.Sf = (Result & HighestBit) ? TRUE : FALSE;
-    State->Flags.Pf = Fast486CalculateParity(Result);
+    if (Operation >= 4)
+    {
+        /* Update ZF, SF and PF */
+        State->Flags.Zf = (Result == 0);
+        State->Flags.Sf = ((Result & HighestBit) != 0);
+        State->Flags.Pf = Fast486CalculateParity(Result);
+    }
 
     /* Return the result */
     return Result;
@@ -944,8 +942,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
             /* Update the flags */
             State->Flags.Cf = FALSE;
             State->Flags.Of = FALSE;
-            State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
-            State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+            State->Flags.Zf = (Result == 0);
+            State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
             State->Flags.Pf = Fast486CalculateParity(Result);
 
             break;
@@ -965,11 +963,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
             UCHAR Result = -Value;
 
             /* Update the flags */
-            State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
+            State->Flags.Cf = (Value != 0);
             State->Flags.Of = (Value & SIGN_FLAG_BYTE) && (Result & SIGN_FLAG_BYTE);
-            State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
-            State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
-            State->Flags.Sf = (Result & SIGN_FLAG_BYTE) ? TRUE : FALSE;
+            State->Flags.Af = ((Value & 0x0F) != 0);
+            State->Flags.Zf = (Result == 0);
+            State->Flags.Sf = ((Result & SIGN_FLAG_BYTE) != 0);
             State->Flags.Pf = Fast486CalculateParity(Result);
 
             /* Write back the result */
@@ -982,7 +980,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
             USHORT Result = (USHORT)Value * (USHORT)State->GeneralRegs[FAST486_REG_EAX].LowByte;
 
             /* Update the flags */
-            State->Flags.Cf = State->Flags.Of = HIBYTE(Result) ? TRUE : FALSE;
+            State->Flags.Cf = State->Flags.Of = (HIBYTE(Result) != 0);
 
             /* Write back the result */
             State->GeneralRegs[FAST486_REG_EAX].LowWord = Result;
@@ -996,8 +994,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
             SHORT Result = (SHORT)((CHAR)Value) * (SHORT)((CHAR)State->GeneralRegs[FAST486_REG_EAX].LowByte);
 
             /* Update the flags */
-            State->Flags.Cf = State->Flags.Of =
-            ((Result < -128) || (Result > 127)) ? TRUE : FALSE;
+            State->Flags.Cf = State->Flags.Of = ((Result < -128) || (Result > 127));
 
             /* Write back the result */
             State->GeneralRegs[FAST486_REG_EAX].LowWord = (USHORT)Result;
@@ -1109,8 +1106,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
             /* Update the flags */
             State->Flags.Cf = FALSE;
             State->Flags.Of = FALSE;
-            State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
-            State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
+            State->Flags.Zf = (Result == 0);
+            State->Flags.Sf = ((Result & SignFlag) != 0);
             State->Flags.Pf = Fast486CalculateParity(Result);
 
             break;
@@ -1140,11 +1137,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
             if (!OperandSize) Result &= 0xFFFF;
 
             /* Update the flags */
-            State->Flags.Cf = (Value != 0) ? TRUE : FALSE;
+            State->Flags.Cf = (Value != 0);
             State->Flags.Of = (Value & SignFlag) && (Result & SignFlag);
-            State->Flags.Af = ((Value & 0x0F) != 0) ? TRUE : FALSE;
-            State->Flags.Zf = (Result == 0) ? TRUE : FALSE;
-            State->Flags.Sf = (Result & SignFlag) ? TRUE : FALSE;
+            State->Flags.Af = ((Value & 0x0F) != 0);
+            State->Flags.Zf = (Result == 0);
+            State->Flags.Sf = ((Result & SignFlag) != 0);
             State->Flags.Pf = Fast486CalculateParity(Result);
 
             /* Write back the result */
@@ -1168,8 +1165,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
                 ULONGLONG Result = (ULONGLONG)Value * (ULONGLONG)State->GeneralRegs[FAST486_REG_EAX].Long;
 
                 /* Update the flags */
-                State->Flags.Cf = State->Flags.Of =
-                (Result & 0xFFFFFFFF00000000ULL) ? TRUE : FALSE;
+                State->Flags.Cf = State->Flags.Of = ((Result & 0xFFFFFFFF00000000ULL) != 0);
 
                 /* Write back the result */
                 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
@@ -1180,7 +1176,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
                 ULONG Result = (ULONG)Value * (ULONG)State->GeneralRegs[FAST486_REG_EAX].LowWord;
 
                 /* Update the flags */
-                State->Flags.Cf = State->Flags.Of = HIWORD(Result) ? TRUE : FALSE;
+                State->Flags.Cf = State->Flags.Of = (HIWORD(Result) != 0);
 
                 /* Write back the result */
                 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
@@ -1198,8 +1194,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
                 LONGLONG Result = (LONGLONG)((LONG)Value) * (LONGLONG)((LONG)State->GeneralRegs[FAST486_REG_EAX].Long);
 
                 /* Update the flags */
-                State->Flags.Cf = State->Flags.Of =
-                ((Result < -2147483648LL) || (Result > 2147483647LL)) ? TRUE : FALSE;
+                State->Flags.Cf = State->Flags.Of = ((Result < -2147483648LL) || (Result > 2147483647LL));
 
                 /* Write back the result */
                 State->GeneralRegs[FAST486_REG_EAX].Long = Result & 0xFFFFFFFFULL;
@@ -1210,8 +1205,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
                 LONG Result = (LONG)((SHORT)Value) * (LONG)((SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord);
 
                 /* Update the flags */
-                State->Flags.Cf = State->Flags.Of =
-                ((Result < -32768) || (Result > 32767)) ? TRUE : FALSE;
+                State->Flags.Cf = State->Flags.Of = ((Result < -32768) || (Result > 32767));
 
                 /* Write back the result */
                 State->GeneralRegs[FAST486_REG_EAX].LowWord = LOWORD(Result);
@@ -1315,20 +1309,20 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFE)
     {
         /* Increment and update OF and AF */
         Value++;
-        State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
+        State->Flags.Of = (Value == SIGN_FLAG_BYTE);
         State->Flags.Af = ((Value & 0x0F) == 0);
     }
     else
     {
         /* Decrement and update OF and AF */
-        State->Flags.Of = (Value == SIGN_FLAG_BYTE) ? TRUE : FALSE;
+        State->Flags.Of = (Value == SIGN_FLAG_BYTE);
         Value--;
         State->Flags.Af = ((Value & 0x0F) == 0x0F);
     }
 
     /* Update flags */
-    State->Flags.Sf = (Value & SIGN_FLAG_BYTE) ? TRUE : FALSE;
-    State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+    State->Flags.Zf = (Value == 0);
+    State->Flags.Sf = ((Value & SIGN_FLAG_BYTE) != 0);
     State->Flags.Pf = Fast486CalculateParity(Value);
 
     /* Write back the result */
@@ -1376,13 +1370,13 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
         {
             /* Increment and update OF and AF */
             Value++;
-            State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
+            State->Flags.Of = (Value == SIGN_FLAG_LONG);
             State->Flags.Af = ((Value & 0x0F) == 0);
         }
         else if (ModRegRm.Register == 1)
         {
             /* Decrement and update OF and AF */
-            State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE;
+            State->Flags.Of = (Value == SIGN_FLAG_LONG);
             Value--;
             State->Flags.Af = ((Value & 0x0F) == 0x0F);
         }
@@ -1494,8 +1488,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
         if (ModRegRm.Register <= 1)
         {
             /* Update flags */
-            State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE;
-            State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+            State->Flags.Sf = ((Value & SIGN_FLAG_LONG) != 0);
+            State->Flags.Zf = (Value == 0);
             State->Flags.Pf = Fast486CalculateParity(Value);
 
             /* Write back the result */
@@ -1519,13 +1513,13 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
         {
             /* Increment and update OF */
             Value++;
-            State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
+            State->Flags.Of = (Value == SIGN_FLAG_WORD);
             State->Flags.Af = ((Value & 0x0F) == 0);
         }
         else if (ModRegRm.Register == 1)
         {
             /* Decrement and update OF */
-            State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE;
+            State->Flags.Of = (Value == SIGN_FLAG_WORD);
             Value--;
             State->Flags.Af = ((Value & 0x0F) == 0x0F);
         }
@@ -1644,8 +1638,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
         if (ModRegRm.Register <= 1)
         {
             /* Update flags */
-            State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE;
-            State->Flags.Zf = (Value == 0) ? TRUE : FALSE;
+            State->Flags.Sf = ((Value & SIGN_FLAG_WORD) != 0);
+            State->Flags.Zf = (Value == 0);
             State->Flags.Pf = Fast486CalculateParity(Value);
 
             /* Write back the result */
@@ -1659,5 +1653,360 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
     return TRUE;
 }
 
+FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0F01)
+{
+    UCHAR TableReg[6];
+    FAST486_MOD_REG_RM ModRegRm;
+    BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+    FAST486_SEG_REGS Segment = FAST486_REG_DS;
+
+    NO_LOCK_PREFIX();
+    TOGGLE_ADSIZE(AddressSize);
+
+    /* Check for the segment override */
+    if (State->PrefixFlags & FAST486_PREFIX_SEG)
+    {
+        /* Use the override segment instead */
+        Segment = State->SegmentOverride;
+    }
+
+    if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* Check which operation this is */
+    switch (ModRegRm.Register)
+    {
+        /* SGDT */
+        case 0:
+        {
+            if (!ModRegRm.Memory)
+            {
+                /* The second operand must be a memory location */
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                return FALSE;
+            }
+
+            /* Fill the 6-byte table register */
+            RtlCopyMemory(TableReg, &State->Gdtr.Size, sizeof(USHORT));
+            RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Gdtr.Address, sizeof(ULONG));
+
+            /* Store the GDTR */
+            return Fast486WriteMemory(State,
+                                      Segment,
+                                      ModRegRm.MemoryAddress,
+                                      TableReg,
+                                      sizeof(TableReg));
+        }
+
+        /* SIDT */
+        case 1:
+        {
+            if (!ModRegRm.Memory)
+            {
+                /* The second operand must be a memory location */
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                return FALSE;
+            }
+
+            /* Fill the 6-byte table register */
+            RtlCopyMemory(TableReg, &State->Idtr.Size, sizeof(USHORT));
+            RtlCopyMemory(&TableReg[sizeof(USHORT)], &State->Idtr.Address, sizeof(ULONG));
+
+            /* Store the IDTR */
+            return Fast486WriteMemory(State,
+                                      Segment,
+                                      ModRegRm.MemoryAddress,
+                                      TableReg,
+                                      sizeof(TableReg));
+        }
+
+        /* LGDT */
+        case 2:
+        {
+            /* This is a privileged instruction */
+            if (Fast486GetCurrentPrivLevel(State) != 0)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            if (!ModRegRm.Memory)
+            {
+                /* The second operand must be a memory location */
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                return FALSE;
+            }
+
+            /* Read the new GDTR */
+            if (!Fast486ReadMemory(State,
+                                   Segment,
+                                   ModRegRm.MemoryAddress,
+                                   FALSE,
+                                   TableReg,
+                                   sizeof(TableReg)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            /* Load the new GDT */
+            State->Gdtr.Size = *((PUSHORT)TableReg);
+            State->Gdtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
+
+            return TRUE;
+        }
+
+        /* LIDT */
+        case 3:
+        {
+            /* This is a privileged instruction */
+            if (Fast486GetCurrentPrivLevel(State) != 0)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            if (!ModRegRm.Memory)
+            {
+                /* The second operand must be a memory location */
+                Fast486Exception(State, FAST486_EXCEPTION_UD);
+                return FALSE;
+            }
+
+            /* Read the new IDTR */
+            if (!Fast486ReadMemory(State,
+                                   Segment,
+                                   ModRegRm.MemoryAddress,
+                                   FALSE,
+                                   TableReg,
+                                   sizeof(TableReg)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            /* Load the new IDT */
+            State->Idtr.Size = *((PUSHORT)TableReg);
+            State->Idtr.Address = *((PULONG)&TableReg[sizeof(USHORT)]);
+
+            return TRUE;
+        }
+
+        /* SMSW */
+        case 4:
+        {
+            /* Store the lower 16 bits of CR0 */
+            return Fast486WriteModrmWordOperands(State,
+                                                 &ModRegRm,
+                                                 FALSE,
+                                                 LOWORD(State->ControlRegisters[FAST486_REG_CR0]));
+        }
+
+        /* LMSW */
+        case 6:
+        {
+            USHORT MasterStatusWord, Dummy;
+
+            /* This is a privileged instruction */
+            if (Fast486GetCurrentPrivLevel(State) != 0)
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            /* Read the new master status word */
+            if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &MasterStatusWord))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+
+            /* This instruction cannot be used to return to real mode */
+            if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                && !(MasterStatusWord & FAST486_CR0_PE))
+            {
+                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                return FALSE;
+            }
+
+            /* Set the lowest 4 bits */
+            State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
+            State->ControlRegisters[FAST486_REG_CR0] |= MasterStatusWord & 0x0F;
+
+            return TRUE;
+        }
+
+        /* INVLPG */
+        case 7:
+        {
+            UNIMPLEMENTED;
+            return FALSE;
+        }
+
+        /* Invalid */
+        default:
+        {
+            Fast486Exception(State, FAST486_EXCEPTION_UD);
+            return FALSE;
+        }
+    }
+}
+
+FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FB9)
+{
+    FAST486_MOD_REG_RM ModRegRm;
+    BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+
+    TOGGLE_ADSIZE(AddressSize);
+
+    if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    /* All of them are reserved (UD2) */
+    Fast486Exception(State, FAST486_EXCEPTION_UD);
+    return FALSE;
+}
+
+FAST486_OPCODE_HANDLER(Fast486OpcodeGroup0FBA)
+{
+    FAST486_MOD_REG_RM ModRegRm;
+    BOOLEAN OperandSize, AddressSize;
+    UINT DataSize;
+    UCHAR BitNumber;
+    
+    OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+
+    TOGGLE_OPSIZE(OperandSize);
+    TOGGLE_ADSIZE(AddressSize);
+
+    /* Get the number of bits */
+    if (OperandSize) DataSize = 32;
+    else DataSize = 16;
+
+    if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (ModRegRm.Register < 4)
+    {
+        /* Invalid */
+        Fast486Exception(State, FAST486_EXCEPTION_UD);
+        return FALSE;
+    }
+
+    /* Get the bit number */
+    if (!Fast486FetchByte(State, &BitNumber))
+    {
+        /* Exception occurred */
+        return FALSE;
+    }
+
+    if (ModRegRm.Memory)
+    {
+        /*
+         * For memory operands, add the bit offset divided by
+         * the data size to the address
+         */
+        ModRegRm.MemoryAddress += BitNumber / DataSize;
+    }
+
+    /* Normalize the bit number */
+    BitNumber &= (1 << DataSize) - 1;
+
+    if (OperandSize)
+    {
+        ULONG Dummy, Value;
+
+        /* Read the value */
+        if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, &Dummy, &Value))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Set CF to the bit value */
+        State->Flags.Cf = (Value >> BitNumber) & 1;
+
+        if (ModRegRm.Register == 5)
+        {
+            /* BTS */
+            Value |= 1 << BitNumber;
+        }
+        else if (ModRegRm.Register == 6)
+        {
+            /* BTR */
+            Value &= ~(1 << BitNumber);
+        }
+        else if (ModRegRm.Register == 7)
+        {
+            /* BTC */
+            Value ^= 1 << BitNumber;
+        }
+
+        if (ModRegRm.Register >= 5)
+        {
+            /* Write back the result */
+            if (!Fast486WriteModrmDwordOperands(State, &ModRegRm, FALSE, Value))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+        }
+    }
+    else
+    {
+        USHORT Dummy, Value;
+
+        /* Read the value */
+        if (!Fast486ReadModrmWordOperands(State, &ModRegRm, &Dummy, &Value))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
+
+        /* Set CF to the bit value */
+        State->Flags.Cf = (Value >> BitNumber) & 1;
+
+        if (ModRegRm.Register == 5)
+        {
+            /* BTS */
+            Value |= 1 << BitNumber;
+        }
+        else if (ModRegRm.Register == 6)
+        {
+            /* BTR */
+            Value &= ~(1 << BitNumber);
+        }
+        else if (ModRegRm.Register == 7)
+        {
+            /* BTC */
+            Value ^= 1 << BitNumber;
+        }
+
+        if (ModRegRm.Register >= 5)
+        {
+            /* Write back the result */
+            if (!Fast486WriteModrmWordOperands(State, &ModRegRm, FALSE, Value))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+        }
+    }
+
+    /* Return success */
+    return TRUE;
+
+    return TRUE;
+}
+
 /* EOF */