From ddcbb9ee92753c69f1198b66e6503ceb848bd8c9 Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Thu, 5 Sep 2013 23:48:07 +0000 Subject: [PATCH] [SOFT386] Implement the TEST instruction, and the XCHG instruction which uses MOD-REG-R/M for operands. svn path=/branches/ntvdm/; revision=59994 --- lib/soft386/opcodes.c | 320 ++++++++++++++++++++++++++++++++++++++++++ lib/soft386/opcodes.h | 4 + 2 files changed, 324 insertions(+) diff --git a/lib/soft386/opcodes.c b/lib/soft386/opcodes.c index f6dccb80da4..c103fbeb528 100644 --- a/lib/soft386/opcodes.c +++ b/lib/soft386/opcodes.c @@ -2290,3 +2290,323 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax) return TRUE; } + +SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm) +{ + UCHAR FirstValue, SecondValue, Result; + SOFT386_MOD_REG_RM ModRegRm; + BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; + + /* Make sure this is the right instruction */ + ASSERT(Opcode == 0x84); + + if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE) + { + /* The ADSIZE prefix toggles the size */ + AddressSize = !AddressSize; + } + else if (State->PrefixFlags + & ~(SOFT386_PREFIX_ADSIZE + | SOFT386_PREFIX_SEG + | SOFT386_PREFIX_LOCK)) + { + /* Invalid prefix */ + Soft386Exception(State, SOFT386_EXCEPTION_UD); + return FALSE; + } + + /* Get the operands */ + if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + if (!Soft386ReadModrmByteOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + /* Calculate the result */ + Result = FirstValue & SecondValue; + + /* 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.Pf = Soft386CalculateParity(Result); + + /* The result is discarded */ + return TRUE; +} + +SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm) +{ + SOFT386_MOD_REG_RM ModRegRm; + BOOLEAN OperandSize, AddressSize; + + /* Make sure this is the right instruction */ + ASSERT(Opcode == 0x85); + + OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; + + if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE) + { + /* The ADSIZE prefix toggles the address size */ + AddressSize = !AddressSize; + } + + if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) + { + /* The OPSIZE prefix toggles the operand size */ + OperandSize = !OperandSize; + } + + if (State->PrefixFlags + & ~(SOFT386_PREFIX_ADSIZE + | SOFT386_PREFIX_OPSIZE + | SOFT386_PREFIX_SEG + | SOFT386_PREFIX_LOCK)) + { + /* Invalid prefix */ + Soft386Exception(State, SOFT386_EXCEPTION_UD); + return FALSE; + } + + /* Get the operands */ + if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + /* Check the operand size */ + if (OperandSize) + { + ULONG FirstValue, SecondValue, Result; + + if (!Soft386ReadModrmDwordOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Calculate the result */ + Result = FirstValue & SecondValue; + + /* Update the flags */ + State->Flags.Cf = FALSE; + State->Flags.Of = FALSE; + State->Flags.Zf = (Result == 0) ? TRUE : FALSE; + State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE; + State->Flags.Pf = Soft386CalculateParity(Result); + } + else + { + USHORT FirstValue, SecondValue, Result; + + if (!Soft386ReadModrmWordOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Calculate the result */ + Result = FirstValue & SecondValue; + + /* Update the flags */ + State->Flags.Cf = FALSE; + State->Flags.Of = FALSE; + State->Flags.Zf = (Result == 0) ? TRUE : FALSE; + State->Flags.Sf = (Result & SIGN_FLAG_LONG) ? TRUE : FALSE; + State->Flags.Pf = Soft386CalculateParity(Result); + } + + /* The result is discarded */ + return TRUE; +} + +SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm) +{ + UCHAR FirstValue, SecondValue; + SOFT386_MOD_REG_RM ModRegRm; + BOOLEAN AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; + + /* Make sure this is the right instruction */ + ASSERT(Opcode == 0x86); + + if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE) + { + /* The ADSIZE prefix toggles the size */ + AddressSize = !AddressSize; + } + else if (State->PrefixFlags + & ~(SOFT386_PREFIX_ADSIZE + | SOFT386_PREFIX_SEG + | SOFT386_PREFIX_LOCK)) + { + /* Invalid prefix */ + Soft386Exception(State, SOFT386_EXCEPTION_UD); + return FALSE; + } + + /* Get the operands */ + if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + if (!Soft386ReadModrmByteOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Write the value from the register to the R/M */ + if (!Soft386WriteModrmByteOperands(State, + &ModRegRm, + FALSE, + FirstValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Write the value from the R/M to the register */ + if (!Soft386WriteModrmByteOperands(State, + &ModRegRm, + TRUE, + SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + return TRUE; +} + +SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm) +{ + SOFT386_MOD_REG_RM ModRegRm; + BOOLEAN OperandSize, AddressSize; + + /* Make sure this is the right instruction */ + ASSERT(Opcode == 0x87); + + OperandSize = AddressSize = State->SegmentRegs[SOFT386_REG_CS].Size; + + if (State->PrefixFlags & SOFT386_PREFIX_ADSIZE) + { + /* The ADSIZE prefix toggles the address size */ + AddressSize = !AddressSize; + } + + if (State->PrefixFlags & SOFT386_PREFIX_OPSIZE) + { + /* The OPSIZE prefix toggles the operand size */ + OperandSize = !OperandSize; + } + + if (State->PrefixFlags + & ~(SOFT386_PREFIX_ADSIZE + | SOFT386_PREFIX_OPSIZE + | SOFT386_PREFIX_SEG + | SOFT386_PREFIX_LOCK)) + { + /* Invalid prefix */ + Soft386Exception(State, SOFT386_EXCEPTION_UD); + return FALSE; + } + + /* Get the operands */ + if (!Soft386ParseModRegRm(State, AddressSize, &ModRegRm)) + { + /* Exception occurred */ + return FALSE; + } + + /* Check the operand size */ + if (OperandSize) + { + ULONG FirstValue, SecondValue; + + if (!Soft386ReadModrmDwordOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Write the value from the register to the R/M */ + if (!Soft386WriteModrmDwordOperands(State, + &ModRegRm, + FALSE, + FirstValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Write the value from the R/M to the register */ + if (!Soft386WriteModrmDwordOperands(State, + &ModRegRm, + TRUE, + SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + } + else + { + USHORT FirstValue, SecondValue; + + if (!Soft386ReadModrmWordOperands(State, + &ModRegRm, + &FirstValue, + &SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Write the value from the register to the R/M */ + if (!Soft386WriteModrmWordOperands(State, + &ModRegRm, + FALSE, + FirstValue)) + { + /* Exception occurred */ + return FALSE; + } + + /* Write the value from the R/M to the register */ + if (!Soft386WriteModrmWordOperands(State, + &ModRegRm, + TRUE, + SecondValue)) + { + /* Exception occurred */ + return FALSE; + } + } + + /* The result is discarded */ + return TRUE; +} diff --git a/lib/soft386/opcodes.h b/lib/soft386/opcodes.h index e0f7ed72353..7deafd821ea 100644 --- a/lib/soft386/opcodes.h +++ b/lib/soft386/opcodes.h @@ -66,5 +66,9 @@ SOFT386_OPCODE_HANDLER(Soft386OpcodeXorByteModrm); SOFT386_OPCODE_HANDLER(Soft386OpcodeXorModrm); SOFT386_OPCODE_HANDLER(Soft386OpcodeXorAl); SOFT386_OPCODE_HANDLER(Soft386OpcodeXorEax); +SOFT386_OPCODE_HANDLER(Soft386OpcodeTestByteModrm); +SOFT386_OPCODE_HANDLER(Soft386OpcodeTestModrm); +SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgByteModrm); +SOFT386_OPCODE_HANDLER(Soft386OpcodeXchgModrm); #endif // _OPCODES_H_