From 7d20f3b861f818dbe52a9c1bf8a378f676ed0edd Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 6 May 2019 17:48:27 +0100 Subject: [PATCH] A32/translate_thumb: Split off implementation into thumb16 and thumb32 --- src/CMakeLists.txt | 3 + src/frontend/A32/translate/impl/thumb16.cpp | 928 ++++++++++++++++ src/frontend/A32/translate/impl/thumb32.cpp | 43 + .../A32/translate/impl/translate_thumb.h | 119 +++ .../A32/translate/translate_thumb.cpp | 993 +----------------- 5 files changed, 1111 insertions(+), 975 deletions(-) create mode 100644 src/frontend/A32/translate/impl/thumb16.cpp create mode 100644 src/frontend/A32/translate/impl/thumb32.cpp create mode 100644 src/frontend/A32/translate/impl/translate_thumb.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23207a9d..01e1238e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -112,7 +112,10 @@ add_library(dynarmic frontend/A32/translate/impl/saturated.cpp frontend/A32/translate/impl/status_register_access.cpp frontend/A32/translate/impl/synchronization.cpp + frontend/A32/translate/impl/thumb16.cpp + frontend/A32/translate/impl/thumb32.cpp frontend/A32/translate/impl/translate_arm.h + frontend/A32/translate/impl/translate_thumb.h frontend/A32/translate/impl/vfp.cpp frontend/A32/translate/translate.cpp frontend/A32/translate/translate.h diff --git a/src/frontend/A32/translate/impl/thumb16.cpp b/src/frontend/A32/translate/impl/thumb16.cpp new file mode 100644 index 00000000..69922451 --- /dev/null +++ b/src/frontend/A32/translate/impl/thumb16.cpp @@ -0,0 +1,928 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2016 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#include "translate_thumb.h" + +#include + +namespace Dynarmic::A32 { + +// LSLS , , # +bool ThumbTranslatorVisitor::thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) { + const u8 shift_n = imm5.ZeroExtend(); + const auto cpsr_c = ir.GetCFlag(); + const auto result = ir.LogicalShiftLeft(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; +} + +// LSRS , , # +bool ThumbTranslatorVisitor::thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) { + const u8 shift_n = imm5 != 0 ? imm5.ZeroExtend() : u8(32); + const auto cpsr_c = ir.GetCFlag(); + const auto result = ir.LogicalShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; +} + +// ASRS , , # +bool ThumbTranslatorVisitor::thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) { + const u8 shift_n = imm5 != 0 ? imm5.ZeroExtend() : u8(32); + const auto cpsr_c = ir.GetCFlag(); + const auto result = ir.ArithmeticShiftRight(ir.GetRegister(m), ir.Imm8(shift_n), cpsr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; +} + +// ADDS , , +// Note that it is not possible to encode Rd == R15. +bool ThumbTranslatorVisitor::thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) { + const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0)); + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// SUBS , , +// Note that it is not possible to encode Rd == R15. +bool ThumbTranslatorVisitor::thumb16_SUB_reg(Reg m, Reg n, Reg d) { + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1)); + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// ADDS , , # +// Rd can never encode R15. +bool ThumbTranslatorVisitor::thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) { + const u32 imm32 = imm3.ZeroExtend(); + const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0)); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// SUBS , , # +// Rd can never encode R15. +bool ThumbTranslatorVisitor::thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d) { + const u32 imm32 = imm3.ZeroExtend(); + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1)); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// MOVS , # +// Rd can never encode R15. +bool ThumbTranslatorVisitor::thumb16_MOV_imm(Reg d, Imm<8> imm8) { + const u32 imm32 = imm8.ZeroExtend(); + const auto result = ir.Imm32(imm32); + + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// CMP , # +bool ThumbTranslatorVisitor::thumb16_CMP_imm(Reg n, Imm<8> imm8) { + const u32 imm32 = imm8.ZeroExtend(); + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1)); + + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// ADDS , # +// Rd can never encode R15. +bool ThumbTranslatorVisitor::thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) { + const u32 imm32 = imm8.ZeroExtend(); + const Reg d = d_n; + const Reg n = d_n; + const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(0)); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// SUBS , , # +// Rd can never encode R15. +bool ThumbTranslatorVisitor::thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8) { + const u32 imm32 = imm8.ZeroExtend(); + const Reg d = d_n; + const Reg n = d_n; + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.Imm1(1)); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// ANDS , +// Note that it is not possible to encode Rdn == R15. +bool ThumbTranslatorVisitor::thumb16_AND_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m)); + + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// EORS , +// Note that it is not possible to encode Rdn == R15. +bool ThumbTranslatorVisitor::thumb16_EOR_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto result = ir.Eor(ir.GetRegister(n), ir.GetRegister(m)); + + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// LSLS , +bool ThumbTranslatorVisitor::thumb16_LSL_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); + const auto apsr_c = ir.GetCFlag(); + const auto result_carry = ir.LogicalShiftLeft(ir.GetRegister(n), shift_n, apsr_c); + + ir.SetRegister(d, result_carry.result); + ir.SetNFlag(ir.MostSignificantBit(result_carry.result)); + ir.SetZFlag(ir.IsZero(result_carry.result)); + ir.SetCFlag(result_carry.carry); + return true; +} + +// LSRS , +bool ThumbTranslatorVisitor::thumb16_LSR_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); + const auto cpsr_c = ir.GetCFlag(); + const auto result = ir.LogicalShiftRight(ir.GetRegister(n), shift_n, cpsr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; +} + +// ASRS , +bool ThumbTranslatorVisitor::thumb16_ASR_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); + const auto cpsr_c = ir.GetCFlag(); + const auto result = ir.ArithmeticShiftRight(ir.GetRegister(n), shift_n, cpsr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; +} + +// ADCS , +// Note that it is not possible to encode Rd == R15. +bool ThumbTranslatorVisitor::thumb16_ADC_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto aspr_c = ir.GetCFlag(); + const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// SBCS , +// Note that it is not possible to encode Rd == R15. +bool ThumbTranslatorVisitor::thumb16_SBC_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto aspr_c = ir.GetCFlag(); + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), aspr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// RORS , +bool ThumbTranslatorVisitor::thumb16_ROR_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); + const auto cpsr_c = ir.GetCFlag(); + const auto result = ir.RotateRight(ir.GetRegister(n), shift_n, cpsr_c); + + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + return true; +} + +// TST , +bool ThumbTranslatorVisitor::thumb16_TST_reg(Reg m, Reg n) { + const auto result = ir.And(ir.GetRegister(n), ir.GetRegister(m)); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// RSBS , , #0 +// Rd can never encode R15. +bool ThumbTranslatorVisitor::thumb16_RSB_imm(Reg n, Reg d) { + const auto result = ir.SubWithCarry(ir.Imm32(0), ir.GetRegister(n), ir.Imm1(1)); + ir.SetRegister(d, result.result); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// CMP , +bool ThumbTranslatorVisitor::thumb16_CMP_reg_t1(Reg m, Reg n) { + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1)); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// CMN , +bool ThumbTranslatorVisitor::thumb16_CMN_reg(Reg m, Reg n) { + const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0)); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// ORRS , +// Rd cannot encode R15. +bool ThumbTranslatorVisitor::thumb16_ORR_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto result = ir.Or(ir.GetRegister(m), ir.GetRegister(n)); + + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// MULS , , +// Rd cannot encode R15. +bool ThumbTranslatorVisitor::thumb16_MUL_reg(Reg n, Reg d_m) { + const Reg d = d_m; + const Reg m = d_m; + const auto result = ir.Mul(ir.GetRegister(m), ir.GetRegister(n)); + + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// BICS , +// Rd cannot encode R15. +bool ThumbTranslatorVisitor::thumb16_BIC_reg(Reg m, Reg d_n) { + const Reg d = d_n; + const Reg n = d_n; + const auto result = ir.And(ir.GetRegister(n), ir.Not(ir.GetRegister(m))); + + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// MVNS , +// Rd cannot encode R15. +bool ThumbTranslatorVisitor::thumb16_MVN_reg(Reg m, Reg d) { + const auto result = ir.Not(ir.GetRegister(m)); + ir.SetRegister(d, result); + ir.SetNFlag(ir.MostSignificantBit(result)); + ir.SetZFlag(ir.IsZero(result)); + return true; +} + +// ADD , +bool ThumbTranslatorVisitor::thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) { + const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo; + const Reg n = d_n; + if (n == Reg::PC && m == Reg::PC) { + return UnpredictableInstruction(); + } + + const Reg d = d_n; + const auto result = ir.AddWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(0)); + if (d == Reg::PC) { + ir.ALUWritePC(result.result); + // Return to dispatch as we can't predict what PC is going to be. Stop compilation. + ir.SetTerm(IR::Term::FastDispatchHint{}); + return false; + } else { + ir.SetRegister(d, result.result); + return true; + } +} + +// CMP , +bool ThumbTranslatorVisitor::thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) { + const Reg n = n_hi ? (n_lo + 8) : n_lo; + if (n < Reg::R8 && m < Reg::R8) { + return UnpredictableInstruction(); + } + if (n == Reg::PC || m == Reg::PC) { + return UnpredictableInstruction(); + } + + const auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1)); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; +} + +// MOV , +bool ThumbTranslatorVisitor::thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) { + const Reg d = d_hi ? (d_lo + 8) : d_lo; + const auto result = ir.GetRegister(m); + + if (d == Reg::PC) { + ir.ALUWritePC(result); + ir.SetTerm(IR::Term::FastDispatchHint{}); + return false; + } else { + ir.SetRegister(d, result); + return true; + } +} + +// LDR ,