From ba7cbe7cf635179d68d62fcd0905a4a048c74836 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Feb 2021 09:01:52 -0500 Subject: [PATCH 1/6] thumb32: Implement SSAT16/USAT16 --- src/frontend/A32/decoder/thumb32.inc | 4 +-- ...data_processing_plain_binary_immediate.cpp | 35 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 2 ++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 71e3e4ef..7796e730 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -78,13 +78,13 @@ INST(thumb32_MOVW_imm, "MOVW (imm)", "11110i100100iiii0iiidd //INST(thumb32_SUB_imm_2, "SUB (imm)", "11110-101010----0---------------") INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiiddddiiiiiiii") //INST(thumb32_SSAT, "SSAT", "11110-110000----0---------------") -//INST(thumb32_SSAT16, "SSAT16", "11110-110010----0000----00------") +INST(thumb32_SSAT16, "SSAT16", "111100110010nnnn0000dddd0000iiii") //INST(thumb32_SSAT, "SSAT", "11110-110010----0---------------") //INST(thumb32_SBFX, "SBFX", "11110-110100----0---------------") //INST(thumb32_BFC, "BFC", "11110-11011011110---------------") //INST(thumb32_BFI, "BFI", "11110-110110----0---------------") //INST(thumb32_USAT, "USAT", "11110-111000----0---------------") -//INST(thumb32_USAT16, "USAT16", "11110-111010----0000----00------") +INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") //INST(thumb32_USAT, "USAT", "11110-111010----0---------------") //INST(thumb32_UBFX, "UBFX", "11110-111100----0---------------") diff --git a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 8244ddc2..dcfd289d 100644 --- a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -6,6 +6,33 @@ #include "frontend/A32/translate/impl/translate_thumb.h" namespace Dynarmic::A32 { +static IR::U32 Pack2x16To1x32(A32::IREmitter& ir, IR::U32 lo, IR::U32 hi) { + return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result); +} + +static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { + return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result); +} + +using SaturationFunction = IR::ResultAndOverflow (IREmitter::*)(const IR::U32&, size_t); + +static bool Saturation16(ThumbTranslatorVisitor& v, Reg n, Reg d, size_t saturate_to, SaturationFunction sat_fn) { + if (d == Reg::PC || n == Reg::PC) { + return v.UnpredictableInstruction(); + } + + const auto reg_n = v.ir.GetRegister(n); + + const auto lo_operand = v.ir.SignExtendHalfToWord(v.ir.LeastSignificantHalf(reg_n)); + const auto hi_operand = v.ir.SignExtendHalfToWord(MostSignificantHalf(v.ir, reg_n)); + const auto lo_result = (v.ir.*sat_fn)(lo_operand, saturate_to); + const auto hi_result = (v.ir.*sat_fn)(hi_operand, saturate_to); + + v.ir.SetRegister(d, Pack2x16To1x32(v.ir, lo_result.result, hi_result.result)); + v.ir.OrQFlag(lo_result.overflow); + v.ir.OrQFlag(hi_result.overflow); + return true; +} bool ThumbTranslatorVisitor::thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8) { if (d == Reg::PC) { @@ -31,4 +58,12 @@ bool ThumbTranslatorVisitor::thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> i return true; } +bool ThumbTranslatorVisitor::thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm) { + return Saturation16(*this, n, d, sat_imm.ZeroExtend() + 1, &IREmitter::SignedSaturation); +} + +bool ThumbTranslatorVisitor::thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm) { + return Saturation16(*this, n, d, sat_imm.ZeroExtend(), &IREmitter::UnsignedSaturation); +} + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 5ffecd9d..2abf2008 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -162,6 +162,8 @@ struct ThumbTranslatorVisitor final { // thumb32 data processing (plain binary immediate) instructions. bool thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); + bool thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm); + bool thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm); // thumb32 miscellaneous control instructions bool thumb32_BXJ(Reg m); From 733491404791fedd599beac4808c6e4ff5677324 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Feb 2021 09:20:55 -0500 Subject: [PATCH 2/6] thumb32: Implement BFC/BFI --- src/frontend/A32/decoder/thumb32.inc | 4 +- ...data_processing_plain_binary_immediate.cpp | 42 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 2 + 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 7796e730..c8aa9b90 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -81,8 +81,8 @@ INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiidd INST(thumb32_SSAT16, "SSAT16", "111100110010nnnn0000dddd0000iiii") //INST(thumb32_SSAT, "SSAT", "11110-110010----0---------------") //INST(thumb32_SBFX, "SBFX", "11110-110100----0---------------") -//INST(thumb32_BFC, "BFC", "11110-11011011110---------------") -//INST(thumb32_BFI, "BFI", "11110-110110----0---------------") +INST(thumb32_BFC, "BFC", "11110011011011110iiiddddii0bbbbb") +INST(thumb32_BFI, "BFI", "111100110110nnnn0iiiddddii0bbbbb") //INST(thumb32_USAT, "USAT", "11110-111000----0---------------") INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") //INST(thumb32_USAT, "USAT", "11110-111010----0---------------") diff --git a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index dcfd289d..086e2333 100644 --- a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -34,6 +34,48 @@ static bool Saturation16(ThumbTranslatorVisitor& v, Reg n, Reg d, size_t saturat return true; } +bool ThumbTranslatorVisitor::thumb32_BFC(Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb) { + if (d == Reg::PC) { + return UnpredictableInstruction(); + } + + const u32 lsbit = concatenate(imm3, imm2).ZeroExtend(); + const u32 msbit = msb.ZeroExtend(); + + if (msbit < lsbit) { + return UnpredictableInstruction(); + } + + const u32 mask = ~(Common::Ones(msbit - lsbit + 1) << lsbit); + const auto reg_d = ir.GetRegister(d); + const auto result = ir.And(reg_d, ir.Imm32(mask)); + + ir.SetRegister(d, result); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_BFI(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb) { + if (d == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const u32 lsbit = concatenate(imm3, imm2).ZeroExtend(); + const u32 msbit = msb.ZeroExtend(); + + if (msbit < lsbit) { + return UnpredictableInstruction(); + } + + const u32 inclusion_mask = Common::Ones(msbit - lsbit + 1) << lsbit; + const u32 exclusion_mask = ~inclusion_mask; + const IR::U32 operand1 = ir.And(ir.GetRegister(d), ir.Imm32(exclusion_mask)); + const IR::U32 operand2 = ir.And(ir.LogicalShiftLeft(ir.GetRegister(n), ir.Imm8(u8(lsbit))), ir.Imm32(inclusion_mask)); + const IR::U32 result = ir.Or(operand1, operand2); + + ir.SetRegister(d, result); + return true; +} + bool ThumbTranslatorVisitor::thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8) { if (d == Reg::PC) { return UnpredictableInstruction(); diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 2abf2008..2d84f3e9 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -160,6 +160,8 @@ struct ThumbTranslatorVisitor final { bool thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8); // thumb32 data processing (plain binary immediate) instructions. + bool thumb32_BFC(Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb); + bool thumb32_BFI(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb); bool thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm); From 68885fdb3cb34ae6718acc41d4cc7aecbb13b386 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Feb 2021 09:32:01 -0500 Subject: [PATCH 3/6] thumb32: Implement SBFX/UBFX --- src/frontend/A32/decoder/thumb32.inc | 8 ++-- ...data_processing_plain_binary_immediate.cpp | 45 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 2 + 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index c8aa9b90..7c188f90 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -78,15 +78,15 @@ INST(thumb32_MOVW_imm, "MOVW (imm)", "11110i100100iiii0iiidd //INST(thumb32_SUB_imm_2, "SUB (imm)", "11110-101010----0---------------") INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiiddddiiiiiiii") //INST(thumb32_SSAT, "SSAT", "11110-110000----0---------------") -INST(thumb32_SSAT16, "SSAT16", "111100110010nnnn0000dddd0000iiii") //INST(thumb32_SSAT, "SSAT", "11110-110010----0---------------") -//INST(thumb32_SBFX, "SBFX", "11110-110100----0---------------") +INST(thumb32_SSAT16, "SSAT16", "111100110010nnnn0000dddd0000iiii") +INST(thumb32_SBFX, "SBFX", "111100110100nnnn0iiiddddii0wwwww") INST(thumb32_BFC, "BFC", "11110011011011110iiiddddii0bbbbb") INST(thumb32_BFI, "BFI", "111100110110nnnn0iiiddddii0bbbbb") //INST(thumb32_USAT, "USAT", "11110-111000----0---------------") -INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") //INST(thumb32_USAT, "USAT", "11110-111010----0---------------") -//INST(thumb32_UBFX, "UBFX", "11110-111100----0---------------") +INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") +INST(thumb32_UBFX, "UBFX", "111100111100nnnn0iiiddddii0wwwww") // Branches and Miscellaneous Control //INST(thumb32_MSR_banked, "MSR (banked)", "11110011100-----10-0------1-----") diff --git a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 086e2333..7a58edc4 100644 --- a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -3,6 +3,7 @@ * SPDX-License-Identifier: 0BSD */ +#include "common/bit_util.h" #include "frontend/A32/translate/impl/translate_thumb.h" namespace Dynarmic::A32 { @@ -100,10 +101,54 @@ bool ThumbTranslatorVisitor::thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> i return true; } +bool ThumbTranslatorVisitor::thumb32_SBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1) { + if (d == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const u32 lsbit = concatenate(imm3, imm2).ZeroExtend(); + const u32 widthm1_value = widthm1.ZeroExtend(); + const u32 msb = lsbit + widthm1_value; + if (msb >= Common::BitSize()) { + return UnpredictableInstruction(); + } + + constexpr size_t max_width = Common::BitSize(); + const auto width = widthm1_value + 1; + const auto left_shift_amount = static_cast(max_width - width - lsbit); + const auto right_shift_amount = static_cast(max_width - width); + const auto operand = ir.GetRegister(n); + const auto tmp = ir.LogicalShiftLeft(operand, ir.Imm8(left_shift_amount)); + const auto result = ir.ArithmeticShiftRight(tmp, ir.Imm8(right_shift_amount)); + + ir.SetRegister(d, result); + return true; +} + bool ThumbTranslatorVisitor::thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm) { return Saturation16(*this, n, d, sat_imm.ZeroExtend() + 1, &IREmitter::SignedSaturation); } +bool ThumbTranslatorVisitor::thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1) { + if (d == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const u32 lsbit = concatenate(imm3, imm2).ZeroExtend(); + const u32 widthm1_value = widthm1.ZeroExtend(); + const u32 msb = lsbit + widthm1_value; + if (msb >= Common::BitSize()) { + return UnpredictableInstruction(); + } + + const auto operand = ir.GetRegister(n); + const auto mask = ir.Imm32(Common::Ones(widthm1_value + 1)); + const auto result = ir.And(ir.LogicalShiftRight(operand, ir.Imm8(u8(lsbit))), mask); + + ir.SetRegister(d, result); + return true; +} + bool ThumbTranslatorVisitor::thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm) { return Saturation16(*this, n, d, sat_imm.ZeroExtend(), &IREmitter::UnsignedSaturation); } diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 2d84f3e9..d2749e57 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -164,7 +164,9 @@ struct ThumbTranslatorVisitor final { bool thumb32_BFI(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb); bool thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); + bool thumb32_SBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1); bool thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm); + bool thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1); bool thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm); // thumb32 miscellaneous control instructions From 9d5505422f85e32ada0d6c9679b760dda6500a10 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Feb 2021 09:46:19 -0500 Subject: [PATCH 4/6] thumb32: Implement ADD/SUB (imm 2) --- src/frontend/A32/decoder/thumb32.inc | 4 +-- ...data_processing_plain_binary_immediate.cpp | 26 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 2 ++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 7c188f90..d4ac8a4e 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -72,10 +72,10 @@ INST(thumb32_EOR_imm, "EOR (imm)", "11110v00100Snnnn0vvvdd // Data Processing (Plain Binary Immediate) //INST(thumb32_ADR, "ADR", "11110-10000011110---------------") -//INST(thumb32_ADD_imm_2, "ADD (imm)", "11110-100000----0---------------") +INST(thumb32_ADD_imm_2, "ADD (imm)", "11110i10000011010iiiddddiiiiiiii") INST(thumb32_MOVW_imm, "MOVW (imm)", "11110i100100iiii0iiiddddiiiiiiii") //INST(thumb32_ADR, "ADR", "11110-10101011110---------------") -//INST(thumb32_SUB_imm_2, "SUB (imm)", "11110-101010----0---------------") +INST(thumb32_SUB_imm_2, "SUB (imm)", "11110i10101011010iiiddddiiiiiiii") INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiiddddiiiiiiii") //INST(thumb32_SSAT, "SSAT", "11110-110000----0---------------") //INST(thumb32_SSAT, "SSAT", "11110-110010----0---------------") diff --git a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 7a58edc4..16ff97cf 100644 --- a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -35,6 +35,19 @@ static bool Saturation16(ThumbTranslatorVisitor& v, Reg n, Reg d, size_t saturat return true; } +bool ThumbTranslatorVisitor::thumb32_ADD_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8) { + if (d == Reg::PC) { + return UnpredictableInstruction(); + } + + const u32 imm = concatenate(imm1, imm3, imm8).ZeroExtend(); + const auto sp = ir.GetRegister(Reg::SP); + const auto result = ir.AddWithCarry(sp, ir.Imm32(imm), ir.Imm1(0)); + + ir.SetRegister(d, result.result); + return true; +} + bool ThumbTranslatorVisitor::thumb32_BFC(Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb) { if (d == Reg::PC) { return UnpredictableInstruction(); @@ -129,6 +142,19 @@ bool ThumbTranslatorVisitor::thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm) { return Saturation16(*this, n, d, sat_imm.ZeroExtend() + 1, &IREmitter::SignedSaturation); } +bool ThumbTranslatorVisitor::thumb32_SUB_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8) { + if (d == Reg::PC) { + return UnpredictableInstruction(); + } + + const u32 imm = concatenate(imm1, imm3, imm8).ZeroExtend(); + const auto sp = ir.GetRegister(Reg::SP); + const auto result = ir.SubWithCarry(sp, ir.Imm32(imm), ir.Imm1(1)); + + ir.SetRegister(d, result.result); + return true; +} + bool ThumbTranslatorVisitor::thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1) { if (d == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index d2749e57..5aab7395 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -160,12 +160,14 @@ struct ThumbTranslatorVisitor final { bool thumb32_EOR_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8); // thumb32 data processing (plain binary immediate) instructions. + bool thumb32_ADD_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_BFC(Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb); bool thumb32_BFI(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb); bool thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_SBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1); bool thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm); + bool thumb32_SUB_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1); bool thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm); From 2ac615b882955cb63936b7e0deb87840426337e5 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 25 Feb 2021 10:11:33 -0500 Subject: [PATCH 5/6] thumb32: Implement SSAT/USAT --- src/frontend/A32/decoder/thumb32.inc | 8 +++--- ...data_processing_plain_binary_immediate.cpp | 27 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 4 +++ .../A32/translate/translate_thumb.cpp | 21 +++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index d4ac8a4e..a8c396bd 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -77,15 +77,13 @@ INST(thumb32_MOVW_imm, "MOVW (imm)", "11110i100100iiii0iiidd //INST(thumb32_ADR, "ADR", "11110-10101011110---------------") INST(thumb32_SUB_imm_2, "SUB (imm)", "11110i10101011010iiiddddiiiiiiii") INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiiddddiiiiiiii") -//INST(thumb32_SSAT, "SSAT", "11110-110000----0---------------") -//INST(thumb32_SSAT, "SSAT", "11110-110010----0---------------") INST(thumb32_SSAT16, "SSAT16", "111100110010nnnn0000dddd0000iiii") +INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") +INST(thumb32_SSAT, "SSAT", "1111001100s0nnnn0iiiddddii0bbbbb") +INST(thumb32_USAT, "USAT", "1111001110s0nnnn0iiiddddii0bbbbb") INST(thumb32_SBFX, "SBFX", "111100110100nnnn0iiiddddii0wwwww") INST(thumb32_BFC, "BFC", "11110011011011110iiiddddii0bbbbb") INST(thumb32_BFI, "BFI", "111100110110nnnn0iiiddddii0bbbbb") -//INST(thumb32_USAT, "USAT", "11110-111000----0---------------") -//INST(thumb32_USAT, "USAT", "11110-111010----0---------------") -INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") INST(thumb32_UBFX, "UBFX", "111100111100nnnn0iiiddddii0wwwww") // Branches and Miscellaneous Control diff --git a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 16ff97cf..44b9a4b5 100644 --- a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -3,6 +3,7 @@ * SPDX-License-Identifier: 0BSD */ +#include "common/assert.h" #include "common/bit_util.h" #include "frontend/A32/translate/impl/translate_thumb.h" @@ -17,6 +18,24 @@ static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { using SaturationFunction = IR::ResultAndOverflow (IREmitter::*)(const IR::U32&, size_t); +static bool Saturation(ThumbTranslatorVisitor& v, bool sh, Reg n, Reg d, Imm<5> shift_amount, size_t saturate_to, SaturationFunction sat_fn) { + if (d == Reg::PC || n == Reg::PC) { + return v.UnpredictableInstruction(); + } + + if (sh && shift_amount == 0) { + ASSERT_FALSE("Invalid decode"); + } + + const auto shift = sh ? ShiftType::ASR : ShiftType::LSL; + const auto operand = v.EmitImmShift(v.ir.GetRegister(n), shift, shift_amount, v.ir.GetCFlag()); + const auto result = (v.ir.*sat_fn)(operand.result, saturate_to); + + v.ir.SetRegister(d, result.result); + v.ir.OrQFlag(result.overflow); + return true; +} + static bool Saturation16(ThumbTranslatorVisitor& v, Reg n, Reg d, size_t saturate_to, SaturationFunction sat_fn) { if (d == Reg::PC || n == Reg::PC) { return v.UnpredictableInstruction(); @@ -138,6 +157,10 @@ bool ThumbTranslatorVisitor::thumb32_SBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2 return true; } +bool ThumbTranslatorVisitor::thumb32_SSAT(bool sh, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> sat_imm) { + return Saturation(*this, sh, n, d, concatenate(imm3, imm2), sat_imm.ZeroExtend() + 1, &IREmitter::SignedSaturation); +} + bool ThumbTranslatorVisitor::thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm) { return Saturation16(*this, n, d, sat_imm.ZeroExtend() + 1, &IREmitter::SignedSaturation); } @@ -175,6 +198,10 @@ bool ThumbTranslatorVisitor::thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2 return true; } +bool ThumbTranslatorVisitor::thumb32_USAT(bool sh, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> sat_imm) { + return Saturation(*this, sh, n, d, concatenate(imm3, imm2), sat_imm.ZeroExtend(), &IREmitter::UnsignedSaturation); +} + bool ThumbTranslatorVisitor::thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm) { return Saturation16(*this, n, d, sat_imm.ZeroExtend(), &IREmitter::UnsignedSaturation); } diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 5aab7395..2cc116a8 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -67,6 +67,8 @@ struct ThumbTranslatorVisitor final { bool UndefinedInstruction(); bool RaiseException(Exception exception); + IR::ResultAndCarry EmitImmShift(IR::U32 value, ShiftType type, Imm<5> imm5, IR::U1 carry_in); + // thumb16 bool thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d); bool thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d); @@ -166,9 +168,11 @@ struct ThumbTranslatorVisitor final { bool thumb32_MOVT(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_MOVW_imm(Imm<1> imm1, Imm<4> imm4, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_SBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1); + bool thumb32_SSAT(bool sh, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> sat_imm); bool thumb32_SSAT16(Reg n, Reg d, Imm<4> sat_imm); bool thumb32_SUB_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8); bool thumb32_UBFX(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> widthm1); + bool thumb32_USAT(bool sh, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> sat_imm); bool thumb32_USAT16(Reg n, Reg d, Imm<4> sat_imm); // thumb32 miscellaneous control instructions diff --git a/src/frontend/A32/translate/translate_thumb.cpp b/src/frontend/A32/translate/translate_thumb.cpp index 7077c52c..0e52cde7 100644 --- a/src/frontend/A32/translate/translate_thumb.cpp +++ b/src/frontend/A32/translate/translate_thumb.cpp @@ -176,4 +176,25 @@ bool ThumbTranslatorVisitor::RaiseException(Exception exception) { return false; } +IR::ResultAndCarry ThumbTranslatorVisitor::EmitImmShift(IR::U32 value, ShiftType type, Imm<5> imm5, IR::U1 carry_in) { + u8 imm5_value = imm5.ZeroExtend(); + switch (type) { + case ShiftType::LSL: + return ir.LogicalShiftLeft(value, ir.Imm8(imm5_value), carry_in); + case ShiftType::LSR: + imm5_value = imm5_value ? imm5_value : 32; + return ir.LogicalShiftRight(value, ir.Imm8(imm5_value), carry_in); + case ShiftType::ASR: + imm5_value = imm5_value ? imm5_value : 32; + return ir.ArithmeticShiftRight(value, ir.Imm8(imm5_value), carry_in); + case ShiftType::ROR: + if (imm5_value) { + return ir.RotateRight(value, ir.Imm8(imm5_value), carry_in); + } else { + return ir.RotateRightExtended(value, carry_in); + } + } + UNREACHABLE(); +} + } // namespace Dynarmic::A32 From 67e954a4cfd24f94503c4bf22f40c37125d40468 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Tue, 2 Mar 2021 20:51:40 +0000 Subject: [PATCH 6/6] thumb32_data_processing_plain_binary_immediate: Make invalid {S,U}SSAT16 decode undefined --- src/frontend/A32/decoder/thumb32.inc | 1 + .../impl/thumb32_data_processing_plain_binary_immediate.cpp | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index a8c396bd..3c4a29bb 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -77,6 +77,7 @@ INST(thumb32_MOVW_imm, "MOVW (imm)", "11110i100100iiii0iiidd //INST(thumb32_ADR, "ADR", "11110-10101011110---------------") INST(thumb32_SUB_imm_2, "SUB (imm)", "11110i10101011010iiiddddiiiiiiii") INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiiddddiiiiiiii") +INST(thumb32_UDF, "Invalid decoding", "11110011-010----0000----0001----") INST(thumb32_SSAT16, "SSAT16", "111100110010nnnn0000dddd0000iiii") INST(thumb32_USAT16, "USAT16", "111100111010nnnn0000dddd0000iiii") INST(thumb32_SSAT, "SSAT", "1111001100s0nnnn0iiiddddii0bbbbb") diff --git a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 44b9a4b5..5094ac31 100644 --- a/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -19,14 +19,12 @@ static IR::U16 MostSignificantHalf(A32::IREmitter& ir, IR::U32 value) { using SaturationFunction = IR::ResultAndOverflow (IREmitter::*)(const IR::U32&, size_t); static bool Saturation(ThumbTranslatorVisitor& v, bool sh, Reg n, Reg d, Imm<5> shift_amount, size_t saturate_to, SaturationFunction sat_fn) { + ASSERT_MSG(!(sh && shift_amount == 0), "Invalid decode"); + if (d == Reg::PC || n == Reg::PC) { return v.UnpredictableInstruction(); } - if (sh && shift_amount == 0) { - ASSERT_FALSE("Invalid decode"); - } - const auto shift = sh ? ShiftType::ASR : ShiftType::LSL; const auto operand = v.EmitImmShift(v.ir.GetRegister(n), shift, shift_amount, v.ir.GetCFlag()); const auto result = (v.ir.*sat_fn)(operand.result, saturate_to);