From d4416d200e25ccc2b8bf1caedc599770c9326161 Mon Sep 17 00:00:00 2001 From: wannacu Date: Wed, 19 Oct 2022 13:56:06 +0800 Subject: [PATCH 1/2] OpcodeDispatcher: Implements DAA, DAS, AAA, AAS, AAM and AAD instruction --- .../Interface/Core/OpcodeDispatcher.cpp | 222 ++++++++++++++++++ .../Source/Interface/Core/OpcodeDispatcher.h | 6 + .../Interface/Core/X86Tables/BaseTables.cpp | 12 +- 3 files changed, 234 insertions(+), 6 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 99a7109e1..e20edbf6a 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -3342,6 +3342,222 @@ void OpDispatchBuilder::PopcountOp(OpcodeArgs) { GenerateFlags_POPCOUNT(Op, Src); } +void OpDispatchBuilder::DAAOp(OpcodeArgs) { + CalculateDeferredFlags(); + auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_LOC); + auto AF = GetRFLAG(FEXCore::X86State::RFLAG_AF_LOC); + auto AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(0)); + + auto Cond = _Or(AF, _Select(FEXCore::IR::COND_UGT, _And(AL, _Constant(0xF)), _Constant(9), _Constant(1), _Constant(0))); + auto FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); + auto TrueBlock = CreateNewCodeBlockAfter(FalseBlock); + auto EndBlock = CreateNewCodeBlockAfter(TrueBlock); + + _CondJump(Cond, TrueBlock, FalseBlock); + SetCurrentCodeBlock(FalseBlock); + { + SetRFLAG(_Constant(0)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(TrueBlock); + { + auto NewAL = _Add(AL, _Constant(0x6)); + _StoreContext(1, GPRClass, NewAL, GPROffset(X86State::REG_RAX)); + CalculateDeferredFlags(); + auto NewCF = GetRFLAG(FEXCore::X86State::RFLAG_CF_LOC); + SetRFLAG(_Or(CF, NewCF)); + SetRFLAG(_Constant(1)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(EndBlock); + + Cond = _Or(CF, _Select(FEXCore::IR::COND_UGT, AL, _Constant(0x99), _Constant(1), _Constant(0))); + FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); + TrueBlock = CreateNewCodeBlockAfter(FalseBlock); + EndBlock = CreateNewCodeBlockAfter(TrueBlock); + _CondJump(Cond, TrueBlock, FalseBlock); + SetCurrentCodeBlock(FalseBlock); + { + SetRFLAG(_Constant(0)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(TrueBlock); + { + AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + auto NewAL = _Add(AL, _Constant(0x60)); + _StoreContext(1, GPRClass, NewAL, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(1)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(EndBlock); + // Update Flags + AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Select(FEXCore::IR::COND_UGE, _And(AL, _Constant(0x80)), _Constant(0), _Constant(1), _Constant(0))); + SetRFLAG(_Select(FEXCore::IR::COND_EQ, _And(AL, _Constant(0xFF)), _Constant(0), _Constant(1), _Constant(0))); + auto EightBitMask = _Constant(0xFF); + auto PopCountOp = _Popcount(_And(AL, EightBitMask)); + auto XorOp = _Xor(PopCountOp, _Constant(1)); + SetRFLAG(XorOp); +} + +void OpDispatchBuilder::DASOp(OpcodeArgs) { + CalculateDeferredFlags(); + auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_LOC); + auto AF = GetRFLAG(FEXCore::X86State::RFLAG_AF_LOC); + auto AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(0)); + + auto Cond = _Or(AF, _Select(FEXCore::IR::COND_UGT, _And(AL, _Constant(0xf)), _Constant(9), _Constant(1), _Constant(0))); + auto FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); + auto TrueBlock = CreateNewCodeBlockAfter(FalseBlock); + auto EndBlock = CreateNewCodeBlockAfter(TrueBlock); + + _CondJump(Cond, TrueBlock, FalseBlock); + SetCurrentCodeBlock(FalseBlock); + { + SetRFLAG(_Constant(0)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(TrueBlock); + { + auto NewAL = _Sub(AL, _Constant(0x6)); + _StoreContext(1, GPRClass, NewAL, GPROffset(X86State::REG_RAX)); + CalculateDeferredFlags(); + auto NewCF = GetRFLAG(FEXCore::X86State::RFLAG_CF_LOC); + SetRFLAG(_Or(CF, NewCF)); + SetRFLAG(_Constant(1)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(EndBlock); + + Cond = _Or(CF, _Select(FEXCore::IR::COND_UGT, AL, _Constant(0x99), _Constant(1), _Constant(0))); + FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); + TrueBlock = CreateNewCodeBlockAfter(FalseBlock); + EndBlock = CreateNewCodeBlockAfter(TrueBlock); + _CondJump(Cond, TrueBlock, FalseBlock); + SetCurrentCodeBlock(FalseBlock); + { + SetRFLAG(_Constant(0)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(TrueBlock); + { + AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + auto NewAL = _Sub(AL, _Constant(0x60)); + _StoreContext(1, GPRClass, NewAL, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(1)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(EndBlock); + // Update Flags + AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Select(FEXCore::IR::COND_UGE, _And(AL, _Constant(0x80)), _Constant(0), _Constant(1), _Constant(0))); + SetRFLAG(_Select(FEXCore::IR::COND_EQ, _And(AL, _Constant(0xFF)), _Constant(0), _Constant(1), _Constant(0))); + auto EightBitMask = _Constant(0xFF); + auto PopCountOp = _Popcount(_And(AL, EightBitMask)); + auto XorOp = _Xor(PopCountOp, _Constant(1)); + SetRFLAG(XorOp); +} + +void OpDispatchBuilder::AAAOp(OpcodeArgs) { + auto AF = GetRFLAG(FEXCore::X86State::RFLAG_AF_LOC); + auto AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + auto AX = _LoadContext(2, GPRClass, GPROffset(X86State::REG_RAX)); + auto Cond = _Or(AF, _Select(FEXCore::IR::COND_UGT, _And(AL, _Constant(0xF)), _Constant(9), _Constant(1), _Constant(0))); + + auto FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); + auto TrueBlock = CreateNewCodeBlockAfter(FalseBlock); + auto EndBlock = CreateNewCodeBlockAfter(TrueBlock); + _CondJump(Cond, TrueBlock, FalseBlock); + + SetCurrentCodeBlock(FalseBlock); + { + auto NewAX = _And(AX, _Constant(0xFF0F)); + _StoreContext(2, GPRClass, NewAX, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(0)); + SetRFLAG(_Constant(0)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(TrueBlock); + { + auto NewAX = _Add(AX, _Constant(0x106)); + auto Result = _And(NewAX, _Constant(0xFF0F)); + _StoreContext(2, GPRClass, Result, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(1)); + SetRFLAG(_Constant(1)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(EndBlock); +} + +void OpDispatchBuilder::AASOp(OpcodeArgs) { + auto AF = GetRFLAG(FEXCore::X86State::RFLAG_AF_LOC); + auto AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + auto AX = _LoadContext(2, GPRClass, GPROffset(X86State::REG_RAX)); + auto Cond = _Or(AF, _Select(FEXCore::IR::COND_UGT, _And(AL, _Constant(0xF)), _Constant(9), _Constant(1), _Constant(0))); + + auto FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock()); + auto TrueBlock = CreateNewCodeBlockAfter(FalseBlock); + auto EndBlock = CreateNewCodeBlockAfter(TrueBlock); + _CondJump(Cond, TrueBlock, FalseBlock); + + SetCurrentCodeBlock(FalseBlock); + { + auto NewAX = _And(AX, _Constant(0xFF0F)); + _StoreContext(2, GPRClass, NewAX, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(0)); + SetRFLAG(_Constant(0)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(TrueBlock); + { + auto NewAX = _Sub(AX, _Constant(6)); + NewAX = _Sub(NewAX, _Constant(0x100)); + auto Result = _And(NewAX, _Constant(0xFF0F)); + _StoreContext(2, GPRClass, Result, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Constant(1)); + SetRFLAG(_Constant(1)); + _Jump(EndBlock); + } + SetCurrentCodeBlock(EndBlock); +} + +void OpDispatchBuilder::AAMOp(OpcodeArgs) { + auto AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + auto Imm8 = _Constant(Op->Src[0].Data.Literal.Value & 0xFF); + auto UDivOp = _UDiv(AL, Imm8); + auto URemOp = _URem(AL, Imm8); + auto AH = _Lshl(UDivOp, _Constant(8)); + auto AX = _Add(AH, URemOp); + _StoreContext(2, GPRClass, AX, GPROffset(X86State::REG_RAX)); + // Update Flags + AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Select(FEXCore::IR::COND_UGE, _And(AL, _Constant(0x80)), _Constant(0), _Constant(1), _Constant(0))); + SetRFLAG(_Select(FEXCore::IR::COND_EQ, _And(AL, _Constant(0xFF)), _Constant(0), _Constant(1), _Constant(0))); + auto EightBitMask = _Constant(0xFF); + auto PopCountOp = _Popcount(_And(AL, EightBitMask)); + auto XorOp = _Xor(PopCountOp, _Constant(1)); + SetRFLAG(XorOp); +} + +void OpDispatchBuilder::AADOp(OpcodeArgs) { + auto AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + auto AH = _Lshr(_LoadContext(2, GPRClass, GPROffset(X86State::REG_RAX)), _Constant(8)); + auto Imm8 = _Constant(Op->Src[0].Data.Literal.Value & 0xFF); + auto NewAL = _Add(AL, _Mul(AH, Imm8)); + auto Result = _And(NewAL, _Constant(0xFF)); + _StoreContext(2, GPRClass, Result, GPROffset(X86State::REG_RAX)); + // Update Flags + AL = _LoadContext(1, GPRClass, GPROffset(X86State::REG_RAX)); + SetRFLAG(_Select(FEXCore::IR::COND_UGE, _And(AL, _Constant(0x80)), _Constant(0), _Constant(1), _Constant(0))); + SetRFLAG(_Select(FEXCore::IR::COND_EQ, _And(AL, _Constant(0xFF)), _Constant(0), _Constant(1), _Constant(0))); + auto EightBitMask = _Constant(0xFF); + auto PopCountOp = _Popcount(_And(AL, EightBitMask)); + auto XorOp = _Xor(PopCountOp, _Constant(1)); + SetRFLAG(XorOp); +} + void OpDispatchBuilder::XLATOp(OpcodeArgs) { const uint32_t RAXOffset = GPROffset(X86State::REG_RAX); const uint32_t RBXOffset = GPROffset(X86State::REG_RBX); @@ -5505,12 +5721,18 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x17, 1, &OpDispatchBuilder::POPSegmentOp}, {0x1E, 1, &OpDispatchBuilder::PUSHSegmentOp}, {0x1F, 1, &OpDispatchBuilder::POPSegmentOp}, + {0x27, 1, &OpDispatchBuilder::DAAOp}, + {0x2F, 1, &OpDispatchBuilder::DASOp}, + {0x37, 1, &OpDispatchBuilder::AAAOp}, + {0x3F, 1, &OpDispatchBuilder::AASOp}, {0x40, 8, &OpDispatchBuilder::INCOp}, {0x48, 8, &OpDispatchBuilder::DECOp}, {0x60, 1, &OpDispatchBuilder::PUSHAOp}, {0x61, 1, &OpDispatchBuilder::POPAOp}, {0xCE, 1, &OpDispatchBuilder::INTOp}, + {0xD4, 1, &OpDispatchBuilder::AAMOp}, + {0xD5, 1, &OpDispatchBuilder::AADOp}, }; constexpr std::tuple BaseOpTable_64[] = { diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 667047d93..ad396c1e0 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -278,6 +278,12 @@ public: void NOTOp(OpcodeArgs); void XADDOp(OpcodeArgs); void PopcountOp(OpcodeArgs); + void DAAOp(OpcodeArgs); + void DASOp(OpcodeArgs); + void AAAOp(OpcodeArgs); + void AASOp(OpcodeArgs); + void AAMOp(OpcodeArgs); + void AADOp(OpcodeArgs); void XLATOp(OpcodeArgs); template void RDRANDOp(OpcodeArgs); diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp index aa8078049..14df6c7ed 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp @@ -266,10 +266,10 @@ void InitializeBaseTables(Context::OperatingMode Mode) { {0x17, 1, X86InstInfo{"POP SS", TYPE_INST, GenFlagsSizes(SIZE_16BIT, SIZE_DEF) | FLAGS_DEBUG_MEM_ACCESS, 0, nullptr}}, {0x1E, 1, X86InstInfo{"PUSH DS", TYPE_INST, GenFlagsSrcSize(SIZE_16BIT) | FLAGS_DEBUG_MEM_ACCESS, 0, nullptr}}, {0x1F, 1, X86InstInfo{"POP DS", TYPE_INST, GenFlagsSizes(SIZE_16BIT, SIZE_DEF) | FLAGS_DEBUG_MEM_ACCESS, 0, nullptr}}, - {0x27, 1, X86InstInfo{"DAA", TYPE_INST, FLAGS_NONE, 0, nullptr}}, - {0x2F, 1, X86InstInfo{"DAS", TYPE_INST, FLAGS_NONE, 0, nullptr}}, - {0x37, 1, X86InstInfo{"AAA", TYPE_INST, FLAGS_NONE, 0, nullptr}}, - {0x3F, 1, X86InstInfo{"AAS", TYPE_INST, FLAGS_NONE, 0, nullptr}}, + {0x27, 1, X86InstInfo{"DAA", TYPE_INST, GenFlagsDstSize(SIZE_8BIT) | FLAGS_SF_DST_RAX, 0, nullptr}}, + {0x2F, 1, X86InstInfo{"DAS", TYPE_INST, GenFlagsDstSize(SIZE_8BIT) | FLAGS_SF_DST_RAX, 0, nullptr}}, + {0x37, 1, X86InstInfo{"AAA", TYPE_INST, GenFlagsDstSize(SIZE_16BIT) | FLAGS_SF_DST_RAX, 0, nullptr}}, + {0x3F, 1, X86InstInfo{"AAS", TYPE_INST, GenFlagsDstSize(SIZE_16BIT) | FLAGS_SF_DST_RAX, 0, nullptr}}, {0x40, 8, X86InstInfo{"INC", TYPE_INST, FLAGS_SF_REX_IN_BYTE, 0, nullptr}}, {0x48, 8, X86InstInfo{"DEC", TYPE_INST, FLAGS_SF_REX_IN_BYTE, 0, nullptr}}, @@ -283,8 +283,8 @@ void InitializeBaseTables(Context::OperatingMode Mode) { {0xA1, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_SF_DST_RAX | FLAGS_MEM_OFFSET, 4, nullptr}}, {0xA3, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_SF_SRC_RAX | FLAGS_MEM_OFFSET, 4, nullptr}}, {0xCE, 1, X86InstInfo{"INTO", TYPE_INST, FLAGS_NONE, 0, nullptr}}, - {0xD4, 1, X86InstInfo{"AAM", TYPE_INST, FLAGS_NONE, 1, nullptr}}, - {0xD5, 1, X86InstInfo{"AAD", TYPE_INST, FLAGS_NONE, 1, nullptr}}, + {0xD4, 1, X86InstInfo{"AAM", TYPE_INST, GenFlagsSameSize(SIZE_8BIT) | FLAGS_SF_DST_RAX, 1, nullptr}}, + {0xD5, 1, X86InstInfo{"AAD", TYPE_INST, GenFlagsSameSize(SIZE_8BIT) | FLAGS_SF_DST_RAX, 1, nullptr}}, {0xEA, 1, X86InstInfo{"JMPF", TYPE_INST, FLAGS_NONE, 0, nullptr}}, }; From 73375a76ac61e827376e34a268c4ee3776f24cca Mon Sep 17 00:00:00 2001 From: wannacu Date: Wed, 19 Oct 2022 13:56:21 +0800 Subject: [PATCH 2/2] unittests: Adds DAA, DAS, AAA, AAS, AAM and AAD unit test --- unittests/32Bit_ASM/Primary/Primary_27.asm | 15 +++++++++++++++ unittests/32Bit_ASM/Primary/Primary_2F.asm | 15 +++++++++++++++ unittests/32Bit_ASM/Primary/Primary_37.asm | 15 +++++++++++++++ unittests/32Bit_ASM/Primary/Primary_3F.asm | 15 +++++++++++++++ unittests/32Bit_ASM/Primary/Primary_D4.asm | 15 +++++++++++++++ unittests/32Bit_ASM/Primary/Primary_D5.asm | 15 +++++++++++++++ 6 files changed, 90 insertions(+) create mode 100644 unittests/32Bit_ASM/Primary/Primary_27.asm create mode 100644 unittests/32Bit_ASM/Primary/Primary_2F.asm create mode 100644 unittests/32Bit_ASM/Primary/Primary_37.asm create mode 100644 unittests/32Bit_ASM/Primary/Primary_3F.asm create mode 100644 unittests/32Bit_ASM/Primary/Primary_D4.asm create mode 100644 unittests/32Bit_ASM/Primary/Primary_D5.asm diff --git a/unittests/32Bit_ASM/Primary/Primary_27.asm b/unittests/32Bit_ASM/Primary/Primary_27.asm new file mode 100644 index 000000000..2ec5f6e2e --- /dev/null +++ b/unittests/32Bit_ASM/Primary/Primary_27.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x12345637" + }, + "Mode": "32BIT" +} +%endif + +mov eax, 0x1234561f +daa +daa +daa +daa +hlt diff --git a/unittests/32Bit_ASM/Primary/Primary_2F.asm b/unittests/32Bit_ASM/Primary/Primary_2F.asm new file mode 100644 index 000000000..ea93faf5e --- /dev/null +++ b/unittests/32Bit_ASM/Primary/Primary_2F.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x12345607" + }, + "Mode": "32BIT" +} +%endif + +mov eax, 0x1234561f +das +das +das +das +hlt diff --git a/unittests/32Bit_ASM/Primary/Primary_37.asm b/unittests/32Bit_ASM/Primary/Primary_37.asm new file mode 100644 index 000000000..f51bd4235 --- /dev/null +++ b/unittests/32Bit_ASM/Primary/Primary_37.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x12345a07" + }, + "Mode": "32BIT" +} +%endif + +mov eax, 0x1234561f +aaa +aaa +aaa +aaa +hlt diff --git a/unittests/32Bit_ASM/Primary/Primary_3F.asm b/unittests/32Bit_ASM/Primary/Primary_3F.asm new file mode 100644 index 000000000..d9ffd71f8 --- /dev/null +++ b/unittests/32Bit_ASM/Primary/Primary_3F.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x12345107" + }, + "Mode": "32BIT" +} +%endif + +mov eax, 0x1234561f +aas +aas +aas +aas +hlt diff --git a/unittests/32Bit_ASM/Primary/Primary_D4.asm b/unittests/32Bit_ASM/Primary/Primary_D4.asm new file mode 100644 index 000000000..cae245d23 --- /dev/null +++ b/unittests/32Bit_ASM/Primary/Primary_D4.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0x2" + }, + "Mode": "32BIT" +} +%endif + +mov eax, 0x1234 +aam +aam 0xc +aam 0x1f +aam 0xff +hlt diff --git a/unittests/32Bit_ASM/Primary/Primary_D5.asm b/unittests/32Bit_ASM/Primary/Primary_D5.asm new file mode 100644 index 000000000..02a610746 --- /dev/null +++ b/unittests/32Bit_ASM/Primary/Primary_D5.asm @@ -0,0 +1,15 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xe8" + }, + "Mode": "32BIT" +} +%endif + +mov eax, 0x1234 +aad +aad 0x3 +aad 0x1f +aad 0xae +hlt